Create a branch for working on csrss and co.
[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
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