* Sync up to trunk head (r64716).
[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 /* intialize key name */
270 RtlInitUnicodeString(&KeyName, *DeviceName);
271
272 /* open device interface key */
273 Status = IoOpenDeviceInterfaceRegistryKey(&KeyName, GENERIC_READ | GENERIC_WRITE, OutKey);
274 #if 0
275 if (!NT_SUCCESS(Status))
276 {
277 /* failed to open key */
278 DPRINT("IoOpenDeviceInterfaceRegistryKey failed with %lx\n", Status);
279 FreeItem(*DeviceName);
280 return MM_STATUS_UNSUCCESSFUL;
281 }
282 #endif
283
284 /* open device handle */
285 Status = OpenDevice(*DeviceName, OutHandle, NULL);
286 if (!NT_SUCCESS(Status))
287 {
288 /* failed to open device */
289 return MM_STATUS_UNSUCCESSFUL;
290 }
291
292 return MM_STATUS_SUCCESS;
293 }
294
295 PVOID
296 AllocEventData(
297 IN ULONG ExtraSize)
298 {
299 PKSEVENTDATA Data = (PKSEVENTDATA)AllocateItem(NonPagedPool, sizeof(KSEVENTDATA) + ExtraSize);
300 if (!Data)
301 return NULL;
302
303 Data->EventObject.Event = AllocateItem(NonPagedPool, sizeof(KEVENT));
304 if (!Data->EventHandle.Event)
305 {
306 FreeItem(Data);
307 return NULL;
308 }
309
310 KeInitializeEvent(Data->EventObject.Event, NotificationEvent, FALSE);
311
312 Data->NotificationType = KSEVENTF_EVENT_HANDLE;
313 return Data;
314 }
315
316 VOID
317 FreeEventData(IN PVOID EventData)
318 {
319 PKSEVENTDATA Data = (PKSEVENTDATA)EventData;
320
321 FreeItem(Data->EventHandle.Event);
322 FreeItem(Data);
323 }
324
325 VOID
326 CALLBACK
327 EventCallback(
328 IN PVOID MixerEventContext,
329 IN HANDLE hMixer,
330 IN ULONG NotificationType,
331 IN ULONG Value)
332 {
333 PWDMAUD_CLIENT ClientInfo;
334 PEVENT_ENTRY Entry;
335 ULONG Index;
336
337 /* get client context */
338 ClientInfo = (PWDMAUD_CLIENT)MixerEventContext;
339
340 /* now search for the mixer which originated the request */
341 for(Index = 0; Index < ClientInfo->NumPins; Index++)
342 {
343 if (ClientInfo->hPins[Index].Handle == hMixer && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
344 {
345 if (ClientInfo->hPins[Index].NotifyEvent)
346 {
347 /* allocate event entry */
348 Entry = AllocateItem(NonPagedPool, sizeof(EVENT_ENTRY));
349 if (!Entry)
350 {
351 /* no memory */
352 break;
353 }
354
355 /* setup event entry */
356 Entry->NotificationType = NotificationType;
357 Entry->Value = Value;
358 Entry->hMixer = hMixer;
359
360 /* insert entry */
361 InsertTailList(&ClientInfo->MixerEventList, &Entry->Entry);
362
363 /* now notify the client */
364 KeSetEvent(ClientInfo->hPins[Index].NotifyEvent, 0, FALSE);
365 }
366 /* done */
367 break;
368 }
369 }
370 }
371
372
373 NTSTATUS
374 WdmAudMixerInitialize(
375 IN PDEVICE_OBJECT DeviceObject)
376 {
377 MIXER_STATUS Status;
378
379 /* initialize the mixer library */
380 Status = MMixerInitialize(&MixerContext, Enum, (PVOID)DeviceObject);
381
382 if (Status != MM_STATUS_SUCCESS)
383 {
384 /* failed to initialize mmixer library */
385 DPRINT("MMixerInitialize failed with %lx\n", Status);
386 }
387
388 return Status;
389 }
390
391 NTSTATUS
392 WdmAudMixerCapabilities(
393 IN PDEVICE_OBJECT DeviceObject,
394 IN PWDMAUD_DEVICE_INFO DeviceInfo,
395 IN PWDMAUD_CLIENT ClientInfo,
396 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
397 {
398 if (MMixerGetCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MixCaps) == MM_STATUS_SUCCESS)
399 return STATUS_SUCCESS;
400
401 return STATUS_INVALID_PARAMETER;
402 }
403
404 NTSTATUS
405 WdmAudControlOpenMixer(
406 IN PDEVICE_OBJECT DeviceObject,
407 IN PIRP Irp,
408 IN PWDMAUD_DEVICE_INFO DeviceInfo,
409 IN PWDMAUD_CLIENT ClientInfo)
410 {
411 HANDLE hMixer;
412 PWDMAUD_HANDLE Handles;
413 //PWDMAUD_DEVICE_EXTENSION DeviceExtension;
414 NTSTATUS Status;
415 PKEVENT EventObject = NULL;
416
417 DPRINT("WdmAudControlOpenMixer\n");
418
419 //DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
420
421 if (DeviceInfo->u.hNotifyEvent)
422 {
423 Status = ObReferenceObjectByHandle(DeviceInfo->u.hNotifyEvent, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode, (LPVOID*)&EventObject, NULL);
424
425 if (!NT_SUCCESS(Status))
426 {
427 DPRINT1("Invalid notify event passed %p from client %p\n", DeviceInfo->u.hNotifyEvent, ClientInfo);
428 DbgBreakPoint();
429 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
430 }
431 }
432
433 if (MMixerOpen(&MixerContext, DeviceInfo->DeviceIndex, ClientInfo, EventCallback, &hMixer) != MM_STATUS_SUCCESS)
434 {
435 ObDereferenceObject(EventObject);
436 DPRINT1("Failed to open mixer\n");
437 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
438 }
439
440
441 Handles = AllocateItem(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
442
443 if (Handles)
444 {
445 if (ClientInfo->NumPins)
446 {
447 RtlMoveMemory(Handles, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
448 FreeItem(ClientInfo->hPins);
449 }
450
451 ClientInfo->hPins = Handles;
452 ClientInfo->hPins[ClientInfo->NumPins].Handle = hMixer;
453 ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
454 ClientInfo->hPins[ClientInfo->NumPins].NotifyEvent = EventObject;
455 ClientInfo->NumPins++;
456 }
457 else
458 {
459 ObDereferenceObject(EventObject);
460 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
461 }
462
463 DeviceInfo->hDevice = hMixer;
464
465 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
466 }
467
468 NTSTATUS
469 NTAPI
470 WdmAudGetControlDetails(
471 IN PDEVICE_OBJECT DeviceObject,
472 IN PIRP Irp,
473 IN PWDMAUD_DEVICE_INFO DeviceInfo,
474 IN PWDMAUD_CLIENT ClientInfo)
475 {
476 MIXER_STATUS Status;
477
478 /* clear hmixer type flag */
479 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
480
481 /* query mmixer library */
482 Status = MMixerGetControlDetails(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixDetails);
483
484 if (Status == MM_STATUS_SUCCESS)
485 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
486 else
487 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
488 }
489
490 NTSTATUS
491 NTAPI
492 WdmAudGetLineInfo(
493 IN PDEVICE_OBJECT DeviceObject,
494 IN PIRP Irp,
495 IN PWDMAUD_DEVICE_INFO DeviceInfo,
496 IN PWDMAUD_CLIENT ClientInfo)
497 {
498 MIXER_STATUS Status;
499
500 /* clear hmixer type flag */
501 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
502
503 /* query mixer library */
504 Status = MMixerGetLineInfo(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixLine);
505
506 if (Status == MM_STATUS_SUCCESS)
507 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
508 else
509 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
510 }
511
512 NTSTATUS
513 NTAPI
514 WdmAudGetLineControls(
515 IN PDEVICE_OBJECT DeviceObject,
516 IN PIRP Irp,
517 IN PWDMAUD_DEVICE_INFO DeviceInfo,
518 IN PWDMAUD_CLIENT ClientInfo)
519 {
520 MIXER_STATUS Status;
521
522 /* clear hmixer type flag */
523 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
524
525 /* query mixer library */
526 Status = MMixerGetLineControls(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixControls);
527
528 if (Status == MM_STATUS_SUCCESS)
529 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
530 else
531 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
532
533
534 }
535
536 NTSTATUS
537 NTAPI
538 WdmAudSetControlDetails(
539 IN PDEVICE_OBJECT DeviceObject,
540 IN PIRP Irp,
541 IN PWDMAUD_DEVICE_INFO DeviceInfo,
542 IN PWDMAUD_CLIENT ClientInfo)
543 {
544 MIXER_STATUS Status;
545
546 /* clear hmixer type flag */
547 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
548
549 /* query mixer library */
550 Status = MMixerSetControlDetails(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixDetails);
551
552 if (Status == MM_STATUS_SUCCESS)
553 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
554 else
555 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
556 }
557
558 NTSTATUS
559 NTAPI
560 WdmAudGetMixerEvent(
561 IN PDEVICE_OBJECT DeviceObject,
562 IN PIRP Irp,
563 IN PWDMAUD_DEVICE_INFO DeviceInfo,
564 IN PWDMAUD_CLIENT ClientInfo)
565 {
566 PLIST_ENTRY Entry;
567 PEVENT_ENTRY EventEntry;
568
569 /* enumerate event list and check if there is a new event */
570 Entry = ClientInfo->MixerEventList.Flink;
571
572 while(Entry != &ClientInfo->MixerEventList)
573 {
574 /* grab event entry */
575 EventEntry = (PEVENT_ENTRY)CONTAINING_RECORD(Entry, EVENT_ENTRY, Entry);
576
577 if (EventEntry->hMixer == DeviceInfo->hDevice)
578 {
579 /* found an entry */
580 DeviceInfo->u.MixerEvent.hMixer = EventEntry->hMixer;
581 DeviceInfo->u.MixerEvent.NotificationType = EventEntry->NotificationType;
582 DeviceInfo->u.MixerEvent.Value = EventEntry->Value;
583
584 /* remove entry from list */
585 RemoveEntryList(&EventEntry->Entry);
586
587 /* free event entry */
588 FreeItem(EventEntry);
589
590 /* done */
591 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
592 }
593
594 /* move to next */
595 Entry = Entry->Flink;
596 }
597
598 /* no event entry available */
599 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
600 }
601
602 ULONG
603 WdmAudGetMixerDeviceCount()
604 {
605 return MMixerGetCount(&MixerContext);
606 }
607
608 ULONG
609 WdmAudGetWaveInDeviceCount()
610 {
611 return MMixerGetWaveInCount(&MixerContext);
612 }
613
614 ULONG
615 WdmAudGetWaveOutDeviceCount()
616 {
617 return MMixerGetWaveOutCount(&MixerContext);
618 }
619
620 ULONG
621 WdmAudGetMidiInDeviceCount()
622 {
623 return MMixerGetMidiInCount(&MixerContext);
624 }
625
626 ULONG
627 WdmAudGetMidiOutDeviceCount()
628 {
629 return MMixerGetWaveOutCount(&MixerContext);
630 }
631
632 NTSTATUS
633 WdmAudGetPnpNameByIndexAndType(
634 IN ULONG DeviceIndex,
635 IN SOUND_DEVICE_TYPE DeviceType,
636 OUT LPWSTR *DevicePath)
637 {
638 if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
639 {
640 if (MMixerGetWaveDevicePath(&MixerContext, DeviceType == WAVE_IN_DEVICE_TYPE, DeviceIndex, DevicePath) == MM_STATUS_SUCCESS)
641 return STATUS_SUCCESS;
642 else
643 return STATUS_UNSUCCESSFUL;
644 }
645 else if (DeviceType == MIDI_IN_DEVICE_TYPE || DeviceType == MIDI_OUT_DEVICE_TYPE)
646 {
647 if (MMixerGetMidiDevicePath(&MixerContext, DeviceType == MIDI_IN_DEVICE_TYPE, DeviceIndex, DevicePath) == MM_STATUS_SUCCESS)
648 return STATUS_SUCCESS;
649 else
650 return STATUS_UNSUCCESSFUL;
651 }
652 else if (DeviceType == MIXER_DEVICE_TYPE)
653 {
654 UNIMPLEMENTED;
655 }
656
657 return STATUS_UNSUCCESSFUL;
658 }
659
660 NTSTATUS
661 WdmAudWaveCapabilities(
662 IN PDEVICE_OBJECT DeviceObject,
663 IN PWDMAUD_DEVICE_INFO DeviceInfo,
664 IN PWDMAUD_CLIENT ClientInfo,
665 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
666 {
667 MIXER_STATUS Status = MM_STATUS_UNSUCCESSFUL;
668
669 if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
670 {
671 /* get capabilities */
672 Status = MMixerWaveInCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.WaveInCaps);
673 }
674 else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
675 {
676 /* get capabilities */
677 Status = MMixerWaveOutCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.WaveOutCaps);
678 }
679
680 if (Status == MM_STATUS_SUCCESS)
681 return STATUS_SUCCESS;
682 else
683 return Status;
684 }
685
686 NTSTATUS
687 WdmAudMidiCapabilities(
688 IN PDEVICE_OBJECT DeviceObject,
689 IN PWDMAUD_DEVICE_INFO DeviceInfo,
690 IN PWDMAUD_CLIENT ClientInfo,
691 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
692 {
693 MIXER_STATUS Status = MM_STATUS_UNSUCCESSFUL;
694
695 if (DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE)
696 {
697 /* get capabilities */
698 Status = MMixerMidiInCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MidiInCaps);
699 }
700 else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
701 {
702 /* get capabilities */
703 Status = MMixerMidiOutCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MidiOutCaps);
704 }
705
706 if (Status == MM_STATUS_SUCCESS)
707 return STATUS_SUCCESS;
708 else
709 return STATUS_UNSUCCESSFUL;
710 }
711
712
713 MIXER_STATUS
714 CreatePinCallback(
715 IN PVOID Ctx,
716 IN ULONG VirtualDeviceId,
717 IN ULONG PinId,
718 IN HANDLE hFilter,
719 IN PKSPIN_CONNECT PinConnect,
720 IN ACCESS_MASK DesiredAccess,
721 OUT PHANDLE PinHandle)
722 {
723 ULONG BytesReturned;
724 SYSAUDIO_INSTANCE_INFO InstanceInfo;
725 NTSTATUS Status;
726 ULONG FreeIndex;
727 PPIN_CREATE_CONTEXT Context = (PPIN_CREATE_CONTEXT)Ctx;
728
729 /* setup property request */
730 InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
731 InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
732 InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
733 InstanceInfo.Flags = 0;
734 InstanceInfo.DeviceNumber = VirtualDeviceId;
735
736 /* attach to virtual device */
737 Status = KsSynchronousIoControlDevice(Context->DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
738
739 if (!NT_SUCCESS(Status))
740 return MM_STATUS_UNSUCCESSFUL;
741
742 /* close existing pin */
743 FreeIndex = ClosePin(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType);
744
745 /* now create the pin */
746 Status = KsCreatePin(Context->DeviceExtension->hSysAudio, PinConnect, DesiredAccess, PinHandle);
747
748 /* check for success */
749 if (!NT_SUCCESS(Status))
750 return MM_STATUS_UNSUCCESSFUL;
751
752 /* store the handle */
753 Status = InsertPinHandle(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType, *PinHandle, FreeIndex);
754 if (!NT_SUCCESS(Status))
755 {
756 /* failed to insert handle */
757 ZwClose(*PinHandle);
758 return MM_STATUS_UNSUCCESSFUL;
759 }
760
761 return MM_STATUS_SUCCESS;
762 }
763
764 NTSTATUS
765 WdmAudControlOpenWave(
766 IN PDEVICE_OBJECT DeviceObject,
767 IN PIRP Irp,
768 IN PWDMAUD_DEVICE_INFO DeviceInfo,
769 IN PWDMAUD_CLIENT ClientInfo)
770 {
771 MIXER_STATUS Status;
772 PIN_CREATE_CONTEXT Context;
773
774 Context.ClientInfo = ClientInfo;
775 Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
776 Context.DeviceType = DeviceInfo->DeviceType;
777
778 Status = MMixerOpenWave(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE, &DeviceInfo->u.WaveFormatEx, CreatePinCallback, &Context, &DeviceInfo->hDevice);
779
780 if (Status == MM_STATUS_SUCCESS)
781 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
782 else
783 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
784 }
785
786 NTSTATUS
787 WdmAudControlOpenMidi(
788 IN PDEVICE_OBJECT DeviceObject,
789 IN PIRP Irp,
790 IN PWDMAUD_DEVICE_INFO DeviceInfo,
791 IN PWDMAUD_CLIENT ClientInfo)
792 {
793 MIXER_STATUS Status;
794 PIN_CREATE_CONTEXT Context;
795
796 Context.ClientInfo = ClientInfo;
797 Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
798 Context.DeviceType = DeviceInfo->DeviceType;
799
800 Status = MMixerOpenMidi(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE, CreatePinCallback, &Context, &DeviceInfo->hDevice);
801
802 if (Status == MM_STATUS_SUCCESS)
803 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
804 else
805 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
806 }