[MMIXER] Cleanup mixer notifications opened by an application when it is closed.
[reactos.git] / reactos / 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))
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 NTSTATUS
501 NTAPI
502 WdmAudGetControlDetails(
503 IN PDEVICE_OBJECT DeviceObject,
504 IN PIRP Irp,
505 IN PWDMAUD_DEVICE_INFO DeviceInfo,
506 IN PWDMAUD_CLIENT ClientInfo)
507 {
508 MIXER_STATUS Status;
509
510 /* clear hmixer type flag */
511 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
512
513 /* query mmixer library */
514 Status = MMixerGetControlDetails(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixDetails);
515
516 if (Status == MM_STATUS_SUCCESS)
517 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
518 else
519 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
520 }
521
522 NTSTATUS
523 NTAPI
524 WdmAudGetLineInfo(
525 IN PDEVICE_OBJECT DeviceObject,
526 IN PIRP Irp,
527 IN PWDMAUD_DEVICE_INFO DeviceInfo,
528 IN PWDMAUD_CLIENT ClientInfo)
529 {
530 MIXER_STATUS Status;
531
532 /* clear hmixer type flag */
533 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
534
535 /* query mixer library */
536 Status = MMixerGetLineInfo(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixLine);
537
538 if (Status == MM_STATUS_SUCCESS)
539 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
540 else
541 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
542 }
543
544 NTSTATUS
545 NTAPI
546 WdmAudGetLineControls(
547 IN PDEVICE_OBJECT DeviceObject,
548 IN PIRP Irp,
549 IN PWDMAUD_DEVICE_INFO DeviceInfo,
550 IN PWDMAUD_CLIENT ClientInfo)
551 {
552 MIXER_STATUS Status;
553
554 /* clear hmixer type flag */
555 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
556
557 /* query mixer library */
558 Status = MMixerGetLineControls(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixControls);
559
560 if (Status == MM_STATUS_SUCCESS)
561 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
562 else
563 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
564
565
566 }
567
568 NTSTATUS
569 NTAPI
570 WdmAudSetControlDetails(
571 IN PDEVICE_OBJECT DeviceObject,
572 IN PIRP Irp,
573 IN PWDMAUD_DEVICE_INFO DeviceInfo,
574 IN PWDMAUD_CLIENT ClientInfo)
575 {
576 MIXER_STATUS Status;
577
578 /* clear hmixer type flag */
579 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
580
581 /* query mixer library */
582 Status = MMixerSetControlDetails(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixDetails);
583
584 if (Status == MM_STATUS_SUCCESS)
585 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
586 else
587 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
588 }
589
590 NTSTATUS
591 NTAPI
592 WdmAudGetMixerEvent(
593 IN PDEVICE_OBJECT DeviceObject,
594 IN PIRP Irp,
595 IN PWDMAUD_DEVICE_INFO DeviceInfo,
596 IN PWDMAUD_CLIENT ClientInfo)
597 {
598 PLIST_ENTRY Entry;
599 PEVENT_ENTRY EventEntry;
600
601 /* enumerate event list and check if there is a new event */
602 Entry = ClientInfo->MixerEventList.Flink;
603
604 while(Entry != &ClientInfo->MixerEventList)
605 {
606 /* grab event entry */
607 EventEntry = (PEVENT_ENTRY)CONTAINING_RECORD(Entry, EVENT_ENTRY, Entry);
608
609 if (EventEntry->hMixer == DeviceInfo->hDevice)
610 {
611 /* found an entry */
612 DeviceInfo->u.MixerEvent.hMixer = EventEntry->hMixer;
613 DeviceInfo->u.MixerEvent.NotificationType = EventEntry->NotificationType;
614 DeviceInfo->u.MixerEvent.Value = EventEntry->Value;
615
616 /* remove entry from list */
617 RemoveEntryList(&EventEntry->Entry);
618
619 /* free event entry */
620 FreeItem(EventEntry);
621
622 /* done */
623 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
624 }
625
626 /* move to next */
627 Entry = Entry->Flink;
628 }
629
630 /* no event entry available */
631 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
632 }
633
634 ULONG
635 WdmAudGetMixerDeviceCount()
636 {
637 return MMixerGetCount(&MixerContext);
638 }
639
640 ULONG
641 WdmAudGetWaveInDeviceCount()
642 {
643 return MMixerGetWaveInCount(&MixerContext);
644 }
645
646 ULONG
647 WdmAudGetWaveOutDeviceCount()
648 {
649 return MMixerGetWaveOutCount(&MixerContext);
650 }
651
652 ULONG
653 WdmAudGetMidiInDeviceCount()
654 {
655 return MMixerGetMidiInCount(&MixerContext);
656 }
657
658 ULONG
659 WdmAudGetMidiOutDeviceCount()
660 {
661 return MMixerGetWaveOutCount(&MixerContext);
662 }
663
664 NTSTATUS
665 WdmAudGetPnpNameByIndexAndType(
666 IN ULONG DeviceIndex,
667 IN SOUND_DEVICE_TYPE DeviceType,
668 OUT LPWSTR *DevicePath)
669 {
670 if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
671 {
672 if (MMixerGetWaveDevicePath(&MixerContext, DeviceType == WAVE_IN_DEVICE_TYPE, DeviceIndex, DevicePath) == MM_STATUS_SUCCESS)
673 return STATUS_SUCCESS;
674 else
675 return STATUS_UNSUCCESSFUL;
676 }
677 else if (DeviceType == MIDI_IN_DEVICE_TYPE || DeviceType == MIDI_OUT_DEVICE_TYPE)
678 {
679 if (MMixerGetMidiDevicePath(&MixerContext, DeviceType == MIDI_IN_DEVICE_TYPE, DeviceIndex, DevicePath) == MM_STATUS_SUCCESS)
680 return STATUS_SUCCESS;
681 else
682 return STATUS_UNSUCCESSFUL;
683 }
684 else if (DeviceType == MIXER_DEVICE_TYPE)
685 {
686 UNIMPLEMENTED;
687 }
688
689 return STATUS_UNSUCCESSFUL;
690 }
691
692 NTSTATUS
693 WdmAudWaveCapabilities(
694 IN PDEVICE_OBJECT DeviceObject,
695 IN PWDMAUD_DEVICE_INFO DeviceInfo,
696 IN PWDMAUD_CLIENT ClientInfo,
697 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
698 {
699 MIXER_STATUS Status = MM_STATUS_UNSUCCESSFUL;
700
701 if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
702 {
703 /* get capabilities */
704 Status = MMixerWaveInCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.WaveInCaps);
705 }
706 else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
707 {
708 /* get capabilities */
709 Status = MMixerWaveOutCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.WaveOutCaps);
710 }
711
712 if (Status == MM_STATUS_SUCCESS)
713 return STATUS_SUCCESS;
714 else
715 return Status;
716 }
717
718 NTSTATUS
719 WdmAudMidiCapabilities(
720 IN PDEVICE_OBJECT DeviceObject,
721 IN PWDMAUD_DEVICE_INFO DeviceInfo,
722 IN PWDMAUD_CLIENT ClientInfo,
723 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
724 {
725 MIXER_STATUS Status = MM_STATUS_UNSUCCESSFUL;
726
727 if (DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE)
728 {
729 /* get capabilities */
730 Status = MMixerMidiInCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MidiInCaps);
731 }
732 else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
733 {
734 /* get capabilities */
735 Status = MMixerMidiOutCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MidiOutCaps);
736 }
737
738 if (Status == MM_STATUS_SUCCESS)
739 return STATUS_SUCCESS;
740 else
741 return STATUS_UNSUCCESSFUL;
742 }
743
744
745 MIXER_STATUS
746 CreatePinCallback(
747 IN PVOID Ctx,
748 IN ULONG VirtualDeviceId,
749 IN ULONG PinId,
750 IN HANDLE hFilter,
751 IN PKSPIN_CONNECT PinConnect,
752 IN ACCESS_MASK DesiredAccess,
753 OUT PHANDLE PinHandle)
754 {
755 ULONG BytesReturned;
756 SYSAUDIO_INSTANCE_INFO InstanceInfo;
757 NTSTATUS Status;
758 ULONG FreeIndex;
759 PPIN_CREATE_CONTEXT Context = (PPIN_CREATE_CONTEXT)Ctx;
760
761 /* setup property request */
762 InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
763 InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
764 InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
765 InstanceInfo.Flags = 0;
766 InstanceInfo.DeviceNumber = VirtualDeviceId;
767
768 /* attach to virtual device */
769 Status = KsSynchronousIoControlDevice(Context->DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
770
771 if (!NT_SUCCESS(Status))
772 return MM_STATUS_UNSUCCESSFUL;
773
774 /* close existing pin */
775 FreeIndex = ClosePin(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType);
776
777 /* now create the pin */
778 Status = KsCreatePin(Context->DeviceExtension->hSysAudio, PinConnect, DesiredAccess, PinHandle);
779
780 /* check for success */
781 if (!NT_SUCCESS(Status))
782 return MM_STATUS_UNSUCCESSFUL;
783
784 /* store the handle */
785 Status = InsertPinHandle(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType, *PinHandle, FreeIndex);
786 if (!NT_SUCCESS(Status))
787 {
788 /* failed to insert handle */
789 ZwClose(*PinHandle);
790 return MM_STATUS_UNSUCCESSFUL;
791 }
792
793 return MM_STATUS_SUCCESS;
794 }
795
796 NTSTATUS
797 WdmAudControlOpenWave(
798 IN PDEVICE_OBJECT DeviceObject,
799 IN PIRP Irp,
800 IN PWDMAUD_DEVICE_INFO DeviceInfo,
801 IN PWDMAUD_CLIENT ClientInfo)
802 {
803 MIXER_STATUS Status;
804 PIN_CREATE_CONTEXT Context;
805
806 Context.ClientInfo = ClientInfo;
807 Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
808 Context.DeviceType = DeviceInfo->DeviceType;
809
810 Status = MMixerOpenWave(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE, &DeviceInfo->u.WaveFormatEx, CreatePinCallback, &Context, &DeviceInfo->hDevice);
811
812 if (Status == MM_STATUS_SUCCESS)
813 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
814 else
815 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
816 }
817
818 NTSTATUS
819 WdmAudControlOpenMidi(
820 IN PDEVICE_OBJECT DeviceObject,
821 IN PIRP Irp,
822 IN PWDMAUD_DEVICE_INFO DeviceInfo,
823 IN PWDMAUD_CLIENT ClientInfo)
824 {
825 MIXER_STATUS Status;
826 PIN_CREATE_CONTEXT Context;
827
828 Context.ClientInfo = ClientInfo;
829 Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
830 Context.DeviceType = DeviceInfo->DeviceType;
831
832 Status = MMixerOpenMidi(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE, CreatePinCallback, &Context, &DeviceInfo->hDevice);
833
834 if (Status == MM_STATUS_SUCCESS)
835 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
836 else
837 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
838 }