xref: /reactos/drivers/wdm/audio/legacy/wdmaud/mmixer.c (revision d6eebaa4)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/wdm/audio/legacy/wdmaud/mmixer.c
5  * PURPOSE:         WDM Legacy Mixer
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "wdmaud.h"
10 
11 #include <mmixer.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 PVOID Alloc(ULONG NumBytes);
17 MIXER_STATUS Close(HANDLE hDevice);
18 VOID Free(PVOID Block);
19 VOID Copy(PVOID Src, PVOID Dst, ULONG NumBytes);
20 MIXER_STATUS Open(IN LPWSTR DevicePath, OUT PHANDLE hDevice);
21 MIXER_STATUS Control(IN HANDLE hMixer, IN ULONG dwIoControlCode, IN PVOID lpInBuffer, IN ULONG nInBufferSize, OUT PVOID lpOutBuffer, ULONG nOutBufferSize, PULONG lpBytesReturned);
22 MIXER_STATUS Enum(IN  PVOID EnumContext, IN  ULONG DeviceIndex, OUT LPWSTR * DeviceName, OUT PHANDLE OutHandle, OUT PHANDLE OutKey);
23 MIXER_STATUS OpenKey(IN HANDLE hKey, IN LPWSTR SubKey, IN ULONG DesiredAccess, OUT PHANDLE OutKey);
24 MIXER_STATUS CloseKey(IN HANDLE hKey);
25 MIXER_STATUS QueryKeyValue(IN HANDLE hKey, IN LPWSTR KeyName, OUT PVOID * ResultBuffer, OUT PULONG ResultLength, OUT PULONG KeyType);
26 PVOID AllocEventData(IN ULONG ExtraSize);
27 VOID FreeEventData(IN PVOID EventData);
28 
29 MIXER_CONTEXT MixerContext =
30 {
31     sizeof(MIXER_CONTEXT),
32     NULL,
33     Alloc,
34     Control,
35     Free,
36     Open,
37     Close,
38     Copy,
39     OpenKey,
40     QueryKeyValue,
41     CloseKey,
42     AllocEventData,
43     FreeEventData
44 };
45 
46 GUID CategoryGuid = {STATIC_KSCATEGORY_AUDIO};
47 
48 MIXER_STATUS
49 QueryKeyValue(
50     IN HANDLE hKey,
51     IN LPWSTR lpKeyName,
52     OUT PVOID * ResultBuffer,
53     OUT PULONG ResultLength,
54     OUT PULONG KeyType)
55 {
56     NTSTATUS Status;
57     UNICODE_STRING KeyName;
58     ULONG Length;
59     PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
60 
61     /* initialize key name */
62     RtlInitUnicodeString(&KeyName, lpKeyName);
63 
64     /* now query MatchingDeviceId key */
65     Status = ZwQueryValueKey(hKey, &KeyName, KeyValuePartialInformation, NULL, 0, &Length);
66 
67     /* check for success */
68     if (Status != STATUS_BUFFER_TOO_SMALL)
69         return MM_STATUS_UNSUCCESSFUL;
70 
71     /* allocate a buffer for key data */
72     PartialInformation = AllocateItem(NonPagedPool, Length);
73 
74     if (!PartialInformation)
75         return MM_STATUS_NO_MEMORY;
76 
77 
78     /* now query MatchingDeviceId key */
79     Status = ZwQueryValueKey(hKey, &KeyName, KeyValuePartialInformation, PartialInformation, Length, &Length);
80 
81     /* check for success */
82     if (!NT_SUCCESS(Status))
83     {
84         FreeItem(PartialInformation);
85         return MM_STATUS_UNSUCCESSFUL;
86     }
87 
88     if (KeyType)
89     {
90         /* return key type */
91         *KeyType = PartialInformation->Type;
92     }
93 
94     if (ResultLength)
95     {
96         /* return data length */
97         *ResultLength = PartialInformation->DataLength;
98     }
99 
100     *ResultBuffer = AllocateItem(NonPagedPool, PartialInformation->DataLength);
101     if (!*ResultBuffer)
102     {
103         /* not enough memory */
104         FreeItem(PartialInformation);
105         return MM_STATUS_NO_MEMORY;
106     }
107 
108     /* copy key value */
109     RtlMoveMemory(*ResultBuffer, PartialInformation->Data, PartialInformation->DataLength);
110 
111     /* free key info */
112     FreeItem(PartialInformation);
113 
114     return MM_STATUS_SUCCESS;
115 }
116 
117 MIXER_STATUS
118 OpenKey(
119     IN HANDLE hKey,
120     IN LPWSTR lpSubKeyName,
121     IN ULONG DesiredAccess,
122     OUT PHANDLE OutKey)
123 {
124     OBJECT_ATTRIBUTES ObjectAttributes;
125     UNICODE_STRING SubKeyName;
126     NTSTATUS Status;
127 
128     /* initialize sub key name */
129     RtlInitUnicodeString(&SubKeyName, lpSubKeyName);
130 
131     /* initialize key attributes */
132     InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF, hKey, NULL);
133 
134     /* open the key */
135     Status = ZwOpenKey(OutKey, DesiredAccess, &ObjectAttributes);
136 
137     if (NT_SUCCESS(Status))
138         return MM_STATUS_SUCCESS;
139     else
140         return MM_STATUS_UNSUCCESSFUL;
141 }
142 
143 MIXER_STATUS
144 CloseKey(
145     IN HANDLE hKey)
146 {
147     if (ZwClose(hKey) == STATUS_SUCCESS)
148         return MM_STATUS_SUCCESS;
149     else
150         return MM_STATUS_UNSUCCESSFUL;
151 }
152 
153 
154 PVOID Alloc(ULONG NumBytes)
155 {
156     return AllocateItem(NonPagedPool, NumBytes);
157 }
158 
159 MIXER_STATUS
160 Close(HANDLE hDevice)
161 {
162     if (ZwClose(hDevice) == STATUS_SUCCESS)
163         return MM_STATUS_SUCCESS;
164     else
165         return MM_STATUS_UNSUCCESSFUL;
166 }
167 
168 VOID
169 Free(PVOID Block)
170 {
171     FreeItem(Block);
172 }
173 
174 VOID
175 Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
176 {
177     RtlMoveMemory(Src, Dst, NumBytes);
178 }
179 
180 MIXER_STATUS
181 Open(
182     IN LPWSTR DevicePath,
183     OUT PHANDLE hDevice)
184 {
185     if (WdmAudOpenSysAudioDevice(DevicePath, hDevice) == STATUS_SUCCESS)
186         return MM_STATUS_SUCCESS;
187     else
188         return MM_STATUS_UNSUCCESSFUL;
189 }
190 
191 MIXER_STATUS
192 Control(
193     IN HANDLE hMixer,
194     IN ULONG dwIoControlCode,
195     IN PVOID lpInBuffer,
196     IN ULONG nInBufferSize,
197     OUT PVOID lpOutBuffer,
198     ULONG nOutBufferSize,
199     PULONG lpBytesReturned)
200 {
201     NTSTATUS Status;
202     PFILE_OBJECT FileObject;
203 
204     /* get file object */
205     Status = ObReferenceObjectByHandle(hMixer, GENERIC_READ | GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
206     if (!NT_SUCCESS(Status))
207     {
208         DPRINT("failed to reference %p with %lx\n", hMixer, Status);
209         return MM_STATUS_UNSUCCESSFUL;
210     }
211 
212     /* perform request */
213     Status = KsSynchronousIoControlDevice(FileObject, KernelMode, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned);
214 
215     /* release object reference */
216     ObDereferenceObject(FileObject);
217 
218     if (Status == STATUS_MORE_ENTRIES || Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
219     {
220         /* more data is available */
221         return MM_STATUS_MORE_ENTRIES;
222     }
223     else if (Status == STATUS_SUCCESS)
224     {
225         /* operation succeeded */
226         return MM_STATUS_SUCCESS;
227     }
228     else
229     {
230         DPRINT("Failed with %lx\n", Status);
231         return MM_STATUS_UNSUCCESSFUL;
232     }
233 }
234 
235 MIXER_STATUS
236 Enum(
237     IN  PVOID EnumContext,
238     IN  ULONG DeviceIndex,
239     OUT LPWSTR * DeviceName,
240     OUT PHANDLE OutHandle,
241     OUT PHANDLE OutKey)
242 {
243     PDEVICE_OBJECT DeviceObject;
244     ULONG DeviceCount;
245     NTSTATUS Status;
246     UNICODE_STRING KeyName;
247 
248     /* get enumeration context */
249     DeviceObject = (PDEVICE_OBJECT)EnumContext;
250 
251     /* get device count */
252     DeviceCount = GetSysAudioDeviceCount(DeviceObject);
253 
254     if (DeviceIndex >= DeviceCount)
255     {
256         /* no more devices */
257         return MM_STATUS_NO_MORE_DEVICES;
258     }
259 
260     /* get device name */
261     Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, DeviceName);
262 
263     if (!NT_SUCCESS(Status))
264     {
265         /* failed to retrieve device name */
266         return MM_STATUS_UNSUCCESSFUL;
267     }
268 
269     /* initialize key name */
270     RtlInitUnicodeString(&KeyName, *DeviceName);
271 
272     /* open device interface key */
273     Status = IoOpenDeviceInterfaceRegistryKey(&KeyName, GENERIC_READ | GENERIC_WRITE, OutKey);
274 
275     if (!NT_SUCCESS(Status))
276     {
277         *OutKey = NULL;
278     }
279 
280 #if 0
281     if (!NT_SUCCESS(Status))
282     {
283         /* failed to open key */
284         DPRINT("IoOpenDeviceInterfaceRegistryKey failed with %lx\n", Status);
285         FreeItem(*DeviceName);
286         return MM_STATUS_UNSUCCESSFUL;
287     }
288 #endif
289 
290     /* open device handle */
291     Status = OpenDevice(*DeviceName, OutHandle, NULL);
292     if (!NT_SUCCESS(Status))
293     {
294         /* failed to open device */
295         return MM_STATUS_UNSUCCESSFUL;
296     }
297 
298     return MM_STATUS_SUCCESS;
299 }
300 
301 PVOID
302 AllocEventData(
303     IN ULONG ExtraSize)
304 {
305     PKSEVENTDATA Data = (PKSEVENTDATA)AllocateItem(NonPagedPool, sizeof(KSEVENTDATA) + ExtraSize);
306     if (!Data)
307         return NULL;
308 
309     Data->EventObject.Event = AllocateItem(NonPagedPool, sizeof(KEVENT));
310     if (!Data->EventHandle.Event)
311     {
312         FreeItem(Data);
313         return NULL;
314     }
315 
316     KeInitializeEvent(Data->EventObject.Event, NotificationEvent, FALSE);
317 
318     Data->NotificationType = KSEVENTF_EVENT_HANDLE;
319     return Data;
320 }
321 
322 VOID
323 FreeEventData(IN PVOID EventData)
324 {
325     PKSEVENTDATA Data = (PKSEVENTDATA)EventData;
326 
327     FreeItem(Data->EventHandle.Event);
328     FreeItem(Data);
329 }
330 
331 VOID
332 CALLBACK
333 EventCallback(
334     IN PVOID MixerEventContext,
335     IN HANDLE hMixer,
336     IN ULONG NotificationType,
337     IN ULONG Value)
338 {
339     PWDMAUD_CLIENT ClientInfo;
340     PEVENT_ENTRY Entry;
341     ULONG Index;
342 
343     /* get client context */
344     ClientInfo = (PWDMAUD_CLIENT)MixerEventContext;
345 
346     /* now search for the mixer which originated the request */
347     for(Index = 0; Index < ClientInfo->NumPins; Index++)
348     {
349         if (ClientInfo->hPins[Index].Handle == hMixer && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
350         {
351             if (ClientInfo->hPins[Index].NotifyEvent)
352             {
353                 /* allocate event entry */
354                 Entry = AllocateItem(NonPagedPool, sizeof(EVENT_ENTRY));
355                 if (!Entry)
356                 {
357                     /* no memory */
358                     break;
359                 }
360 
361                 /* setup event entry */
362                 Entry->NotificationType = NotificationType;
363                 Entry->Value = Value;
364                 Entry->hMixer = hMixer;
365 
366                 /* insert entry */
367                 InsertTailList(&ClientInfo->MixerEventList, &Entry->Entry);
368 
369                 /* now notify the client */
370                 KeSetEvent(ClientInfo->hPins[Index].NotifyEvent, 0, FALSE);
371             }
372             /* done */
373             break;
374         }
375     }
376 }
377 
378 
379 NTSTATUS
380 WdmAudMixerInitialize(
381     IN PDEVICE_OBJECT DeviceObject)
382 {
383     MIXER_STATUS Status;
384 
385     /* initialize the mixer library */
386     Status = MMixerInitialize(&MixerContext, Enum, (PVOID)DeviceObject);
387 
388     if (Status != MM_STATUS_SUCCESS)
389     {
390         /* failed to initialize mmixer library */
391         DPRINT("MMixerInitialize failed with %lx\n", Status);
392     }
393 
394     return Status;
395 }
396 
397 NTSTATUS
398 WdmAudMixerCapabilities(
399     IN PDEVICE_OBJECT DeviceObject,
400     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
401     IN  PWDMAUD_CLIENT ClientInfo,
402     IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
403 {
404     if (MMixerGetCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MixCaps) == MM_STATUS_SUCCESS)
405         return STATUS_SUCCESS;
406 
407     return STATUS_INVALID_PARAMETER;
408 }
409 
410 NTSTATUS
411 WdmAudControlOpenMixer(
412     IN  PDEVICE_OBJECT DeviceObject,
413     IN  PIRP Irp,
414     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
415     IN  PWDMAUD_CLIENT ClientInfo)
416 {
417     HANDLE hMixer;
418     PWDMAUD_HANDLE Handles;
419     //PWDMAUD_DEVICE_EXTENSION DeviceExtension;
420     NTSTATUS Status;
421     PKEVENT EventObject = NULL;
422 
423     DPRINT("WdmAudControlOpenMixer\n");
424 
425     //DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
426 
427     if (DeviceInfo->u.hNotifyEvent)
428     {
429         Status = ObReferenceObjectByHandle(DeviceInfo->u.hNotifyEvent, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode, (LPVOID*)&EventObject, NULL);
430 
431         if (!NT_SUCCESS(Status))
432         {
433             DPRINT1("Invalid notify event passed %p from client %p\n", DeviceInfo->u.hNotifyEvent, ClientInfo);
434             DbgBreakPoint();
435             return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
436         }
437     }
438 
439     if (MMixerOpen(&MixerContext, DeviceInfo->DeviceIndex, ClientInfo, EventCallback, &hMixer) != MM_STATUS_SUCCESS)
440     {
441         ObDereferenceObject(EventObject);
442         DPRINT1("Failed to open mixer\n");
443         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
444     }
445 
446 
447     Handles = AllocateItem(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
448 
449     if (Handles)
450     {
451         if (ClientInfo->NumPins)
452         {
453             RtlMoveMemory(Handles, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
454             FreeItem(ClientInfo->hPins);
455         }
456 
457         ClientInfo->hPins = Handles;
458         ClientInfo->hPins[ClientInfo->NumPins].Handle = hMixer;
459         ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
460         ClientInfo->hPins[ClientInfo->NumPins].NotifyEvent = EventObject;
461         ClientInfo->NumPins++;
462     }
463     else
464     {
465         ObDereferenceObject(EventObject);
466         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
467     }
468 
469     DeviceInfo->hDevice = hMixer;
470 
471     return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
472 }
473 
474 NTSTATUS
475 WdmAudControlCloseMixer(
476     IN  PDEVICE_OBJECT DeviceObject,
477     IN  PIRP Irp,
478     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
479     IN  PWDMAUD_CLIENT ClientInfo,
480     IN  ULONG Index)
481 {
482     /* Remove event associated to this client */
483     if (MMixerClose(&MixerContext, DeviceInfo->DeviceIndex, ClientInfo, EventCallback) != MM_STATUS_SUCCESS)
484     {
485         DPRINT1("Failed to close mixer\n");
486         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
487     }
488 
489     /* Dereference event */
490     if (ClientInfo->hPins[Index].NotifyEvent)
491     {
492         ObDereferenceObject(ClientInfo->hPins[Index].NotifyEvent);
493         ClientInfo->hPins[Index].NotifyEvent = NULL;
494     }
495 
496     /* FIXME: do we need to free ClientInfo->hPins ? */
497     return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
498 }
499 
500 VOID
501 WdmAudCloseAllMixers(
502     IN PDEVICE_OBJECT DeviceObject,
503     IN PWDMAUD_CLIENT ClientInfo,
504     IN ULONG Index)
505 {
506     ULONG DeviceCount, DeviceIndex;
507 
508     /* Get all mixers */
509     DeviceCount = GetSysAudioDeviceCount(DeviceObject);
510 
511     /* Close every mixer attached to the device */
512     for (DeviceIndex = 0; DeviceIndex < DeviceCount; DeviceIndex++)
513     {
514         if (MMixerClose(&MixerContext, DeviceIndex, ClientInfo, EventCallback) != MM_STATUS_SUCCESS)
515         {
516             DPRINT1("Failed to close mixer for device %lu\n", DeviceIndex);
517         }
518     }
519 
520     /* Dereference event */
521     if (ClientInfo->hPins[Index].NotifyEvent)
522     {
523         ObDereferenceObject(ClientInfo->hPins[Index].NotifyEvent);
524         ClientInfo->hPins[Index].NotifyEvent = NULL;
525     }
526 }
527 
528 NTSTATUS
529 NTAPI
530 WdmAudGetControlDetails(
531     IN  PDEVICE_OBJECT DeviceObject,
532     IN  PIRP Irp,
533     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
534     IN  PWDMAUD_CLIENT ClientInfo)
535 {
536     MIXER_STATUS Status;
537 
538     /* clear hmixer type flag */
539     DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
540 
541     /* query mmixer library */
542     Status = MMixerGetControlDetails(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixDetails);
543 
544     if (Status == MM_STATUS_SUCCESS)
545         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
546     else
547         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
548 }
549 
550 NTSTATUS
551 NTAPI
552 WdmAudGetLineInfo(
553     IN  PDEVICE_OBJECT DeviceObject,
554     IN  PIRP Irp,
555     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
556     IN  PWDMAUD_CLIENT ClientInfo)
557 {
558     MIXER_STATUS Status;
559 
560     /* clear hmixer type flag */
561     DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
562 
563     /* query mixer library */
564     Status = MMixerGetLineInfo(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixLine);
565 
566     if (Status == MM_STATUS_SUCCESS)
567         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
568     else
569         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
570 }
571 
572 NTSTATUS
573 NTAPI
574 WdmAudGetLineControls(
575     IN  PDEVICE_OBJECT DeviceObject,
576     IN  PIRP Irp,
577     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
578     IN  PWDMAUD_CLIENT ClientInfo)
579 {
580     MIXER_STATUS Status;
581 
582     /* clear hmixer type flag */
583     DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
584 
585     /* query mixer library */
586     Status = MMixerGetLineControls(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixControls);
587 
588     if (Status == MM_STATUS_SUCCESS)
589         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
590     else
591         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
592 
593 
594 }
595 
596 NTSTATUS
597 NTAPI
598 WdmAudSetControlDetails(
599     IN  PDEVICE_OBJECT DeviceObject,
600     IN  PIRP Irp,
601     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
602     IN  PWDMAUD_CLIENT ClientInfo)
603 {
604     MIXER_STATUS Status;
605 
606     /* clear hmixer type flag */
607     DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
608 
609     /* query mixer library */
610     Status = MMixerSetControlDetails(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixDetails);
611 
612     if (Status == MM_STATUS_SUCCESS)
613         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
614     else
615         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
616 }
617 
618 NTSTATUS
619 NTAPI
620 WdmAudGetMixerEvent(
621     IN  PDEVICE_OBJECT DeviceObject,
622     IN  PIRP Irp,
623     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
624     IN  PWDMAUD_CLIENT ClientInfo)
625 {
626     PLIST_ENTRY Entry;
627     PEVENT_ENTRY EventEntry;
628 
629     /* enumerate event list and check if there is a new event */
630     Entry = ClientInfo->MixerEventList.Flink;
631 
632     while(Entry != &ClientInfo->MixerEventList)
633     {
634         /* grab event entry */
635         EventEntry = (PEVENT_ENTRY)CONTAINING_RECORD(Entry, EVENT_ENTRY, Entry);
636 
637         if (EventEntry->hMixer == DeviceInfo->hDevice)
638         {
639             /* found an entry */
640             DeviceInfo->u.MixerEvent.hMixer = EventEntry->hMixer;
641             DeviceInfo->u.MixerEvent.NotificationType = EventEntry->NotificationType;
642             DeviceInfo->u.MixerEvent.Value = EventEntry->Value;
643 
644             /* remove entry from list */
645             RemoveEntryList(&EventEntry->Entry);
646 
647             /* free event entry */
648             FreeItem(EventEntry);
649 
650             /* done */
651             return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
652         }
653 
654         /* move to next */
655         Entry = Entry->Flink;
656     }
657 
658     /* no event entry available */
659     return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
660 }
661 
662 ULONG
663 WdmAudGetMixerDeviceCount()
664 {
665     return MMixerGetCount(&MixerContext);
666 }
667 
668 ULONG
669 WdmAudGetWaveInDeviceCount()
670 {
671     return MMixerGetWaveInCount(&MixerContext);
672 }
673 
674 ULONG
675 WdmAudGetWaveOutDeviceCount()
676 {
677     return MMixerGetWaveOutCount(&MixerContext);
678 }
679 
680 ULONG
681 WdmAudGetMidiInDeviceCount()
682 {
683     return MMixerGetMidiInCount(&MixerContext);
684 }
685 
686 ULONG
687 WdmAudGetMidiOutDeviceCount()
688 {
689     return MMixerGetWaveOutCount(&MixerContext);
690 }
691 
692 NTSTATUS
693 WdmAudGetPnpNameByIndexAndType(
694     IN ULONG DeviceIndex,
695     IN SOUND_DEVICE_TYPE DeviceType,
696     OUT LPWSTR *DevicePath)
697 {
698     if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
699     {
700         if (MMixerGetWaveDevicePath(&MixerContext, DeviceType == WAVE_IN_DEVICE_TYPE, DeviceIndex, DevicePath) == MM_STATUS_SUCCESS)
701             return STATUS_SUCCESS;
702         else
703             return STATUS_UNSUCCESSFUL;
704     }
705     else if (DeviceType == MIDI_IN_DEVICE_TYPE || DeviceType == MIDI_OUT_DEVICE_TYPE)
706     {
707         if (MMixerGetMidiDevicePath(&MixerContext, DeviceType == MIDI_IN_DEVICE_TYPE, DeviceIndex, DevicePath) == MM_STATUS_SUCCESS)
708             return STATUS_SUCCESS;
709         else
710             return STATUS_UNSUCCESSFUL;
711     }
712     else if (DeviceType == MIXER_DEVICE_TYPE)
713     {
714         UNIMPLEMENTED;
715     }
716 
717     return STATUS_UNSUCCESSFUL;
718 }
719 
720 NTSTATUS
721 WdmAudWaveCapabilities(
722     IN PDEVICE_OBJECT DeviceObject,
723     IN PWDMAUD_DEVICE_INFO DeviceInfo,
724     IN PWDMAUD_CLIENT ClientInfo,
725     IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
726 {
727     MIXER_STATUS Status = MM_STATUS_UNSUCCESSFUL;
728 
729     if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
730     {
731         /* get capabilities */
732         Status = MMixerWaveInCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.WaveInCaps);
733     }
734     else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
735     {
736         /* get capabilities */
737         Status = MMixerWaveOutCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.WaveOutCaps);
738     }
739 
740     if (Status == MM_STATUS_SUCCESS)
741         return STATUS_SUCCESS;
742     else
743         return Status;
744 }
745 
746 NTSTATUS
747 WdmAudMidiCapabilities(
748     IN PDEVICE_OBJECT DeviceObject,
749     IN PWDMAUD_DEVICE_INFO DeviceInfo,
750     IN PWDMAUD_CLIENT ClientInfo,
751     IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
752 {
753     MIXER_STATUS Status = MM_STATUS_UNSUCCESSFUL;
754 
755     if (DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE)
756     {
757         /* get capabilities */
758         Status = MMixerMidiInCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MidiInCaps);
759     }
760     else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
761     {
762         /* get capabilities */
763         Status = MMixerMidiOutCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MidiOutCaps);
764     }
765 
766     if (Status == MM_STATUS_SUCCESS)
767         return STATUS_SUCCESS;
768     else
769         return STATUS_UNSUCCESSFUL;
770 }
771 
772 NTSTATUS
773 NTAPI
774 WdmAudGetPosition(
775     _In_ PDEVICE_OBJECT DeviceObject,
776     _In_ PIRP Irp,
777     _In_ PWDMAUD_DEVICE_INFO DeviceInfo)
778 {
779     MIXER_STATUS Status;
780     ULONG Position;
781 
782     /* Get position */
783     Status = MMixerGetWavePosition(&MixerContext, DeviceInfo->hDevice, &Position);
784 
785     if (Status == MM_STATUS_SUCCESS)
786     {
787         DeviceInfo->u.Position = (ULONGLONG)Position;
788         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
789     }
790     else
791         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
792 }
793 
794 
795 MIXER_STATUS
796 CreatePinCallback(
797     IN PVOID Ctx,
798     IN ULONG VirtualDeviceId,
799     IN ULONG PinId,
800     IN HANDLE hFilter,
801     IN PKSPIN_CONNECT PinConnect,
802     IN ACCESS_MASK DesiredAccess,
803     OUT PHANDLE PinHandle)
804 {
805     ULONG BytesReturned;
806     SYSAUDIO_INSTANCE_INFO InstanceInfo;
807     NTSTATUS Status;
808     ULONG FreeIndex;
809     PPIN_CREATE_CONTEXT Context = (PPIN_CREATE_CONTEXT)Ctx;
810 
811     /* setup property request */
812     InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
813     InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
814     InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
815     InstanceInfo.Flags = 0;
816     InstanceInfo.DeviceNumber = VirtualDeviceId;
817 
818     /* attach to virtual device */
819     Status = KsSynchronousIoControlDevice(Context->DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
820 
821     if (!NT_SUCCESS(Status))
822         return MM_STATUS_UNSUCCESSFUL;
823 
824     /* close existing pin */
825     FreeIndex = ClosePin(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType);
826 
827     /* now create the pin */
828     Status = KsCreatePin(Context->DeviceExtension->hSysAudio, PinConnect, DesiredAccess, PinHandle);
829 
830     /* check for success */
831     if (!NT_SUCCESS(Status))
832         return MM_STATUS_UNSUCCESSFUL;
833 
834     /* store the handle */
835     Status = InsertPinHandle(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType, *PinHandle, FreeIndex);
836     if (!NT_SUCCESS(Status))
837     {
838         /* failed to insert handle */
839         ZwClose(*PinHandle);
840         return MM_STATUS_UNSUCCESSFUL;
841     }
842 
843     return MM_STATUS_SUCCESS;
844 }
845 
846 NTSTATUS
847 WdmAudControlOpenWave(
848     IN  PDEVICE_OBJECT DeviceObject,
849     IN  PIRP Irp,
850     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
851     IN  PWDMAUD_CLIENT ClientInfo)
852 {
853     MIXER_STATUS Status;
854     PIN_CREATE_CONTEXT Context;
855 
856     Context.ClientInfo = ClientInfo;
857     Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
858     Context.DeviceType = DeviceInfo->DeviceType;
859 
860     Status = MMixerOpenWave(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE, &DeviceInfo->u.WaveFormatEx, CreatePinCallback, &Context, &DeviceInfo->hDevice);
861 
862     if (Status == MM_STATUS_SUCCESS)
863         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
864     else
865         return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
866 }
867 
868 NTSTATUS
869 WdmAudControlOpenMidi(
870     IN  PDEVICE_OBJECT DeviceObject,
871     IN  PIRP Irp,
872     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
873     IN  PWDMAUD_CLIENT ClientInfo)
874 {
875     MIXER_STATUS Status;
876     PIN_CREATE_CONTEXT Context;
877 
878     Context.ClientInfo = ClientInfo;
879     Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
880     Context.DeviceType = DeviceInfo->DeviceType;
881 
882     Status = MMixerOpenMidi(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE, CreatePinCallback, &Context, &DeviceInfo->hDevice);
883 
884     if (Status == MM_STATUS_SUCCESS)
885         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
886     else
887         return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
888 }
889