Author: janderwald Date: Fri Nov 13 02:48:28 2009 New Revision: 44122
URL: http://svn.reactos.org/svn/reactos?rev=44122&view=rev Log: [WDMAUD_KERNEL] - Implement kernel side of notifying clients of volume / mute control changes
Modified: trunk/reactos/drivers/wdm/audio/legacy/wdmaud/control.c trunk/reactos/drivers/wdm/audio/legacy/wdmaud/deviface.c trunk/reactos/drivers/wdm/audio/legacy/wdmaud/entry.c trunk/reactos/drivers/wdm/audio/legacy/wdmaud/interface.h trunk/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c trunk/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h
Modified: trunk/reactos/drivers/wdm/audio/legacy/wdmaud/control.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/legacy/wd... ============================================================================== --- trunk/reactos/drivers/wdm/audio/legacy/wdmaud/control.c [iso-8859-1] (original) +++ trunk/reactos/drivers/wdm/audio/legacy/wdmaud/control.c [iso-8859-1] Fri Nov 13 02:48:28 2009 @@ -372,6 +372,8 @@ 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:
Modified: trunk/reactos/drivers/wdm/audio/legacy/wdmaud/deviface.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/legacy/wd... ============================================================================== --- trunk/reactos/drivers/wdm/audio/legacy/wdmaud/deviface.c [iso-8859-1] (original) +++ trunk/reactos/drivers/wdm/audio/legacy/wdmaud/deviface.c [iso-8859-1] Fri Nov 13 02:48:28 2009 @@ -205,22 +205,41 @@ 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; }
Modified: trunk/reactos/drivers/wdm/audio/legacy/wdmaud/entry.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/legacy/wd... ============================================================================== --- trunk/reactos/drivers/wdm/audio/legacy/wdmaud/entry.c [iso-8859-1] (original) +++ trunk/reactos/drivers/wdm/audio/legacy/wdmaud/entry.c [iso-8859-1] Fri Nov 13 02:48:28 2009 @@ -54,6 +54,9 @@ /* initialize sysaudio device list */ InitializeListHead(&DeviceExtension->SysAudioDeviceList);
+ /* initialize client context device list */ + InitializeListHead(&DeviceExtension->WdmAudClientList); + /* initialize spinlock */ KeInitializeSpinLock(&DeviceExtension->Lock);
@@ -123,14 +126,11 @@ 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 @@ 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 @@ 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 @@ Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ /* done */ return STATUS_SUCCESS; }
@@ -196,45 +200,67 @@ IN PIRP Irp) { PIO_STACK_LOCATION IoStack; - WDMAUD_CLIENT *pClient; + PWDMAUD_CLIENT pClient; + PWDMAUD_DEVICE_EXTENSION DeviceExtension; ULONG Index; - - DPRINT("WdmAudCleanup\n"); - + KIRQL OldIrql; + + /* get device extension */ + DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* get current irp stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp);
- pClient = (WDMAUD_CLIENT*)IoStack->FileObject->FsContext; - - if (pClient) - { - 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; - } - + /* sanity check */ + ASSERT(IoStack->FileObject); + + /* 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++) + { + 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
Modified: trunk/reactos/drivers/wdm/audio/legacy/wdmaud/interface.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/legacy/wd... ============================================================================== --- trunk/reactos/drivers/wdm/audio/legacy/wdmaud/interface.h [iso-8859-1] (original) +++ trunk/reactos/drivers/wdm/audio/legacy/wdmaud/interface.h [iso-8859-1] Fri Nov 13 02:48:28 2009 @@ -49,9 +49,17 @@ 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 @@ 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
Modified: trunk/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/legacy/wd... ============================================================================== --- trunk/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c [iso-8859-1] (original) +++ trunk/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c [iso-8859-1] Fri Nov 13 02:48:28 2009 @@ -1770,6 +1770,7 @@ { /* 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 @@ 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 @@ -2050,10 +2052,94 @@ }
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 @@ /* 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,8 +2245,74 @@ } 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 @@ -2193,7 +2357,7 @@ 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 @@ 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) {
Modified: trunk/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/legacy/wd... ============================================================================== --- trunk/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h [iso-8859-1] (original) +++ trunk/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h [iso-8859-1] Fri Nov 13 02:48:28 2009 @@ -18,19 +18,30 @@
typedef struct { + 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 -{ +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 @@ ULONG WaveOutDeviceCount; LIST_ENTRY WaveOutList;
- + LIST_ENTRY WdmAudClientList; }WDMAUD_DEVICE_EXTENSION, *PWDMAUD_DEVICE_EXTENSION;
NTSTATUS @@ -245,6 +256,14 @@
NTSTATUS NTAPI +WdmAudGetMixerEvent( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PWDMAUD_DEVICE_INFO DeviceInfo, + IN PWDMAUD_CLIENT ClientInfo); + +NTSTATUS +NTAPI WdmAudGetControlDetails( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,