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
QueryKeyValue(IN HANDLE hKey,IN LPWSTR lpKeyName,OUT PVOID * ResultBuffer,OUT PULONG ResultLength,OUT PULONG KeyType)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
OpenKey(IN HANDLE hKey,IN LPWSTR lpSubKeyName,IN ULONG DesiredAccess,OUT PHANDLE OutKey)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_KERNEL_HANDLE | 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
CloseKey(IN HANDLE hKey)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
Alloc(ULONG NumBytes)154 PVOID Alloc(ULONG NumBytes)
155 {
156 return AllocateItem(NonPagedPool, NumBytes);
157 }
158
159 MIXER_STATUS
Close(HANDLE hDevice)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
Free(PVOID Block)169 Free(PVOID Block)
170 {
171 FreeItem(Block);
172 }
173
174 VOID
Copy(PVOID Src,PVOID Dst,ULONG NumBytes)175 Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
176 {
177 RtlMoveMemory(Src, Dst, NumBytes);
178 }
179
180 MIXER_STATUS
Open(IN LPWSTR DevicePath,OUT PHANDLE hDevice)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
Control(IN HANDLE hMixer,IN ULONG dwIoControlCode,IN PVOID lpInBuffer,IN ULONG nInBufferSize,OUT PVOID lpOutBuffer,ULONG nOutBufferSize,PULONG lpBytesReturned)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
Enum(IN PVOID EnumContext,IN ULONG DeviceIndex,OUT LPWSTR * DeviceName,OUT PHANDLE OutHandle,OUT PHANDLE OutKey)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
AllocEventData(IN ULONG ExtraSize)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
FreeEventData(IN PVOID EventData)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
EventCallback(IN PVOID MixerEventContext,IN HANDLE hMixer,IN ULONG NotificationType,IN ULONG Value)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
WdmAudMixerInitialize(IN PDEVICE_OBJECT DeviceObject)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
WdmAudMixerCapabilities(IN PDEVICE_OBJECT DeviceObject,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo,IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)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
WdmAudControlOpenMixer(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudControlCloseMixer(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo,IN ULONG Index)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
WdmAudCloseAllMixers(IN PDEVICE_OBJECT DeviceObject,IN PWDMAUD_CLIENT ClientInfo,IN ULONG Index)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
WdmAudGetControlDetails(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudGetLineInfo(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudGetLineControls(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudSetControlDetails(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudGetMixerEvent(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)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
WdmAudGetMixerDeviceCount()663 WdmAudGetMixerDeviceCount()
664 {
665 return MMixerGetCount(&MixerContext);
666 }
667
668 ULONG
WdmAudGetWaveInDeviceCount()669 WdmAudGetWaveInDeviceCount()
670 {
671 return MMixerGetWaveInCount(&MixerContext);
672 }
673
674 ULONG
WdmAudGetWaveOutDeviceCount()675 WdmAudGetWaveOutDeviceCount()
676 {
677 return MMixerGetWaveOutCount(&MixerContext);
678 }
679
680 ULONG
WdmAudGetMidiInDeviceCount()681 WdmAudGetMidiInDeviceCount()
682 {
683 return MMixerGetMidiInCount(&MixerContext);
684 }
685
686 ULONG
WdmAudGetMidiOutDeviceCount()687 WdmAudGetMidiOutDeviceCount()
688 {
689 return MMixerGetWaveOutCount(&MixerContext);
690 }
691
692 NTSTATUS
WdmAudGetPnpNameByIndexAndType(IN ULONG DeviceIndex,IN SOUND_DEVICE_TYPE DeviceType,OUT LPWSTR * DevicePath)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
WdmAudWaveCapabilities(IN PDEVICE_OBJECT DeviceObject,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo,IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)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
WdmAudMidiCapabilities(IN PDEVICE_OBJECT DeviceObject,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo,IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)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 NTSTATUS
773 NTAPI
WdmAudGetPosition(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp,_In_ PWDMAUD_DEVICE_INFO DeviceInfo)774 WdmAudGetPosition(
775 _In_ PDEVICE_OBJECT DeviceObject,
776 _In_ PIRP Irp,
777 _In_ PWDMAUD_DEVICE_INFO DeviceInfo)
778 {
779 MIXER_STATUS Status;
780 ULONG Position;
781
782 /* Get position */
783 Status = MMixerGetWavePosition(&MixerContext, DeviceInfo->hDevice, &Position);
784
785 if (Status == MM_STATUS_SUCCESS)
786 {
787 DeviceInfo->u.Position = (ULONGLONG)Position;
788 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
789 }
790 else
791 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
792 }
793
794
795 MIXER_STATUS
CreatePinCallback(IN PVOID Ctx,IN ULONG VirtualDeviceId,IN ULONG PinId,IN HANDLE hFilter,IN PKSPIN_CONNECT PinConnect,IN ACCESS_MASK DesiredAccess,OUT PHANDLE PinHandle)796 CreatePinCallback(
797 IN PVOID Ctx,
798 IN ULONG VirtualDeviceId,
799 IN ULONG PinId,
800 IN HANDLE hFilter,
801 IN PKSPIN_CONNECT PinConnect,
802 IN ACCESS_MASK DesiredAccess,
803 OUT PHANDLE PinHandle)
804 {
805 ULONG BytesReturned;
806 SYSAUDIO_INSTANCE_INFO InstanceInfo;
807 NTSTATUS Status;
808 ULONG FreeIndex;
809 PPIN_CREATE_CONTEXT Context = (PPIN_CREATE_CONTEXT)Ctx;
810
811 /* setup property request */
812 InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
813 InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
814 InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
815 InstanceInfo.Flags = 0;
816 InstanceInfo.DeviceNumber = VirtualDeviceId;
817
818 /* attach to virtual device */
819 Status = KsSynchronousIoControlDevice(Context->DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
820
821 if (!NT_SUCCESS(Status))
822 return MM_STATUS_UNSUCCESSFUL;
823
824 /* close existing pin */
825 FreeIndex = ClosePin(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType);
826
827 /* now create the pin */
828 Status = KsCreatePin(Context->DeviceExtension->hSysAudio, PinConnect, DesiredAccess, PinHandle);
829
830 /* check for success */
831 if (!NT_SUCCESS(Status))
832 return MM_STATUS_UNSUCCESSFUL;
833
834 /* store the handle */
835 Status = InsertPinHandle(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType, *PinHandle, FreeIndex);
836 if (!NT_SUCCESS(Status))
837 {
838 /* failed to insert handle */
839 ZwClose(*PinHandle);
840 return MM_STATUS_UNSUCCESSFUL;
841 }
842
843 return MM_STATUS_SUCCESS;
844 }
845
846 NTSTATUS
WdmAudControlOpenWave(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)847 WdmAudControlOpenWave(
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 = MMixerOpenWave(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE, &DeviceInfo->u.WaveFormatEx, 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 }
867
868 NTSTATUS
WdmAudControlOpenMidi(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)869 WdmAudControlOpenMidi(
870 IN PDEVICE_OBJECT DeviceObject,
871 IN PIRP Irp,
872 IN PWDMAUD_DEVICE_INFO DeviceInfo,
873 IN PWDMAUD_CLIENT ClientInfo)
874 {
875 MIXER_STATUS Status;
876 PIN_CREATE_CONTEXT Context;
877
878 Context.ClientInfo = ClientInfo;
879 Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
880 Context.DeviceType = DeviceInfo->DeviceType;
881
882 Status = MMixerOpenMidi(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE, CreatePinCallback, &Context, &DeviceInfo->hDevice);
883
884 if (Status == MM_STATUS_SUCCESS)
885 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
886 else
887 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
888 }
889