xref: /reactos/drivers/wdm/audio/legacy/wdmaud/mmixer.c (revision d1b8feb6)
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
QueryKeyValue(IN HANDLE hKey,IN LPWSTR lpKeyName,OUT PVOID * ResultBuffer,OUT PULONG ResultLength,OUT PULONG KeyType)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
OpenKey(IN HANDLE hKey,IN LPWSTR lpSubKeyName,IN ULONG DesiredAccess,OUT PHANDLE OutKey)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
CloseKey(IN HANDLE hKey)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 
Alloc(ULONG NumBytes)154 PVOID Alloc(ULONG NumBytes)
155 {
156     return AllocateItem(NonPagedPool, NumBytes);
157 }
158 
159 MIXER_STATUS
Close(HANDLE hDevice)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
Free(PVOID Block)169 Free(PVOID Block)
170 {
171     FreeItem(Block);
172 }
173 
174 VOID
Copy(PVOID Src,PVOID Dst,ULONG NumBytes)175 Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
176 {
177     RtlMoveMemory(Src, Dst, NumBytes);
178 }
179 
180 MIXER_STATUS
Open(IN LPWSTR DevicePath,OUT PHANDLE hDevice)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
Control(IN HANDLE hMixer,IN ULONG dwIoControlCode,IN PVOID lpInBuffer,IN ULONG nInBufferSize,OUT PVOID lpOutBuffer,ULONG nOutBufferSize,PULONG lpBytesReturned)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
Enum(IN PVOID EnumContext,IN ULONG DeviceIndex,OUT LPWSTR * DeviceName,OUT PHANDLE OutHandle,OUT PHANDLE OutKey)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
AllocEventData(IN ULONG ExtraSize)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
FreeEventData(IN PVOID EventData)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
EventCallback(IN PVOID MixerEventContext,IN HANDLE hMixer,IN ULONG NotificationType,IN ULONG Value)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
WdmAudMixerInitialize(IN PDEVICE_OBJECT DeviceObject)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
WdmAudMixerCapabilities(IN PDEVICE_OBJECT DeviceObject,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo,IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)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
WdmAudControlOpenMixer(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudControlCloseMixer(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo,IN ULONG Index)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
WdmAudCloseAllMixers(IN PDEVICE_OBJECT DeviceObject,IN PWDMAUD_CLIENT ClientInfo,IN ULONG Index)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
WdmAudGetControlDetails(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudGetLineInfo(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudGetLineControls(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudSetControlDetails(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudGetMixerEvent(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudGetMixerDeviceCount()663 WdmAudGetMixerDeviceCount()
664 {
665     return MMixerGetCount(&MixerContext);
666 }
667 
668 ULONG
WdmAudGetWaveInDeviceCount()669 WdmAudGetWaveInDeviceCount()
670 {
671     return MMixerGetWaveInCount(&MixerContext);
672 }
673 
674 ULONG
WdmAudGetWaveOutDeviceCount()675 WdmAudGetWaveOutDeviceCount()
676 {
677     return MMixerGetWaveOutCount(&MixerContext);
678 }
679 
680 ULONG
WdmAudGetMidiInDeviceCount()681 WdmAudGetMidiInDeviceCount()
682 {
683     return MMixerGetMidiInCount(&MixerContext);
684 }
685 
686 ULONG
WdmAudGetMidiOutDeviceCount()687 WdmAudGetMidiOutDeviceCount()
688 {
689     return MMixerGetWaveOutCount(&MixerContext);
690 }
691 
692 NTSTATUS
WdmAudGetPnpNameByIndexAndType(IN ULONG DeviceIndex,IN SOUND_DEVICE_TYPE DeviceType,OUT LPWSTR * DevicePath)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
WdmAudWaveCapabilities(IN PDEVICE_OBJECT DeviceObject,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo,IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)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
WdmAudMidiCapabilities(IN PDEVICE_OBJECT DeviceObject,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo,IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)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
WdmAudGetPosition(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp,_In_ PWDMAUD_DEVICE_INFO DeviceInfo)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
CreatePinCallback(IN PVOID Ctx,IN ULONG VirtualDeviceId,IN ULONG PinId,IN HANDLE hFilter,IN PKSPIN_CONNECT PinConnect,IN ACCESS_MASK DesiredAccess,OUT PHANDLE PinHandle)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
WdmAudControlOpenWave(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudControlOpenMidi(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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