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