[WDMAUD_KERNEL]

- Implement kernel side of notifying clients of volume / mute control changes

svn path=/trunk/; revision=44122
This commit is contained in:
Johannes Anderwald 2009-11-13 01:48:28 +00:00
parent a8286c3821
commit 61887111ab
6 changed files with 296 additions and 41 deletions

View file

@ -372,6 +372,8 @@ WdmAudDeviceControl(
return WdmAudGetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
case IOCTL_QUERYDEVICEINTERFACESTRING:
return WdmAudGetDeviceInterface(DeviceObject, Irp, DeviceInfo);
case IOCTL_GET_MIXER_EVENT:
return WdmAudGetMixerEvent(DeviceObject, Irp, DeviceInfo, ClientInfo);
case IOCTL_GETPOS:
case IOCTL_GETDEVID:
case IOCTL_GETVOLUME:

View file

@ -205,22 +205,41 @@ WdmAudOpenSysaudio(
PWDMAUD_CLIENT Client;
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
/* get device extension */
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
if (!DeviceExtension->NumSysAudioDevices)
{
/* wdmaud failed to open sysaudio */
return STATUS_UNSUCCESSFUL;
}
/* sanity check */
ASSERT(!IsListEmpty(&DeviceExtension->SysAudioDeviceList));
/* allocate client context struct */
Client = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_CLIENT));
/* check for allocation failure */
if (!Client)
{
/* not enough memory */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* zero client context struct */
RtlZeroMemory(Client, sizeof(WDMAUD_CLIENT));
/* initialize mixer event list */
InitializeListHead(&Client->MixerEventList);
/* store result */
*pClient = Client;
/* insert client into list */
ExInterlockedInsertTailList(&DeviceExtension->WdmAudClientList, &Client->Entry, &DeviceExtension->Lock);
/* done */
return STATUS_SUCCESS;
}

View file

@ -54,6 +54,9 @@ WdmAudInstallDevice(
/* initialize sysaudio device list */
InitializeListHead(&DeviceExtension->SysAudioDeviceList);
/* initialize client context device list */
InitializeListHead(&DeviceExtension->WdmAudClientList);
/* initialize spinlock */
KeInitializeSpinLock(&DeviceExtension->Lock);
@ -123,14 +126,11 @@ WdmAudCreate(
IN PIRP Irp)
{
NTSTATUS Status;
PIO_STACK_LOCATION IoStack;
PWDMAUD_CLIENT pClient;
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
DPRINT("WdmAudCreate\n");
/* get device extension */
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
#if KS_IMPLEMENTED
@ -146,8 +146,12 @@ WdmAudCreate(
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to open sysaudio!\n");
if (pClient)
ExFreePool(pClient);
/* complete and forget */
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
/* done */
return STATUS_UNSUCCESSFUL;
}
IoStack = IoGetCurrentIrpStackLocation(Irp);
@ -170,8 +174,7 @@ WdmAudClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
DPRINT("WdmAudClose\n");
/* nothing to do complete request */
#if KS_IMPLEMENTED
Status = KsDereferenceSoftwareBusObject(DeviceExtension->DeviceHeader);
@ -186,6 +189,7 @@ WdmAudClose(
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
/* done */
return STATUS_SUCCESS;
}
@ -196,45 +200,67 @@ WdmAudCleanup(
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
WDMAUD_CLIENT *pClient;
PWDMAUD_CLIENT pClient;
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
ULONG Index;
KIRQL OldIrql;
DPRINT("WdmAudCleanup\n");
/* get device extension */
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
pClient = (WDMAUD_CLIENT*)IoStack->FileObject->FsContext;
/* sanity check */
ASSERT(IoStack->FileObject);
if (pClient)
/* get client context struct */
pClient = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
/* sanity check */
ASSERT(pClient);
/* acquire client context list lock */
KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
/* remove entry */
RemoveEntryList(&pClient->Entry);
/* release lock */
KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
/* check if all audio pins have been closed */
for (Index = 0; Index < pClient->NumPins; Index++)
{
for (Index = 0; Index < pClient->NumPins; Index++)
{
DPRINT("Index %u Pin %p Type %x\n", Index, pClient->hPins[Index].Handle, pClient->hPins[Index].Type);
if (pClient->hPins[Index].Handle && pClient->hPins[Index].Type != MIXER_DEVICE_TYPE)
{
ZwClose(pClient->hPins[Index].Handle);
}
}
if (pClient->hPins)
{
ExFreePool(pClient->hPins);
}
ExFreePool(pClient);
IoStack->FileObject->FsContext = NULL;
DPRINT("Index %u Pin %p Type %x\n", Index, pClient->hPins[Index].Handle, pClient->hPins[Index].Type);
if (pClient->hPins[Index].Handle && pClient->hPins[Index].Type != MIXER_DEVICE_TYPE)
{
/* found an still open audio pin */
ZwClose(pClient->hPins[Index].Handle);
}
}
/* free pin array */
if (pClient->hPins)
ExFreePool(pClient->hPins);
/* free client context struct */
ExFreePool(pClient);
/* clear old client pointer */
IoStack->FileObject->FsContext = NULL;
/* complete request */
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
DPRINT("WdmAudCleanup complete\n");
/* done */
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
NTSTATUS
NTAPI
DriverEntry(
IN PDRIVER_OBJECT Driver,
IN PUNICODE_STRING Registry_path

View file

@ -49,9 +49,17 @@ typedef struct
LPWSTR DeviceInterfaceString;
ULONG DeviceInterfaceStringSize;
}Interface;
struct
{
HANDLE hMixer;
ULONG NotificationType;
ULONG Value;
}MixerEvent;
KSSTATE State;
ULONG Volume;
ULONG FrameSize;
HANDLE hNotifyEvent;
}u;
}WDMAUD_DEVICE_INFO, *PWDMAUD_DEVICE_INFO;
@ -336,4 +344,21 @@ typedef struct
METHOD_BUFFERED, \
FILE_CREATE_TREE_CONNECTION | FILE_ANY_ACCESS)
/// IOCTL_GET_MIXER_EVENT
///
/// Description: This IOCTL queries for
///
/// Arguments: InputBuffer is a pointer to a WDMAUD_DEVICE_INFO structure,
/// InputBufferSize is size of WDMAUD_DEVICE_INFO structure
/// Note: The hDevice member must be set
/// Result: The result is returned in the struct MixerInfo
/// ReturnCode: STATUS_SUCCESS indicates success
#define IOCTL_GET_MIXER_EVENT \
CTL_CODE(FILE_DEVICE_SOUND, \
16, \
METHOD_BUFFERED, \
FILE_CREATE_TREE_CONNECTION | FILE_ANY_ACCESS)
#endif

