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
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
);
25 MIXER_CONTEXT MixerContext
=
27 sizeof(MIXER_CONTEXT
),
42 GUID CategoryGuid
= {STATIC_KSCATEGORY_AUDIO
};
48 OUT PVOID
* ResultBuffer
,
49 OUT PULONG ResultLength
,
53 UNICODE_STRING KeyName
;
55 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation
;
57 /* initialize key name */
58 RtlInitUnicodeString(&KeyName
, lpKeyName
);
60 /* now query MatchingDeviceId key */
61 Status
= ZwQueryValueKey(hKey
, &KeyName
, KeyValuePartialInformation
, NULL
, 0, &Length
);
63 /* check for success */
64 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
65 return MM_STATUS_UNSUCCESSFUL
;
67 /* allocate a buffer for key data */
68 PartialInformation
= ExAllocatePool(NonPagedPool
, Length
);
70 if (!PartialInformation
)
71 return MM_STATUS_NO_MEMORY
;
74 /* now query MatchingDeviceId key */
75 Status
= ZwQueryValueKey(hKey
, &KeyName
, KeyValuePartialInformation
, PartialInformation
, Length
, &Length
);
77 /* check for success */
78 if (!NT_SUCCESS(Status
))
80 ExFreePool(PartialInformation
);
81 return MM_STATUS_UNSUCCESSFUL
;
87 *KeyType
= PartialInformation
->Type
;
92 /* return data length */
93 *ResultLength
= PartialInformation
->DataLength
;
96 *ResultBuffer
= ExAllocatePool(NonPagedPool
, PartialInformation
->DataLength
);
99 /* not enough memory */
100 ExFreePool(PartialInformation
);
101 return MM_STATUS_NO_MEMORY
;
105 RtlMoveMemory(*ResultBuffer
, PartialInformation
->Data
, PartialInformation
->DataLength
);
108 ExFreePool(PartialInformation
);
110 return MM_STATUS_SUCCESS
;
116 IN LPWSTR lpSubKeyName
,
117 IN ULONG DesiredAccess
,
120 OBJECT_ATTRIBUTES ObjectAttributes
;
121 UNICODE_STRING SubKeyName
;
124 /* initialize sub key name */
125 RtlInitUnicodeString(&SubKeyName
, lpSubKeyName
);
127 /* initialize key attributes */
128 InitializeObjectAttributes(&ObjectAttributes
, &SubKeyName
, OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
, hKey
, NULL
);
131 Status
= ZwOpenKey(OutKey
, DesiredAccess
, &ObjectAttributes
);
133 if (NT_SUCCESS(Status
))
134 return MM_STATUS_SUCCESS
;
136 return MM_STATUS_UNSUCCESSFUL
;
143 if (ZwClose(hKey
) == STATUS_SUCCESS
)
144 return MM_STATUS_SUCCESS
;
146 return MM_STATUS_UNSUCCESSFUL
;
150 PVOID
Alloc(ULONG NumBytes
)
152 PVOID Mem
= ExAllocatePool(NonPagedPool
, NumBytes
);
156 RtlZeroMemory(Mem
, NumBytes
);
161 Close(HANDLE hDevice
)
163 if (ZwClose(hDevice
) == STATUS_SUCCESS
)
164 return MM_STATUS_SUCCESS
;
166 return MM_STATUS_UNSUCCESSFUL
;
176 Copy(PVOID Src
, PVOID Dst
, ULONG NumBytes
)
178 RtlMoveMemory(Src
, Dst
, NumBytes
);
183 IN LPWSTR DevicePath
,
186 if (WdmAudOpenSysAudioDevice(DevicePath
, hDevice
) == STATUS_SUCCESS
)
187 return MM_STATUS_SUCCESS
;
189 return MM_STATUS_UNSUCCESSFUL
;
195 IN ULONG dwIoControlCode
,
197 IN ULONG nInBufferSize
,
198 OUT PVOID lpOutBuffer
,
199 ULONG nOutBufferSize
,
200 PULONG lpBytesReturned
)
203 PFILE_OBJECT FileObject
;
205 /* get file object */
206 Status
= ObReferenceObjectByHandle(hMixer
, GENERIC_READ
| GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
207 if (!NT_SUCCESS(Status
))
209 DPRINT("failed to reference %p with %lx\n", hMixer
, Status
);
210 return MM_STATUS_UNSUCCESSFUL
;
213 /* perform request */
214 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, dwIoControlCode
, lpInBuffer
, nInBufferSize
, lpOutBuffer
, nOutBufferSize
, lpBytesReturned
);
216 /* release object reference */
217 ObDereferenceObject(FileObject
);
219 if (Status
== STATUS_MORE_ENTRIES
|| Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
221 /* more data is available */
222 return MM_STATUS_MORE_ENTRIES
;
224 else if (Status
== STATUS_SUCCESS
)
226 /* operation succeeded */
227 return MM_STATUS_SUCCESS
;
231 DPRINT("Failed with %lx\n", Status
);
232 return MM_STATUS_UNSUCCESSFUL
;
238 IN PVOID EnumContext
,
239 IN ULONG DeviceIndex
,
240 OUT LPWSTR
* DeviceName
,
241 OUT PHANDLE OutHandle
,
244 PDEVICE_OBJECT DeviceObject
;
247 UNICODE_STRING KeyName
;
249 /* get enumeration context */
250 DeviceObject
= (PDEVICE_OBJECT
)EnumContext
;
252 /* get device count */
253 DeviceCount
= GetSysAudioDeviceCount(DeviceObject
);
255 if (DeviceIndex
>= DeviceCount
)
257 /* no more devices */
258 return MM_STATUS_NO_MORE_DEVICES
;
261 /* get device name */
262 Status
= GetSysAudioDevicePnpName(DeviceObject
, DeviceIndex
, DeviceName
);
264 if (!NT_SUCCESS(Status
))
266 /* failed to retrieve device name */
267 return MM_STATUS_UNSUCCESSFUL
;
270 /* intialize key name */
271 RtlInitUnicodeString(&KeyName
, *DeviceName
);
273 /* open device interface key */
274 Status
= IoOpenDeviceInterfaceRegistryKey(&KeyName
, GENERIC_READ
| GENERIC_WRITE
, OutKey
);
276 if (!NT_SUCCESS(Status
))
278 /* failed to open key */
279 DPRINT("IoOpenDeviceInterfaceRegistryKey failed with %lx\n", Status
);
280 ExFreePool(*DeviceName
);
281 return MM_STATUS_UNSUCCESSFUL
;
285 /* open device handle */
286 Status
= OpenDevice(*DeviceName
, OutHandle
, NULL
);
287 if (!NT_SUCCESS(Status
))
289 /* failed to open device */
290 return MM_STATUS_UNSUCCESSFUL
;
293 return MM_STATUS_SUCCESS
;
300 PKSEVENTDATA Data
= (PKSEVENTDATA
)ExAllocatePool(NonPagedPool
, sizeof(KSEVENTDATA
) + ExtraSize
);
304 Data
->EventObject
.Event
= ExAllocatePool(NonPagedPool
, sizeof(KEVENT
));
305 if (!Data
->EventHandle
.Event
)
311 KeInitializeEvent(Data
->EventObject
.Event
, NotificationEvent
, FALSE
);
313 Data
->NotificationType
= KSEVENTF_EVENT_HANDLE
;
318 FreeEventData(IN PVOID EventData
)
320 PKSEVENTDATA Data
= (PKSEVENTDATA
)EventData
;
322 ExFreePool(Data
->EventHandle
.Event
);
327 WdmAudMixerInitialize(
328 IN PDEVICE_OBJECT DeviceObject
)
332 /* initialize the mixer library */
333 Status
= MMixerInitialize(&MixerContext
, Enum
, (PVOID
)DeviceObject
);
335 if (Status
!= MM_STATUS_SUCCESS
)
337 /* failed to initialize mmixer library */
338 DPRINT("MMixerInitialize failed with %lx\n", Status
);
345 WdmAudMixerCapabilities(
346 IN PDEVICE_OBJECT DeviceObject
,
347 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
348 IN PWDMAUD_CLIENT ClientInfo
,
349 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension
)
351 if (MMixerGetCapabilities(&MixerContext
, DeviceInfo
->DeviceIndex
, &DeviceInfo
->u
.MixCaps
) == MM_STATUS_SUCCESS
)
352 return STATUS_SUCCESS
;
354 return STATUS_INVALID_PARAMETER
;
358 WdmAudControlOpenMixer(
359 IN PDEVICE_OBJECT DeviceObject
,
361 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
362 IN PWDMAUD_CLIENT ClientInfo
)
365 PWDMAUD_HANDLE Handles
;
366 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
368 PKEVENT EventObject
= NULL
;
370 DPRINT("WdmAudControlOpenMixer\n");
372 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
374 if (DeviceInfo
->u
.hNotifyEvent
)
376 Status
= ObReferenceObjectByHandle(DeviceInfo
->u
.hNotifyEvent
, EVENT_MODIFY_STATE
, ExEventObjectType
, UserMode
, (LPVOID
*)&EventObject
, NULL
);
378 if (!NT_SUCCESS(Status
))
380 DPRINT1("Invalid notify event passed %p from client %p\n", DeviceInfo
->u
.hNotifyEvent
, ClientInfo
);
382 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
386 if (MMixerOpen(&MixerContext
, DeviceInfo
->DeviceIndex
, EventObject
, NULL
/* FIXME */, &hMixer
) != MM_STATUS_SUCCESS
)
388 ObDereferenceObject(EventObject
);
389 DPRINT1("Failed to open mixer\n");
390 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
394 Handles
= ExAllocatePool(NonPagedPool
, sizeof(WDMAUD_HANDLE
) * (ClientInfo
->NumPins
+1));
398 if (ClientInfo
->NumPins
)
400 RtlMoveMemory(Handles
, ClientInfo
->hPins
, sizeof(WDMAUD_HANDLE
) * ClientInfo
->NumPins
);
401 ExFreePool(ClientInfo
->hPins
);
404 ClientInfo
->hPins
= Handles
;
405 ClientInfo
->hPins
[ClientInfo
->NumPins
].Handle
= hMixer
;
406 ClientInfo
->hPins
[ClientInfo
->NumPins
].Type
= MIXER_DEVICE_TYPE
;
407 ClientInfo
->hPins
[ClientInfo
->NumPins
].NotifyEvent
= EventObject
;
408 ClientInfo
->NumPins
++;
412 ObDereferenceObject(EventObject
);
413 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
416 DeviceInfo
->hDevice
= hMixer
;
418 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
423 WdmAudGetControlDetails(
424 IN PDEVICE_OBJECT DeviceObject
,
426 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
427 IN PWDMAUD_CLIENT ClientInfo
)
431 /* clear hmixer type flag */
432 DeviceInfo
->Flags
&= ~MIXER_OBJECTF_HMIXER
;
434 /* query mmixer library */
435 Status
= MMixerGetControlDetails(&MixerContext
, DeviceInfo
->hDevice
, DeviceInfo
->Flags
, &DeviceInfo
->u
.MixDetails
);
437 if (Status
== MM_STATUS_SUCCESS
)
438 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
440 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
446 IN PDEVICE_OBJECT DeviceObject
,
448 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
449 IN PWDMAUD_CLIENT ClientInfo
)
453 /* clear hmixer type flag */
454 DeviceInfo
->Flags
&= ~MIXER_OBJECTF_HMIXER
;
456 /* query mixer library */
457 Status
= MMixerGetLineInfo(&MixerContext
, DeviceInfo
->hDevice
, DeviceInfo
->Flags
, &DeviceInfo
->u
.MixLine
);
459 if (Status
== MM_STATUS_SUCCESS
)
460 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
462 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
467 WdmAudGetLineControls(
468 IN PDEVICE_OBJECT DeviceObject
,
470 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
471 IN PWDMAUD_CLIENT ClientInfo
)
475 /* clear hmixer type flag */
476 DeviceInfo
->Flags
&= ~MIXER_OBJECTF_HMIXER
;
478 /* query mixer library */
479 Status
= MMixerGetLineControls(&MixerContext
, DeviceInfo
->hDevice
, DeviceInfo
->Flags
, &DeviceInfo
->u
.MixControls
);
481 if (Status
== MM_STATUS_SUCCESS
)
482 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
484 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
491 WdmAudSetControlDetails(
492 IN PDEVICE_OBJECT DeviceObject
,
494 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
495 IN PWDMAUD_CLIENT ClientInfo
)
499 /* clear hmixer type flag */
500 DeviceInfo
->Flags
&= ~MIXER_OBJECTF_HMIXER
;
502 /* query mixer library */
503 Status
= MMixerSetControlDetails(&MixerContext
, DeviceInfo
->hDevice
, DeviceInfo
->Flags
, &DeviceInfo
->u
.MixDetails
);
505 if (Status
== MM_STATUS_SUCCESS
)
506 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
508 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
514 IN PDEVICE_OBJECT DeviceObject
,
516 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
517 IN PWDMAUD_CLIENT ClientInfo
)
520 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
524 WdmAudGetMixerDeviceCount()
526 return MMixerGetCount(&MixerContext
);
530 WdmAudGetWaveInDeviceCount()
532 return MMixerGetWaveInCount(&MixerContext
);
536 WdmAudGetWaveOutDeviceCount()
538 return MMixerGetWaveOutCount(&MixerContext
);
542 WdmAudGetMixerPnpNameByIndex(
543 IN ULONG DeviceIndex
,
547 return STATUS_NOT_IMPLEMENTED
;
551 WdmAudGetPnpNameByIndexAndType(
552 IN ULONG DeviceIndex
,
553 IN SOUND_DEVICE_TYPE DeviceType
,
557 return STATUS_NOT_IMPLEMENTED
;
561 WdmAudWaveCapabilities(
562 IN PDEVICE_OBJECT DeviceObject
,
563 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
564 IN PWDMAUD_CLIENT ClientInfo
,
565 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension
)
569 if (DeviceInfo
->DeviceType
== WAVE_IN_DEVICE_TYPE
)
571 /* get capabilities */
572 Status
= MMixerWaveInCapabilities(&MixerContext
, DeviceInfo
->DeviceIndex
, &DeviceInfo
->u
.WaveInCaps
);
574 else if (DeviceInfo
->DeviceType
== WAVE_OUT_DEVICE_TYPE
)
576 /* get capabilities */
577 Status
= MMixerWaveOutCapabilities(&MixerContext
, DeviceInfo
->DeviceIndex
, &DeviceInfo
->u
.WaveOutCaps
);
582 return STATUS_UNSUCCESSFUL
;
585 if (Status
== MM_STATUS_SUCCESS
)
586 return STATUS_SUCCESS
;
588 return STATUS_UNSUCCESSFUL
;
595 IN ULONG VirtualDeviceId
,
598 IN PKSPIN_CONNECT PinConnect
,
599 IN ACCESS_MASK DesiredAccess
,
600 OUT PHANDLE PinHandle
)
603 SYSAUDIO_INSTANCE_INFO InstanceInfo
;
606 PPIN_CREATE_CONTEXT Context
= (PPIN_CREATE_CONTEXT
)Ctx
;
608 /* setup property request */
609 InstanceInfo
.Property
.Set
= KSPROPSETID_Sysaudio
;
610 InstanceInfo
.Property
.Id
= KSPROPERTY_SYSAUDIO_INSTANCE_INFO
;
611 InstanceInfo
.Property
.Flags
= KSPROPERTY_TYPE_SET
;
612 InstanceInfo
.Flags
= 0;
613 InstanceInfo
.DeviceNumber
= VirtualDeviceId
;
615 /* attach to virtual device */
616 Status
= KsSynchronousIoControlDevice(Context
->DeviceExtension
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&InstanceInfo
, sizeof(SYSAUDIO_INSTANCE_INFO
), NULL
, 0, &BytesReturned
);
618 if (!NT_SUCCESS(Status
))
619 return MM_STATUS_UNSUCCESSFUL
;
621 /* close existing pin */
622 FreeIndex
= ClosePin(Context
->ClientInfo
, VirtualDeviceId
, PinId
, Context
->DeviceType
);
624 /* now create the pin */
625 Status
= KsCreatePin(Context
->DeviceExtension
->hSysAudio
, PinConnect
, DesiredAccess
, PinHandle
);
627 /* check for success */
628 if (!NT_SUCCESS(Status
))
629 return MM_STATUS_UNSUCCESSFUL
;
631 /* store the handle */
632 Status
= InsertPinHandle(Context
->ClientInfo
, VirtualDeviceId
, PinId
, Context
->DeviceType
, *PinHandle
, FreeIndex
);
633 if (!NT_SUCCESS(Status
))
635 /* failed to insert handle */
637 return MM_STATUS_UNSUCCESSFUL
;
640 return MM_STATUS_SUCCESS
;
644 WdmAudControlOpenWave(
645 IN PDEVICE_OBJECT DeviceObject
,
647 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
648 IN PWDMAUD_CLIENT ClientInfo
)
651 PIN_CREATE_CONTEXT Context
;
653 Context
.ClientInfo
= ClientInfo
;
654 Context
.DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
655 Context
.DeviceType
= DeviceInfo
->DeviceType
;
657 Status
= MMixerOpenWave(&MixerContext
, DeviceInfo
->DeviceIndex
, DeviceInfo
->DeviceType
== WAVE_IN_DEVICE_TYPE
, &DeviceInfo
->u
.WaveFormatEx
, CreatePinCallback
, &Context
, &DeviceInfo
->hDevice
);
659 if (Status
== MM_STATUS_SUCCESS
)
660 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
662 return SetIrpIoStatus(Irp
, STATUS_NOT_SUPPORTED
, sizeof(WDMAUD_DEVICE_INFO
));