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