From 61887111ab41b36e1f31d3ecd233304d78f47671 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Fri, 13 Nov 2009 01:48:28 +0000 Subject: [PATCH] [WDMAUD_KERNEL] - Implement kernel side of notifying clients of volume / mute control changes svn path=/trunk/; revision=44122 --- .../drivers/wdm/audio/legacy/wdmaud/control.c | 2 + .../wdm/audio/legacy/wdmaud/deviface.c | 19 ++ .../drivers/wdm/audio/legacy/wdmaud/entry.c | 90 ++++++---- .../wdm/audio/legacy/wdmaud/interface.h | 25 +++ .../drivers/wdm/audio/legacy/wdmaud/mixer.c | 170 +++++++++++++++++- .../drivers/wdm/audio/legacy/wdmaud/wdmaud.h | 31 +++- 6 files changed, 296 insertions(+), 41 deletions(-) diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/control.c b/reactos/drivers/wdm/audio/legacy/wdmaud/control.c index 2bac8107ae2..3d4ceb2bb7e 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/control.c +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/control.c @@ -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: diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/deviface.c b/reactos/drivers/wdm/audio/legacy/wdmaud/deviface.c index aa5a9c050a6..83309177a4c 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/deviface.c +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/deviface.c @@ -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; } diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/entry.c b/reactos/drivers/wdm/audio/legacy/wdmaud/entry.c index 694719bf6fd..7d774da359d 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/entry.c +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/entry.c @@ -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 diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/interface.h b/reactos/drivers/wdm/audio/legacy/wdmaud/interface.h index 44eef61c028..13e748fea0c 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/interface.h +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/interface.h @@ -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 diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c b/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c index df9cad510fa..845263994f1 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c @@ -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) { diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h b/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h index 598d3747a4b..bc27c367f0f 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h @@ -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(