[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); return WdmAudGetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
case IOCTL_QUERYDEVICEINTERFACESTRING: case IOCTL_QUERYDEVICEINTERFACESTRING:
return WdmAudGetDeviceInterface(DeviceObject, Irp, DeviceInfo); return WdmAudGetDeviceInterface(DeviceObject, Irp, DeviceInfo);
case IOCTL_GET_MIXER_EVENT:
return WdmAudGetMixerEvent(DeviceObject, Irp, DeviceInfo, ClientInfo);
case IOCTL_GETPOS: case IOCTL_GETPOS:
case IOCTL_GETDEVID: case IOCTL_GETDEVID:
case IOCTL_GETVOLUME: case IOCTL_GETVOLUME:

View file

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

View file

@ -54,6 +54,9 @@ WdmAudInstallDevice(
/* initialize sysaudio device list */ /* initialize sysaudio device list */
InitializeListHead(&DeviceExtension->SysAudioDeviceList); InitializeListHead(&DeviceExtension->SysAudioDeviceList);
/* initialize client context device list */
InitializeListHead(&DeviceExtension->WdmAudClientList);
/* initialize spinlock */ /* initialize spinlock */
KeInitializeSpinLock(&DeviceExtension->Lock); KeInitializeSpinLock(&DeviceExtension->Lock);
@ -123,14 +126,11 @@ WdmAudCreate(
IN PIRP Irp) IN PIRP Irp)
{ {
NTSTATUS Status; NTSTATUS Status;
PIO_STACK_LOCATION IoStack; PIO_STACK_LOCATION IoStack;
PWDMAUD_CLIENT pClient; PWDMAUD_CLIENT pClient;
PWDMAUD_DEVICE_EXTENSION DeviceExtension; PWDMAUD_DEVICE_EXTENSION DeviceExtension;
DPRINT("WdmAudCreate\n"); /* get device extension */
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension; DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
#if KS_IMPLEMENTED #if KS_IMPLEMENTED
@ -146,8 +146,12 @@ WdmAudCreate(
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failed to open sysaudio!\n"); 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); IoStack = IoGetCurrentIrpStackLocation(Irp);
@ -170,8 +174,7 @@ WdmAudClose(
IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp) IN PIRP Irp)
{ {
DPRINT("WdmAudClose\n"); /* nothing to do complete request */
#if KS_IMPLEMENTED #if KS_IMPLEMENTED
Status = KsDereferenceSoftwareBusObject(DeviceExtension->DeviceHeader); Status = KsDereferenceSoftwareBusObject(DeviceExtension->DeviceHeader);
@ -186,6 +189,7 @@ WdmAudClose(
Irp->IoStatus.Information = 0; Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT); IoCompleteRequest(Irp, IO_NO_INCREMENT);
/* done */
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -196,45 +200,67 @@ WdmAudCleanup(
IN PIRP Irp) IN PIRP Irp)
{ {
PIO_STACK_LOCATION IoStack; PIO_STACK_LOCATION IoStack;
WDMAUD_CLIENT *pClient; PWDMAUD_CLIENT pClient;
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
ULONG Index; ULONG Index;
KIRQL OldIrql;
DPRINT("WdmAudCleanup\n"); /* get device extension */
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp); 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)
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);
ZwClose(pClient->hPins[Index].Handle); }
}
}
if (pClient->hPins)
{
ExFreePool(pClient->hPins);
}
ExFreePool(pClient);
IoStack->FileObject->FsContext = NULL;
} }
/* 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.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0; Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT); IoCompleteRequest(Irp, IO_NO_INCREMENT);
DPRINT("WdmAudCleanup complete\n");
/* done */
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS
NTAPI
NTSTATUS NTAPI
DriverEntry( DriverEntry(
IN PDRIVER_OBJECT Driver, IN PDRIVER_OBJECT Driver,
IN PUNICODE_STRING Registry_path IN PUNICODE_STRING Registry_path

View file

@ -49,9 +49,17 @@ typedef struct
LPWSTR DeviceInterfaceString; LPWSTR DeviceInterfaceString;
ULONG DeviceInterfaceStringSize; ULONG DeviceInterfaceStringSize;
}Interface; }Interface;
struct
{
HANDLE hMixer;
ULONG NotificationType;
ULONG Value;
}MixerEvent;
KSSTATE State; KSSTATE State;
ULONG Volume; ULONG Volume;
ULONG FrameSize; ULONG FrameSize;
HANDLE hNotifyEvent;
}u; }u;
}WDMAUD_DEVICE_INFO, *PWDMAUD_DEVICE_INFO; }WDMAUD_DEVICE_INFO, *PWDMAUD_DEVICE_INFO;
@ -336,4 +344,21 @@ typedef struct
METHOD_BUFFERED, \ METHOD_BUFFERED, \
FILE_CREATE_TREE_CONNECTION | FILE_ANY_ACCESS) 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 #endif

View file

@ -1770,6 +1770,7 @@ WdmAudControlOpenMixer(
{ {
/* re-use pseudo handle */ /* re-use pseudo handle */
DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex; DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
ClientInfo->hPins[Index].hNotifyEvent = DeviceInfo->u.hNotifyEvent;
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO)); return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
} }
} }
@ -1787,6 +1788,7 @@ WdmAudControlOpenMixer(
ClientInfo->hPins = Handels; ClientInfo->hPins = Handels;
ClientInfo->hPins[ClientInfo->NumPins].Handle = (HANDLE)DeviceInfo->DeviceIndex; ClientInfo->hPins[ClientInfo->NumPins].Handle = (HANDLE)DeviceInfo->DeviceIndex;
ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE; ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
ClientInfo->hPins[ClientInfo->NumPins].hNotifyEvent = DeviceInfo->u.hNotifyEvent;
ClientInfo->NumPins++; ClientInfo->NumPins++;
} }
else else
@ -2049,11 +2051,95 @@ SetGetControlDetails(
return Status; 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 NTSTATUS
SetGetMuteControlDetails( SetGetMuteControlDetails(
IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_OBJECT DeviceObject,
IN ULONG DeviceId, IN ULONG DeviceId,
IN ULONG NodeId, IN ULONG NodeId,
IN ULONG dwLineID,
IN PWDMAUD_DEVICE_INFO DeviceInfo, IN PWDMAUD_DEVICE_INFO DeviceInfo,
IN ULONG bSet) IN ULONG bSet)
{ {
@ -2074,9 +2160,21 @@ SetGetMuteControlDetails(
/* set control details */ /* set control details */
Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_MUTE, MAXULONG, &Value); Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_MUTE, MAXULONG, &Value);
if (!NT_SUCCESS(Status))
return Status;
/* FIXME SEH */ /* FIXME SEH */
if (!bSet) if (!bSet)
{
Input->fValue = Value; Input->fValue = Value;
return Status;
}
else
{
/* notify clients of a line change */
NotifyWdmAudClients(DeviceObject, MM_MIXM_LINE_CHANGE, DeviceInfo->hDevice, dwLineID);
}
return Status; return Status;
} }
@ -2147,10 +2245,76 @@ SetGetVolumeControlDetails(
} }
Input->dwValue = VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1); 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; 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 NTSTATUS
NTAPI NTAPI
WdmAudSetControlDetails( WdmAudSetControlDetails(
@ -2193,7 +2357,7 @@ WdmAudSetControlDetails(
if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
{ {
/* send the request */ /* 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) else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
{ {
@ -2245,7 +2409,7 @@ WdmAudGetControlDetails(
if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
{ {
/* send the request */ /* 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) else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
{ {

View file

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