- Implement enumerating mixer source and destination lines
[reactos.git] / reactos / drivers / wdm / audio / legacy / wdmaud / mixer.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/mixer.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9 #include "wdmaud.h"
10
11 const GUID KSNODETYPE_DAC = {0x507AE360L, 0xC554, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
12 const GUID KSNODETYPE_ADC = {0x4D837FE0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
13 const GUID KSNODETYPE_AGC = {0xE88C9BA0L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
14 const GUID KSNODETYPE_LOUDNESS = {0x41887440L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
15 const GUID KSNODETYPE_MUTE = {0x02B223C0L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
16 const GUID KSNODETYPE_TONE = {0x7607E580L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
17 const GUID KSNODETYPE_VOLUME = {0x3A5ACC00L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
18 const GUID KSNODETYPE_PEAKMETER = {0xa085651e, 0x5f0d, 0x4b36, {0xa8, 0x69, 0xd1, 0x95, 0xd6, 0xab, 0x4b, 0x9e}};
19 const GUID KSNODETYPE_MUX = {0x2CEAF780, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
20 const GUID KSNODETYPE_STEREO_WIDE = {0xA9E69800L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
21 const GUID KSNODETYPE_CHORUS = {0x20173F20L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
22 const GUID KSNODETYPE_REVERB = {0xEF0328E0L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
23 const GUID KSNODETYPE_SUPERMIX = {0xE573ADC0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
24
25
26 LPMIXERLINE_SOURCE
27 GetSourceMixerLine(
28 LPMIXER_INFO MixerInfo,
29 DWORD dwSource)
30 {
31 PLIST_ENTRY Entry;
32 LPMIXERLINE_SOURCE MixerLineSrc;
33
34 /* get first entry */
35 Entry = MixerInfo->SourceLineList.Flink;
36
37 while(Entry != &MixerInfo->SourceLineList)
38 {
39 MixerLineSrc = (LPMIXERLINE_SOURCE)CONTAINING_RECORD(Entry, MIXERLINE_SOURCE, Entry);
40 DPRINT("dwSource %x dwSource %x\n", MixerLineSrc->Line.dwSource, dwSource);
41 if (MixerLineSrc->Line.dwSource == dwSource)
42 return MixerLineSrc;
43
44 Entry = Entry->Flink;
45 }
46
47 return NULL;
48 }
49
50 LPMIXERLINE_SOURCE
51 GetSourceMixerLineByLineId(
52 LPMIXER_INFO MixerInfo,
53 DWORD dwLineID)
54 {
55 PLIST_ENTRY Entry;
56 LPMIXERLINE_SOURCE MixerLineSrc;
57
58 /* get first entry */
59 Entry = MixerInfo->SourceLineList.Flink;
60
61 while(Entry != &MixerInfo->SourceLineList)
62 {
63 MixerLineSrc = (LPMIXERLINE_SOURCE)CONTAINING_RECORD(Entry, MIXERLINE_SOURCE, Entry);
64 DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID);
65 if (MixerLineSrc->Line.dwLineID == dwLineID)
66 return MixerLineSrc;
67
68 Entry = Entry->Flink;
69 }
70
71 return NULL;
72 }
73
74
75
76 ULONG
77 GetPinCount(
78 IN PFILE_OBJECT FileObject)
79 {
80 KSPROPERTY Pin;
81 NTSTATUS Status;
82 ULONG NumPins, BytesReturned;
83
84 Pin.Flags = KSPROPERTY_TYPE_GET;
85 Pin.Set = KSPROPSETID_Pin;
86 Pin.Id = KSPROPERTY_PIN_CTYPES;
87
88 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
89 if (!NT_SUCCESS(Status))
90 return 0;
91
92 return NumPins;
93 }
94
95
96 ULONG
97 GetSysAudioDeviceCount(
98 IN PDEVICE_OBJECT DeviceObject)
99 {
100 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
101 KSPROPERTY Pin;
102 ULONG Count, BytesReturned;
103 NTSTATUS Status;
104
105 /* setup the query request */
106 Pin.Set = KSPROPSETID_Sysaudio;
107 Pin.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
108 Pin.Flags = KSPROPERTY_TYPE_GET;
109
110 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
111
112 /* query sysaudio for the device count */
113 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
114 if (!NT_SUCCESS(Status))
115 return 0;
116
117 return Count;
118 }
119
120 NTSTATUS
121 GetSysAudioDevicePnpName(
122 IN PDEVICE_OBJECT DeviceObject,
123 IN ULONG DeviceIndex,
124 OUT LPWSTR * Device)
125 {
126 ULONG BytesReturned;
127 KSP_PIN Pin;
128 NTSTATUS Status;
129 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
130
131 /* first check if the device index is within bounds */
132 if (DeviceIndex >= GetSysAudioDeviceCount(DeviceObject))
133 return STATUS_INVALID_PARAMETER;
134
135 /* setup the query request */
136 Pin.Property.Set = KSPROPSETID_Sysaudio;
137 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
138 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
139 Pin.PinId = DeviceIndex;
140
141 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
142
143 /* query sysaudio for the device path */
144 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), NULL, 0, &BytesReturned);
145
146 /* check if the request failed */
147 if (Status != STATUS_BUFFER_TOO_SMALL || BytesReturned == 0)
148 return STATUS_UNSUCCESSFUL;
149
150 /* allocate buffer for the device */
151 *Device = ExAllocatePool(NonPagedPool, BytesReturned);
152 if (!Device)
153 return STATUS_INSUFFICIENT_RESOURCES;
154
155 /* query sysaudio again for the device path */
156 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), (PVOID)*Device, BytesReturned, &BytesReturned);
157
158 if (!NT_SUCCESS(Status))
159 {
160 /* failed */
161 ExFreePool(*Device);
162 return Status;
163 }
164
165 return Status;
166 }
167
168 NTSTATUS
169 OpenDevice(
170 IN LPWSTR Device,
171 OUT PHANDLE DeviceHandle,
172 OUT PFILE_OBJECT * FileObject)
173 {
174 NTSTATUS Status;
175 HANDLE hDevice;
176
177 /* now open the device */
178 Status = WdmAudOpenSysAudioDevice(Device, &hDevice);
179
180 if (!NT_SUCCESS(Status))
181 {
182 return Status;
183 }
184
185 *DeviceHandle = hDevice;
186
187 if (FileObject)
188 {
189 Status = ObReferenceObjectByHandle(hDevice, FILE_READ_DATA | FILE_WRITE_DATA, IoFileObjectType, KernelMode, (PVOID*)FileObject, NULL);
190
191 if (!NT_SUCCESS(Status))
192 {
193 ZwClose(hDevice);
194 }
195 }
196
197 return Status;
198
199 }
200
201
202 NTSTATUS
203 OpenSysAudioDeviceByIndex(
204 IN PDEVICE_OBJECT DeviceObject,
205 IN ULONG DeviceIndex,
206 IN PHANDLE DeviceHandle,
207 IN PFILE_OBJECT * FileObject)
208 {
209 LPWSTR Device = NULL;
210 NTSTATUS Status;
211
212 Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, &Device);
213 if (!NT_SUCCESS(Status))
214 return Status;
215
216 Status = OpenDevice(Device, DeviceHandle, FileObject);
217
218 /* free device buffer */
219 ExFreePool(Device);
220
221 return Status;
222 }
223
224 NTSTATUS
225 GetFilterNodeProperty(
226 IN PFILE_OBJECT FileObject,
227 IN ULONG PropertyId,
228 PKSMULTIPLE_ITEM * Item)
229 {
230 NTSTATUS Status;
231 ULONG BytesReturned;
232 PKSMULTIPLE_ITEM MultipleItem;
233 KSPROPERTY Property;
234
235 /* setup query request */
236 Property.Id = PropertyId;
237 Property.Flags = KSPROPERTY_TYPE_GET;
238 Property.Set = KSPROPSETID_Topology;
239
240 /* query for required size */
241 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
242
243 /* check for success */
244 if (Status != STATUS_MORE_ENTRIES)
245 return Status;
246
247 /* allocate buffer */
248 MultipleItem = (PKSMULTIPLE_ITEM)ExAllocatePool(NonPagedPool, BytesReturned);
249 if (!MultipleItem)
250 return STATUS_INSUFFICIENT_RESOURCES;
251
252 /* query for required size */
253 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
254
255 if (!NT_SUCCESS(Status))
256 {
257 /* failed */
258 ExFreePool(MultipleItem);
259 return Status;
260 }
261
262 *Item = MultipleItem;
263 return Status;
264 }
265
266 ULONG
267 CountNodeType(
268 PKSMULTIPLE_ITEM MultipleItem,
269 LPGUID NodeType)
270 {
271 ULONG Count;
272 ULONG Index;
273 LPGUID Guid;
274
275 Count = 0;
276 Guid = (LPGUID)(MultipleItem+1);
277
278 /* iterate through node type array */
279 for(Index = 0; Index < MultipleItem->Count; Index++)
280 {
281 if (IsEqualGUIDAligned(NodeType, Guid))
282 {
283 /* found matching guid */
284 Count++;
285 }
286 Guid++;
287 }
288 return Count;
289 }
290
291 ULONG
292 GetNodeTypeIndex(
293 PKSMULTIPLE_ITEM MultipleItem,
294 LPGUID NodeType)
295 {
296 ULONG Index;
297 LPGUID Guid;
298
299 Guid = (LPGUID)(MultipleItem+1);
300
301 /* iterate through node type array */
302 for(Index = 0; Index < MultipleItem->Count; Index++)
303 {
304 if (IsEqualGUIDAligned(NodeType, Guid))
305 {
306 /* found matching guid */
307 return Index;
308 }
309 Guid++;
310 }
311 return MAXULONG;
312 }
313
314 ULONG
315 GetControlTypeFromTopologyNode(
316 IN LPGUID NodeType)
317 {
318 if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_AGC))
319 {
320 // automatic gain control
321 return MIXERCONTROL_CONTROLTYPE_ONOFF;
322 }
323 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_LOUDNESS))
324 {
325 // loudness control
326 return MIXERCONTROL_CONTROLTYPE_LOUDNESS;
327 }
328 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUTE ))
329 {
330 // mute control
331 return MIXERCONTROL_CONTROLTYPE_MUTE;
332 }
333 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_TONE))
334 {
335 // tpne control
336 //FIXME
337 // MIXERCONTROL_CONTROLTYPE_ONOFF if KSPROPERTY_AUDIO_BASS_BOOST is supported
338 // MIXERCONTROL_CONTROLTYPE_BASS if KSPROPERTY_AUDIO_BASS is supported
339 // MIXERCONTROL_CONTROLTYPE_TREBLE if KSPROPERTY_AUDIO_TREBLE is supported
340 UNIMPLEMENTED;
341 return MIXERCONTROL_CONTROLTYPE_ONOFF;
342 }
343 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_VOLUME))
344 {
345 // volume control
346 return MIXERCONTROL_CONTROLTYPE_VOLUME;
347 }
348 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_PEAKMETER))
349 {
350 // peakmeter control
351 return MIXERCONTROL_CONTROLTYPE_PEAKMETER;
352 }
353 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX))
354 {
355 // mux control
356 return MIXERCONTROL_CONTROLTYPE_MUX;
357 }
358 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX))
359 {
360 // mux control
361 return MIXERCONTROL_CONTROLTYPE_MUX;
362 }
363 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_STEREO_WIDE))
364 {
365 // stero wide control
366 return MIXERCONTROL_CONTROLTYPE_FADER;
367 }
368 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_CHORUS))
369 {
370 // chorus control
371 return MIXERCONTROL_CONTROLTYPE_FADER;
372 }
373 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_REVERB))
374 {
375 // reverb control
376 return MIXERCONTROL_CONTROLTYPE_FADER;
377 }
378 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_SUPERMIX))
379 {
380 // supermix control
381 // MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported
382 UNIMPLEMENTED;
383 return MIXERCONTROL_CONTROLTYPE_VOLUME;
384 }
385 UNIMPLEMENTED
386 return 0;
387 }
388
389 NTSTATUS
390 GetPhysicalConnection(
391 IN PFILE_OBJECT FileObject,
392 IN ULONG PinId,
393 OUT PKSPIN_PHYSICALCONNECTION *OutConnection)
394 {
395 KSP_PIN Pin;
396 NTSTATUS Status;
397 ULONG BytesReturned;
398 PKSPIN_PHYSICALCONNECTION Connection;
399
400 /* setup the request */
401 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
402 Pin.Property.Id = KSPROPERTY_PIN_PHYSICALCONNECTION;
403 Pin.Property.Set = KSPROPSETID_Pin;
404 Pin.PinId = PinId;
405
406 /* query the pin for the physical connection */
407 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
408
409 if (Status == STATUS_NOT_FOUND)
410 {
411 /* pin does not have a physical connection */
412 return Status;
413 }
414
415 Connection = ExAllocatePool(NonPagedPool, BytesReturned);
416 if (!Connection)
417 {
418 /* not enough memory */
419 return STATUS_INSUFFICIENT_RESOURCES;
420 }
421
422 /* query the pin for the physical connection */
423 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Connection, BytesReturned, &BytesReturned);
424 if (!NT_SUCCESS(Status))
425 {
426 /* failed to query the physical connection */
427 ExFreePool(Connection);
428 return Status;
429 }
430
431 /* store connection */
432 *OutConnection = Connection;
433 return Status;
434 }
435
436 NTSTATUS
437 GetNodeIndexes(
438 IN PKSMULTIPLE_ITEM MultipleItem,
439 IN ULONG NodeIndex,
440 IN ULONG bNode,
441 IN ULONG bFrom,
442 OUT PULONG NodeReferenceCount,
443 OUT PULONG *NodeReference)
444 {
445 ULONG Index, Count = 0;
446 PKSTOPOLOGY_CONNECTION Connection;
447 PULONG Refs;
448
449 /* KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION */
450 Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
451
452 /* first count all referenced nodes */
453 for(Index = 0; Index < MultipleItem->Count; Index++)
454 {
455 //DPRINT1("FromPin %u FromNode %u ToPin %u ToNode %u\n", Connection->FromNodePin, Connection->FromNode, Connection->ToNodePin, Connection->ToNode);
456 if (bNode)
457 {
458 if (bFrom)
459 {
460 if (Connection->FromNode == NodeIndex)
461 {
462 /* node id has a connection */
463 Count++;
464 }
465 }
466 else
467 {
468 if (Connection->ToNode == NodeIndex)
469 {
470 /* node id has a connection */
471 Count++;
472 }
473 }
474 }
475 else
476 {
477 if (bFrom)
478 {
479 if (Connection->FromNodePin == NodeIndex)
480 {
481 /* node id has a connection */
482 Count++;
483 }
484 }
485 else
486 {
487 if (Connection->ToNodePin == NodeIndex)
488 {
489 /* node id has a connection */
490 Count++;
491 }
492 }
493 }
494
495
496 /* move to next connection */
497 Connection++;
498 }
499
500 ASSERT(Count != 0);
501
502 /* now allocate node index array */
503 Refs = ExAllocatePool(NonPagedPool, sizeof(ULONG) * Count);
504 if (!Refs)
505 {
506 /* not enough memory */
507 return STATUS_INSUFFICIENT_RESOURCES;
508 }
509
510 Count = 0;
511 Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
512 for(Index = 0; Index < MultipleItem->Count; Index++)
513 {
514 if (bNode)
515 {
516 if (bFrom)
517 {
518 if (Connection->FromNode == NodeIndex)
519 {
520 /* node id has a connection */
521 Refs[Count] = Index;
522 Count++;
523 }
524 }
525 else
526 {
527 if (Connection->ToNode == NodeIndex)
528 {
529 /* node id has a connection */
530 Refs[Count] = Index;
531 Count++;
532 }
533 }
534 }
535 else
536 {
537 if (bFrom)
538 {
539 if (Connection->FromNodePin == NodeIndex)
540 {
541 /* node id has a connection */
542 Refs[Count] = Index;
543 Count++;
544 }
545 }
546 else
547 {
548 if (Connection->ToNodePin == NodeIndex)
549 {
550 /* node id has a connection */
551 Refs[Count] = Index;
552 Count++;
553 }
554 }
555 }
556
557 /* move to next connection */
558 Connection++;
559 }
560
561 /* store result */
562 *NodeReference = Refs;
563 *NodeReferenceCount = Count;
564
565 return STATUS_SUCCESS;
566 }
567
568
569 NTSTATUS
570 GetTargetPinsByNodeConnectionIndex(
571 IN PKSMULTIPLE_ITEM NodeConnections,
572 IN PKSMULTIPLE_ITEM NodeTypes,
573 IN ULONG bUpDirection,
574 IN ULONG NodeConnectionIndex,
575 OUT PULONG Pins)
576 {
577 PKSTOPOLOGY_CONNECTION Connection;
578 ULONG PinId, NodeConnectionCount, Index;
579 PULONG NodeConnection;
580 NTSTATUS Status;
581
582
583 /* sanity check */
584 ASSERT(NodeConnectionIndex < NodeConnections->Count);
585
586 Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1);
587
588 DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection[NodeConnectionIndex].FromNode, Connection[NodeConnectionIndex].FromNodePin, Connection[NodeConnectionIndex].ToNode, Connection[NodeConnectionIndex].ToNodePin );
589
590 if ((Connection[NodeConnectionIndex].ToNode == KSFILTER_NODE && bUpDirection == FALSE) ||
591 (Connection[NodeConnectionIndex].FromNode == KSFILTER_NODE && bUpDirection == TRUE))
592 {
593 /* iteration stops here */
594 if (bUpDirection)
595 PinId = Connection[NodeConnectionIndex].FromNodePin;
596 else
597 PinId = Connection[NodeConnectionIndex].ToNodePin;
598
599 DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId, Pins[PinId]);
600
601 /* mark pin index as a target pin */
602 Pins[PinId] = TRUE;
603 return STATUS_SUCCESS;
604 }
605
606 /* get all node indexes referenced by that node */
607 if (bUpDirection)
608 {
609 Status = GetNodeIndexes(NodeConnections, Connection[NodeConnectionIndex].FromNode, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
610 }
611 else
612 {
613 Status = GetNodeIndexes(NodeConnections, Connection[NodeConnectionIndex].ToNode, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
614 }
615
616 if (NT_SUCCESS(Status))
617 {
618 for(Index = 0; Index < NodeConnectionCount; Index++)
619 {
620 /* iterate recursively into the nodes */
621 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins);
622 ASSERT(Status == STATUS_SUCCESS);
623 }
624 /* free node connection indexes */
625 ExFreePool(NodeConnection);
626 }
627
628 return Status;
629 }
630
631
632
633 NTSTATUS
634 GetTargetPins(
635 PKSMULTIPLE_ITEM NodeTypes,
636 PKSMULTIPLE_ITEM NodeConnections,
637 IN ULONG NodeIndex,
638 IN ULONG bUpDirection,
639 PULONG Pins,
640 ULONG PinCount)
641 {
642 ULONG NodeConnectionCount, Index;
643 NTSTATUS Status;
644 PULONG NodeConnection;
645
646 /* sanity check */
647 ASSERT(NodeIndex != (ULONG)-1);
648
649 /* get all node indexes referenced by that pin */
650 if (bUpDirection)
651 Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
652 else
653 Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
654
655 DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex, Status, NodeConnectionCount);
656
657 if (NT_SUCCESS(Status))
658 {
659 for(Index = 0; Index < NodeConnectionCount; Index++)
660 {
661 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins);
662 ASSERT(Status == STATUS_SUCCESS);
663 }
664 ExFreePool(NodeConnection);
665 }
666
667 return Status;
668 }
669
670 PULONG
671 AllocatePinArray(
672 ULONG PinCount)
673 {
674 PULONG Pins = ExAllocatePool(NonPagedPool, PinCount * sizeof(ULONG));
675 if (!Pins)
676 return NULL;
677
678 RtlZeroMemory(Pins, sizeof(ULONG) * PinCount);
679
680 return Pins;
681 }
682
683 NTSTATUS
684 AddMixerSourceLine(
685 IN OUT LPMIXER_INFO MixerInfo,
686 IN PFILE_OBJECT FileObject,
687 IN ULONG PinId)
688 {
689 LPMIXERLINE_SOURCE SrcLine;
690 NTSTATUS Status;
691 KSP_PIN Pin;
692 LPWSTR PinName;
693 GUID NodeType;
694 ULONG BytesReturned;
695
696 /* allocate src mixer line */
697 SrcLine = (LPMIXERLINE_SOURCE)ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_SOURCE));
698 if (!SrcLine)
699 return STATUS_INSUFFICIENT_RESOURCES;
700
701 /* zero struct */
702 RtlZeroMemory(SrcLine, sizeof(MIXERLINE_SOURCE));
703
704 /* initialize mixer src line */
705 SrcLine->FileObject = FileObject;
706 SrcLine->PinId = PinId;
707 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
708
709 /* initialize mixer destination line */
710 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
711 SrcLine->Line.dwDestination = 0;
712 SrcLine->Line.dwSource = MixerInfo->DestinationLine.cConnections;
713 SrcLine->Line.dwLineID = (MixerInfo->DestinationLine.cConnections * 0x10000);
714 SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
715 SrcLine->Line.dwUser = 0;
716 SrcLine->Line.cChannels = MixerInfo->DestinationLine.cChannels;
717 SrcLine->Line.cConnections = 0;
718 SrcLine->Line.cControls = 1; //FIXME
719
720 //HACK
721 SrcLine->LineControls = ExAllocatePool(NonPagedPool, SrcLine->Line.cControls * sizeof(MIXERCONTROLW));
722 if (!SrcLine->LineControls)
723 {
724 /* not enough memory */
725 ExFreePool(SrcLine);
726 return STATUS_INSUFFICIENT_RESOURCES;
727 }
728
729 /* clear line controls */
730 RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW));
731
732 /* fill in pseudo mixer control */
733 SrcLine->LineControls->dwControlID = 1; //FIXME
734 SrcLine->LineControls->cbStruct = sizeof(MIXERCONTROLW);
735 SrcLine->LineControls->fdwControl = 0;
736 SrcLine->LineControls->cMultipleItems = 0;
737 wcscpy(SrcLine->LineControls->szName, L"test");
738 wcscpy(SrcLine->LineControls->szShortName, L"test");
739
740
741 /* get pin category */
742 Pin.PinId = PinId;
743 Pin.Reserved = 0;
744 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
745 Pin.Property.Set = KSPROPSETID_Pin;
746 Pin.Property.Id = KSPROPERTY_PIN_CATEGORY;
747
748 /* try get pin category */
749 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)&NodeType, sizeof(GUID), &BytesReturned);
750 if (NT_SUCCESS(Status))
751 {
752 //FIXME
753 //map component type
754 }
755
756 /* retrieve pin name */
757 Pin.PinId = PinId;
758 Pin.Reserved = 0;
759 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
760 Pin.Property.Set = KSPROPSETID_Pin;
761 Pin.Property.Id = KSPROPERTY_PIN_NAME;
762
763 /* try get pin name size */
764 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
765
766 if (Status != STATUS_MORE_ENTRIES)
767 {
768 SrcLine->Line.szShortName[0] = L'\0';
769 SrcLine->Line.szName[0] = L'\0';
770 }
771 else
772 {
773 PinName = (LPWSTR)ExAllocatePool(NonPagedPool, BytesReturned);
774 if (PinName)
775 {
776 /* try get pin name */
777 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)PinName, BytesReturned, &BytesReturned);
778
779 if (NT_SUCCESS(Status))
780 {
781 RtlMoveMemory(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
782 SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
783
784 RtlMoveMemory(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
785 SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
786 }
787 ExFreePool(PinName);
788 }
789 }
790
791 SrcLine->Line.Target.dwType = 1;
792 SrcLine->Line.Target.dwDeviceID = MixerInfo->DestinationLine.Target.dwDeviceID;
793 SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
794 SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
795 SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
796 wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
797
798
799 /* insert src line */
800 InsertTailList(&MixerInfo->SourceLineList, &SrcLine->Entry);
801 MixerInfo->DestinationLine.cConnections++;
802
803 return STATUS_SUCCESS;
804 }
805
806
807 NTSTATUS
808 AddMixerSourceLines(
809 IN OUT LPMIXER_INFO MixerInfo,
810 IN PFILE_OBJECT FileObject,
811 IN ULONG PinsCount,
812 IN PULONG Pins)
813 {
814 ULONG Index;
815 NTSTATUS Status = STATUS_SUCCESS;
816
817 for(Index = PinsCount; Index > 0; Index--)
818 {
819 if (Pins[Index-1])
820 {
821 AddMixerSourceLine(MixerInfo, FileObject, Index-1);
822 }
823 }
824 return Status;
825 }
826
827
828
829 NTSTATUS
830 HandlePhysicalConnection(
831 IN OUT LPMIXER_INFO MixerInfo,
832 IN ULONG bInput,
833 IN PKSPIN_PHYSICALCONNECTION OutConnection)
834 {
835 PULONG PinsRef = NULL, PinConnectionIndex = NULL, PinsSrcRef;
836 ULONG PinsRefCount, Index, PinConnectionIndexCount;
837 NTSTATUS Status;
838 HANDLE hDevice = NULL;
839 PFILE_OBJECT FileObject = NULL;
840 PKSMULTIPLE_ITEM NodeTypes = NULL;
841 PKSMULTIPLE_ITEM NodeConnections = NULL;
842 PULONG MixerControls;
843 ULONG MixerControlsCount;
844
845
846 /* open the connected filter */
847 Status = OpenDevice(OutConnection->SymbolicLinkName, &hDevice, &FileObject);
848 if (!NT_SUCCESS(Status))
849 {
850 DPRINT1("OpenDevice failed with %x\n", Status);
851 return Status;
852 }
853
854 /* get connected filter pin count */
855 PinsRefCount = GetPinCount(FileObject);
856 ASSERT(PinsRefCount);
857
858 PinsRef = AllocatePinArray(PinsRefCount);
859 if (!PinsRef)
860 {
861 /* no memory */
862 Status = STATUS_INSUFFICIENT_RESOURCES;
863 goto cleanup;
864 }
865
866 /* get topology node types */
867 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
868 if (!NT_SUCCESS(Status))
869 {
870 DPRINT1("GetFilterNodeProperty failed with %x\n", Status);
871 goto cleanup;
872 }
873
874 /* get topology connections */
875 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
876 if (!NT_SUCCESS(Status))
877 {
878 DPRINT1("GetFilterNodeProperty failed with %x\n", Status);
879 goto cleanup;
880 }
881 /* gets connection index of the bridge pin which connects to a node */
882 DPRINT("Pin %u\n", OutConnection->Pin);
883 Status = GetNodeIndexes(NodeConnections, OutConnection->Pin, FALSE, !bInput, &PinConnectionIndexCount, &PinConnectionIndex);
884 if (!NT_SUCCESS(Status))
885 {
886 DPRINT1("GetNodeIndexes failed with %x\n", Status);
887 goto cleanup;
888 }
889
890 /* there should be no split in the bride pin */
891 ASSERT(PinConnectionIndexCount == 1);
892
893 /* find all target pins of this connection */
894 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRef);
895 if (!NT_SUCCESS(Status))
896 {
897 DPRINT1("GetTargetPinsByNodeConnectionIndex failed with %x\n", Status);
898 goto cleanup;
899 }
900
901 for(Index = 0; Index < PinsRefCount; Index++)
902 {
903 if (PinsRef[Index])
904 {
905
906 /* found a target pin, now get all references */
907 Status = GetNodeIndexes(NodeConnections, Index, FALSE, FALSE, &MixerControlsCount, &MixerControls);
908 if (!NT_SUCCESS(Status))
909 break;
910
911 /* sanity check */
912 ASSERT(MixerControlsCount == 1);
913
914
915 PinsSrcRef = AllocatePinArray(PinsRefCount);
916 if (!PinsSrcRef)
917 {
918 /* no memory */
919 ExFreePool(MixerControls);
920 Status = STATUS_INSUFFICIENT_RESOURCES;
921 goto cleanup;
922 }
923 /* now get all connected source pins */
924 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, TRUE, MixerControls[0], PinsSrcRef);
925 if (!NT_SUCCESS(Status))
926 {
927 /* no memory */
928 ExFreePool(MixerControls);
929 ExFreePool(PinsSrcRef);
930 Status = STATUS_INSUFFICIENT_RESOURCES;
931 goto cleanup;
932 }
933
934 /* add pins from target line */
935 if (!bInput)
936 {
937 // dont add bridge pin for input mixers
938 PinsSrcRef[Index] = TRUE;
939 PinsSrcRef[OutConnection->Pin] = TRUE;
940 }
941
942 Status = AddMixerSourceLines(MixerInfo, FileObject, PinsRefCount, PinsSrcRef);
943
944 ExFreePool(MixerControls);
945 ExFreePool(PinsSrcRef);
946 }
947 }
948
949 cleanup:
950
951 if (PinsRef)
952 ExFreePool(PinsRef);
953
954 if (NodeConnections)
955 ExFreePool(NodeConnections);
956
957 if (NodeTypes)
958 ExFreePool(NodeTypes);
959
960 if (FileObject)
961 ObDereferenceObject(FileObject);
962
963 if (hDevice)
964 ZwClose(hDevice);
965
966 if (PinConnectionIndex)
967 ExFreePool(PinConnectionIndex);
968
969
970 return Status;
971 }
972
973
974
975 NTSTATUS
976 InitializeMixer(
977 IN PDEVICE_OBJECT DeviceObject,
978 IN ULONG DeviceIndex,
979 IN OUT LPMIXER_INFO MixerInfo,
980 IN HANDLE hDevice,
981 IN PFILE_OBJECT FileObject,
982 IN ULONG PinCount,
983 IN PKSMULTIPLE_ITEM NodeTypes,
984 IN PKSMULTIPLE_ITEM NodeConnections,
985 IN ULONG NodeIndex,
986 IN ULONG bInput)
987 {
988 WCHAR Buffer[100];
989 LPWSTR Device;
990 NTSTATUS Status;
991 PULONG Pins;
992 ULONG Index;
993 PKSPIN_PHYSICALCONNECTION OutConnection;
994
995 /* initialize mixer info */
996 MixerInfo->hMixer = hDevice;
997 MixerInfo->MixerFileObject = FileObject;
998
999 /* intialize mixer caps */
1000 MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
1001 MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
1002 MixerInfo->MixCaps.vDriverVersion = 1; //FIXME
1003 MixerInfo->MixCaps.fdwSupport = 0;
1004 MixerInfo->MixCaps.cDestinations = 1;
1005
1006 /* get target pnp name */
1007 Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, &Device);
1008 if (NT_SUCCESS(Status))
1009 {
1010 /* find product name */
1011 Status = FindProductName(Device, sizeof(Buffer) / sizeof(WCHAR), Buffer);
1012 if (NT_SUCCESS(Status))
1013 {
1014 if (bInput)
1015 wcscat(Buffer, L" Input");
1016 else
1017 wcscat(Buffer, L" output");
1018 RtlMoveMemory(MixerInfo->MixCaps.szPname, Buffer, min(MAXPNAMELEN, wcslen(Buffer)+1) * sizeof(WCHAR));
1019 MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
1020 }
1021 ExFreePool(Device);
1022 }
1023
1024 /* initialize mixer destination line */
1025 MixerInfo->DestinationLine.cbStruct = sizeof(MIXERLINEW);
1026 MixerInfo->DestinationLine.dwSource = MAXULONG;
1027 MixerInfo->DestinationLine.dwLineID = 0xFFFF0000;
1028 MixerInfo->DestinationLine.fdwLine = MIXERLINE_LINEF_ACTIVE;
1029 MixerInfo->DestinationLine.dwUser = 0;
1030 MixerInfo->DestinationLine.dwComponentType = (bInput == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
1031 MixerInfo->DestinationLine.cChannels = 2; //FIXME
1032 MixerInfo->DestinationLine.cControls = 0; //FIXME
1033 wcscpy(MixerInfo->DestinationLine.szShortName, L"Summe"); //FIXME
1034 wcscpy(MixerInfo->DestinationLine.szName, L"Summe"); //FIXME
1035 MixerInfo->DestinationLine.Target.dwType = (bInput == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
1036 MixerInfo->DestinationLine.Target.dwDeviceID = !bInput;
1037 MixerInfo->DestinationLine.Target.wMid = MixerInfo->MixCaps.wMid;
1038 MixerInfo->DestinationLine.Target.wPid = MixerInfo->MixCaps.wPid;
1039 MixerInfo->DestinationLine.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
1040 wcscpy(MixerInfo->DestinationLine.Target.szPname, MixerInfo->MixCaps.szPname);
1041
1042
1043 /* initialize source line list */
1044 InitializeListHead(&MixerInfo->SourceLineList);
1045
1046 Pins = AllocatePinArray(PinCount);
1047 if (!Pins)
1048 return STATUS_INSUFFICIENT_RESOURCES;
1049
1050 if (bInput)
1051 {
1052 Status = GetTargetPins(NodeTypes, NodeConnections, NodeIndex, TRUE, Pins, PinCount);
1053 }
1054 else
1055 {
1056 Status = GetTargetPins(NodeTypes, NodeConnections, NodeIndex, FALSE, Pins, PinCount);
1057 }
1058
1059 for(Index = 0; Index < PinCount; Index++)
1060 {
1061 if (Pins[Index])
1062 {
1063 Status = GetPhysicalConnection(FileObject, Index, &OutConnection);
1064 if (NT_SUCCESS(Status))
1065 {
1066 Status = HandlePhysicalConnection(MixerInfo, bInput, OutConnection);
1067 }
1068 }
1069 }
1070 ExFreePool(Pins);
1071
1072 return STATUS_SUCCESS;
1073 }
1074
1075 NTSTATUS
1076 WdmAudMixerInitialize(
1077 IN PDEVICE_OBJECT DeviceObject)
1078 {
1079 ULONG DeviceCount, Index, Count, NodeIndex, PinCount;
1080 NTSTATUS Status;
1081 HANDLE hDevice;
1082 PFILE_OBJECT FileObject;
1083 PKSMULTIPLE_ITEM NodeTypes, NodeConnections;
1084 BOOL bCloseHandle;
1085 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1086
1087 /* get device extension */
1088 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1089
1090
1091 /* get number of devices */
1092 DeviceCount = GetSysAudioDeviceCount(DeviceObject);
1093
1094 if (!DeviceCount)
1095 {
1096 /* no audio devices available atm */
1097 DeviceExtension->MixerInfoCount = 0;
1098 DeviceExtension->MixerInfo = NULL;
1099 return STATUS_SUCCESS;
1100 }
1101
1102 /* each virtual audio device can at most have an input + output mixer */
1103 DeviceExtension->MixerInfo = ExAllocatePool(NonPagedPool, sizeof(MIXER_INFO) * DeviceCount * 2);
1104 if (!DeviceExtension->MixerInfo)
1105 {
1106 /* not enough memory */
1107 return STATUS_INSUFFICIENT_RESOURCES;
1108 }
1109
1110 /* clear mixer info */
1111 RtlZeroMemory(DeviceExtension->MixerInfo, sizeof(MIXER_INFO) * DeviceCount * 2);
1112
1113 Index = 0;
1114 Count = 0;
1115 do
1116 {
1117 /* open the virtual audio device */
1118 Status = OpenSysAudioDeviceByIndex(DeviceObject, Index, &hDevice, &FileObject);
1119
1120 if (NT_SUCCESS(Status))
1121 {
1122 /* retrieve all available node types */
1123 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
1124 if (!NT_SUCCESS(Status))
1125 {
1126 ObDereferenceObject(FileObject);
1127 ZwClose(hDevice);
1128 break;
1129 }
1130
1131 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
1132 if (!NT_SUCCESS(Status))
1133 {
1134 ObDereferenceObject(FileObject);
1135 ZwClose(hDevice);
1136 ExFreePool(NodeTypes);
1137 break;
1138 }
1139
1140 /* get num of pins */
1141 PinCount = GetPinCount(FileObject);
1142 bCloseHandle = TRUE;
1143 /* get the first available dac node index */
1144 NodeIndex = GetNodeTypeIndex(NodeTypes, (LPGUID)&KSNODETYPE_DAC);
1145 if (NodeIndex != (ULONG)-1)
1146 {
1147 Status = InitializeMixer(DeviceObject, Index, &DeviceExtension->MixerInfo[Count], hDevice, FileObject, PinCount, NodeTypes, NodeConnections, NodeIndex, FALSE);
1148 if (NT_SUCCESS(Status))
1149 {
1150 /* increment mixer offset */
1151 Count++;
1152 bCloseHandle = FALSE;
1153 }
1154 }
1155
1156 /* get the first available adc node index */
1157 NodeIndex = GetNodeTypeIndex(NodeTypes, (LPGUID)&KSNODETYPE_ADC);
1158 if (NodeIndex != (ULONG)-1)
1159 {
1160 Status = InitializeMixer(DeviceObject, Index, &DeviceExtension->MixerInfo[Count], hDevice, FileObject, PinCount, NodeTypes, NodeConnections, NodeIndex, TRUE);
1161 if (NT_SUCCESS(Status))
1162 {
1163 /* increment mixer offset */
1164 Count++;
1165 bCloseHandle = FALSE;
1166 }
1167 }
1168
1169 /* free node connections array */
1170 ExFreePool(NodeTypes);
1171 ExFreePool(NodeConnections);
1172
1173 if (bCloseHandle)
1174 {
1175 /* close virtual audio device */
1176 ObDereferenceObject(FileObject);
1177 ZwClose(hDevice);
1178 }
1179 }
1180 /* increment virtual audio device index */
1181 Index++;
1182 }while(Index < DeviceCount);
1183
1184 /* store mixer count */
1185 DeviceExtension->MixerInfoCount = Count;
1186
1187 return Status;
1188 }
1189
1190
1191
1192 NTSTATUS
1193 WdmAudMixerCapabilities(
1194 IN PDEVICE_OBJECT DeviceObject,
1195 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1196 IN PWDMAUD_CLIENT ClientInfo,
1197 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
1198 {
1199 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1200 {
1201 /* invalid parameter */
1202 return STATUS_INVALID_PARAMETER;
1203 }
1204
1205 /* copy cached mixer caps */
1206 RtlMoveMemory(&DeviceInfo->u.MixCaps, &DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice].MixCaps, sizeof(MIXERCAPSW));
1207
1208 return STATUS_SUCCESS;
1209 }
1210
1211
1212 NTSTATUS
1213 WdmAudControlOpenMixer(
1214 IN PDEVICE_OBJECT DeviceObject,
1215 IN PIRP Irp,
1216 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1217 IN PWDMAUD_CLIENT ClientInfo)
1218 {
1219 ULONG Index;
1220 PWDMAUD_HANDLE Handels;
1221 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1222
1223 DPRINT("WdmAudControlOpenMixer\n");
1224
1225 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1226
1227
1228 if (DeviceInfo->DeviceIndex >= DeviceExtension->MixerInfoCount)
1229 {
1230 /* mixer index doesnt exist */
1231 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
1232 }
1233
1234 for(Index = 0; Index < ClientInfo->NumPins; Index++)
1235 {
1236 if (ClientInfo->hPins[Index].Handle == (HANDLE)DeviceInfo->DeviceIndex && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
1237 {
1238 /* re-use pseudo handle */
1239 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
1240 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1241 }
1242 }
1243
1244 Handels = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
1245
1246 if (Handels)
1247 {
1248 if (ClientInfo->NumPins)
1249 {
1250 RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
1251 ExFreePool(ClientInfo->hPins);
1252 }
1253
1254 ClientInfo->hPins = Handels;
1255 ClientInfo->hPins[ClientInfo->NumPins].Handle = (HANDLE)DeviceInfo->DeviceIndex;
1256 ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
1257 ClientInfo->NumPins++;
1258 }
1259 else
1260 {
1261 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
1262 }
1263 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
1264
1265 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1266 }
1267
1268 NTSTATUS
1269 NTAPI
1270 WdmAudGetLineInfo(
1271 IN PDEVICE_OBJECT DeviceObject,
1272 IN PIRP Irp,
1273 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1274 IN PWDMAUD_CLIENT ClientInfo)
1275 {
1276 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1277 LPMIXERLINE_SOURCE MixerLineSrc;
1278
1279 /* get device extension */
1280 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1281
1282 if (DeviceInfo->Flags == MIXER_GETLINEINFOF_DESTINATION)
1283 {
1284 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1285 {
1286 /* invalid parameter */
1287 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1288 }
1289
1290 if (DeviceInfo->u.MixLine.dwDestination != 0)
1291 {
1292 /* invalid parameter */
1293 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1294 }
1295
1296 /* copy cached data */
1297 RtlCopyMemory(&DeviceInfo->u.MixLine, &DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice].DestinationLine, sizeof(MIXERLINEW));
1298 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1299 }
1300 else if (DeviceInfo->Flags == MIXER_GETLINEINFOF_SOURCE)
1301 {
1302 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1303 {
1304 /* invalid parameter */
1305 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1306 }
1307
1308 if (DeviceInfo->u.MixLine.dwSource >= DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice].DestinationLine.cConnections)
1309 {
1310 DPRINT1("dwSource %u Destinations %u\n", DeviceInfo->u.MixLine.dwSource, DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice].DestinationLine.cConnections);
1311 /* invalid parameter */
1312 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1313 }
1314
1315 MixerLineSrc = GetSourceMixerLine(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixLine.dwSource);
1316 if (MixerLineSrc)
1317 {
1318 DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
1319 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1320 }
1321 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1322 }
1323
1324 DPRINT1("Flags %x\n", DeviceInfo->Flags);
1325 UNIMPLEMENTED;
1326
1327 //DbgBreakPoint();
1328 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1329
1330 }
1331
1332 NTSTATUS
1333 NTAPI
1334 WdmAudGetLineControls(
1335 IN PDEVICE_OBJECT DeviceObject,
1336 IN PIRP Irp,
1337 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1338 IN PWDMAUD_CLIENT ClientInfo)
1339 {
1340 LPMIXERLINE_SOURCE MixerLineSrc;
1341 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1342
1343 /* get device extension */
1344 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1345
1346 if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ALL)
1347 {
1348 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1349 {
1350 /* invalid parameter */
1351 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1352 }
1353
1354 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
1355 ASSERT(MixerLineSrc);
1356 if (MixerLineSrc)
1357 {
1358 RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, DeviceInfo->u.MixControls.cControls) * sizeof(MIXERLINECONTROLSW));
1359 }
1360 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1361
1362
1363
1364 }
1365
1366 UNIMPLEMENTED;
1367 //DbgBreakPoint();
1368 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1369
1370 }
1371
1372 NTSTATUS
1373 NTAPI
1374 WdmAudSetControlDetails(
1375 IN PDEVICE_OBJECT DeviceObject,
1376 IN PIRP Irp,
1377 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1378 IN PWDMAUD_CLIENT ClientInfo)
1379 {
1380 UNIMPLEMENTED;
1381 //DbgBreakPoint();
1382 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1383
1384 }
1385
1386 NTSTATUS
1387 NTAPI
1388 WdmAudGetControlDetails(
1389 IN PDEVICE_OBJECT DeviceObject,
1390 IN PIRP Irp,
1391 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1392 IN PWDMAUD_CLIENT ClientInfo)
1393 {
1394 UNIMPLEMENTED;
1395 //DbgBreakPoint();
1396 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1397
1398 }
1399