[WDMAUD_KERNEL]
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Fri, 13 Nov 2009 01:48:28 +0000 (01:48 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Fri, 13 Nov 2009 01:48:28 +0000 (01:48 +0000)
- Implement kernel side of notifying clients of volume / mute control changes

svn path=/trunk/; revision=44122

reactos/drivers/wdm/audio/legacy/wdmaud/control.c
reactos/drivers/wdm/audio/legacy/wdmaud/deviface.c
reactos/drivers/wdm/audio/legacy/wdmaud/entry.c
reactos/drivers/wdm/audio/legacy/wdmaud/interface.h
reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c
reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h

index 2bac810..3d4ceb2 100644 (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:
index aa5a9c0..8330917 100644 (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;
 }
 
index 694719b..7d774da 100644 (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);
+
+    /* get client context struct */
+    pClient = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
+
+    /* sanity check */
+    ASSERT(pClient);
 
-    if (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
index 44eef61..13e748f 100644 (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
index df9cad5..8452639 100644 (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)
     {
index 598d374..bc27c36 100644 (file)
 
 #include "interface.h"
 
+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
 {
+    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(