xref: /reactos/drivers/wdm/audio/legacy/wdmaud/mmixer.c (revision 9ea495ba)
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 = ExAllocatePool(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         ExFreePool(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 = ExAllocatePool(NonPagedPool, PartialInformation->DataLength);
97     if (!*ResultBuffer)
98     {
99         /* not enough memory */
100         ExFreePool(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     ExFreePool(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     PVOID Mem = ExAllocatePool(NonPagedPool, NumBytes);
153     if (!Mem)
154         return Mem;
155 
156     RtlZeroMemory(Mem, NumBytes);
157     return Mem;
158 }
159 
160 MIXER_STATUS
161 Close(HANDLE hDevice)
162 {
163     if (ZwClose(hDevice) == STATUS_SUCCESS)
164         return MM_STATUS_SUCCESS;
165     else
166         return MM_STATUS_UNSUCCESSFUL;
167 }
168 
169 VOID
170 Free(PVOID Block)
171 {
172     ExFreePool(Block);
173 }
174 
175 VOID
176 Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
177 {
178     RtlMoveMemory(Src, Dst, NumBytes);
179 }
180 
181 MIXER_STATUS
182 Open(
183     IN LPWSTR DevicePath,
184     OUT PHANDLE hDevice)
185 {
186     if (WdmAudOpenSysAudioDevice(DevicePath, hDevice) == STATUS_SUCCESS)
187         return MM_STATUS_SUCCESS;
188     else
189         return MM_STATUS_UNSUCCESSFUL;
190 }
191 
192 MIXER_STATUS
193 Control(
194     IN HANDLE hMixer,
195     IN ULONG dwIoControlCode,
196     IN PVOID lpInBuffer,
197     IN ULONG nInBufferSize,
198     OUT PVOID lpOutBuffer,
199     ULONG nOutBufferSize,
200     PULONG lpBytesReturned)
201 {
202     NTSTATUS Status;
203     PFILE_OBJECT FileObject;
204 
205     /* get file object */
206     Status = ObReferenceObjectByHandle(hMixer, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
207     if (!NT_SUCCESS(Status))
208     {
209         DPRINT("failed to reference %p with %lx\n", hMixer, Status);
210         return MM_STATUS_UNSUCCESSFUL;
211     }
212 
213     /* perform request */
214     Status = KsSynchronousIoControlDevice(FileObject, KernelMode, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned);
215 
216     /* release object reference */
217     ObDereferenceObject(FileObject);
218 
219     if (Status == STATUS_MORE_ENTRIES || Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
220     {
221         /* more data is available */
222         return MM_STATUS_MORE_ENTRIES;
223     }
224     else if (Status == STATUS_SUCCESS)
225     {
226         /* operation succeeded */
227         return MM_STATUS_SUCCESS;
228     }
229     else
230     {
231         DPRINT("Failed with %lx\n", Status);
232         return MM_STATUS_UNSUCCESSFUL;
233     }
234 }
235 
236 MIXER_STATUS
237 Enum(
238     IN  PVOID EnumContext,
239     IN  ULONG DeviceIndex,
240     OUT LPWSTR * DeviceName,
241     OUT PHANDLE OutHandle,
242     OUT PHANDLE OutKey)
243 {
244     PDEVICE_OBJECT DeviceObject;
245     ULONG DeviceCount;
246     NTSTATUS Status;
247     UNICODE_STRING KeyName;
248 
249     /* get enumeration context */
250     DeviceObject = (PDEVICE_OBJECT)EnumContext;
251 
252     /* get device count */
253     DeviceCount = GetSysAudioDeviceCount(DeviceObject);
254 
255     if (DeviceIndex >= DeviceCount)
256     {
257         /* no more devices */
258         return MM_STATUS_NO_MORE_DEVICES;
259     }
260 
261     /* get device name */
262     Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, DeviceName);
263 
264     if (!NT_SUCCESS(Status))
265     {
266         /* failed to retrieve device name */
267         return MM_STATUS_UNSUCCESSFUL;
268     }
269 
270     /* intialize key name */
271     RtlInitUnicodeString(&KeyName, *DeviceName);
272 
273     /* open device interface key */
274     Status = IoOpenDeviceInterfaceRegistryKey(&KeyName, GENERIC_READ | GENERIC_WRITE, OutKey);
275 #if 0
276     if (!NT_SUCCESS(Status))
277     {
278         /* failed to open key */
279         DPRINT("IoOpenDeviceInterfaceRegistryKey failed with %lx\n", Status);
280         ExFreePool(*DeviceName);
281         return MM_STATUS_UNSUCCESSFUL;
282     }
283 #endif
284 
285     /* open device handle */
286     Status = OpenDevice(*DeviceName, OutHandle, NULL);
287     if (!NT_SUCCESS(Status))
288     {
289         /* failed to open device */
290         return MM_STATUS_UNSUCCESSFUL;
291     }
292 
293     return MM_STATUS_SUCCESS;
294 }
295 
296 PVOID
297 AllocEventData(
298     IN ULONG ExtraSize)
299 {
300     PKSEVENTDATA Data = (PKSEVENTDATA)ExAllocatePool(NonPagedPool, sizeof(KSEVENTDATA) + ExtraSize);
301     if (!Data)
302         return NULL;
303 
304     Data->EventObject.Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
305     if (!Data->EventHandle.Event)
306     {
307         ExFreePool(Data);
308         return NULL;
309     }
310 
311     KeInitializeEvent(Data->EventObject.Event, NotificationEvent, FALSE);
312 
313     Data->NotificationType = KSEVENTF_EVENT_HANDLE;
314     return Data;
315 }
316 
317 VOID
318 FreeEventData(IN PVOID EventData)
319 {
320     PKSEVENTDATA Data = (PKSEVENTDATA)EventData;
321 
322     ExFreePool(Data->EventHandle.Event);
323     ExFreePool(Data);
324 }
325 
326 NTSTATUS
327 WdmAudMixerInitialize(
328     IN PDEVICE_OBJECT DeviceObject)
329 {
330     MIXER_STATUS Status;
331 
332     /* initialize the mixer library */
333     Status = MMixerInitialize(&MixerContext, Enum, (PVOID)DeviceObject);
334 
335     if (Status != MM_STATUS_SUCCESS)
336     {
337         /* failed to initialize mmixer library */
338         DPRINT("MMixerInitialize failed with %lx\n", Status);
339     }
340 
341     return Status;
342 }
343 
344 NTSTATUS
345 WdmAudMixerCapabilities(
346     IN PDEVICE_OBJECT DeviceObject,
347     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
348     IN  PWDMAUD_CLIENT ClientInfo,
349     IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
350 {
351     if (MMixerGetCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MixCaps) == MM_STATUS_SUCCESS)
352         return STATUS_SUCCESS;
353 
354     return STATUS_INVALID_PARAMETER;
355 }
356 
357 NTSTATUS
358 WdmAudControlOpenMixer(
359     IN  PDEVICE_OBJECT DeviceObject,
360     IN  PIRP Irp,
361     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
362     IN  PWDMAUD_CLIENT ClientInfo)
363 {
364     HANDLE hMixer;
365     PWDMAUD_HANDLE Handles;
366     PWDMAUD_DEVICE_EXTENSION DeviceExtension;
367     NTSTATUS Status;
368     PKEVENT EventObject = NULL;
369 
370     DPRINT("WdmAudControlOpenMixer\n");
371 
372     DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
373 
374     if (DeviceInfo->u.hNotifyEvent)
375     {
376         Status = ObReferenceObjectByHandle(DeviceInfo->u.hNotifyEvent, EVENT_MODIFY_STATE, ExEventObjectType, UserMode, (LPVOID*)&EventObject, NULL);
377 
378         if (!NT_SUCCESS(Status))
379         {
380             DPRINT1("Invalid notify event passed %p from client %p\n", DeviceInfo->u.hNotifyEvent, ClientInfo);
381             DbgBreakPoint();
382             return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
383         }
384     }
385 
386     if (MMixerOpen(&MixerContext, DeviceInfo->DeviceIndex, EventObject, NULL /* FIXME */, &hMixer) != MM_STATUS_SUCCESS)
387     {
388         ObDereferenceObject(EventObject);
389         DPRINT1("Failed to open mixer\n");
390         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
391     }
392 
393 
394     Handles = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
395 
396     if (Handles)
397     {
398         if (ClientInfo->NumPins)
399         {
400             RtlMoveMemory(Handles, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
401             ExFreePool(ClientInfo->hPins);
402         }
403 
404         ClientInfo->hPins = Handles;
405         ClientInfo->hPins[ClientInfo->NumPins].Handle = hMixer;
406         ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
407         ClientInfo->hPins[ClientInfo->NumPins].NotifyEvent = EventObject;
408         ClientInfo->NumPins++;
409     }
410     else
411     {
412         ObDereferenceObject(EventObject);
413         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
414     }
415 
416     DeviceInfo->hDevice = hMixer;
417 
418     return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
419 }
420 
421 NTSTATUS
422 NTAPI
423 WdmAudGetControlDetails(
424     IN  PDEVICE_OBJECT DeviceObject,
425     IN  PIRP Irp,
426     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
427     IN  PWDMAUD_CLIENT ClientInfo)
428 {
429     MIXER_STATUS Status;
430 
431     /* clear hmixer type flag */
432     DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
433 
434     /* query mmixer library */
435     Status = MMixerGetControlDetails(&MixerContext, DeviceInfo->hDevice, DeviceInfo->Flags, &DeviceInfo->u.MixDetails);
436 
437     if (Status == MM_STATUS_SUCCESS)
438         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
439     else
440         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
441 }
442 
443 NTSTATUS
444 NTAPI
445 WdmAudGetLineInfo(
446     IN  PDEVICE_OBJECT DeviceObject,
447     IN  PIRP Irp,
448     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
449     IN  PWDMAUD_CLIENT ClientInfo)
450 {
451     MIXER_STATUS Status;
452 
453     /* clear hmixer type flag */
454     DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
455 
456     /* query mixer library */
457     Status = MMixerGetLineInfo(&MixerContext, DeviceInfo->hDevice, DeviceInfo->Flags, &DeviceInfo->u.MixLine);
458 
459     if (Status == MM_STATUS_SUCCESS)
460         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
461     else
462         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
463 }
464 
465 NTSTATUS
466 NTAPI
467 WdmAudGetLineControls(
468     IN  PDEVICE_OBJECT DeviceObject,
469     IN  PIRP Irp,
470     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
471     IN  PWDMAUD_CLIENT ClientInfo)
472 {
473     MIXER_STATUS Status;
474 
475     /* clear hmixer type flag */
476     DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
477 
478     /* query mixer library */
479     Status = MMixerGetLineControls(&MixerContext, DeviceInfo->hDevice, DeviceInfo->Flags, &DeviceInfo->u.MixControls);
480 
481     if (Status == MM_STATUS_SUCCESS)
482         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
483     else
484         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
485 
486 
487 }
488 
489 NTSTATUS
490 NTAPI
491 WdmAudSetControlDetails(
492     IN  PDEVICE_OBJECT DeviceObject,
493     IN  PIRP Irp,
494     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
495     IN  PWDMAUD_CLIENT ClientInfo)
496 {
497     MIXER_STATUS Status;
498 
499     /* clear hmixer type flag */
500     DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
501 
502     /* query mixer library */
503     Status = MMixerSetControlDetails(&MixerContext, DeviceInfo->hDevice, DeviceInfo->Flags, &DeviceInfo->u.MixDetails);
504 
505     if (Status == MM_STATUS_SUCCESS)
506         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
507     else
508         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
509 }
510 
511 NTSTATUS
512 NTAPI
513 WdmAudGetMixerEvent(
514     IN  PDEVICE_OBJECT DeviceObject,
515     IN  PIRP Irp,
516     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
517     IN  PWDMAUD_CLIENT ClientInfo)
518 {
519     UNIMPLEMENTED
520     return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
521 }
522 
523 ULONG
524 WdmAudGetMixerDeviceCount()
525 {
526     return MMixerGetCount(&MixerContext);
527 }
528 
529 ULONG
530 WdmAudGetWaveInDeviceCount()
531 {
532     return MMixerGetWaveInCount(&MixerContext);
533 }
534 
535 ULONG
536 WdmAudGetWaveOutDeviceCount()
537 {
538     return MMixerGetWaveOutCount(&MixerContext);
539 }
540 
541 NTSTATUS
542 WdmAudGetMixerPnpNameByIndex(
543     IN  ULONG DeviceIndex,
544     OUT LPWSTR * Device)
545 {
546     UNIMPLEMENTED
547     return STATUS_NOT_IMPLEMENTED;
548 }
549 
550 NTSTATUS
551 WdmAudGetPnpNameByIndexAndType(
552     IN ULONG DeviceIndex,
553     IN SOUND_DEVICE_TYPE DeviceType,
554     OUT LPWSTR *DevicePath)
555 {
556     if (MMixerGetWaveDevicePath(&MixerContext, DeviceType == WAVE_IN_DEVICE_TYPE, DeviceIndex, DevicePath) == MM_STATUS_SUCCESS)
557         return STATUS_SUCCESS;
558     else
559         return STATUS_UNSUCCESSFUL;
560 }
561 
562 NTSTATUS
563 WdmAudWaveCapabilities(
564     IN PDEVICE_OBJECT DeviceObject,
565     IN PWDMAUD_DEVICE_INFO DeviceInfo,
566     IN PWDMAUD_CLIENT ClientInfo,
567     IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
568 {
569     MIXER_STATUS Status;
570 
571     if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
572     {
573         /* get capabilities */
574         Status = MMixerWaveInCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.WaveInCaps);
575     }
576     else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
577     {
578         /* get capabilities */
579         Status = MMixerWaveOutCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.WaveOutCaps);
580     }
581     else
582     {
583         ASSERT(0);
584         return STATUS_UNSUCCESSFUL;
585     }
586 
587     if (Status == MM_STATUS_SUCCESS)
588         return STATUS_SUCCESS;
589     else
590         return STATUS_UNSUCCESSFUL;
591 }
592 
593 
594 MIXER_STATUS
595 CreatePinCallback(
596     IN PVOID Ctx,
597     IN ULONG VirtualDeviceId,
598     IN ULONG PinId,
599     IN HANDLE hFilter,
600     IN PKSPIN_CONNECT PinConnect,
601     IN ACCESS_MASK DesiredAccess,
602     OUT PHANDLE PinHandle)
603 {
604     ULONG BytesReturned;
605     SYSAUDIO_INSTANCE_INFO InstanceInfo;
606     NTSTATUS Status;
607     ULONG FreeIndex;
608     PPIN_CREATE_CONTEXT Context = (PPIN_CREATE_CONTEXT)Ctx;
609 
610     /* setup property request */
611     InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
612     InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
613     InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
614     InstanceInfo.Flags = 0;
615     InstanceInfo.DeviceNumber = VirtualDeviceId;
616 
617     /* attach to virtual device */
618     Status = KsSynchronousIoControlDevice(Context->DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
619 
620     if (!NT_SUCCESS(Status))
621         return MM_STATUS_UNSUCCESSFUL;
622 
623     /* close existing pin */
624     FreeIndex = ClosePin(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType);
625 
626     /* now create the pin */
627     Status = KsCreatePin(Context->DeviceExtension->hSysAudio, PinConnect, DesiredAccess, PinHandle);
628 
629     /* check for success */
630     if (!NT_SUCCESS(Status))
631         return MM_STATUS_UNSUCCESSFUL;
632 
633     /* store the handle */
634     Status = InsertPinHandle(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType, *PinHandle, FreeIndex);
635     if (!NT_SUCCESS(Status))
636     {
637         /* failed to insert handle */
638         ZwClose(*PinHandle);
639         return MM_STATUS_UNSUCCESSFUL;
640     }
641 
642     return MM_STATUS_SUCCESS;
643 }
644 
645 NTSTATUS
646 WdmAudControlOpenWave(
647     IN  PDEVICE_OBJECT DeviceObject,
648     IN  PIRP Irp,
649     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
650     IN  PWDMAUD_CLIENT ClientInfo)
651 {
652     MIXER_STATUS Status;
653     PIN_CREATE_CONTEXT Context;
654 
655     Context.ClientInfo = ClientInfo;
656     Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
657     Context.DeviceType = DeviceInfo->DeviceType;
658 
659     Status = MMixerOpenWave(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE, &DeviceInfo->u.WaveFormatEx, CreatePinCallback, &Context, &DeviceInfo->hDevice);
660 
661     if (Status == MM_STATUS_SUCCESS)
662         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
663     else
664         return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
665 }
666