8bd09bdfe42fe893d903f80f9e487f22191afd39
[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 const GUID KSNODETYPE_SUM = {0xDA441A60L, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
25 const GUID KSPROPSETID_Audio = {0x45FFAAA0L, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
26
27 #define DESTINATION_LINE 0xFFFF0000
28
29 LPMIXERLINE_EXT
30 GetSourceMixerLine(
31 LPMIXER_INFO MixerInfo,
32 DWORD dwSource)
33 {
34 PLIST_ENTRY Entry;
35 LPMIXERLINE_EXT MixerLineSrc;
36
37 /* get first entry */
38 Entry = MixerInfo->LineList.Flink;
39
40 while(Entry != &MixerInfo->LineList)
41 {
42 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
43 DPRINT("dwSource %x dwSource %x\n", MixerLineSrc->Line.dwSource, dwSource);
44 if (MixerLineSrc->Line.dwSource == dwSource)
45 return MixerLineSrc;
46
47 Entry = Entry->Flink;
48 }
49
50 return NULL;
51 }
52
53 NTSTATUS
54 GetMixerControlById(
55 LPMIXER_INFO MixerInfo,
56 DWORD dwControlID,
57 LPMIXERLINE_EXT *MixerLine,
58 LPMIXERCONTROLW *MixerControl,
59 PULONG NodeId)
60 {
61 PLIST_ENTRY Entry;
62 LPMIXERLINE_EXT MixerLineSrc;
63 ULONG Index;
64
65 /* get first entry */
66 Entry = MixerInfo->LineList.Flink;
67
68 while(Entry != &MixerInfo->LineList)
69 {
70 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
71
72 for(Index = 0; Index < MixerLineSrc->Line.cConnections; Index++)
73 {
74 if (MixerLineSrc->LineControls[Index].dwControlID == dwControlID)
75 {
76 *MixerLine = MixerLineSrc;
77 *MixerControl = &MixerLineSrc->LineControls[Index];
78 *NodeId = MixerLineSrc->NodeIds[Index];
79 return STATUS_SUCCESS;
80 }
81 }
82 Entry = Entry->Flink;
83 }
84
85 return STATUS_NOT_FOUND;
86 }
87
88
89
90 LPMIXERLINE_EXT
91 GetSourceMixerLineByLineId(
92 LPMIXER_INFO MixerInfo,
93 DWORD dwLineID)
94 {
95 PLIST_ENTRY Entry;
96 LPMIXERLINE_EXT MixerLineSrc;
97
98 /* get first entry */
99 Entry = MixerInfo->LineList.Flink;
100
101 while(Entry != &MixerInfo->LineList)
102 {
103 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
104 DPRINT1("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID);
105 if (MixerLineSrc->Line.dwLineID == dwLineID)
106 return MixerLineSrc;
107
108 Entry = Entry->Flink;
109 }
110
111 return NULL;
112 }
113
114
115
116 ULONG
117 GetPinCount(
118 IN PFILE_OBJECT FileObject)
119 {
120 KSPROPERTY Pin;
121 NTSTATUS Status;
122 ULONG NumPins, BytesReturned;
123
124 Pin.Flags = KSPROPERTY_TYPE_GET;
125 Pin.Set = KSPROPSETID_Pin;
126 Pin.Id = KSPROPERTY_PIN_CTYPES;
127
128 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
129 if (!NT_SUCCESS(Status))
130 return 0;
131
132 return NumPins;
133 }
134
135
136 ULONG
137 GetSysAudioDeviceCount(
138 IN PDEVICE_OBJECT DeviceObject)
139 {
140 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
141 KSPROPERTY Pin;
142 ULONG Count, BytesReturned;
143 NTSTATUS Status;
144
145 /* setup the query request */
146 Pin.Set = KSPROPSETID_Sysaudio;
147 Pin.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
148 Pin.Flags = KSPROPERTY_TYPE_GET;
149
150 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
151
152 /* query sysaudio for the device count */
153 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
154 if (!NT_SUCCESS(Status))
155 return 0;
156
157 return Count;
158 }
159
160 NTSTATUS
161 GetSysAudioDevicePnpName(
162 IN PDEVICE_OBJECT DeviceObject,
163 IN ULONG DeviceIndex,
164 OUT LPWSTR * Device)
165 {
166 ULONG BytesReturned;
167 KSP_PIN Pin;
168 NTSTATUS Status;
169 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
170
171 /* first check if the device index is within bounds */
172 if (DeviceIndex >= GetSysAudioDeviceCount(DeviceObject))
173 return STATUS_INVALID_PARAMETER;
174
175 /* setup the query request */
176 Pin.Property.Set = KSPROPSETID_Sysaudio;
177 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
178 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
179 Pin.PinId = DeviceIndex;
180
181 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
182
183 /* query sysaudio for the device path */
184 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), NULL, 0, &BytesReturned);
185
186 /* check if the request failed */
187 if (Status != STATUS_BUFFER_TOO_SMALL || BytesReturned == 0)
188 return STATUS_UNSUCCESSFUL;
189
190 /* allocate buffer for the device */
191 *Device = ExAllocatePool(NonPagedPool, BytesReturned);
192 if (!Device)
193 return STATUS_INSUFFICIENT_RESOURCES;
194
195 /* query sysaudio again for the device path */
196 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), (PVOID)*Device, BytesReturned, &BytesReturned);
197
198 if (!NT_SUCCESS(Status))
199 {
200 /* failed */
201 ExFreePool(*Device);
202 return Status;
203 }
204
205 return Status;
206 }
207
208 ULONG
209 GetDeviceIndexFromPnpName(
210 IN PDEVICE_OBJECT DeviceObject,
211 LPWSTR Device)
212 {
213 ULONG Count, Index;
214 LPWSTR DeviceName;
215 NTSTATUS Status;
216
217 /* get device count */
218 Count = GetSysAudioDeviceCount(DeviceObject);
219
220 if (!Count)
221 return MAXULONG;
222
223 for(Index = 0; Index < Count; Index++)
224 {
225 /* get device name */
226 Status = GetSysAudioDevicePnpName(DeviceObject, Index, &DeviceName);
227 if (NT_SUCCESS(Status))
228 {
229 if (!wcsicmp(Device, DeviceName))
230 {
231 /* found device index */
232 ExFreePool(DeviceName);
233 return Index;
234 }
235 ExFreePool(DeviceName);
236 }
237 }
238
239 return MAXULONG;
240 }
241
242
243 NTSTATUS
244 OpenDevice(
245 IN LPWSTR Device,
246 OUT PHANDLE DeviceHandle,
247 OUT PFILE_OBJECT * FileObject)
248 {
249 NTSTATUS Status;
250 HANDLE hDevice;
251
252 /* now open the device */
253 Status = WdmAudOpenSysAudioDevice(Device, &hDevice);
254
255 if (!NT_SUCCESS(Status))
256 {
257 return Status;
258 }
259
260 *DeviceHandle = hDevice;
261
262 if (FileObject)
263 {
264 Status = ObReferenceObjectByHandle(hDevice, FILE_READ_DATA | FILE_WRITE_DATA, IoFileObjectType, KernelMode, (PVOID*)FileObject, NULL);
265
266 if (!NT_SUCCESS(Status))
267 {
268 ZwClose(hDevice);
269 }
270 }
271
272 return Status;
273
274 }
275
276
277 NTSTATUS
278 OpenSysAudioDeviceByIndex(
279 IN PDEVICE_OBJECT DeviceObject,
280 IN ULONG DeviceIndex,
281 IN PHANDLE DeviceHandle,
282 IN PFILE_OBJECT * FileObject)
283 {
284 LPWSTR Device = NULL;
285 NTSTATUS Status;
286
287 Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, &Device);
288 if (!NT_SUCCESS(Status))
289 return Status;
290
291 Status = OpenDevice(Device, DeviceHandle, FileObject);
292
293 /* free device buffer */
294 ExFreePool(Device);
295
296 return Status;
297 }
298
299 NTSTATUS
300 GetFilterNodeProperty(
301 IN PFILE_OBJECT FileObject,
302 IN ULONG PropertyId,
303 PKSMULTIPLE_ITEM * Item)
304 {
305 NTSTATUS Status;
306 ULONG BytesReturned;
307 PKSMULTIPLE_ITEM MultipleItem;
308 KSPROPERTY Property;
309
310 /* setup query request */
311 Property.Id = PropertyId;
312 Property.Flags = KSPROPERTY_TYPE_GET;
313 Property.Set = KSPROPSETID_Topology;
314
315 /* query for required size */
316 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
317
318 /* check for success */
319 if (Status != STATUS_MORE_ENTRIES)
320 return Status;
321
322 /* allocate buffer */
323 MultipleItem = (PKSMULTIPLE_ITEM)ExAllocatePool(NonPagedPool, BytesReturned);
324 if (!MultipleItem)
325 return STATUS_INSUFFICIENT_RESOURCES;
326
327 /* query for required size */
328 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
329
330 if (!NT_SUCCESS(Status))
331 {
332 /* failed */
333 ExFreePool(MultipleItem);
334 return Status;
335 }
336
337 *Item = MultipleItem;
338 return Status;
339 }
340
341 ULONG
342 CountNodeType(
343 PKSMULTIPLE_ITEM MultipleItem,
344 LPGUID NodeType)
345 {
346 ULONG Count;
347 ULONG Index;
348 LPGUID Guid;
349
350 Count = 0;
351 Guid = (LPGUID)(MultipleItem+1);
352
353 /* iterate through node type array */
354 for(Index = 0; Index < MultipleItem->Count; Index++)
355 {
356 if (IsEqualGUIDAligned(NodeType, Guid))
357 {
358 /* found matching guid */
359 Count++;
360 }
361 Guid++;
362 }
363 return Count;
364 }
365
366 ULONG
367 GetNodeTypeIndex(
368 PKSMULTIPLE_ITEM MultipleItem,
369 LPGUID NodeType)
370 {
371 ULONG Index;
372 LPGUID Guid;
373
374 Guid = (LPGUID)(MultipleItem+1);
375
376 /* iterate through node type array */
377 for(Index = 0; Index < MultipleItem->Count; Index++)
378 {
379 if (IsEqualGUIDAligned(NodeType, Guid))
380 {
381 /* found matching guid */
382 return Index;
383 }
384 Guid++;
385 }
386 return MAXULONG;
387 }
388
389 ULONG
390 GetControlTypeFromTopologyNode(
391 IN LPGUID NodeType)
392 {
393 if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_AGC))
394 {
395 // automatic gain control
396 return MIXERCONTROL_CONTROLTYPE_ONOFF;
397 }
398 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_LOUDNESS))
399 {
400 // loudness control
401 return MIXERCONTROL_CONTROLTYPE_LOUDNESS;
402 }
403 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUTE ))
404 {
405 // mute control
406 return MIXERCONTROL_CONTROLTYPE_MUTE;
407 }
408 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_TONE))
409 {
410 // tpne control
411 //FIXME
412 // MIXERCONTROL_CONTROLTYPE_ONOFF if KSPROPERTY_AUDIO_BASS_BOOST is supported
413 // MIXERCONTROL_CONTROLTYPE_BASS if KSPROPERTY_AUDIO_BASS is supported
414 // MIXERCONTROL_CONTROLTYPE_TREBLE if KSPROPERTY_AUDIO_TREBLE is supported
415 UNIMPLEMENTED;
416 return MIXERCONTROL_CONTROLTYPE_ONOFF;
417 }
418 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_VOLUME))
419 {
420 // volume control
421 return MIXERCONTROL_CONTROLTYPE_VOLUME;
422 }
423 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_PEAKMETER))
424 {
425 // peakmeter control
426 return MIXERCONTROL_CONTROLTYPE_PEAKMETER;
427 }
428 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX))
429 {
430 // mux control
431 return MIXERCONTROL_CONTROLTYPE_MUX;
432 }
433 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX))
434 {
435 // mux control
436 return MIXERCONTROL_CONTROLTYPE_MUX;
437 }
438 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_STEREO_WIDE))
439 {
440 // stero wide control
441 return MIXERCONTROL_CONTROLTYPE_FADER;
442 }
443 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_CHORUS))
444 {
445 // chorus control
446 return MIXERCONTROL_CONTROLTYPE_FADER;
447 }
448 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_REVERB))
449 {
450 // reverb control
451 return MIXERCONTROL_CONTROLTYPE_FADER;
452 }
453 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_SUPERMIX))
454 {
455 // supermix control
456 // MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported
457 UNIMPLEMENTED;
458 return MIXERCONTROL_CONTROLTYPE_VOLUME;
459 }
460 UNIMPLEMENTED
461 return 0;
462 }
463
464 NTSTATUS
465 GetPhysicalConnection(
466 IN PFILE_OBJECT FileObject,
467 IN ULONG PinId,
468 OUT PKSPIN_PHYSICALCONNECTION *OutConnection)
469 {
470 KSP_PIN Pin;
471 NTSTATUS Status;
472 ULONG BytesReturned;
473 PKSPIN_PHYSICALCONNECTION Connection;
474
475 /* setup the request */
476 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
477 Pin.Property.Id = KSPROPERTY_PIN_PHYSICALCONNECTION;
478 Pin.Property.Set = KSPROPSETID_Pin;
479 Pin.PinId = PinId;
480
481 /* query the pin for the physical connection */
482 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
483
484 if (Status == STATUS_NOT_FOUND)
485 {
486 /* pin does not have a physical connection */
487 return Status;
488 }
489
490 Connection = ExAllocatePool(NonPagedPool, BytesReturned);
491 if (!Connection)
492 {
493 /* not enough memory */
494 return STATUS_INSUFFICIENT_RESOURCES;
495 }
496
497 /* query the pin for the physical connection */
498 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Connection, BytesReturned, &BytesReturned);
499 if (!NT_SUCCESS(Status))
500 {
501 /* failed to query the physical connection */
502 ExFreePool(Connection);
503 return Status;
504 }
505
506 /* store connection */
507 *OutConnection = Connection;
508 return Status;
509 }
510
511 NTSTATUS
512 GetNodeIndexes(
513 IN PKSMULTIPLE_ITEM MultipleItem,
514 IN ULONG NodeIndex,
515 IN ULONG bNode,
516 IN ULONG bFrom,
517 OUT PULONG NodeReferenceCount,
518 OUT PULONG *NodeReference)
519 {
520 ULONG Index, Count = 0;
521 PKSTOPOLOGY_CONNECTION Connection;
522 PULONG Refs;
523
524 /* KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION */
525 Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
526
527 /* first count all referenced nodes */
528 for(Index = 0; Index < MultipleItem->Count; Index++)
529 {
530 //DbgPrint("FromPin %u FromNode %u ToPin %u ToNode %u\n", Connection->FromNodePin, Connection->FromNode, Connection->ToNodePin, Connection->ToNode);
531 if (bNode)
532 {
533 if (bFrom)
534 {
535 if (Connection->FromNode == NodeIndex)
536 {
537 /* node id has a connection */
538 Count++;
539 }
540 }
541 else
542 {
543 if (Connection->ToNode == NodeIndex)
544 {
545 /* node id has a connection */
546 Count++;
547 }
548 }
549 }
550 else
551 {
552 if (bFrom)
553 {
554 if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE)
555 {
556 /* node id has a connection */
557 Count++;
558 }
559 }
560 else
561 {
562 if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE)
563 {
564 /* node id has a connection */
565 Count++;
566 }
567 }
568 }
569
570
571 /* move to next connection */
572 Connection++;
573 }
574
575 ASSERT(Count != 0);
576
577 /* now allocate node index array */
578 Refs = ExAllocatePool(NonPagedPool, sizeof(ULONG) * Count);
579 if (!Refs)
580 {
581 /* not enough memory */
582 return STATUS_INSUFFICIENT_RESOURCES;
583 }
584
585 /* clear node index array */
586 RtlZeroMemory(Refs, Count * sizeof(ULONG));
587
588 Count = 0;
589 Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
590 for(Index = 0; Index < MultipleItem->Count; Index++)
591 {
592 if (bNode)
593 {
594 if (bFrom)
595 {
596 if (Connection->FromNode == NodeIndex)
597 {
598 /* node id has a connection */
599 Refs[Count] = Index;
600 Count++;
601 }
602 }
603 else
604 {
605 if (Connection->ToNode == NodeIndex)
606 {
607 /* node id has a connection */
608 Refs[Count] = Index;
609 Count++;
610 }
611 }
612 }
613 else
614 {
615 if (bFrom)
616 {
617 if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE)
618 {
619 /* node id has a connection */
620 Refs[Count] = Index;
621 Count++;
622 }
623 }
624 else
625 {
626 if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE)
627 {
628 /* node id has a connection */
629 Refs[Count] = Index;
630 Count++;
631 }
632 }
633 }
634
635 /* move to next connection */
636 Connection++;
637 }
638
639 /* store result */
640 *NodeReference = Refs;
641 *NodeReferenceCount = Count;
642
643 return STATUS_SUCCESS;
644 }
645
646
647 NTSTATUS
648 GetTargetPinsByNodeConnectionIndex(
649 IN PKSMULTIPLE_ITEM NodeConnections,
650 IN PKSMULTIPLE_ITEM NodeTypes,
651 IN ULONG bUpDirection,
652 IN ULONG NodeConnectionIndex,
653 OUT PULONG Pins)
654 {
655 PKSTOPOLOGY_CONNECTION Connection;
656 ULONG PinId, NodeConnectionCount, Index;
657 PULONG NodeConnection;
658 NTSTATUS Status;
659
660
661 /* sanity check */
662 ASSERT(NodeConnectionIndex < NodeConnections->Count);
663
664 Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1);
665
666 DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection[NodeConnectionIndex].FromNode, Connection[NodeConnectionIndex].FromNodePin, Connection[NodeConnectionIndex].ToNode, Connection[NodeConnectionIndex].ToNodePin );
667
668 if ((Connection[NodeConnectionIndex].ToNode == KSFILTER_NODE && bUpDirection == FALSE) ||
669 (Connection[NodeConnectionIndex].FromNode == KSFILTER_NODE && bUpDirection == TRUE))
670 {
671 /* iteration stops here */
672 if (bUpDirection)
673 PinId = Connection[NodeConnectionIndex].FromNodePin;
674 else
675 PinId = Connection[NodeConnectionIndex].ToNodePin;
676
677 DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId, Pins[PinId]);
678
679 /* mark pin index as a target pin */
680 Pins[PinId] = TRUE;
681 return STATUS_SUCCESS;
682 }
683
684 /* get all node indexes referenced by that node */
685 if (bUpDirection)
686 {
687 Status = GetNodeIndexes(NodeConnections, Connection[NodeConnectionIndex].FromNode, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
688 }
689 else
690 {
691 Status = GetNodeIndexes(NodeConnections, Connection[NodeConnectionIndex].ToNode, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
692 }
693
694 if (NT_SUCCESS(Status))
695 {
696 for(Index = 0; Index < NodeConnectionCount; Index++)
697 {
698 /* iterate recursively into the nodes */
699 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins);
700 ASSERT(Status == STATUS_SUCCESS);
701 }
702 /* free node connection indexes */
703 ExFreePool(NodeConnection);
704 }
705
706 return Status;
707 }
708
709
710
711 NTSTATUS
712 GetTargetPins(
713 PKSMULTIPLE_ITEM NodeTypes,
714 PKSMULTIPLE_ITEM NodeConnections,
715 IN ULONG NodeIndex,
716 IN ULONG bUpDirection,
717 PULONG Pins,
718 ULONG PinCount)
719 {
720 ULONG NodeConnectionCount, Index;
721 NTSTATUS Status;
722 PULONG NodeConnection;
723
724 /* sanity check */
725 ASSERT(NodeIndex != (ULONG)-1);
726
727 /* get all node indexes referenced by that pin */
728 if (bUpDirection)
729 Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
730 else
731 Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
732
733 DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex, Status, NodeConnectionCount);
734
735 if (NT_SUCCESS(Status))
736 {
737 for(Index = 0; Index < NodeConnectionCount; Index++)
738 {
739 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins);
740 ASSERT(Status == STATUS_SUCCESS);
741 }
742 ExFreePool(NodeConnection);
743 }
744
745 return Status;
746 }
747
748 PULONG
749 AllocatePinArray(
750 ULONG PinCount)
751 {
752 PULONG Pins = ExAllocatePool(NonPagedPool, PinCount * sizeof(ULONG));
753 if (!Pins)
754 return NULL;
755
756 RtlZeroMemory(Pins, sizeof(ULONG) * PinCount);
757
758 return Pins;
759 }
760
761 PKSTOPOLOGY_CONNECTION
762 GetConnectionByIndex(
763 IN PKSMULTIPLE_ITEM MultipleItem,
764 IN ULONG Index)
765 {
766 PKSTOPOLOGY_CONNECTION Descriptor;
767
768 ASSERT(Index < MultipleItem->Count);
769
770 Descriptor = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
771 return &Descriptor[Index];
772 }
773
774 LPGUID
775 GetNodeType(
776 IN PKSMULTIPLE_ITEM MultipleItem,
777 IN ULONG Index)
778 {
779 LPGUID NodeType;
780
781 ASSERT(Index < MultipleItem->Count);
782
783 NodeType = (LPGUID)(MultipleItem + 1);
784 return &NodeType[Index];
785 }
786
787 NTSTATUS
788 GetControlsFromPinByConnectionIndex(
789 IN PKSMULTIPLE_ITEM NodeConnections,
790 IN PKSMULTIPLE_ITEM NodeTypes,
791 IN ULONG bUpDirection,
792 IN ULONG NodeConnectionIndex,
793 OUT PULONG Nodes)
794 {
795 PKSTOPOLOGY_CONNECTION CurConnection;
796 LPGUID NodeType;
797 ULONG NodeIndex;
798 NTSTATUS Status;
799 ULONG NodeConnectionCount, Index;
800 PULONG NodeConnection;
801
802
803 /* get current connection */
804 CurConnection = GetConnectionByIndex(NodeConnections, NodeConnectionIndex);
805
806 if (bUpDirection)
807 NodeIndex = CurConnection->FromNode;
808 else
809 NodeIndex = CurConnection->ToNode;
810
811 /* get target node type of current connection */
812 NodeType = GetNodeType(NodeTypes, NodeIndex);
813
814 if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_SUM) || IsEqualGUIDAligned(NodeType, &KSNODETYPE_MUX))
815 {
816 if (bUpDirection)
817 {
818 /* add the sum / mux node to destination line */
819 //Nodes[NodeIndex] = TRUE;
820 }
821
822 return STATUS_SUCCESS;
823 }
824
825 /* now add the node */
826 Nodes[NodeIndex] = TRUE;
827
828
829 /* get all node indexes referenced by that node */
830 if (bUpDirection)
831 {
832 Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
833 }
834 else
835 {
836 Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
837 }
838
839 if (NT_SUCCESS(Status))
840 {
841 for(Index = 0; Index < NodeConnectionCount; Index++)
842 {
843 /* iterate recursively into the nodes */
844 Status = GetControlsFromPinByConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
845 ASSERT(Status == STATUS_SUCCESS);
846 }
847 /* free node connection indexes */
848 ExFreePool(NodeConnection);
849 }
850
851 return Status;
852 }
853
854 NTSTATUS
855 GetControlsFromPin(
856 IN PKSMULTIPLE_ITEM NodeConnections,
857 IN PKSMULTIPLE_ITEM NodeTypes,
858 IN ULONG PinId,
859 IN ULONG bUpDirection,
860 OUT PULONG Nodes)
861 {
862 ULONG NodeConnectionCount, Index;
863 NTSTATUS Status;
864 PULONG NodeConnection;
865
866 /* sanity check */
867 ASSERT(PinId != (ULONG)-1);
868
869 /* get all node indexes referenced by that pin */
870 if (bUpDirection)
871 Status = GetNodeIndexes(NodeConnections, PinId, FALSE, FALSE, &NodeConnectionCount, &NodeConnection);
872 else
873 Status = GetNodeIndexes(NodeConnections, PinId, FALSE, TRUE, &NodeConnectionCount, &NodeConnection);
874
875 for(Index = 0; Index < NodeConnectionCount; Index++)
876 {
877 /* get all associated controls */
878 Status = GetControlsFromPinByConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
879 }
880
881 ExFreePool(NodeConnection);
882
883 return Status;
884 }
885
886 NTSTATUS
887 AddMixerControl(
888 IN LPMIXER_INFO MixerInfo,
889 IN PFILE_OBJECT FileObject,
890 IN PKSMULTIPLE_ITEM NodeTypes,
891 IN ULONG NodeIndex,
892 OUT LPMIXERCONTROLW MixerControl)
893 {
894 LPGUID NodeType;
895 KSP_NODE Node;
896 ULONG BytesReturned;
897 NTSTATUS Status;
898 LPWSTR Name;
899
900
901 /* initialize mixer control */
902 MixerControl->cbStruct = sizeof(MIXERCONTROLW);
903 MixerControl->dwControlID = MixerInfo->ControlId;
904
905 /* get node type */
906 NodeType = GetNodeType(NodeTypes, NodeIndex);
907 /* store control type */
908 MixerControl->dwControlType = GetControlTypeFromTopologyNode(NodeType);
909
910 MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; //FIXME
911 MixerControl->cMultipleItems = 0; //FIXME
912
913 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
914 {
915 MixerControl->Bounds.dwMinimum = 0;
916 MixerControl->Bounds.dwMaximum = 1;
917 }
918 else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
919 {
920 MixerControl->Bounds.dwMinimum = 0;
921 MixerControl->Bounds.dwMaximum = 0xFFFF;
922 MixerControl->Metrics.cSteps = 0xC0; //FIXME
923 }
924
925 /* setup request to retrieve name */
926 Node.NodeId = NodeIndex;
927 Node.Property.Id = KSPROPERTY_TOPOLOGY_NAME;
928 Node.Property.Flags = KSPROPERTY_TYPE_GET;
929 Node.Property.Set = KSPROPSETID_Topology;
930 Node.Reserved = 0;
931
932 /* get node name size */
933 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
934
935 if (Status == STATUS_BUFFER_TOO_SMALL)
936 {
937 ASSERT(BytesReturned != 0);
938 Name = ExAllocatePool(NonPagedPool, BytesReturned);
939 if (!Name)
940 {
941 /* not enough memory */
942 return STATUS_INSUFFICIENT_RESOURCES;
943 }
944
945 /* get node name */
946 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
947 if (NT_SUCCESS(Status))
948 {
949 RtlMoveMemory(MixerControl->szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
950 MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
951
952 RtlMoveMemory(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
953 MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
954 }
955
956 /* free name buffer */
957 ExFreePool(Name);
958 }
959
960 MixerInfo->ControlId++;
961
962 DPRINT("Status %x Name %S\n", Status, MixerControl->szName);
963 return STATUS_SUCCESS;
964 }
965
966 NTSTATUS
967 AddMixerSourceLine(
968 IN OUT LPMIXER_INFO MixerInfo,
969 IN PFILE_OBJECT FileObject,
970 IN PKSMULTIPLE_ITEM NodeConnections,
971 IN PKSMULTIPLE_ITEM NodeTypes,
972 IN ULONG DeviceIndex,
973 IN ULONG PinId,
974 IN ULONG bBridgePin,
975 IN ULONG bTargetPin)
976 {
977 LPMIXERLINE_EXT SrcLine, DstLine;
978 NTSTATUS Status;
979 KSP_PIN Pin;
980 LPWSTR PinName;
981 GUID NodeType;
982 ULONG BytesReturned, ControlCount, Index;
983 PULONG Nodes;
984
985 if (!bTargetPin)
986 {
987 /* allocate src mixer line */
988 SrcLine = (LPMIXERLINE_EXT)ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
989
990 if (!SrcLine)
991 return STATUS_INSUFFICIENT_RESOURCES;
992
993 /* zero struct */
994 RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
995
996 }
997 else
998 {
999 ASSERT(!IsListEmpty(&MixerInfo->LineList));
1000 SrcLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
1001 }
1002
1003 /* get destination line */
1004 DstLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
1005 ASSERT(DstLine);
1006
1007
1008 if (!bTargetPin)
1009 {
1010 /* initialize mixer src line */
1011 SrcLine->DeviceIndex = DeviceIndex;
1012 SrcLine->PinId = PinId;
1013 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
1014
1015 /* initialize mixer destination line */
1016 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
1017 SrcLine->Line.dwDestination = 0;
1018 SrcLine->Line.dwSource = DstLine->Line.cConnections;
1019 SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000);
1020 SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
1021 SrcLine->Line.dwUser = 0;
1022 SrcLine->Line.cChannels = DstLine->Line.cChannels;
1023 SrcLine->Line.cConnections = 0;
1024 SrcLine->Line.Target.dwType = 1;
1025 SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
1026 SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
1027 SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
1028 SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
1029 wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
1030
1031 }
1032
1033 /* allocate a node arrary */
1034 Nodes = ExAllocatePool(NonPagedPool, sizeof(ULONG) * NodeTypes->Count);
1035
1036 if (!Nodes)
1037 {
1038 /* not enough memory */
1039 if (!bTargetPin)
1040 {
1041 ExFreePool(SrcLine);
1042 }
1043 return STATUS_INSUFFICIENT_RESOURCES;
1044 }
1045
1046 /* clear nodes array */
1047 RtlZeroMemory(Nodes, sizeof(ULONG) * NodeTypes->Count);
1048
1049 Status = GetControlsFromPin(NodeConnections, NodeTypes, PinId, bTargetPin, Nodes);
1050 if (!NT_SUCCESS(Status))
1051 {
1052 /* something went wrong */
1053 if (!bTargetPin)
1054 {
1055 ExFreePool(SrcLine);
1056 }
1057 ExFreePool(Nodes);
1058 return Status;
1059 }
1060
1061 /* now count all nodes controlled by that pin */
1062 ControlCount = 0;
1063 for(Index = 0; Index < NodeTypes->Count; Index++)
1064 {
1065 if (Nodes[Index])
1066 ControlCount++;
1067 }
1068
1069 /* now allocate the line controls */
1070 if (ControlCount)
1071 {
1072 SrcLine->LineControls = ExAllocatePool(NonPagedPool, sizeof(MIXERCONTROLW) * ControlCount);
1073
1074 if (!SrcLine->LineControls)
1075 {
1076 /* no memory available */
1077 if (!bTargetPin)
1078 {
1079 ExFreePool(SrcLine);
1080 }
1081 ExFreePool(Nodes);
1082 return STATUS_INSUFFICIENT_RESOURCES;
1083 }
1084
1085 SrcLine->NodeIds = ExAllocatePool(NonPagedPool, sizeof(ULONG) * ControlCount);
1086 if (!SrcLine->NodeIds)
1087 {
1088 /* no memory available */
1089 ExFreePool(SrcLine->LineControls);
1090 if (!bTargetPin)
1091 {
1092 ExFreePool(SrcLine);
1093 }
1094 ExFreePool(Nodes);
1095 return STATUS_INSUFFICIENT_RESOURCES;
1096 }
1097
1098 /* zero line controls */
1099 RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount);
1100 RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount);
1101
1102 ControlCount = 0;
1103 for(Index = 0; Index < NodeTypes->Count; Index++)
1104 {
1105 if (Nodes[Index])
1106 {
1107 /* store the node index for retrieving / setting details */
1108 SrcLine->NodeIds[ControlCount] = Index;
1109
1110 Status = AddMixerControl(MixerInfo, FileObject, NodeTypes, Index, &SrcLine->LineControls[ControlCount]);
1111 if (NT_SUCCESS(Status))
1112 {
1113 /* increment control count on success */
1114 ControlCount++;
1115 }
1116 }
1117 }
1118 /* store control count */
1119 SrcLine->Line.cControls = ControlCount;
1120 }
1121
1122 /* release nodes array */
1123 ExFreePool(Nodes);
1124
1125 /* get pin category */
1126 Pin.PinId = PinId;
1127 Pin.Reserved = 0;
1128 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
1129 Pin.Property.Set = KSPROPSETID_Pin;
1130 Pin.Property.Id = KSPROPERTY_PIN_CATEGORY;
1131
1132 /* try get pin category */
1133 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)&NodeType, sizeof(GUID), &BytesReturned);
1134 if (NT_SUCCESS(Status))
1135 {
1136 //FIXME
1137 //map component type
1138 }
1139
1140 /* retrieve pin name */
1141 Pin.PinId = PinId;
1142 Pin.Reserved = 0;
1143 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
1144 Pin.Property.Set = KSPROPSETID_Pin;
1145 Pin.Property.Id = KSPROPERTY_PIN_NAME;
1146
1147 /* try get pin name size */
1148 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
1149
1150 if (Status != STATUS_MORE_ENTRIES)
1151 {
1152 SrcLine->Line.szShortName[0] = L'\0';
1153 SrcLine->Line.szName[0] = L'\0';
1154 }
1155 else
1156 {
1157 PinName = (LPWSTR)ExAllocatePool(NonPagedPool, BytesReturned);
1158 if (PinName)
1159 {
1160 /* try get pin name */
1161 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)PinName, BytesReturned, &BytesReturned);
1162
1163 if (NT_SUCCESS(Status))
1164 {
1165 RtlMoveMemory(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
1166 SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
1167
1168 RtlMoveMemory(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
1169 SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
1170 }
1171 ExFreePool(PinName);
1172 }
1173 }
1174
1175 /* insert src line */
1176 if (!bTargetPin)
1177 {
1178 InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
1179 DstLine->Line.cConnections++;
1180 }
1181
1182 return STATUS_SUCCESS;
1183 }
1184
1185
1186 NTSTATUS
1187 AddMixerSourceLines(
1188 IN OUT LPMIXER_INFO MixerInfo,
1189 IN PFILE_OBJECT FileObject,
1190 IN PKSMULTIPLE_ITEM NodeConnections,
1191 IN PKSMULTIPLE_ITEM NodeTypes,
1192 IN ULONG DeviceIndex,
1193 IN ULONG PinsCount,
1194 IN ULONG BridgePinIndex,
1195 IN ULONG TargetPinIndex,
1196 IN PULONG Pins)
1197 {
1198 ULONG Index;
1199 NTSTATUS Status = STATUS_SUCCESS;
1200
1201 for(Index = PinsCount; Index > 0; Index--)
1202 {
1203 if (Pins[Index-1])
1204 {
1205 AddMixerSourceLine(MixerInfo, FileObject, NodeConnections, NodeTypes, DeviceIndex, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex));
1206 }
1207 }
1208 return Status;
1209 }
1210
1211
1212
1213 NTSTATUS
1214 HandlePhysicalConnection(
1215 IN OUT LPMIXER_INFO MixerInfo,
1216 IN PDEVICE_OBJECT DeviceObject,
1217 IN ULONG bInput,
1218 IN PKSPIN_PHYSICALCONNECTION OutConnection)
1219 {
1220 PULONG PinsRef = NULL, PinConnectionIndex = NULL, PinsSrcRef;
1221 ULONG PinsRefCount, Index, PinConnectionIndexCount, DeviceIndex;
1222 NTSTATUS Status;
1223 HANDLE hDevice = NULL;
1224 PFILE_OBJECT FileObject = NULL;
1225 PKSMULTIPLE_ITEM NodeTypes = NULL;
1226 PKSMULTIPLE_ITEM NodeConnections = NULL;
1227 PULONG MixerControls;
1228 ULONG MixerControlsCount;
1229
1230
1231 /* open the connected filter */
1232 Status = OpenDevice(OutConnection->SymbolicLinkName, &hDevice, &FileObject);
1233 if (!NT_SUCCESS(Status))
1234 {
1235 DPRINT1("OpenDevice failed with %x\n", Status);
1236 return Status;
1237 }
1238
1239 /* get device index */
1240 DeviceIndex = GetDeviceIndexFromPnpName(DeviceObject, OutConnection->SymbolicLinkName);
1241
1242 /* get connected filter pin count */
1243 PinsRefCount = GetPinCount(FileObject);
1244 ASSERT(PinsRefCount);
1245
1246 PinsRef = AllocatePinArray(PinsRefCount);
1247 if (!PinsRef)
1248 {
1249 /* no memory */
1250 Status = STATUS_INSUFFICIENT_RESOURCES;
1251 goto cleanup;
1252 }
1253
1254 /* get topology node types */
1255 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
1256 if (!NT_SUCCESS(Status))
1257 {
1258 DPRINT1("GetFilterNodeProperty failed with %x\n", Status);
1259 goto cleanup;
1260 }
1261
1262 /* get topology connections */
1263 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
1264 if (!NT_SUCCESS(Status))
1265 {
1266 DPRINT1("GetFilterNodeProperty failed with %x\n", Status);
1267 goto cleanup;
1268 }
1269 /* gets connection index of the bridge pin which connects to a node */
1270 DPRINT("Pin %u\n", OutConnection->Pin);
1271 Status = GetNodeIndexes(NodeConnections, OutConnection->Pin, FALSE, !bInput, &PinConnectionIndexCount, &PinConnectionIndex);
1272 if (!NT_SUCCESS(Status))
1273 {
1274 DPRINT1("GetNodeIndexes failed with %x\n", Status);
1275 goto cleanup;
1276 }
1277
1278 /* there should be no split in the bride pin */
1279 ASSERT(PinConnectionIndexCount == 1);
1280
1281 /* find all target pins of this connection */
1282 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRef);
1283 if (!NT_SUCCESS(Status))
1284 {
1285 DPRINT1("GetTargetPinsByNodeConnectionIndex failed with %x\n", Status);
1286 goto cleanup;
1287 }
1288
1289 for(Index = 0; Index < PinsRefCount; Index++)
1290 {
1291 if (PinsRef[Index])
1292 {
1293
1294 /* found a target pin, now get all references */
1295 Status = GetNodeIndexes(NodeConnections, Index, FALSE, FALSE, &MixerControlsCount, &MixerControls);
1296 if (!NT_SUCCESS(Status))
1297 break;
1298
1299 /* sanity check */
1300 ASSERT(MixerControlsCount == 1);
1301
1302
1303 PinsSrcRef = AllocatePinArray(PinsRefCount);
1304 if (!PinsSrcRef)
1305 {
1306 /* no memory */
1307 ExFreePool(MixerControls);
1308 Status = STATUS_INSUFFICIENT_RESOURCES;
1309 goto cleanup;
1310 }
1311 /* now get all connected source pins */
1312 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, TRUE, MixerControls[0], PinsSrcRef);
1313 if (!NT_SUCCESS(Status))
1314 {
1315 /* no memory */
1316 ExFreePool(MixerControls);
1317 ExFreePool(PinsSrcRef);
1318 Status = STATUS_INSUFFICIENT_RESOURCES;
1319 goto cleanup;
1320 }
1321
1322 /* add pins from target line */
1323 if (!bInput)
1324 {
1325 // dont add bridge pin for input mixers
1326 PinsSrcRef[Index] = TRUE;
1327 PinsSrcRef[OutConnection->Pin] = TRUE;
1328 }
1329
1330 Status = AddMixerSourceLines(MixerInfo, FileObject, NodeConnections, NodeTypes, DeviceIndex, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef);
1331
1332 ExFreePool(MixerControls);
1333 ExFreePool(PinsSrcRef);
1334 }
1335 }
1336
1337 cleanup:
1338
1339 if (PinsRef)
1340 ExFreePool(PinsRef);
1341
1342 if (NodeConnections)
1343 ExFreePool(NodeConnections);
1344
1345 if (NodeTypes)
1346 ExFreePool(NodeTypes);
1347
1348 if (FileObject)
1349 ObDereferenceObject(FileObject);
1350
1351 if (hDevice)
1352 ZwClose(hDevice);
1353
1354 if (PinConnectionIndex)
1355 ExFreePool(PinConnectionIndex);
1356
1357
1358 return Status;
1359 }
1360
1361
1362
1363 NTSTATUS
1364 InitializeMixer(
1365 IN PDEVICE_OBJECT DeviceObject,
1366 IN ULONG DeviceIndex,
1367 IN OUT LPMIXER_INFO MixerInfo,
1368 IN HANDLE hDevice,
1369 IN PFILE_OBJECT FileObject,
1370 IN ULONG PinCount,
1371 IN PKSMULTIPLE_ITEM NodeTypes,
1372 IN PKSMULTIPLE_ITEM NodeConnections,
1373 IN ULONG NodeIndex,
1374 IN ULONG bInput)
1375 {
1376 WCHAR Buffer[100];
1377 LPWSTR Device;
1378 NTSTATUS Status;
1379 PULONG Pins;
1380 ULONG Index;
1381 PKSPIN_PHYSICALCONNECTION OutConnection;
1382 LPMIXERLINE_EXT DestinationLine;
1383
1384 DestinationLine = ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
1385 if (!DestinationLine)
1386 return STATUS_INSUFFICIENT_RESOURCES;
1387
1388 /* intialize mixer caps */
1389 MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
1390 MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
1391 MixerInfo->MixCaps.vDriverVersion = 1; //FIXME
1392 MixerInfo->MixCaps.fdwSupport = 0;
1393 MixerInfo->MixCaps.cDestinations = 1;
1394
1395 /* get target pnp name */
1396 Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, &Device);
1397 if (NT_SUCCESS(Status))
1398 {
1399 /* find product name */
1400 Status = FindProductName(Device, sizeof(Buffer) / sizeof(WCHAR), Buffer);
1401 if (NT_SUCCESS(Status))
1402 {
1403 if (bInput)
1404 wcscat(Buffer, L" Input");
1405 else
1406 wcscat(Buffer, L" output");
1407 RtlMoveMemory(MixerInfo->MixCaps.szPname, Buffer, min(MAXPNAMELEN, wcslen(Buffer)+1) * sizeof(WCHAR));
1408 MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
1409 }
1410 ExFreePool(Device);
1411 }
1412
1413 /* initialize mixer destination line */
1414 RtlZeroMemory(DestinationLine, sizeof(MIXERLINEW));
1415 DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
1416 DestinationLine->Line.dwSource = MAXULONG;
1417 DestinationLine->Line.dwLineID = DESTINATION_LINE;
1418 DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
1419 DestinationLine->Line.dwUser = 0;
1420 DestinationLine->Line.dwComponentType = (bInput == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
1421 DestinationLine->Line.cChannels = 2; //FIXME
1422 wcscpy(DestinationLine->Line.szShortName, L"Summe"); //FIXME
1423 wcscpy(DestinationLine->Line.szName, L"Summe"); //FIXME
1424 DestinationLine->Line.Target.dwType = (bInput == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
1425 DestinationLine->Line.Target.dwDeviceID = !bInput;
1426 DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
1427 DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
1428 DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
1429 wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
1430
1431 /* initialize source line list */
1432 InitializeListHead(&MixerInfo->LineList);
1433
1434 /* insert destination line */
1435 InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
1436
1437 Pins = AllocatePinArray(PinCount);
1438 if (!Pins)
1439 return STATUS_INSUFFICIENT_RESOURCES;
1440
1441 if (bInput)
1442 {
1443 Status = GetTargetPins(NodeTypes, NodeConnections, NodeIndex, TRUE, Pins, PinCount);
1444 }
1445 else
1446 {
1447 Status = GetTargetPins(NodeTypes, NodeConnections, NodeIndex, FALSE, Pins, PinCount);
1448 }
1449
1450 for(Index = 0; Index < PinCount; Index++)
1451 {
1452 if (Pins[Index])
1453 {
1454 Status = GetPhysicalConnection(FileObject, Index, &OutConnection);
1455 if (NT_SUCCESS(Status))
1456 {
1457 Status = HandlePhysicalConnection(MixerInfo, DeviceObject, bInput, OutConnection);
1458 ExFreePool(OutConnection);
1459 }
1460 }
1461 }
1462 ExFreePool(Pins);
1463
1464 return STATUS_SUCCESS;
1465 }
1466
1467 NTSTATUS
1468 WdmAudMixerInitialize(
1469 IN PDEVICE_OBJECT DeviceObject)
1470 {
1471 ULONG DeviceCount, Index, Count, NodeIndex, PinCount;
1472 NTSTATUS Status;
1473 HANDLE hDevice;
1474 PFILE_OBJECT FileObject;
1475 PKSMULTIPLE_ITEM NodeTypes, NodeConnections;
1476 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1477
1478 /* get device extension */
1479 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1480
1481
1482 /* get number of devices */
1483 DeviceCount = GetSysAudioDeviceCount(DeviceObject);
1484
1485 if (!DeviceCount)
1486 {
1487 /* no audio devices available atm */
1488 DeviceExtension->MixerInfoCount = 0;
1489 DeviceExtension->MixerInfo = NULL;
1490 return STATUS_SUCCESS;
1491 }
1492
1493 /* each virtual audio device can at most have an input + output mixer */
1494 DeviceExtension->MixerInfo = ExAllocatePool(NonPagedPool, sizeof(MIXER_INFO) * DeviceCount * 2);
1495 if (!DeviceExtension->MixerInfo)
1496 {
1497 /* not enough memory */
1498 return STATUS_INSUFFICIENT_RESOURCES;
1499 }
1500
1501 /* clear mixer info */
1502 RtlZeroMemory(DeviceExtension->MixerInfo, sizeof(MIXER_INFO) * DeviceCount * 2);
1503
1504 Index = 0;
1505 Count = 0;
1506 do
1507 {
1508 /* open the virtual audio device */
1509 Status = OpenSysAudioDeviceByIndex(DeviceObject, Index, &hDevice, &FileObject);
1510
1511 if (NT_SUCCESS(Status))
1512 {
1513 /* retrieve all available node types */
1514 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
1515 if (!NT_SUCCESS(Status))
1516 {
1517 ObDereferenceObject(FileObject);
1518 ZwClose(hDevice);
1519 break;
1520 }
1521
1522 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
1523 if (!NT_SUCCESS(Status))
1524 {
1525 ObDereferenceObject(FileObject);
1526 ZwClose(hDevice);
1527 ExFreePool(NodeTypes);
1528 break;
1529 }
1530
1531 /* get num of pins */
1532 PinCount = GetPinCount(FileObject);
1533 /* get the first available dac node index */
1534 NodeIndex = GetNodeTypeIndex(NodeTypes, (LPGUID)&KSNODETYPE_DAC);
1535 if (NodeIndex != (ULONG)-1)
1536 {
1537 Status = InitializeMixer(DeviceObject, Index, &DeviceExtension->MixerInfo[Count], hDevice, FileObject, PinCount, NodeTypes, NodeConnections, NodeIndex, FALSE);
1538 if (NT_SUCCESS(Status))
1539 {
1540 /* increment mixer offset */
1541 Count++;
1542 }
1543 }
1544
1545 /* get the first available adc node index */
1546 NodeIndex = GetNodeTypeIndex(NodeTypes, (LPGUID)&KSNODETYPE_ADC);
1547 if (NodeIndex != (ULONG)-1)
1548 {
1549 Status = InitializeMixer(DeviceObject, Index, &DeviceExtension->MixerInfo[Count], hDevice, FileObject, PinCount, NodeTypes, NodeConnections, NodeIndex, TRUE);
1550 if (NT_SUCCESS(Status))
1551 {
1552 /* increment mixer offset */
1553 Count++;
1554 }
1555 }
1556
1557 /* free node connections array */
1558 ExFreePool(NodeTypes);
1559 ExFreePool(NodeConnections);
1560
1561 /* close virtual audio device */
1562 ObDereferenceObject(FileObject);
1563 ZwClose(hDevice);
1564
1565 }
1566 /* increment virtual audio device index */
1567 Index++;
1568 }while(Index < DeviceCount);
1569
1570 /* store mixer count */
1571 DeviceExtension->MixerInfoCount = Count;
1572
1573 return Status;
1574 }
1575
1576
1577
1578 NTSTATUS
1579 WdmAudMixerCapabilities(
1580 IN PDEVICE_OBJECT DeviceObject,
1581 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1582 IN PWDMAUD_CLIENT ClientInfo,
1583 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
1584 {
1585 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1586 {
1587 /* invalid parameter */
1588 return STATUS_INVALID_PARAMETER;
1589 }
1590
1591 /* copy cached mixer caps */
1592 RtlMoveMemory(&DeviceInfo->u.MixCaps, &DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice].MixCaps, sizeof(MIXERCAPSW));
1593
1594 return STATUS_SUCCESS;
1595 }
1596
1597
1598 NTSTATUS
1599 WdmAudControlOpenMixer(
1600 IN PDEVICE_OBJECT DeviceObject,
1601 IN PIRP Irp,
1602 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1603 IN PWDMAUD_CLIENT ClientInfo)
1604 {
1605 ULONG Index;
1606 PWDMAUD_HANDLE Handels;
1607 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1608
1609 DPRINT("WdmAudControlOpenMixer\n");
1610
1611 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1612
1613
1614 if (DeviceInfo->DeviceIndex >= DeviceExtension->MixerInfoCount)
1615 {
1616 /* mixer index doesnt exist */
1617 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
1618 }
1619
1620 for(Index = 0; Index < ClientInfo->NumPins; Index++)
1621 {
1622 if (ClientInfo->hPins[Index].Handle == (HANDLE)DeviceInfo->DeviceIndex && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
1623 {
1624 /* re-use pseudo handle */
1625 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
1626 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1627 }
1628 }
1629
1630 Handels = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
1631
1632 if (Handels)
1633 {
1634 if (ClientInfo->NumPins)
1635 {
1636 RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
1637 ExFreePool(ClientInfo->hPins);
1638 }
1639
1640 ClientInfo->hPins = Handels;
1641 ClientInfo->hPins[ClientInfo->NumPins].Handle = (HANDLE)DeviceInfo->DeviceIndex;
1642 ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
1643 ClientInfo->NumPins++;
1644 }
1645 else
1646 {
1647 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
1648 }
1649 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
1650
1651 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1652 }
1653
1654 NTSTATUS
1655 NTAPI
1656 WdmAudGetLineInfo(
1657 IN PDEVICE_OBJECT DeviceObject,
1658 IN PIRP Irp,
1659 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1660 IN PWDMAUD_CLIENT ClientInfo)
1661 {
1662 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1663 LPMIXERLINE_EXT MixerLineSrc;
1664
1665 /* get device extension */
1666 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1667
1668 if (DeviceInfo->Flags == MIXER_GETLINEINFOF_DESTINATION)
1669 {
1670 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1671 {
1672 /* invalid parameter */
1673 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1674 }
1675
1676 if (DeviceInfo->u.MixLine.dwDestination != 0)
1677 {
1678 /* invalid parameter */
1679 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1680 }
1681 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DESTINATION_LINE);
1682 ASSERT(MixerLineSrc);
1683
1684 /* copy cached data */
1685 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1686 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1687 }
1688 else if (DeviceInfo->Flags == MIXER_GETLINEINFOF_SOURCE)
1689 {
1690 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1691 {
1692 /* invalid parameter */
1693 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1694 }
1695
1696 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DESTINATION_LINE);
1697 ASSERT(MixerLineSrc);
1698
1699 if (DeviceInfo->u.MixLine.dwSource >= MixerLineSrc->Line.cConnections)
1700 {
1701 DPRINT1("dwSource %u Destinations %u\n", DeviceInfo->u.MixLine.dwSource, MixerLineSrc->Line.cConnections);
1702 /* invalid parameter */
1703 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1704 }
1705
1706 MixerLineSrc = GetSourceMixerLine(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixLine.dwSource);
1707 if (MixerLineSrc)
1708 {
1709 DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
1710 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1711 }
1712 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1713 }
1714 else if (DeviceInfo->Flags == MIXER_GETLINEINFOF_LINEID)
1715 {
1716 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1717 {
1718 /* invalid parameter */
1719 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1720 }
1721
1722 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixLine.dwLineID);
1723 ASSERT(MixerLineSrc);
1724
1725 /* copy cached data */
1726 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1727 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1728 }
1729
1730
1731 DPRINT1("Flags %x\n", DeviceInfo->Flags);
1732 UNIMPLEMENTED;
1733
1734 //DbgBreakPoint();
1735 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1736
1737 }
1738
1739 NTSTATUS
1740 NTAPI
1741 WdmAudGetLineControls(
1742 IN PDEVICE_OBJECT DeviceObject,
1743 IN PIRP Irp,
1744 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1745 IN PWDMAUD_CLIENT ClientInfo)
1746 {
1747 LPMIXERLINE_EXT MixerLineSrc;
1748 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1749 ULONG Index;
1750
1751 /* get device extension */
1752 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1753
1754 if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ALL)
1755 {
1756 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1757 {
1758 /* invalid parameter */
1759 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1760 }
1761
1762 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
1763 ASSERT(MixerLineSrc);
1764 if (MixerLineSrc)
1765 {
1766 RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, DeviceInfo->u.MixControls.cControls) * sizeof(MIXERCONTROLW));
1767 }
1768 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1769 }
1770 else if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
1771 {
1772 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1773 {
1774 /* invalid parameter */
1775 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1776 }
1777
1778 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
1779 ASSERT(MixerLineSrc);
1780
1781 Index = 0;
1782 for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
1783 {
1784 if (DeviceInfo->u.MixControls.dwControlType == MixerLineSrc->LineControls[Index].dwControlType)
1785 {
1786 RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
1787 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1788 }
1789 }
1790 DPRINT1("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x\n", DeviceInfo->u.MixControls.dwControlType, DeviceInfo->u.MixControls.dwLineID);
1791 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
1792 }
1793
1794 UNIMPLEMENTED;
1795 //DbgBreakPoint();
1796 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1797
1798 }
1799
1800 NTSTATUS
1801 SetGetMuteControlDetails(
1802 IN PDEVICE_OBJECT DeviceObject,
1803 IN ULONG DeviceId,
1804 IN ULONG NodeId,
1805 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1806 IN ULONG bSet)
1807 {
1808 KSNODEPROPERTY_AUDIO_CHANNEL Property;
1809 NTSTATUS Status;
1810 HANDLE hDevice;
1811 PFILE_OBJECT FileObject;
1812 BOOL Value;
1813 ULONG BytesReturned;
1814 LPMIXERCONTROLDETAILS_BOOLEAN Input;
1815
1816 if (DeviceInfo->u.MixDetails.cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
1817 return STATUS_INVALID_PARAMETER;
1818
1819 /* get input */
1820 Input = (LPMIXERCONTROLDETAILS_BOOLEAN)DeviceInfo->u.MixDetails.paDetails;
1821
1822
1823 //
1824 // FIXME SEH!!!
1825 //
1826 if (bSet)
1827 Value = Input->fValue;
1828
1829 /* open virtual audio device */
1830 Status = OpenSysAudioDeviceByIndex(DeviceObject, DeviceId, &hDevice, &FileObject);
1831
1832 if (!NT_SUCCESS(Status))
1833 {
1834 /* failed */
1835 return Status;
1836 }
1837
1838 /* setup the request */
1839 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
1840
1841 Property.NodeProperty.NodeId = NodeId;
1842 Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_MUTE;
1843 Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY;
1844 Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
1845 Property.Channel = MAXULONG;
1846
1847 if (bSet)
1848 Property.NodeProperty.Property.Flags |= KSPROPERTY_TYPE_SET;
1849 else
1850 Property.NodeProperty.Property.Flags |= KSPROPERTY_TYPE_GET;
1851
1852 /* send the request */
1853 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), (PVOID)&Value, sizeof(BOOL), &BytesReturned);
1854
1855 ObDereferenceObject(FileObject);
1856 ZwClose(hDevice);
1857
1858 if (!bSet)
1859 {
1860 // FIXME SEH !!!
1861 Input->fValue = Value;
1862 }
1863
1864 DPRINT("Status %x bSet %u NodeId %u Value %u\n", Status, bSet, NodeId, Value);
1865 return Status;
1866 }
1867
1868 NTSTATUS
1869 NTAPI
1870 WdmAudSetControlDetails(
1871 IN PDEVICE_OBJECT DeviceObject,
1872 IN PIRP Irp,
1873 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1874 IN PWDMAUD_CLIENT ClientInfo)
1875 {
1876 LPMIXERLINE_EXT MixerLine;
1877 LPMIXERCONTROLW MixerControl;
1878 ULONG NodeId;
1879 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1880 NTSTATUS Status;
1881
1882 DPRINT1("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
1883 DeviceInfo->u.MixDetails.cbStruct, sizeof(MIXERCONTROLDETAILS), DeviceInfo->u.MixDetails.dwControlID, DeviceInfo->u.MixDetails.cChannels, DeviceInfo->u.MixDetails.cMultipleItems, DeviceInfo->u.MixDetails.cbDetails, DeviceInfo->u.MixDetails.paDetails, DeviceInfo->Flags);
1884
1885 if (DeviceInfo->Flags & MIXER_GETCONTROLDETAILSF_LISTTEXT)
1886 {
1887 UNIMPLEMENTED;
1888 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1889 }
1890
1891 /* get device extension */
1892 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1893
1894 /* get mixer control */
1895 Status = GetMixerControlById(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixDetails.dwControlID, &MixerLine, &MixerControl, &NodeId);
1896
1897 if (!NT_SUCCESS(Status))
1898 {
1899 DPRINT1("MixerControl %x not found\n", DeviceInfo->u.MixDetails.dwControlID);
1900 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1901 }
1902
1903 Status = STATUS_NOT_IMPLEMENTED;
1904 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
1905 {
1906 /* send the request */
1907 Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, TRUE);
1908 }
1909
1910 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
1911
1912 }
1913
1914 NTSTATUS
1915 NTAPI
1916 WdmAudGetControlDetails(
1917 IN PDEVICE_OBJECT DeviceObject,
1918 IN PIRP Irp,
1919 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1920 IN PWDMAUD_CLIENT ClientInfo)
1921 {
1922 LPMIXERLINE_EXT MixerLine;
1923 LPMIXERCONTROLW MixerControl;
1924 ULONG NodeId;
1925 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1926 NTSTATUS Status;
1927
1928 DPRINT1("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
1929 DeviceInfo->u.MixDetails.cbStruct, sizeof(MIXERCONTROLDETAILS), DeviceInfo->u.MixDetails.dwControlID, DeviceInfo->u.MixDetails.cChannels, DeviceInfo->u.MixDetails.cMultipleItems, DeviceInfo->u.MixDetails.cbDetails, DeviceInfo->u.MixDetails.paDetails, DeviceInfo->Flags);
1930
1931 if (DeviceInfo->Flags & MIXER_GETCONTROLDETAILSF_LISTTEXT)
1932 {
1933 UNIMPLEMENTED;
1934 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1935 }
1936
1937 /* get device extension */
1938 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1939
1940 /* get mixer control */
1941 Status = GetMixerControlById(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixDetails.dwControlID, &MixerLine, &MixerControl, &NodeId);
1942
1943 if (!NT_SUCCESS(Status))
1944 {
1945 DPRINT1("MixerControl %x not found\n", DeviceInfo->u.MixDetails.dwControlID);
1946 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1947 }
1948
1949 Status = STATUS_NOT_IMPLEMENTED;
1950 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
1951 {
1952 /* send the request */
1953 Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, FALSE);
1954 }
1955
1956 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
1957
1958 }
1959