[WDMAUD] Close mixers on cleanup. Should fix CORE-10735 definitely (#21)
[reactos.git] / drivers / wdm / audio / legacy / wdmaud / entry.c
index 495abdc..eede791 100644 (file)
  * PROGRAMMER:      Andrew Greenwood
  *                  Johannes Anderwald
  */
+
 #include "wdmaud.h"
 
+#define NDEBUG
+#include <debug.h>
+
 const GUID KSCATEGORY_SYSAUDIO = {0xA7C7A5B1L, 0x5AF3, 0x11D1, {0x9C, 0xED, 0x00, 0xA0, 0x24, 0xBF, 0x04, 0x07}};
 const GUID KSCATEGORY_WDMAUD   = {0x3E227E76L, 0x690D, 0x11D2, {0x81, 0x61, 0x00, 0x00, 0xF8, 0x77, 0x5B, 0xF1}};
 
+IO_WORKITEM_ROUTINE WdmAudInitWorkerRoutine;
+IO_TIMER_ROUTINE WdmAudTimerRoutine;
+
+VOID
+NTAPI
+WdmAudInitWorkerRoutine(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PVOID Context)
+{
+    NTSTATUS Status;
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
+    ULONG DeviceCount;
+
+    /* get device extension */
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+
+    if (DeviceExtension->FileObject == NULL)
+    {
+        /* find available sysaudio devices */
+        Status = WdmAudOpenSysAudioDevices(DeviceObject, DeviceExtension);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("WdmAudOpenSysAudioDevices failed with %x\n", Status);
+            return;
+        }
+    }
+
+
+    /* get device count */
+    DeviceCount = GetSysAudioDeviceCount(DeviceObject);
+
+    DPRINT("WdmAudInitWorkerRoutine SysAudioDeviceCount %ld\n", DeviceCount);
+
+    /* was a device added / removed */
+    if (DeviceCount != DeviceExtension->SysAudioDeviceCount)
+    {
+        /* init mmixer library */
+        Status = WdmAudMixerInitialize(DeviceObject);
+        DPRINT("WdmAudMixerInitialize Status %x WaveIn %lu WaveOut %lu Mixer %lu\n", Status, WdmAudGetWaveInDeviceCount(), WdmAudGetWaveOutDeviceCount(), WdmAudGetMixerDeviceCount());
+
+        /* store sysaudio device count */
+        DeviceExtension->SysAudioDeviceCount = DeviceCount;
+    }
+
+    /* signal completion */
+    KeSetEvent(&DeviceExtension->InitializationCompletionEvent, IO_NO_INCREMENT, FALSE);
+
+    /* reset work item status indicator */
+    InterlockedDecrement((volatile long *)&DeviceExtension->WorkItemActive);
+}
+
+VOID
+NTAPI
+WdmAudTimerRoutine(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PVOID Context)
+{
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
+
+    /* get device extension */
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    if (InterlockedCompareExchange((volatile long *)&DeviceExtension->WorkItemActive, 1, 0) == 0)
+    {
+        /* queue work item */
+        IoQueueWorkItem(DeviceExtension->WorkItem, WdmAudInitWorkerRoutine, DelayedWorkQueue, (PVOID)DeviceExtension);
+    }
+}
+
 NTSTATUS
 NTAPI