View file

@ -1770,6 +1770,7 @@ WdmAudControlOpenMixer(
{
/* re-use pseudo handle */
DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
ClientInfo->hPins[Index].hNotifyEvent = DeviceInfo->u.hNotifyEvent;
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
}
}
@ -1787,6 +1788,7 @@ WdmAudControlOpenMixer(
ClientInfo->hPins = Handels;
ClientInfo->hPins[ClientInfo->NumPins].Handle = (HANDLE)DeviceInfo->DeviceIndex;
ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
ClientInfo->hPins[ClientInfo->NumPins].hNotifyEvent = DeviceInfo->u.hNotifyEvent;
ClientInfo->NumPins++;
}
else
@ -2049,11 +2051,95 @@ SetGetControlDetails(
return Status;
}
NTSTATUS
NotifyWdmAudClients(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG NotificationType,
IN HANDLE hMixer,
IN ULONG Value)
{
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
PLIST_ENTRY Entry;
PWDMAUD_CLIENT CurClient;
PKEVENT EventObject;
PMIXER_EVENT Event;
KIRQL OldIrql;
ULONG Index;
NTSTATUS Status;
/* get device extension */
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* acquire client context lock */
KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
/* point to first entry */
Entry = DeviceExtension->WdmAudClientList.Flink;
/* iterate through all clients */
while(Entry != &DeviceExtension->WdmAudClientList)
{
/* get client context */
CurClient = (PWDMAUD_CLIENT)CONTAINING_RECORD(Entry, WDMAUD_CLIENT, Entry);
/* now iterate through all pins and try to find an matching handle */
for(Index = 0; Index < CurClient->NumPins; Index++)
{
if (CurClient->hPins[Index].Handle == hMixer && CurClient->hPins[Index].Type == MIXER_DEVICE_TYPE && CurClient->hPins[Index].hNotifyEvent)
{
/* found a matching mixer handle and a valid notify event */
Status = ObReferenceObjectByHandle(CurClient->hPins[Index].hNotifyEvent, EVENT_MODIFY_STATE, ExEventObjectType, UserMode, (LPVOID*)&EventObject, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Invalid notify event passed %p from client %p\n", CurClient->hPins[Index].hNotifyEvent, CurClient);
break;
}
/* allocate event entry */
Event = (PMIXER_EVENT)ExAllocatePool(NonPagedPool, sizeof(MIXER_EVENT));
if (!Event)
{
/* no memory */
ObDereferenceObject(EventObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* initialize event entry */
Event->hMixer = hMixer;
Event->NotificationType = NotificationType;
Event->Value = Value;
/* insert event entry */
InsertTailList(&CurClient->MixerEventList, &Event->Entry);
/* now signal the event */
KeSetEvent(EventObject, 0, FALSE);
/* dereference event */
ObDereferenceObject(EventObject);
/* search next client */
break;
}
}
/* move to next client */
Entry = Entry->Flink;
}
/* release client context lock */
KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
/* done */
return STATUS_SUCCESS;
}
NTSTATUS
SetGetMuteControlDetails(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG DeviceId,
IN ULONG NodeId,
IN ULONG dwLineID,
IN PWDMAUD_DEVICE_INFO DeviceInfo,
IN ULONG bSet)
{
@ -2074,9 +2160,21 @@ SetGetMuteControlDetails(
/* set control details */
Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_MUTE, MAXULONG, &Value);
if (!NT_SUCCESS(Status))
return Status;
/* FIXME SEH */
if (!bSet)
{
Input->fValue = Value;
return Status;
}
else
{
/* notify clients of a line change */
NotifyWdmAudClients(DeviceObject, MM_MIXM_LINE_CHANGE, DeviceInfo->hDevice, dwLineID);
}
return Status;
}
@ -2147,10 +2245,76 @@ SetGetVolumeControlDetails(
}
Input->dwValue = VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
}
else
{
/* notify clients of a line change */
NotifyWdmAudClients(DeviceObject, MM_MIXM_CONTROL_CHANGE, DeviceInfo->hDevice, MixerControl->dwControlID);
}
return Status;
}
NTSTATUS
NTAPI
WdmAudGetMixerEvent(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PWDMAUD_DEVICE_INFO DeviceInfo,
IN PWDMAUD_CLIENT ClientInfo)
{
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
PMIXER_EVENT Event = NULL;
PLIST_ENTRY Entry;
KIRQL OldIrql;
/* get device extension */
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* acquire client context lock */
KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
/* point to first entry */
Entry = ClientInfo->MixerEventList.Flink;
while(Entry != &ClientInfo->MixerEventList)
{
/* get mixer event */
Event = (PMIXER_EVENT)CONTAINING_RECORD(Entry, MIXER_EVENT, Entry);
if (Event->hMixer == DeviceInfo->hDevice)
{
/* found an event for that particular device */
break;
}
/* no match found */
Event = NULL;
/* move to next entry */
Entry = Entry->Flink;
}
/* release client context lock */
KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
if (!Event)
{
/* no events available */
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
}
/* store event result */
DeviceInfo->u.MixerEvent.hMixer = Event->hMixer;
DeviceInfo->u.MixerEvent.NotificationType = Event->NotificationType;
DeviceInfo->u.MixerEvent.Value = Event->Value;
/* free event info */
ExFreePool(Event);
/* done */
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
}
NTSTATUS
NTAPI
WdmAudSetControlDetails(
@ -2193,7 +2357,7 @@ WdmAudSetControlDetails(
if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
{
/* send the request */
Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, TRUE);
Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, MixerLine->Line.dwLineID, DeviceInfo, TRUE);
}
else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
{
@ -2245,7 +2409,7 @@ WdmAudGetControlDetails(
if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
{
/* send the request */
Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, FALSE);
Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, MixerLine->Line.dwLineID, DeviceInfo, FALSE);
}
else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
{

View file

@ -18,19 +18,30 @@
typedef struct
{
HANDLE Handle;
SOUND_DEVICE_TYPE Type;
ULONG FilterId;
ULONG PinId;
}WDMAUD_HANDLE, *PWDMAUD_HANDLE;
LIST_ENTRY Entry;
HANDLE hMixer;
ULONG NotificationType;
ULONG Value;
}MIXER_EVENT, *PMIXER_EVENT;
typedef struct
{
HANDLE Handle;
SOUND_DEVICE_TYPE Type;
ULONG FilterId;
ULONG PinId;
HANDLE hNotifyEvent;
}WDMAUD_HANDLE, *PWDMAUD_HANDLE;
typedef struct
{
LIST_ENTRY Entry;
HANDLE hProcess;
ULONG NumPins;
WDMAUD_HANDLE * hPins;
LIST_ENTRY MixerEventList;
}WDMAUD_CLIENT, *PWDMAUD_CLIENT;
typedef struct
@ -115,7 +126,7 @@ typedef struct
ULONG WaveOutDeviceCount;
LIST_ENTRY WaveOutList;
LIST_ENTRY WdmAudClientList;
}WDMAUD_DEVICE_EXTENSION, *PWDMAUD_DEVICE_EXTENSION;
NTSTATUS
@ -243,6 +254,14 @@ WdmAudSetControlDetails(
IN PWDMAUD_DEVICE_INFO DeviceInfo,
IN PWDMAUD_CLIENT ClientInfo);
NTSTATUS
NTAPI
WdmAudGetMixerEvent(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PWDMAUD_DEVICE_INFO DeviceInfo,
IN PWDMAUD_CLIENT ClientInfo);
NTSTATUS
NTAPI
WdmAudGetControlDetails(