[WDMAUD.DRV]
[reactos.git] / reactos / drivers / wdm / audio / legacy / wdmaud / control.c
index 4bfcead..3b34803 100644 (file)
@@ -17,6 +17,7 @@ const GUID KSMEDIUMSETID_Standard               = {0x4747B320L, 0x62CE, 0x11CF,
 const GUID KSDATAFORMAT_TYPE_AUDIO              = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
 const GUID KSDATAFORMAT_SUBTYPE_PCM             = {0x00000001L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX  = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
+const GUID KSPROPSETID_Topology                 = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
 
 NTSTATUS
 SetIrpIoStatus(
@@ -44,6 +45,7 @@ GetFilterIdAndPinId(
     NTSTATUS Status;
     KSPIN_COMMUNICATION Communication;
     KSPIN_DATAFLOW DataFlow;
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
 
     if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
     {
@@ -55,7 +57,9 @@ GetFilterIdAndPinId(
     Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
     Pin.Property.Flags = KSPROPERTY_TYPE_GET;
 
-    Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
     if (!NT_SUCCESS(Status))
         return STATUS_UNSUCCESSFUL;
 
@@ -69,7 +73,7 @@ GetFilterIdAndPinId(
         Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
         Pin.PinId = 0;
 
-        Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
+        Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
         if (NT_SUCCESS(Status))
         {
             /* enumerate now all pins */
@@ -80,13 +84,13 @@ GetFilterIdAndPinId(
                 Communication = KSPIN_COMMUNICATION_NONE;
 
                 /* get pin communication type */
-                KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
+                KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
 
                 Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
                 DataFlow = 0;
 
                 /* get pin dataflow type */
-                KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
+                KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
 
                 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
                 {
@@ -131,7 +135,8 @@ WdmAudControlOpen(
     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
     IN  PWDMAUD_CLIENT ClientInfo)
 {
-    PSYSAUDIO_INSTANCE_INFO InstanceInfo;
+    SYSAUDIO_INSTANCE_INFO InstanceInfo;
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
     ULONG BytesReturned;
     NTSTATUS Status;
     ACCESS_MASK DesiredAccess = 0;
@@ -141,6 +146,12 @@ WdmAudControlOpen(
     KSDATAFORMAT_WAVEFORMATEX * DataFormat;
     ULONG FilterId;
     ULONG PinId;
+    ULONG FreeIndex;
+
+    if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
+    {
+        return WdmAudControlOpenMixer(DeviceObject, Irp, DeviceInfo, ClientInfo);
+    }
 
     if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
     {
@@ -148,6 +159,12 @@ WdmAudControlOpen(
         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
     }
 
+    if (DeviceInfo->u.WaveFormatEx.wFormatTag != WAVE_FORMAT_PCM)
+    {
+        DPRINT("FIXME: Only WAVE_FORMAT_PCM is supported RequestFormat %x\n", DeviceInfo->u.WaveFormatEx.wFormatTag);
+        return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
+    }
+
     Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
     if (!NT_SUCCESS(Status))
     {
@@ -155,30 +172,29 @@ WdmAudControlOpen(
         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
     }
 
-    Length = sizeof(KSDATAFORMAT_WAVEFORMATEX) + sizeof(KSPIN_CONNECT) + sizeof(SYSAUDIO_INSTANCE_INFO);
-    InstanceInfo = ExAllocatePool(NonPagedPool, Length);
-    if (!InstanceInfo)
+    /* close pin handle which uses same virtual audio device id and pin id */
+    FreeIndex = (ULONG)-1;
+    for(Index = 0; Index < ClientInfo->NumPins; Index++)
     {
-        /* no memory */
-        return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
+        if (ClientInfo->hPins[Index].FilterId == FilterId && ClientInfo->hPins[Index].PinId == PinId && ClientInfo->hPins[Index].Handle && ClientInfo->hPins[Index].Type == DeviceInfo->DeviceType)
+        {
+            ZwClose(ClientInfo->hPins[Index].Handle);
+            ClientInfo->hPins[Index].Handle = NULL;
+            FreeIndex = Index;
+        }
     }
 
-    InstanceInfo->Property.Set = KSPROPSETID_Sysaudio;
-    InstanceInfo->Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
-    InstanceInfo->Property.Flags = KSPROPERTY_TYPE_SET;
-    InstanceInfo->Flags = 0;
-    InstanceInfo->DeviceNumber = FilterId;
-
-    Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
 
-    if (!NT_SUCCESS(Status))
+    Length = sizeof(KSDATAFORMAT_WAVEFORMATEX) + sizeof(KSPIN_CONNECT);
+    PinConnect = ExAllocatePool(NonPagedPool, Length);
+    if (!PinConnect)
     {
-        /* failed to acquire audio device */
-        DPRINT1("KsSynchronousIoControlDevice failed with %x\n", Status);
-        ExFreePool(InstanceInfo);
-        return SetIrpIoStatus(Irp, Status, 0);
+        /* no memory */
+        return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
     }
 
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
     if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE ||
         DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE ||
         DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
@@ -194,17 +210,14 @@ WdmAudControlOpen(
         DesiredAccess |= GENERIC_WRITE;
     }
 
-    PinConnect = (KSPIN_CONNECT*)(InstanceInfo + 1);
-
-
     PinConnect->Interface.Set = KSINTERFACESETID_Standard;
     PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
     PinConnect->Interface.Flags = 0;
     PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
     PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
     PinConnect->Medium.Flags = 0;
+    PinConnect->PinToHandle = NULL;
     PinConnect->PinId = PinId;
-    PinConnect->PinToHandle = ClientInfo->hSysAudio;
     PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
     PinConnect->Priority.PrioritySubClass = 1;
 
@@ -222,43 +235,64 @@ WdmAudControlOpen(
     DataFormat->DataFormat.Reserved = 0;
     DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
 
-    if (DeviceInfo->u.WaveFormatEx.wFormatTag != WAVE_FORMAT_PCM)
-        DPRINT1("FIXME\n");
-
     DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
     DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
     DataFormat->DataFormat.SampleSize = 4;
 
-    /* ros specific pin creation request */
-    InstanceInfo->Property.Id = (ULONG)-1;
-    Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)InstanceInfo, Length, &PinHandle, sizeof(HANDLE), &BytesReturned);
+    /* setup property request */
+    InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
+    InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
+    InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
+    InstanceInfo.Flags = 0;
+    InstanceInfo.DeviceNumber = FilterId;
+
+    /* first open the virtual device */
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
+
+    if (!NT_SUCCESS(Status))
+    {
+        /* failed */
+        ExFreePool(PinConnect);
+        return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
+    }
+
+    /* now create the pin */
+    Status = KsCreatePin(DeviceExtension->hSysAudio, PinConnect, DesiredAccess, &PinHandle);
+
+    /* free create info */
+    ExFreePool(PinConnect);
+
     if (NT_SUCCESS(Status))
     {
-        PHANDLE Handels;
+        PWDMAUD_HANDLE Handels;
 
-        for(Index = 0; Index < ClientInfo->NumPins; Index++)
+        if (FreeIndex != (ULONG)-1)
         {
-            if (ClientInfo->hPins[Index] == PinHandle)
-            {
-                /* the pin handle has been re-used */
-                DeviceInfo->hDevice = PinHandle;
-                return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
-            }
-
+            /* re-use a free index */
+            ClientInfo->hPins[Index].Handle = PinHandle;
+            ClientInfo->hPins[Index].FilterId = FilterId;
+            ClientInfo->hPins[Index].PinId = PinId;
+            ClientInfo->hPins[Index].Type = DeviceInfo->DeviceType;
+
+            DeviceInfo->hDevice = PinHandle;
+            return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
         }
 
-        Handels = ExAllocatePool(NonPagedPool, sizeof(HANDLE) * (ClientInfo->NumPins+1));
+        Handels = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
 
         if (Handels)
         {
             if (ClientInfo->NumPins)
             {
-                RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(HANDLE) * ClientInfo->NumPins);
+                RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
                 ExFreePool(ClientInfo->hPins);
             }
 
             ClientInfo->hPins = Handels;
-            ClientInfo->hPins[ClientInfo->NumPins] = PinHandle;
+            ClientInfo->hPins[ClientInfo->NumPins].Handle = PinHandle;
+            ClientInfo->hPins[ClientInfo->NumPins].Type = DeviceInfo->DeviceType;
+            ClientInfo->hPins[ClientInfo->NumPins].FilterId = FilterId;
+            ClientInfo->hPins[ClientInfo->NumPins].PinId = PinId;
             ClientInfo->NumPins++;
         }
         DeviceInfo->hDevice = PinHandle;
@@ -283,18 +317,27 @@ WdmAudControlDeviceType(
     NTSTATUS Status;
     KSPIN_COMMUNICATION Communication;
     KSPIN_DATAFLOW DataFlow;
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
+
+    if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
+    {
+        DeviceInfo->DeviceCount = GetNumOfMixerDevices(DeviceObject);
+        return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
+    }
 
     if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
     {
-        DPRINT1("FIXME: Unsupported device type %x\n", DeviceInfo->DeviceType);
-        return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
+        DPRINT("FIXME: Unsupported device type %x\n", DeviceInfo->DeviceType);
+        DeviceInfo->DeviceCount = 0;
+        return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
     }
 
     Pin.Property.Set = KSPROPSETID_Sysaudio;
     Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
     Pin.Property.Flags = KSPROPERTY_TYPE_GET;
 
-    Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("KSPROPERTY_SYSAUDIO_DEVICE_COUNT failed with %x\n", Status);
@@ -311,7 +354,7 @@ WdmAudControlDeviceType(
         Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
         Pin.PinId = 0;
 
-        Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
+        Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
         if (NT_SUCCESS(Status))
         {
             /* enumerate now all pins */
@@ -322,13 +365,17 @@ WdmAudControlDeviceType(
                 Communication = KSPIN_COMMUNICATION_NONE;
 
                 /* get pin communication type */
-                KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
+                Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
+                if (!NT_SUCCESS(Status))
+                    continue;
 
                 Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
                 DataFlow = 0;
 
                 /* get pin dataflow type */
-                KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
+                Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
+                if (!NT_SUCCESS(Status))
+                    continue;
 
                 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
                 {
@@ -344,14 +391,11 @@ WdmAudControlDeviceType(
         }
     }
 
+    /* store result count */
+    DeviceInfo->DeviceCount = Result;
 
-    if (NT_SUCCESS(Status))
-        DeviceInfo->DeviceCount = Result;
-    else
-        DeviceInfo->DeviceCount = 0;
-
-    DPRINT1("WdmAudControlDeviceType Status %x Devices %u\n", Status, DeviceInfo->DeviceCount);
-    return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
+    DPRINT("WdmAudControlDeviceType Status %x Devices %u\n", Status, DeviceInfo->DeviceCount);
+    return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
 }
 
 NTSTATUS
@@ -372,7 +416,7 @@ WdmAudControlDeviceState(
     Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Error: invalid device handle provided %p\n", DeviceInfo->hDevice);
+        DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo->hDevice, DeviceInfo->DeviceType);
         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
     }
 
@@ -380,7 +424,7 @@ WdmAudControlDeviceState(
     Property.Id = KSPROPERTY_CONNECTION_STATE;
     Property.Flags = KSPROPERTY_TYPE_SET;
 
-    State = DeviceInfo->State;
+    State = DeviceInfo->u.State;
 
     Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
 
@@ -390,23 +434,6 @@ WdmAudControlDeviceState(
     return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
 }
 
-NTSTATUS
-NTAPI
-WdmAudWriteCompleted(
-    IN PDEVICE_OBJECT  DeviceObject,
-    IN PIRP  Irp,
-    IN PVOID  Ctx)
-{
-    PWRITE_CONTEXT Context = (PWRITE_CONTEXT)Ctx;
-
-    Context->Irp->IoStatus.Information = Context->Length;
-    Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
-    IoCompleteRequest(Context->Irp, IO_SOUND_INCREMENT);
-
-    ExFreePool(Context);
-    return STATUS_SUCCESS;
-}
-
 ULONG
 CheckFormatSupport(
     IN PKSDATARANGE_AUDIO DataRangeAudio,
@@ -442,6 +469,218 @@ CheckFormatSupport(
 
 }
 
+PKEY_VALUE_PARTIAL_INFORMATION
+ReadKeyValue(
+    IN HANDLE hSubKey,
+    IN PUNICODE_STRING KeyName)
+{
+    NTSTATUS Status;
+    ULONG Length;
+    PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
+
+    /* now query MatchingDeviceId key */
+    Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, NULL, 0, &Length);
+
+    /* check for success */
+    if (Status != STATUS_BUFFER_TOO_SMALL)
+        return NULL;
+
+    /* allocate a buffer for key data */
+    PartialInformation = ExAllocatePool(NonPagedPool, Length);
+
+    if (!PartialInformation)
+        return NULL;
+
+
+    /* now query MatchingDeviceId key */
+    Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, PartialInformation, Length, &Length);
+
+    /* check for success */
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePool(PartialInformation);
+        return NULL;
+    }
+
+    if (PartialInformation->Type != REG_SZ)
+    {
+        /* invalid key type */
+        ExFreePool(PartialInformation);
+        return NULL;
+    }
+
+    return PartialInformation;
+}
+
+
+NTSTATUS
+CompareProductName(
+    IN HANDLE hSubKey,
+    IN LPWSTR PnpName,
+    IN ULONG ProductNameSize,
+    OUT LPWSTR ProductName)
+{
+    PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
+    UNICODE_STRING DriverDescName = RTL_CONSTANT_STRING(L"DriverDesc");
+    UNICODE_STRING MatchingDeviceIdName = RTL_CONSTANT_STRING(L"MatchingDeviceId");
+    ULONG Length;
+    LPWSTR DeviceName;
+
+    /* read MatchingDeviceId value */
+    PartialInformation = ReadKeyValue(hSubKey, &MatchingDeviceIdName);
+
+    if (!PartialInformation)
+        return STATUS_UNSUCCESSFUL;
+
+
+    /* extract last '&' */
+    DeviceName = wcsrchr((LPWSTR)PartialInformation->Data, L'&');
+    ASSERT(DeviceName);
+    /* terminate it */
+    DeviceName[0] = L'\0';
+
+    Length = wcslen((LPWSTR)PartialInformation->Data);
+
+    DPRINT("DeviceName %S PnpName %S Length %u\n", (LPWSTR)PartialInformation->Data, PnpName, Length);
+
+    if (_wcsnicmp((LPWSTR)PartialInformation->Data, &PnpName[4], Length))
+    {
+        ExFreePool(PartialInformation);
+        return STATUS_NO_MATCH;
+    }
+
+    /* free buffer */
+    ExFreePool(PartialInformation);
+
+    /* read DriverDescName value */
+    PartialInformation = ReadKeyValue(hSubKey, &DriverDescName);
+
+    if (!PartialInformation)
+    {
+        /* failed to read driver desc key */
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    /* copy key name */
+    Length = min(ProductNameSize * sizeof(WCHAR), PartialInformation->DataLength);
+    RtlMoveMemory(ProductName, (PVOID)PartialInformation->Data, Length);
+
+    /* zero terminate it */
+    ProductName[ProductNameSize-1] = L'\0';
+
+    /* free buffer */
+    ExFreePool(PartialInformation);
+
+    return STATUS_SUCCESS;
+}
+
+
+
+NTSTATUS
+FindProductName(
+    IN LPWSTR PnpName,
+    IN ULONG ProductNameSize,
+    OUT LPWSTR ProductName)
+{
+    UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E96C-E325-11CE-BFC1-08002BE10318}");
+
+    UNICODE_STRING SubKeyName;
+    WCHAR SubKey[20];
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE hKey, hSubKey;
+    NTSTATUS Status;
+    ULONG Length, Index;
+    PKEY_FULL_INFORMATION KeyInformation;
+
+    for(Index = 0; Index < wcslen(PnpName); Index++)
+    {
+        if (PnpName[Index] == '#')
+            PnpName[Index] = L'\\';
+    }
+
+
+    /* initialize key attributes */
+    InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL);
+
+    /* open the key */
+    Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjectAttributes);
+
+    /* check for success */
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* query num of subkeys */
+    Status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &Length);
+
+    if (Status != STATUS_BUFFER_TOO_SMALL)
+    {
+        DPRINT1("ZwQueryKey failed with %x\n", Status);
+        /* failed */
+        ZwClose(hKey);
+        return Status;
+    }
+
+    /* allocate key information struct */
+    KeyInformation = ExAllocatePool(NonPagedPool, Length);
+    if (!KeyInformation)
+    {
+        /* no memory */
+        ZwClose(hKey);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* query num of subkeys */
+    Status = ZwQueryKey(hKey, KeyFullInformation, (PVOID)KeyInformation, Length, &Length);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("ZwQueryKey failed with %x\n", Status);
+        ExFreePool(KeyInformation);
+        ZwClose(hKey);
+        return Status;
+    }
+
+    /* now iterate through all subkeys */
+    for(Index = 0; Index < KeyInformation->SubKeys; Index++)
+    {
+        /* subkeys are always in the format 0000-XXXX */
+        swprintf(SubKey, L"%04u", Index);
+
+        /* initialize subkey name */
+        RtlInitUnicodeString(&SubKeyName, SubKey);
+
+        /* initialize key attributes */
+        InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, hKey, NULL);
+
+        /* open the sub key */
+        Status = ZwOpenKey(&hSubKey, GENERIC_READ, &ObjectAttributes);
+
+        /* check for success */
+        if (NT_SUCCESS(Status))
+        {
+            /* compare product name */
+            Status = CompareProductName(hSubKey, PnpName, ProductNameSize, ProductName);
+
+            /* close subkey */
+            ZwClose(hSubKey);
+
+            if (NT_SUCCESS(Status))
+                break;
+        }
+    }
+
+    /* free buffer */
+    ExFreePool(KeyInformation);
+
+    /* close key */
+    ZwClose(hKey);
+
+    /* no matching key found */
+    return Status;
+}
+
+
+
 NTSTATUS
 WdmAudCapabilities(
     IN  PDEVICE_OBJECT DeviceObject,
@@ -449,6 +688,7 @@ WdmAudCapabilities(
     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
     IN  PWDMAUD_CLIENT ClientInfo)
 {
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
     NTSTATUS Status = STATUS_UNSUCCESSFUL;
     KSP_PIN PinProperty;
     KSCOMPONENTID ComponentId;
@@ -462,9 +702,17 @@ WdmAudCapabilities(
     ULONG dwSupport = 0;
     ULONG FilterId;
     ULONG PinId;
+    WCHAR DeviceName[MAX_PATH];
 
     DPRINT("WdmAudCapabilities entered\n");
 
+    if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
+    {
+        Status = WdmAudMixerCapabilities(DeviceObject, DeviceInfo, ClientInfo);
+        return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
+    }
+
+
     Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
     if (!NT_SUCCESS(Status))
     {
@@ -479,13 +727,33 @@ WdmAudCapabilities(
 
     RtlZeroMemory(&ComponentId, sizeof(KSCOMPONENTID));
 
-    Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)&ComponentId, sizeof(KSCOMPONENTID), &BytesReturned);
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)&ComponentId, sizeof(KSCOMPONENTID), &BytesReturned);
     if (NT_SUCCESS(Status))
     {
         DeviceInfo->u.WaveOutCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
         DeviceInfo->u.WaveOutCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
     }
 
+    /* retrieve pnp base name */
+    PinProperty.PinId = FilterId;
+    PinProperty.Property.Set = KSPROPSETID_Sysaudio;
+    PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
+    PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
+
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)DeviceName, sizeof(DeviceName), &BytesReturned);
+    if (NT_SUCCESS(Status))
+    {
+        /* find product name */
+        Status = FindProductName(DeviceName, MAXPNAMELEN, DeviceInfo->u.WaveOutCaps.szPname);
+
+        /* check for success */
+        if (!NT_SUCCESS(Status))
+        {
+            DeviceInfo->u.WaveOutCaps.szPname[0] = L'\0';
+        }
+    }
+
     PinProperty.Reserved = DeviceInfo->DeviceIndex;
     PinProperty.PinId = PinId;
     PinProperty.Property.Set = KSPROPSETID_Pin;
@@ -493,7 +761,7 @@ WdmAudCapabilities(
     PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
 
     BytesReturned = 0;
-    Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
     if (Status != STATUS_BUFFER_TOO_SMALL)
     {
         return SetIrpIoStatus(Irp, Status, 0);
@@ -506,7 +774,7 @@ WdmAudCapabilities(
         return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
     }
 
-    Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
     if (!NT_SUCCESS(Status))
     {
         ExFreePool(MultipleItem);
@@ -547,10 +815,9 @@ WdmAudCapabilities(
     DeviceInfo->u.WaveOutCaps.dwFormats = dwFormats;
     DeviceInfo->u.WaveOutCaps.dwSupport = dwSupport;
     DeviceInfo->u.WaveOutCaps.wChannels = wChannels;
-    DeviceInfo->u.WaveOutCaps.szPname[0] = L'\0';
-
 
     ExFreePool(MultipleItem);
+
     return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
 }
 
@@ -566,11 +833,11 @@ WdmAudIoctlClose(
 
     for(Index = 0; Index < ClientInfo->NumPins; Index++)
     {
-        if (ClientInfo->hPins[Index] == DeviceInfo->hDevice)
+        if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
         {
             DPRINT1("Closing device %p\n", DeviceInfo->hDevice);
             ZwClose(DeviceInfo->hDevice);
-            ClientInfo->hPins[Index] = NULL;
+            ClientInfo->hPins[Index].Handle = NULL;
             SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
             return STATUS_SUCCESS;
         }
@@ -579,6 +846,49 @@ WdmAudIoctlClose(
     return STATUS_INVALID_PARAMETER;
 }
 
+NTSTATUS
+NTAPI
+WdmAudFrameSize(
+    IN  PDEVICE_OBJECT DeviceObject,
+    IN  PIRP Irp,
+    IN  PWDMAUD_DEVICE_INFO DeviceInfo,
+    IN  PWDMAUD_CLIENT ClientInfo)
+{
+    PFILE_OBJECT FileObject;
+    KSPROPERTY Property;
+    ULONG BytesReturned;
+    KSALLOCATOR_FRAMING Framing;
+    NTSTATUS Status;
+
+    /* Get sysaudio pin file object */
+    Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Invalid buffer handle %x\n", DeviceInfo->hDevice);
+        return SetIrpIoStatus(Irp, Status, 0);
+    }
+
+    /* Setup get framing request */
+    Property.Id = KSPROPERTY_CONNECTION_ALLOCATORFRAMING;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+    Property.Set = KSPROPSETID_Connection;
+
+    Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Framing, sizeof(KSALLOCATOR_FRAMING), &BytesReturned);
+    /* Did we succeed */
+    if (NT_SUCCESS(Status))
+    {
+        /* Store framesize */
+        DeviceInfo->u.FrameSize = Framing.FrameSize;
+    }
+
+    /* Release file object */
+    ObDereferenceObject(FileObject);
+
+    return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
+
+}
+
+
 NTSTATUS
 NTAPI
 WdmAudDeviceControl(
@@ -631,6 +941,9 @@ WdmAudDeviceControl(
             return WdmAudCapabilities(DeviceObject, Irp, DeviceInfo, ClientInfo);
         case IOCTL_CLOSE_WDMAUD:
             return WdmAudIoctlClose(DeviceObject, Irp, DeviceInfo, ClientInfo);
+        case IOCTL_GETFRAMESIZE:
+            return WdmAudFrameSize(DeviceObject, Irp, DeviceInfo, ClientInfo);
+        case IOCTL_GETPOS:
         case IOCTL_GETDEVID:
         case IOCTL_GETVOLUME:
         case IOCTL_SETVOLUME:
@@ -642,6 +955,28 @@ WdmAudDeviceControl(
     return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
 }
 
+NTSTATUS
+NTAPI
+WdmAudWriteCompletion(
+    IN PDEVICE_OBJECT  DeviceObject,
+    IN PIRP LowerIrp,
+    IN PVOID  Context)
+{
+    //PIRP Irp;
+    ASSERT(LowerIrp->PendingReturned == FALSE);
+    /* get original irp */
+    //Irp = (PIRP)Context;
+
+    /* save status */
+    //Irp->IoStatus.Status = LowerIrp->IoStatus.Status;
+    //Irp->IoStatus.Information = LowerIrp->IoStatus.Information;
+    /* complete request */
+    //IoCompleteRequest(Irp, IO_SOUND_INCREMENT);
+    /* return success to free irp */
+    return STATUS_SUCCESS;
+}
+
+
 NTSTATUS
 NTAPI
 WdmAudWrite(
@@ -653,8 +988,12 @@ WdmAudWrite(
     PWDMAUD_CLIENT ClientInfo;
     NTSTATUS Status = STATUS_SUCCESS;
     PUCHAR Buffer;
-    PCONTEXT_WRITE Packet;
     PFILE_OBJECT FileObject;
+    PMDL Mdl;
+    //PIRP LowerIrp;
+    PCONTEXT_WRITE Packet;
+    PVOID SystemBuffer;
+    //LARGE_INTEGER Offset;
     IO_STATUS_BLOCK IoStatusBlock;
 
     IoStack = IoGetCurrentIrpStackLocation(Irp);
@@ -684,6 +1023,7 @@ WdmAudWrite(
     {
         /* invalid parameter */
         DPRINT1("Error: device type not set\n");
+        ObDereferenceObject(FileObject);
         return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
     }
 
@@ -691,6 +1031,7 @@ WdmAudWrite(
     {
         /* file object parameter */
         DPRINT1("Error: file object is not attached\n");
+        ObDereferenceObject(FileObject);
         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
     }
     ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
@@ -704,26 +1045,36 @@ WdmAudWrite(
         return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
     }
 
-    Packet->Header.FrameExtent = DeviceInfo->BufferSize;
-    Packet->Header.DataUsed = DeviceInfo->BufferSize;
+    Packet->Header.FrameExtent = DeviceInfo->Header.FrameExtent;
+    Packet->Header.DataUsed = DeviceInfo->Header.DataUsed;
     Packet->Header.Size = sizeof(KSSTREAM_HEADER);
     Packet->Header.PresentationTime.Numerator = 1;
     Packet->Header.PresentationTime.Denominator = 1;
     Packet->Irp = Irp;
 
-    Buffer = ExAllocatePool(NonPagedPool, DeviceInfo->BufferSize);
+    Buffer = ExAllocatePool(NonPagedPool, DeviceInfo->Header.DataUsed);
     if (!Buffer)
     {
         /* no memory */
         ExFreePool(Packet);
+        ObDereferenceObject(FileObject);
         return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
     }
     Packet->Header.Data = Buffer;
 
+    Mdl = IoAllocateMdl(DeviceInfo->Header.Data, DeviceInfo->Header.DataUsed, FALSE, FALSE, FALSE);
+    if (!Mdl)
+    {
+        /* no memory */
+        ExFreePool(Packet);
+        ObDereferenceObject(FileObject);
+        ExFreePool(Buffer);
+        return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
+    }
+
     _SEH2_TRY
     {
-        ProbeForRead(DeviceInfo->Buffer, DeviceInfo->BufferSize, TYPE_ALIGNMENT(char));
-        RtlMoveMemory(Buffer, DeviceInfo->Buffer, DeviceInfo->BufferSize);
+        MmProbeAndLockPages(Mdl, UserMode, IoReadAccess);
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
@@ -737,12 +1088,73 @@ WdmAudWrite(
         DPRINT1("Invalid buffer supplied\n");
         ExFreePool(Buffer);
         ExFreePool(Packet);
+        IoFreeMdl(Mdl);
+        ObDereferenceObject(FileObject);
         return SetIrpIoStatus(Irp, Status, 0);
     }
 
-    KsStreamIo(FileObject, NULL, NULL, NULL, NULL, 0, &IoStatusBlock, Packet, sizeof(CONTEXT_WRITE), KSSTREAM_WRITE, KernelMode);
+    SystemBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority );
+    if (!SystemBuffer)
+    {
+        DPRINT1("Invalid buffer supplied\n");
+        ExFreePool(Buffer);
+        ExFreePool(Packet);
+        IoFreeMdl(Mdl);
+        ObDereferenceObject(FileObject);
+        return SetIrpIoStatus(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
+    }
 
+    RtlMoveMemory(Buffer, SystemBuffer, DeviceInfo->Header.DataUsed);
+    MmUnlockPages(Mdl);
+    IoFreeMdl(Mdl);
 
+#if 1
+    KsStreamIo(FileObject, NULL, NULL, NULL, NULL, 0, &IoStatusBlock, Packet, sizeof(CONTEXT_WRITE), KSSTREAM_WRITE, UserMode);
+    /* dereference file object */
+    ObDereferenceObject(FileObject);
     return IoStatusBlock.Status;
-}
+#else
+    Offset.QuadPart = 0L;
+
+    /* now build the irp */
+    LowerIrp = IoBuildAsynchronousFsdRequest (IRP_MJ_WRITE,
+                                              IoGetRelatedDeviceObject(FileObject),
+                                              Packet,
+                                              sizeof(KSSTREAM_HEADER),
+                                              &Offset,
+                                              NULL);
+
+    if (!LowerIrp)
+    {
+        /* failed to create an associated irp */
+        ExFreePool(Buffer);
+        ExFreePool(Packet);
+        ObDereferenceObject(FileObject);
+
+        return SetIrpIoStatus(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
+    }
+
+    /* get next stack location */
+    IoStack = IoGetNextIrpStackLocation(LowerIrp);
+
+    /* attach file object */
+    IoStack->FileObject = FileObject;
 
+    /* set a completion routine */
+    IoSetCompletionRoutine(LowerIrp, WdmAudWriteCompletion, (PVOID)Irp, TRUE, TRUE, TRUE);
+
+    /* mark irp as pending */
+    //IoMarkIrpPending(Irp);
+    Irp->IoStatus.Information = DeviceInfo->BufferSize;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    DPRINT1("Wrote %u\n", DeviceInfo->BufferSize);
+    /* call the driver */
+    Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), LowerIrp);
+
+    /* dereference file object */
+    ObDereferenceObject(FileObject);
+
+    return STATUS_SUCCESS;
+#endif
+}