mirror of
https://github.com/reactos/reactos.git
synced 2024-09-11 05:12:43 +00:00
867 lines
23 KiB
C
867 lines
23 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel Streaming
|
|
* FILE: drivers/wdm/audio/legacy/wdmaud/mmixer.c
|
|
* PURPOSE: WDM Legacy Mixer
|
|
* PROGRAMMER: Johannes Anderwald
|
|
*/
|
|
|
|
#include "wdmaud.h"
|
|
|
|
#include <mmixer.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
PVOID Alloc(ULONG NumBytes);
|
|
MIXER_STATUS Close(HANDLE hDevice);
|
|
VOID Free(PVOID Block);
|
|
VOID Copy(PVOID Src, PVOID Dst, ULONG NumBytes);
|
|
MIXER_STATUS Open(IN LPWSTR DevicePath, OUT PHANDLE hDevice);
|
|
MIXER_STATUS Control(IN HANDLE hMixer, IN ULONG dwIoControlCode, IN PVOID lpInBuffer, IN ULONG nInBufferSize, OUT PVOID lpOutBuffer, ULONG nOutBufferSize, PULONG lpBytesReturned);
|
|
MIXER_STATUS Enum(IN PVOID EnumContext, IN ULONG DeviceIndex, OUT LPWSTR * DeviceName, OUT PHANDLE OutHandle, OUT PHANDLE OutKey);
|
|
MIXER_STATUS OpenKey(IN HANDLE hKey, IN LPWSTR SubKey, IN ULONG DesiredAccess, OUT PHANDLE OutKey);
|
|
MIXER_STATUS CloseKey(IN HANDLE hKey);
|
|
MIXER_STATUS QueryKeyValue(IN HANDLE hKey, IN LPWSTR KeyName, OUT PVOID * ResultBuffer, OUT PULONG ResultLength, OUT PULONG KeyType);
|
|
PVOID AllocEventData(IN ULONG ExtraSize);
|
|
VOID FreeEventData(IN PVOID EventData);
|
|
|
|
MIXER_CONTEXT MixerContext =
|
|
{
|
|
sizeof(MIXER_CONTEXT),
|
|
NULL,
|
|
Alloc,
|
|
Control,
|
|
Free,
|
|
Open,
|
|
Close,
|
|
Copy,
|
|
OpenKey,
|
|
QueryKeyValue,
|
|
CloseKey,
|
|
AllocEventData,
|
|
FreeEventData
|
|
};
|
|
|
|
GUID CategoryGuid = {STATIC_KSCATEGORY_AUDIO};
|
|
|
|
MIXER_STATUS
|
|
QueryKeyValue(
|
|
IN HANDLE hKey,
|
|
IN LPWSTR lpKeyName,
|
|
OUT PVOID * ResultBuffer,
|
|
OUT PULONG ResultLength,
|
|
OUT PULONG KeyType)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING KeyName;
|
|
ULONG Length;
|
|
PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
|
|
|
|
/* initialize key name */
|
|
RtlInitUnicodeString(&KeyName, lpKeyName);
|
|
|
|
/* now query MatchingDeviceId key */
|
|
Status = ZwQueryValueKey(hKey, &KeyName, KeyValuePartialInformation, NULL, 0, &Length);
|
|
|
|
/* check for success */
|
|
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
|
|
/* allocate a buffer for key data */
|
|
PartialInformation = AllocateItem(NonPagedPool, Length);
|
|
|
|
if (!PartialInformation)
|
|
return MM_STATUS_NO_MEMORY;
|
|
|
|
|
|
/* now query MatchingDeviceId key */
|
|
Status = ZwQueryValueKey(hKey, &KeyName, KeyValuePartialInformation, PartialInformation, Length, &Length);
|
|
|
|
/* check for success */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
FreeItem(PartialInformation);
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (KeyType)
|
|
{
|
|
/* return key type */
|
|
*KeyType = PartialInformation->Type;
|
|
}
|
|
|
|
if (ResultLength)
|
|
{
|
|
/* return data length */
|
|
*ResultLength = PartialInformation->DataLength;
|
|
}
|
|
|
|
*ResultBuffer = AllocateItem(NonPagedPool, PartialInformation->DataLength);
|
|
if (!*ResultBuffer)
|
|
{
|
|
/* not enough memory */
|
|
FreeItem(PartialInformation);
|
|
return MM_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* copy key value */
|
|
RtlMoveMemory(*ResultBuffer, PartialInformation->Data, PartialInformation->DataLength);
|
|
|
|
/* free key info */
|
|
FreeItem(PartialInformation);
|
|
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
OpenKey(
|
|
IN HANDLE hKey,
|
|
IN LPWSTR lpSubKeyName,
|
|
IN ULONG DesiredAccess,
|
|
OUT PHANDLE OutKey)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING SubKeyName;
|
|
NTSTATUS Status;
|
|
|
|
/* initialize sub key name */
|
|
RtlInitUnicodeString(&SubKeyName, lpSubKeyName);
|
|
|
|
/* initialize key attributes */
|
|
InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, hKey, NULL);
|
|
|
|
/* open the key */
|
|
Status = ZwOpenKey(OutKey, DesiredAccess, &ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
return MM_STATUS_SUCCESS;
|
|
else
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
CloseKey(
|
|
IN HANDLE hKey)
|
|
{
|
|
if (ZwClose(hKey) == STATUS_SUCCESS)
|
|
return MM_STATUS_SUCCESS;
|
|
else
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
PVOID Alloc(ULONG NumBytes)
|
|
{
|
|
return AllocateItem(NonPagedPool, NumBytes);
|
|
}
|
|
|
|
MIXER_STATUS
|
|
Close(HANDLE hDevice)
|
|
{
|
|
if (ZwClose(hDevice) == STATUS_SUCCESS)
|
|
return MM_STATUS_SUCCESS;
|
|
else
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
VOID
|
|
Free(PVOID Block)
|
|
{
|
|
FreeItem(Block);
|
|
}
|
|
|
|
VOID
|
|
Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
|
|
{
|
|
RtlMoveMemory(Src, Dst, NumBytes);
|
|
}
|
|
|
|
MIXER_STATUS
|
|
Open(
|
|
IN LPWSTR DevicePath,
|
|
OUT PHANDLE hDevice)
|
|
{
|
|
if (WdmAudOpenSysAudioDevice(DevicePath, hDevice) == STATUS_SUCCESS)
|
|
return MM_STATUS_SUCCESS;
|
|
else
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
Control(
|
|
IN HANDLE hMixer,
|
|
IN ULONG dwIoControlCode,
|
|
IN PVOID lpInBuffer,
|
|
IN ULONG nInBufferSize,
|
|
OUT PVOID lpOutBuffer,
|
|
ULONG nOutBufferSize,
|
|
PULONG lpBytesReturned)
|
|
{
|
|
NTSTATUS Status;
|
|
PFILE_OBJECT FileObject;
|
|
|
|
/* get file object */
|
|
Status = ObReferenceObjectByHandle(hMixer, GENERIC_READ | GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("failed to reference %p with %lx\n", hMixer, Status);
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* perform request */
|
|
Status = KsSynchronousIoControlDevice(FileObject, KernelMode, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned);
|
|
|
|
/* release object reference */
|
|
ObDereferenceObject(FileObject);
|
|
|
|
if (Status == STATUS_MORE_ENTRIES || Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
/* more data is available */
|
|
return MM_STATUS_MORE_ENTRIES;
|
|
}
|
|
else if (Status == STATUS_SUCCESS)
|
|
{
|
|
/* operation succeeded */
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Failed with %lx\n", Status);
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
MIXER_STATUS
|
|
Enum(
|
|
IN PVOID EnumContext,
|
|
IN ULONG DeviceIndex,
|
|
OUT LPWSTR * DeviceName,
|
|
OUT PHANDLE OutHandle,
|
|
OUT PHANDLE OutKey)
|
|
{
|
|
PDEVICE_OBJECT DeviceObject;
|
|
ULONG DeviceCount;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING KeyName;
|
|
|
|
/* get enumeration context */
|
|
DeviceObject = (PDEVICE_OBJECT)EnumContext;
|
|
|
|
/* get device count */
|
|
DeviceCount = GetSysAudioDeviceCount(DeviceObject);
|
|
|
|
if (DeviceIndex >= DeviceCount)
|
|
{
|
|
/* no more devices */
|
|
return MM_STATUS_NO_MORE_DEVICES;
|
|
}
|
|
|
|
/* get device name */
|
|
Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, DeviceName);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* failed to retrieve device name */
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* initialize key name */
|
|
RtlInitUnicodeString(&KeyName, *DeviceName);
|
|
|
|
/* open device interface key */
|
|
Status = IoOpenDeviceInterfaceRegistryKey(&KeyName, GENERIC_READ | GENERIC_WRITE, OutKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
*OutKey = NULL;
|
|
}
|
|
|
|
#if 0
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* failed to open key */
|
|
DPRINT("IoOpenDeviceInterfaceRegistryKey failed with %lx\n", Status);
|
|
FreeItem(*DeviceName);
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
#endif
|
|
|
|
/* open device handle */
|
|
Status = OpenDevice(*DeviceName, OutHandle, NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* failed to open device */
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
PVOID
|
|
AllocEventData(
|
|
IN ULONG ExtraSize)
|
|
{
|
|
PKSEVENTDATA Data = (PKSEVENTDATA)AllocateItem(NonPagedPool, sizeof(KSEVENTDATA) + ExtraSize);
|
|
if (!Data)
|
|
return NULL;
|
|
|
|
Data->EventObject.Event = AllocateItem(NonPagedPool, sizeof(KEVENT));
|
|
if (!Data->EventHandle.Event)
|
|
{
|
|
FreeItem(Data);
|
|
return NULL;
|
|
}
|
|
|
|
KeInitializeEvent(Data->EventObject.Event, NotificationEvent, FALSE);
|
|
|
|
Data->NotificationType = KSEVENTF_EVENT_HANDLE;
|
|
return Data;
|
|
}
|
|
|
|
VOID
|
|
FreeEventData(IN PVOID EventData)
|
|
{
|
|
PKSEVENTDATA Data = (PKSEVENTDATA)EventData;
|
|
|
|
FreeItem(Data->EventHandle.Event);
|
|
FreeItem(Data);
|
|
}
|
|
|
|
VOID
|
|
CALLBACK
|
|
EventCallback(
|
|
IN PVOID MixerEventContext,
|
|
IN HANDLE hMixer,
|
|
IN ULONG NotificationType,
|
|
IN ULONG Value)
|
|
{
|
|
PWDMAUD_CLIENT ClientInfo;
|
|
PEVENT_ENTRY Entry;
|
|
ULONG Index;
|
|
|
|
/* get client context */
|
|
ClientInfo = (PWDMAUD_CLIENT)MixerEventContext;
|
|
|
|
/* now search for the mixer which originated the request */
|
|
for(Index = 0; Index < ClientInfo->NumPins; Index++)
|
|
{
|
|
if (ClientInfo->hPins[Index].Handle == hMixer && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
|
|
{
|
|
if (ClientInfo->hPins[Index].NotifyEvent)
|
|
{
|
|
/* allocate event entry */
|
|
Entry = AllocateItem(NonPagedPool, sizeof(EVENT_ENTRY));
|
|
if (!Entry)
|
|
{
|
|
/* no memory */
|
|
break;
|
|
}
|
|
|
|
/* setup event entry */
|
|
Entry->NotificationType = NotificationType;
|
|
Entry->Value = Value;
|
|
Entry->hMixer = hMixer;
|
|
|
|
/* insert entry */
|
|
InsertTailList(&ClientInfo->MixerEventList, &Entry->Entry);
|
|
|
|
/* now notify the client */
|
|
KeSetEvent(ClientInfo->hPins[Index].NotifyEvent, 0, FALSE);
|
|
}
|
|
/* done */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
WdmAudMixerInitialize(
|
|
IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
MIXER_STATUS Status;
|
|
|
|
/* initialize the mixer library */
|
|
Status = MMixerInitialize(&MixerContext, Enum, (PVOID)DeviceObject);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* failed to initialize mmixer library */
|
|
DPRINT("MMixerInitialize failed with %lx\n", Status);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
WdmAudMixerCapabilities(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo,
|
|
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
if (MMixerGetCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MixCaps) == MM_STATUS_SUCCESS)
|
|
return STATUS_SUCCESS;
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
NTSTATUS
|
|
WdmAudControlOpenMixer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo)
|
|
{
|
|
HANDLE hMixer;
|
|
PWDMAUD_HANDLE Handles;
|
|
//PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
|
NTSTATUS Status;
|
|
PKEVENT EventObject = NULL;
|
|
|
|
DPRINT("WdmAudControlOpenMixer\n");
|
|
|
|
//DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
if (DeviceInfo->u.hNotifyEvent)
|
|
{
|
|
Status = ObReferenceObjectByHandle(DeviceInfo->u.hNotifyEvent, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode, (LPVOID*)&EventObject, NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Invalid notify event passed %p from client %p\n", DeviceInfo->u.hNotifyEvent, ClientInfo);
|
|
DbgBreakPoint();
|
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
|
}
|
|
}
|
|
|
|
if (MMixerOpen(&MixerContext, DeviceInfo->DeviceIndex, ClientInfo, EventCallback, &hMixer) != MM_STATUS_SUCCESS)
|
|
{
|
|
ObDereferenceObject(EventObject);
|
|
DPRINT1("Failed to open mixer\n");
|
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
|
}
|
|
|
|
|
|
Handles = AllocateItem(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
|
|
|
|
if (Handles)
|
|
{
|
|
if (ClientInfo->NumPins)
|
|
{
|
|
RtlMoveMemory(Handles, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
|
|
FreeItem(ClientInfo->hPins);
|
|
}
|
|
|
|
ClientInfo->hPins = Handles;
|
|
ClientInfo->hPins[ClientInfo->NumPins].Handle = hMixer;
|
|
ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
|
|
ClientInfo->hPins[ClientInfo->NumPins].NotifyEvent = EventObject;
|
|
ClientInfo->NumPins++;
|
|
}
|
|
else
|
|
{
|
|
ObDereferenceObject(EventObject);
|
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|
|
|
|
DeviceInfo->hDevice = hMixer;
|
|
|
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|
|
|
|
NTSTATUS
|
|
WdmAudControlCloseMixer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo,
|
|
IN ULONG Index)
|
|
{
|
|
/* Remove event associated to this client */
|
|
if (MMixerClose(&MixerContext, DeviceInfo->DeviceIndex, ClientInfo, EventCallback) != MM_STATUS_SUCCESS)
|
|
{
|
|
DPRINT1("Failed to close mixer\n");
|
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|
|
|
|
/* Dereference event */
|
|
if (ClientInfo->hPins[Index].NotifyEvent)
|
|
{
|
|
ObDereferenceObject(ClientInfo->hPins[Index].NotifyEvent);
|
|
ClientInfo->hPins[Index].NotifyEvent = NULL;
|
|
}
|
|
|
|
/* FIXME: do we need to free ClientInfo->hPins ? */
|
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|
|
|
|
VOID
|
|
WdmAudCloseAllMixers(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PWDMAUD_CLIENT ClientInfo,
|
|
IN ULONG Index)
|
|
{
|
|
ULONG DeviceCount, DeviceIndex;
|
|
|
|
/* Get all mixers */
|
|
DeviceCount = GetSysAudioDeviceCount(DeviceObject);
|
|
|
|
/* Close every mixer attached to the device */
|
|
for (DeviceIndex = 0; DeviceIndex < DeviceCount; DeviceIndex++)
|
|
{
|
|
if (MMixerClose(&MixerContext, DeviceIndex, ClientInfo, EventCallback) != MM_STATUS_SUCCESS)
|
|
{
|
|
DPRINT1("Failed to close mixer for device %lu\n", DeviceIndex);
|
|
}
|
|
}
|
|
|
|
/* Dereference event */
|
|
if (ClientInfo->hPins[Index].NotifyEvent)
|
|
{
|
|
ObDereferenceObject(ClientInfo->hPins[Index].NotifyEvent);
|
|
ClientInfo->hPins[Index].NotifyEvent = NULL;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
WdmAudGetControlDetails(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo)
|
|
{
|
|
MIXER_STATUS Status;
|
|
|
|
/* clear hmixer type flag */
|
|
DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
|
|
|
|
/* query mmixer library */
|
|
Status = MMixerGetControlDetails(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixDetails);
|
|
|
|
if (Status == MM_STATUS_SUCCESS)
|
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
else
|
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
WdmAudGetLineInfo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo)
|
|
{
|
|
MIXER_STATUS Status;
|
|
|
|
/* clear hmixer type flag */
|
|
DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
|
|
|
|
/* query mixer library */
|
|
Status = MMixerGetLineInfo(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixLine);
|
|
|
|
if (Status == MM_STATUS_SUCCESS)
|
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
else
|
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
WdmAudGetLineControls(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo)
|
|
{
|
|
MIXER_STATUS Status;
|
|
|
|
/* clear hmixer type flag */
|
|
DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
|
|
|
|
/* query mixer library */
|
|
Status = MMixerGetLineControls(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixControls);
|
|
|
|
if (Status == MM_STATUS_SUCCESS)
|
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
else
|
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
|
|
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
WdmAudSetControlDetails(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo)
|
|
{
|
|
MIXER_STATUS Status;
|
|
|
|
/* clear hmixer type flag */
|
|
DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
|
|
|
|
/* query mixer library */
|
|
Status = MMixerSetControlDetails(&MixerContext, DeviceInfo->hDevice, DeviceInfo->DeviceIndex, DeviceInfo->Flags, &DeviceInfo->u.MixDetails);
|
|
|
|
if (Status == MM_STATUS_SUCCESS)
|
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
else
|
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
WdmAudGetMixerEvent(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PEVENT_ENTRY EventEntry;
|
|
|
|
/* enumerate event list and check if there is a new event */
|
|
Entry = ClientInfo->MixerEventList.Flink;
|
|
|
|
while(Entry != &ClientInfo->MixerEventList)
|
|
{
|
|
/* grab event entry */
|
|
EventEntry = (PEVENT_ENTRY)CONTAINING_RECORD(Entry, EVENT_ENTRY, Entry);
|
|
|
|
if (EventEntry->hMixer == DeviceInfo->hDevice)
|
|
{
|
|
/* found an entry */
|
|
DeviceInfo->u.MixerEvent.hMixer = EventEntry->hMixer;
|
|
DeviceInfo->u.MixerEvent.NotificationType = EventEntry->NotificationType;
|
|
DeviceInfo->u.MixerEvent.Value = EventEntry->Value;
|
|
|
|
/* remove entry from list */
|
|
RemoveEntryList(&EventEntry->Entry);
|
|
|
|
/* free event entry */
|
|
FreeItem(EventEntry);
|
|
|
|
/* done */
|
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|
|
|
|
/* move to next */
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
/* no event entry available */
|
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|
|
|
|
ULONG
|
|
WdmAudGetMixerDeviceCount()
|
|
{
|
|
return MMixerGetCount(&MixerContext);
|
|
}
|
|
|
|
ULONG
|
|
WdmAudGetWaveInDeviceCount()
|
|
{
|
|
return MMixerGetWaveInCount(&MixerContext);
|
|
}
|
|
|
|
ULONG
|
|
WdmAudGetWaveOutDeviceCount()
|
|
{
|
|
return MMixerGetWaveOutCount(&MixerContext);
|
|
}
|
|
|
|
ULONG
|
|
WdmAudGetMidiInDeviceCount()
|
|
{
|
|
return MMixerGetMidiInCount(&MixerContext);
|
|
}
|
|
|
|
ULONG
|
|
WdmAudGetMidiOutDeviceCount()
|
|
{
|
|
return MMixerGetWaveOutCount(&MixerContext);
|
|
}
|
|
|
|
NTSTATUS
|
|
WdmAudGetPnpNameByIndexAndType(
|
|
IN ULONG DeviceIndex,
|
|
IN SOUND_DEVICE_TYPE DeviceType,
|
|
OUT LPWSTR *DevicePath)
|
|
{
|
|
if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
|
|
{
|
|
if (MMixerGetWaveDevicePath(&MixerContext, DeviceType == WAVE_IN_DEVICE_TYPE, DeviceIndex, DevicePath) == MM_STATUS_SUCCESS)
|
|
return STATUS_SUCCESS;
|
|
else
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
else if (DeviceType == MIDI_IN_DEVICE_TYPE || DeviceType == MIDI_OUT_DEVICE_TYPE)
|
|
{
|
|
if (MMixerGetMidiDevicePath(&MixerContext, DeviceType == MIDI_IN_DEVICE_TYPE, DeviceIndex, DevicePath) == MM_STATUS_SUCCESS)
|
|
return STATUS_SUCCESS;
|
|
else
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
else if (DeviceType == MIXER_DEVICE_TYPE)
|
|
{
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
NTSTATUS
|
|
WdmAudWaveCapabilities(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo,
|
|
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
MIXER_STATUS Status = MM_STATUS_UNSUCCESSFUL;
|
|
|
|
if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
|
|
{
|
|
/* get capabilities */
|
|
Status = MMixerWaveInCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.WaveInCaps);
|
|
}
|
|
else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
|
|
{
|
|
/* get capabilities */
|
|
Status = MMixerWaveOutCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.WaveOutCaps);
|
|
}
|
|
|
|
if (Status == MM_STATUS_SUCCESS)
|
|
return STATUS_SUCCESS;
|
|
else
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
WdmAudMidiCapabilities(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo,
|
|
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
MIXER_STATUS Status = MM_STATUS_UNSUCCESSFUL;
|
|
|
|
if (DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE)
|
|
{
|
|
/* get capabilities */
|
|
Status = MMixerMidiInCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MidiInCaps);
|
|
}
|
|
else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
|
|
{
|
|
/* get capabilities */
|
|
Status = MMixerMidiOutCapabilities(&MixerContext, DeviceInfo->DeviceIndex, &DeviceInfo->u.MidiOutCaps);
|
|
}
|
|
|
|
if (Status == MM_STATUS_SUCCESS)
|
|
return STATUS_SUCCESS;
|
|
else
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
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)
|
|
{
|
|
ULONG BytesReturned;
|
|
SYSAUDIO_INSTANCE_INFO InstanceInfo;
|
|
NTSTATUS Status;
|
|
ULONG FreeIndex;
|
|
PPIN_CREATE_CONTEXT Context = (PPIN_CREATE_CONTEXT)Ctx;
|
|
|
|
/* setup property request */
|
|
InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
|
|
InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
|
|
InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
|
|
InstanceInfo.Flags = 0;
|
|
InstanceInfo.DeviceNumber = VirtualDeviceId;
|
|
|
|
/* attach to virtual device */
|
|
Status = KsSynchronousIoControlDevice(Context->DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
|
|
/* close existing pin */
|
|
FreeIndex = ClosePin(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType);
|
|
|
|
/* now create the pin */
|
|
Status = KsCreatePin(Context->DeviceExtension->hSysAudio, PinConnect, DesiredAccess, PinHandle);
|
|
|
|
/* check for success */
|
|
if (!NT_SUCCESS(Status))
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
|
|
/* store the handle */
|
|
Status = InsertPinHandle(Context->ClientInfo, VirtualDeviceId, PinId, Context->DeviceType, *PinHandle, FreeIndex);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* failed to insert handle */
|
|
ZwClose(*PinHandle);
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
WdmAudControlOpenWave(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo)
|
|
{
|
|
MIXER_STATUS Status;
|
|
PIN_CREATE_CONTEXT Context;
|
|
|
|
Context.ClientInfo = ClientInfo;
|
|
Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
Context.DeviceType = DeviceInfo->DeviceType;
|
|
|
|
Status = MMixerOpenWave(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE, &DeviceInfo->u.WaveFormatEx, CreatePinCallback, &Context, &DeviceInfo->hDevice);
|
|
|
|
if (Status == MM_STATUS_SUCCESS)
|
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
else
|
|
return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|
|
|
|
NTSTATUS
|
|
WdmAudControlOpenMidi(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
IN PWDMAUD_CLIENT ClientInfo)
|
|
{
|
|
MIXER_STATUS Status;
|
|
PIN_CREATE_CONTEXT Context;
|
|
|
|
Context.ClientInfo = ClientInfo;
|
|
Context.DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
Context.DeviceType = DeviceInfo->DeviceType;
|
|
|
|
Status = MMixerOpenMidi(&MixerContext, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE, CreatePinCallback, &Context, &DeviceInfo->hDevice);
|
|
|
|
if (Status == MM_STATUS_SUCCESS)
|
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
else
|
|
return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
|
|
}
|