[WDMAUD] Close mixers on cleanup. Should fix CORE-10735 definitely (#21)
[reactos.git] / drivers / wdm / audio / legacy / wdmaud / mmixer.c
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_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
773 MIXER_STATUS
774 CreatePinCallback(
775 IN PVOID Ctx,
776 IN ULONG VirtualDeviceId,
777 IN ULONG PinId,
778 IN HANDLE hFilter,
779 IN PKSPIN_CONNECT PinConnect,
780 IN ACCESS_MASK DesiredAccess,
781 OUT PHANDLE PinHandle)
782 {
783 ULONG BytesReturned;
784 SYSAUDIO_INSTANCE_INFO InstanceInfo;
785 NTSTATUS Status;
786 ULONG FreeIndex;
787 PPIN_CREATE_CONTEXT Context = (PPIN_CREATE_CONTEXT)Ctx;
788
789 /* setup property request */
790 InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
791 InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
792 InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
793 InstanceInfo.Flags = 0;
794 InstanceInfo.DeviceNumber = VirtualDeviceId;
795
796 /* attach to virtual device */
797 Status = KsSynchronousIoControlDevice(Context->DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
798
799 if (!NT_SUCCESS(Status))
800 return MM_STATUS_UNSUCCESSFUL;
801
802 /* close existing pin */
803 FreeIndex = ClosePin(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType);
804
805 /* now create the pin */
806 Status = KsCreatePin(Context->DeviceExtension->hSysAudio, PinConnect, DesiredAccess, PinHandle);
807
808 /* check for success */
809 if (!NT_SUCCESS(Status))
810 return MM_STATUS_UNSUCCESSFUL;
811
812 /* store the handle */
813 Status = InsertPinHandle(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType, *PinHandle, FreeIndex);
814 if (!NT_SUCCESS(Status))
815 {
816 /* failed to insert handle */
817 ZwClose(*PinHandle);
818 return MM_STATUS_UNSUCCESSFUL;
819 }
820
821 return MM_STATUS_SUCCESS;
822 }
823
824 NTSTATUS
825 WdmAudControlOpenWave(
826 IN PDEVICE_OBJECT DeviceObject,
827 IN PIRP Irp,
828 IN PWDMAUD_DEVICE_INFO DeviceInfo,
829 IN PWDMAUD_CLIENT ClientInfo)
830 {
831 MIXER_STATUS Status;
832 PIN_CREATE_CONTEXT Context;
833
834 Context.ClientInfo = ClientInfo;
835 Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
836 Context.DeviceType = DeviceInfo->DeviceType;
837
838 Status = MMixerOpenWave(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE, &DeviceInfo->u.WaveFormatEx, CreatePinCallback, &Context, &DeviceInfo->hDevice);
839
840 if (Status == MM_STATUS_SUCCESS)
841 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
842 else
843 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
844 }
845
846 NTSTATUS
847 WdmAudControlOpenMidi(
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 = MMixerOpenMidi(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE, 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 }