-WdmAudInstallDevice(
-    IN  PDRIVER_OBJECT  DriverObject)
+WdmaudAddDevice(
+    IN PDRIVER_OBJECT DriverObject,
+    IN PDEVICE_OBJECT PhysicalDeviceObject)
 {
-    UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\wdmaud");
-    UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\wdmaud");
     PDEVICE_OBJECT DeviceObject;
     NTSTATUS Status;
     PWDMAUD_DEVICE_EXTENSION DeviceExtension;
 
-    DPRINT("WdmAudInstallDevice called\n");
+    DPRINT("WdmaudAddDevice called\n");
 
     Status = IoCreateDevice(DriverObject,
                             sizeof(WDMAUD_DEVICE_EXTENSION),
-                            &DeviceName,
+                            NULL,
                             FILE_DEVICE_KS,
                             0,
                             FALSE,
@@ -38,12 +111,21 @@ WdmAudInstallDevice(
         return Status;
     }
 
-    /* clear device extension */
+    /* get device extension */
     DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
     RtlZeroMemory(DeviceExtension, sizeof(WDMAUD_DEVICE_EXTENSION));
 
+    /* allocate work item */
+    DeviceExtension->WorkItem = IoAllocateWorkItem(DeviceObject);
+    if (!DeviceExtension->WorkItem)
+    {
+        /* failed to allocate work item */
+        IoDeleteDevice(DeviceObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
     /* register device interfaces */
-    Status = WdmAudRegisterDeviceInterface(DeviceObject, DeviceExtension);
+    Status = WdmAudRegisterDeviceInterface(PhysicalDeviceObject, DeviceExtension);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("WdmRegisterDeviceInterface failed with %x\n", Status);
@@ -60,27 +142,28 @@ WdmAudInstallDevice(
     /* initialize spinlock */
     KeInitializeSpinLock(&DeviceExtension->Lock);
 
-    /* find available sysaudio devices */
-    Status = WdmAudOpenSysAudioDevices(DeviceObject, DeviceExtension);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("WdmAudOpenSysAudioDevices failed with %x\n", Status);
-        IoDeleteSymbolicLink(&SymlinkName);
-        IoDeleteDevice(DeviceObject);
-        return Status;
-    }
+    /* initialization completion event */
+    KeInitializeEvent(&DeviceExtension->InitializationCompletionEvent, NotificationEvent, FALSE);
+
+    /* initialize timer */
+    IoInitializeTimer(DeviceObject, WdmAudTimerRoutine, (PVOID)WdmAudTimerRoutine);
+
     /* allocate ks device header */
     Status = KsAllocateDeviceHeader(&DeviceExtension->DeviceHeader, 0, NULL);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("KsAllocateDeviceHeader failed with %x\n", Status);
-        IoDeleteSymbolicLink(&SymlinkName);
         IoDeleteDevice(DeviceObject);
         return Status;
     }
 
-    Status = WdmAudMixerInitialize(DeviceObject);
-    DPRINT("WdmAudMixerInitialize Status %x WaveIn %lu WaveOut %lu Mixer %lu\n", Status, WdmAudGetWaveInDeviceCount(), WdmAudGetWaveOutDeviceCount(), WdmAudGetMixerDeviceCount());
+    /* attach to device stack */
+    DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
+    KsSetDevicePnpAndBaseObject(DeviceExtension->DeviceHeader, DeviceExtension->NextDeviceObject, DeviceObject);
+
+
+    /* start the timer */
+    IoStartTimer(DeviceObject);
 
     DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
     DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
@@ -126,10 +209,10 @@ WdmAudCreate(
     NTSTATUS Status;
     PIO_STACK_LOCATION IoStack;
     PWDMAUD_CLIENT pClient;
-    //PWDMAUD_DEVICE_EXTENSION DeviceExtension;
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
 
     /* get device extension */
-    //DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
 #if KS_IMPLEMENTED
     Status = KsReferenceSoftwareBusObject((KSDEVICE_HEADER)DeviceObject->DeviceExtension);
@@ -140,6 +223,13 @@ WdmAudCreate(
     }
 #endif
 
+    if (DeviceExtension->FileObject == NULL)
+    {
+        /* initialize */
+        WdmAudInitWorkerRoutine(DeviceObject, NULL);
+    }
+
+
     Status = WdmAudOpenSysaudio(DeviceObject, &pClient);
     if (!NT_SUCCESS(Status))
     {
@@ -236,6 +326,7 @@ WdmAudCleanup(
            /* found an still open audio pin */
            ZwClose(pClient->hPins[Index].Handle);
        }
+       WdmAudCloseAllMixers(DeviceObject, pClient, Index);
     }
 
     /* free pin array */
@@ -277,6 +368,7 @@ DriverEntry(
     Driver->MajorFunction[IRP_MJ_WRITE] = WdmAudReadWrite;
     Driver->MajorFunction[IRP_MJ_READ] = WdmAudReadWrite;
     Driver->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
+    Driver->DriverExtension->AddDevice = WdmaudAddDevice;
 
-    return WdmAudInstallDevice(Driver);
+    return STATUS_SUCCESS;
 }