- Rewrite Wave API to enumerate wave out / in devices at startup
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Fri, 2 Oct 2009 10:57:24 +0000 (10:57 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Fri, 2 Oct 2009 10:57:24 +0000 (10:57 +0000)
- Improves speedup of application minus short delay in system boot
- Enumerate controls for source and destination lines

svn path=/trunk/; revision=43254

reactos/drivers/wdm/audio/legacy/wdmaud/control.c
reactos/drivers/wdm/audio/legacy/wdmaud/entry.c
reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c
reactos/drivers/wdm/audio/legacy/wdmaud/sup.c [new file with mode: 0644]
reactos/drivers/wdm/audio/legacy/wdmaud/wave.c [new file with mode: 0644]
reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h
reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.rbuild

index b2a2cf5..ecf3645 100644 (file)
@@ -19,114 +19,6 @@ const GUID KSDATAFORMAT_SUBTYPE_PCM             = {0x00000001L, 0x0000, 0x0010,
 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(
-    IN PIRP Irp,
-    IN NTSTATUS Status,
-    IN ULONG Length)
-{
-    Irp->IoStatus.Information = Length;
-    Irp->IoStatus.Status = Status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
-    return Status;
-
-}
-
-NTSTATUS
-GetFilterIdAndPinId(
-    IN  PDEVICE_OBJECT DeviceObject,
-    IN  PWDMAUD_DEVICE_INFO DeviceInfo,
-    IN  PWDMAUD_CLIENT ClientInfo,
-    IN PULONG FilterId,
-    IN PULONG PinId)
-{
-    KSP_PIN Pin;
-    ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
-    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)
-    {
-        DPRINT1("FIXME: Unsupported device type %x\n", DeviceInfo->DeviceType);
-        return STATUS_UNSUCCESSFUL;
-    }
-
-    Pin.Property.Set = KSPROPSETID_Sysaudio;
-    Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
-    Pin.Property.Flags = KSPROPERTY_TYPE_GET;
-
-    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;
-
-    Result = 0;
-    for(Index = 0; Index < Count; Index++)
-    {
-        /* query number of pins */
-        Pin.Reserved = Index; // see sysaudio
-        Pin.Property.Flags = KSPROPERTY_TYPE_GET;
-        Pin.Property.Set = KSPROPSETID_Pin;
-        Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
-        Pin.PinId = 0;
-
-        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 */
-            for(SubIndex = 0; SubIndex < NumPins; SubIndex++)
-            {
-                Pin.PinId = SubIndex;
-                Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
-                Communication = KSPIN_COMMUNICATION_NONE;
-
-                /* get pin communication type */
-                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(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
-
-                if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
-                {
-                    if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
-                    {
-                        if(DeviceInfo->DeviceIndex == Result)
-                        {
-                            /* found the index */
-                            *FilterId = Index;
-                            *PinId = SubIndex;
-                            return STATUS_SUCCESS;
-                        }
-
-                        Result++;
-                    }
-                }
-                else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
-                {
-                    if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
-                    {
-                        if(DeviceInfo->DeviceIndex == Result)
-                        {
-                            /* found the index */
-                            *FilterId = Index;
-                            *PinId = SubIndex;
-                            return STATUS_SUCCESS;
-                        }
-                        Result++;
-                    }
-                }
-            }
-        }
-    }
-
-    return STATUS_UNSUCCESSFUL;
-}
 
 NTSTATUS
 WdmAudControlOpen(
@@ -135,174 +27,17 @@ WdmAudControlOpen(
     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
     IN  PWDMAUD_CLIENT ClientInfo)
 {
-    SYSAUDIO_INSTANCE_INFO InstanceInfo;
-    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
-    ULONG BytesReturned;
-    NTSTATUS Status;
-    ACCESS_MASK DesiredAccess = 0;
-    HANDLE PinHandle;
-    KSPIN_CONNECT * PinConnect;
-    ULONG Length, Index;
-    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)
-    {
-        DPRINT1("FIXME: only waveout / wavein devices are supported\n");
-        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))
-    {
-        DPRINT1("Invalid device index %u\n", DeviceInfo->DeviceIndex);
-        return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
-    }
-
-    /* close pin handle which uses same virtual audio device id and pin id */
-    FreeIndex = MAXULONG;
-    for(Index = 0; Index < ClientInfo->NumPins; Index++)
-    {
-        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;
-        }
-    }
-
-
-    Length = sizeof(KSDATAFORMAT_WAVEFORMATEX) + sizeof(KSPIN_CONNECT);
-    PinConnect = ExAllocatePool(NonPagedPool, Length);
-    if (!PinConnect)
+    if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
     {
-        /* no memory */
-        return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
+        return WdmAudControlOpenWave(DeviceObject, Irp, DeviceInfo, ClientInfo);
     }
 
-    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
-    if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE ||
-        DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE ||
-        DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
-    {
-        DesiredAccess |= GENERIC_READ;
-    }
-
-    if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE ||
-        DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE ||
-        DeviceInfo->DeviceType == AUX_DEVICE_TYPE ||
-        DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
-    {
-        DesiredAccess |= GENERIC_WRITE;
-    }
-
-    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->Priority.PriorityClass = KSPRIORITY_NORMAL;
-    PinConnect->Priority.PrioritySubClass = 1;
-
-
-    DataFormat = (KSDATAFORMAT_WAVEFORMATEX*) (PinConnect + 1);
-    DataFormat->WaveFormatEx.wFormatTag = DeviceInfo->u.WaveFormatEx.wFormatTag;
-    DataFormat->WaveFormatEx.nChannels = DeviceInfo->u.WaveFormatEx.nChannels;
-    DataFormat->WaveFormatEx.nSamplesPerSec = DeviceInfo->u.WaveFormatEx.nSamplesPerSec;
-    DataFormat->WaveFormatEx.nBlockAlign = DeviceInfo->u.WaveFormatEx.nBlockAlign;
-    DataFormat->WaveFormatEx.nAvgBytesPerSec = DeviceInfo->u.WaveFormatEx.nAvgBytesPerSec;
-    DataFormat->WaveFormatEx.wBitsPerSample = DeviceInfo->u.WaveFormatEx.wBitsPerSample;
-    DataFormat->WaveFormatEx.cbSize = 0;
-    DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
-    DataFormat->DataFormat.Flags = 0;
-    DataFormat->DataFormat.Reserved = 0;
-    DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
-
-    DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
-    DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
-    DataFormat->DataFormat.SampleSize = 4;
-
-    /* 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))
-    {
-        PWDMAUD_HANDLE Handels;
-
-        if (FreeIndex != MAXULONG)
-        {
-            /* 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(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
-
-        if (Handels)
-        {
-            if (ClientInfo->NumPins)
-            {
-                RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
-                ExFreePool(ClientInfo->hPins);
-            }
-
-            ClientInfo->hPins = Handels;
-            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;
-    }
-    else
-    {
-        DeviceInfo->hDevice = NULL;
-    }
-
-    return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
+    return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
 }
 
 NTSTATUS
@@ -312,85 +47,23 @@ WdmAudControlDeviceType(
     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
     IN  PWDMAUD_CLIENT ClientInfo)
 {
-    KSP_PIN Pin;
-    ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
+    ULONG Result = 0;
     NTSTATUS Status;
-    KSPIN_COMMUNICATION Communication;
-    KSPIN_DATAFLOW DataFlow;
     PWDMAUD_DEVICE_EXTENSION DeviceExtension;
 
     DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
     if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
     {
-        DeviceInfo->DeviceCount = DeviceExtension->MixerInfoCount;
-        return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
+        Result = DeviceExtension->MixerInfoCount;
     }
-
-    if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
+    else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
     {
-        DPRINT("FIXME: Unsupported device type %x\n", DeviceInfo->DeviceType);
-        DeviceInfo->DeviceCount = 0;
-        return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
+        Result = DeviceExtension->WaveOutDeviceCount;
     }
-
-    Pin.Property.Set = KSPROPSETID_Sysaudio;
-    Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
-    Pin.Property.Flags = KSPROPERTY_TYPE_GET;
-
-
-    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
-    if (!NT_SUCCESS(Status))
+    else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
     {
-        DPRINT1("KSPROPERTY_SYSAUDIO_DEVICE_COUNT failed with %x\n", Status);
-        return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
-    }
-    Result = 0;
-    /* now enumerate all available filters */
-    for(Index = 0; Index < Count; Index++)
-    {
-        /* query number of pins */
-        Pin.Reserved = Index; // see sysaudio
-        Pin.Property.Flags = KSPROPERTY_TYPE_GET;
-        Pin.Property.Set = KSPROPSETID_Pin;
-        Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
-        Pin.PinId = 0;
-
-        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 */
-            for(SubIndex = 0; SubIndex < NumPins; SubIndex++)
-            {
-                Pin.PinId = SubIndex;
-                Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
-                Communication = KSPIN_COMMUNICATION_NONE;
-
-                /* get pin communication type */
-                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 */
-                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)
-                {
-                    if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
-                        Result++;
-                }
-                else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
-                {
-                    if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
-                        Result++;
-                }
-            }
-        }
+        Result = DeviceExtension->WaveInDeviceCount;
     }
 
     /* store result count */
@@ -436,253 +109,6 @@ WdmAudControlDeviceState(
     return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
 }
 
-ULONG
-CheckFormatSupport(
-    IN PKSDATARANGE_AUDIO DataRangeAudio,
-    ULONG SampleFrequency,
-    ULONG Mono8Bit,
-    ULONG Stereo8Bit,
-    ULONG Mono16Bit,
-    ULONG Stereo16Bit)
-{
-    ULONG Result = 0;
-
-    if (DataRangeAudio->MinimumSampleFrequency <= SampleFrequency && DataRangeAudio->MaximumSampleFrequency >= SampleFrequency)
-    {
-        if (DataRangeAudio->MinimumBitsPerSample <= 8 && DataRangeAudio->MaximumBitsPerSample >= 8)
-        {
-            Result |= Mono8Bit;
-            if (DataRangeAudio->MaximumChannels >= 2)
-            {
-                Result |= Stereo8Bit;
-            }
-        }
-
-        if (DataRangeAudio->MinimumBitsPerSample <= 16 && DataRangeAudio->MaximumBitsPerSample >= 16)
-        {
-            Result |= Mono16Bit;
-            if (DataRangeAudio->MaximumChannels >= 2)
-            {
-                Result |= Stereo8Bit;
-            }
-        }
-    }
-    return Result;
-
-}
-
-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,
@@ -692,19 +118,6 @@ WdmAudCapabilities(
 {
     PWDMAUD_DEVICE_EXTENSION DeviceExtension;
     NTSTATUS Status = STATUS_UNSUCCESSFUL;
-    KSP_PIN PinProperty;
-    KSCOMPONENTID ComponentId;
-    KSMULTIPLE_ITEM * MultipleItem;
-    ULONG BytesReturned;
-    PKSDATARANGE_AUDIO DataRangeAudio;
-    PKSDATARANGE DataRange;
-    ULONG Index;
-    ULONG wChannels = 0;
-    ULONG dwFormats = 0;
-    ULONG dwSupport = 0;
-    ULONG FilterId;
-    ULONG PinId;
-    WCHAR DeviceName[MAX_PATH];
 
     DPRINT("WdmAudCapabilities entered\n");
 
@@ -713,115 +126,12 @@ WdmAudCapabilities(
     if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
     {
         Status = WdmAudMixerCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
-        return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
     }
-
-
-    Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
-    if (!NT_SUCCESS(Status))
+    else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
     {
-        DPRINT1("Invalid device index provided %u\n", DeviceInfo->DeviceIndex);
-        return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
+        Status = WdmAudWaveCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
     }
 
-    PinProperty.PinId = FilterId;
-    PinProperty.Property.Set = KSPROPSETID_Sysaudio;
-    PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_COMPONENT_ID;
-    PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
-
-    RtlZeroMemory(&ComponentId, sizeof(KSCOMPONENTID));
-
-
-    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;
-    PinProperty.Property.Id = KSPROPERTY_PIN_DATARANGES;
-    PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
-
-    BytesReturned = 0;
-    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);
-    }
-
-    MultipleItem = ExAllocatePool(NonPagedPool, BytesReturned);
-    if (!MultipleItem)
-    {
-        /* no memory */
-        return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
-    }
-
-    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
-    if (!NT_SUCCESS(Status))
-    {
-        ExFreePool(MultipleItem);
-        return SetIrpIoStatus(Irp, Status, 0);
-    }
-
-    DataRange = (PKSDATARANGE) (MultipleItem + 1);
-    for(Index = 0; Index < MultipleItem->Count; Index++)
-    {
-        if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
-        {
-            if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO))
-            {
-                DataRangeAudio = (PKSDATARANGE_AUDIO)DataRange;
-                
-                if (IsEqualGUIDAligned(&DataRangeAudio->DataRange.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
-                    IsEqualGUIDAligned(&DataRangeAudio->DataRange.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
-                    IsEqualGUIDAligned(&DataRangeAudio->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
-                {
-                    DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio->MinimumSampleFrequency, DataRangeAudio->MaximumSampleFrequency,
-                                                             DataRangeAudio->MinimumBitsPerSample, DataRangeAudio->MaximumBitsPerSample, DataRangeAudio->MaximumChannels);
-
-                    dwFormats |= CheckFormatSupport(DataRangeAudio, 11025, WAVE_FORMAT_1M08, WAVE_FORMAT_1S08, WAVE_FORMAT_1M16, WAVE_FORMAT_1S16);
-                    dwFormats |= CheckFormatSupport(DataRangeAudio, 22050, WAVE_FORMAT_2M08, WAVE_FORMAT_2S08, WAVE_FORMAT_2M16, WAVE_FORMAT_2S16);
-                    dwFormats |= CheckFormatSupport(DataRangeAudio, 44100, WAVE_FORMAT_4M08, WAVE_FORMAT_4S08, WAVE_FORMAT_4M16, WAVE_FORMAT_4S16);
-                    dwFormats |= CheckFormatSupport(DataRangeAudio, 48000, WAVE_FORMAT_48M08, WAVE_FORMAT_48S08, WAVE_FORMAT_48M16, WAVE_FORMAT_48S16);
-                    dwFormats |= CheckFormatSupport(DataRangeAudio, 96000, WAVE_FORMAT_96M08, WAVE_FORMAT_96S08, WAVE_FORMAT_96M16, WAVE_FORMAT_96S16);
-
-
-                    wChannels = DataRangeAudio->MaximumChannels;
-                    dwSupport = WAVECAPS_VOLUME; //FIXME get info from nodes
-                }
-            }
-        }
-        DataRange = (PKSDATARANGE)((PUCHAR)DataRange + DataRange->FormatSize);
-    }
-
-    DeviceInfo->u.WaveOutCaps.dwFormats = dwFormats;
-    DeviceInfo->u.WaveOutCaps.dwSupport = dwSupport;
-    DeviceInfo->u.WaveOutCaps.wChannels = wChannels;
-
-    ExFreePool(MultipleItem);
-
     return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
 }
 
@@ -846,6 +156,7 @@ WdmAudIoctlClose(
             return STATUS_SUCCESS;
         }
     }
+
     SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
     return STATUS_INVALID_PARAMETER;
 }
index 3e7bb58..a648315 100644 (file)
@@ -78,6 +78,8 @@ WdmAudInstallDevice(
 
     Status = WdmAudMixerInitialize(DeviceObject);
     DPRINT("WdmAudMixerInitialize Status %x\n", Status);
+    Status = WdmAudWaveInitialize(DeviceObject);
+    DPRINT("WdmAudWaveInitialize Status %x\n", Status);
 
     DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
     DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
index 28cd154..b4d7518 100644 (file)
@@ -21,6 +21,7 @@ const GUID KSNODETYPE_STEREO_WIDE = {0xA9E69800L, 0xC558, 0x11D0, {0x8A, 0x2B, 0
 const GUID KSNODETYPE_CHORUS =      {0x20173F20L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
 const GUID KSNODETYPE_REVERB =      {0xEF0328E0L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
 const GUID KSNODETYPE_SUPERMIX =    {0xE573ADC0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
+const GUID KSNODETYPE_SUM = {0xDA441A60L, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
 
 #define DESTINATION_LINE 0xFFFF0000
 
@@ -62,7 +63,7 @@ GetSourceMixerLineByLineId(
     while(Entry != &MixerInfo->LineList)
     {
         MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
-        DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID);
+        DPRINT1("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID);
         if (MixerLineSrc->Line.dwLineID == dwLineID)
             return MixerLineSrc;
 
@@ -719,67 +720,369 @@ AllocatePinArray(
     return Pins;
 }
 
+PKSTOPOLOGY_CONNECTION
+GetConnectionByIndex(
+    IN PKSMULTIPLE_ITEM MultipleItem,
+    IN ULONG Index)
+{
+    PKSTOPOLOGY_CONNECTION Descriptor;
+
+    ASSERT(Index < MultipleItem->Count);
+
+    Descriptor = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
+    return &Descriptor[Index];
+}
+
+LPGUID
+GetNodeType(
+    IN PKSMULTIPLE_ITEM MultipleItem,
+    IN ULONG Index)
+{
+    LPGUID NodeType;
+
+    ASSERT(Index < MultipleItem->Count);
+
+    NodeType = (LPGUID)(MultipleItem + 1);
+    return &NodeType[Index];
+}
+
+NTSTATUS
+GetControlsFromPinByConnectionIndex(
+    IN PKSMULTIPLE_ITEM NodeConnections,
+    IN PKSMULTIPLE_ITEM NodeTypes,
+    IN ULONG bUpDirection,
+    IN ULONG NodeConnectionIndex,
+    OUT PULONG Nodes)
+{
+    PKSTOPOLOGY_CONNECTION CurConnection;
+    LPGUID NodeType;
+    ULONG NodeIndex;
+    NTSTATUS Status;
+    ULONG NodeConnectionCount, Index;
+    PULONG NodeConnection;
+
+
+    /* get current connection */
+    CurConnection = GetConnectionByIndex(NodeConnections, NodeConnectionIndex);
+
+    if (bUpDirection)
+        NodeIndex = CurConnection->FromNode;
+    else
+        NodeIndex = CurConnection->ToNode;
+
+    /* get target node type of current connection */
+    NodeType = GetNodeType(NodeTypes, NodeIndex);
+
+    if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_SUM) || IsEqualGUIDAligned(NodeType, &KSNODETYPE_MUX))
+    {
+        if (bUpDirection)
+        {
+            /* add the sum / mux node to destination line */
+            //Nodes[NodeIndex] = TRUE;
+        }
+
+        return STATUS_SUCCESS;
+    }
+
+    /* now add the node */
+    Nodes[NodeIndex] = TRUE;
+
+
+    /* get all node indexes referenced by that node */
+    if (bUpDirection)
+    {
+        Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
+    }
+    else
+    {
+        Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
+    }
+
+    if (NT_SUCCESS(Status))
+    {
+        for(Index = 0; Index < NodeConnectionCount; Index++)
+        {
+            /* iterate recursively into the nodes */
+            Status = GetControlsFromPinByConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
+            ASSERT(Status == STATUS_SUCCESS);
+        }
+        /* free node connection indexes */
+        ExFreePool(NodeConnection);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+GetControlsFromPin(
+    IN PKSMULTIPLE_ITEM NodeConnections,
+    IN PKSMULTIPLE_ITEM NodeTypes,
+    IN ULONG PinId,
+    IN ULONG bUpDirection,
+    OUT PULONG Nodes)
+{
+    ULONG NodeConnectionCount, Index;
+    NTSTATUS Status;
+    PULONG NodeConnection;
+
+    /* sanity check */
+    ASSERT(PinId != (ULONG)-1);
+
+    /* get all node indexes referenced by that pin */
+    if (bUpDirection)
+        Status = GetNodeIndexes(NodeConnections, PinId, FALSE, FALSE, &NodeConnectionCount, &NodeConnection);
+    else
+        Status = GetNodeIndexes(NodeConnections, PinId, FALSE, TRUE, &NodeConnectionCount, &NodeConnection);
+
+    for(Index = 0; Index < NodeConnectionCount; Index++)
+    {
+        /* get all associated controls */
+        Status = GetControlsFromPinByConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
+    }
+
+    ExFreePool(NodeConnection);
+
+    return Status;
+}
+
+NTSTATUS
+AddMixerControl(
+    IN LPMIXER_INFO MixerInfo,
+    IN PFILE_OBJECT FileObject,
+    IN PKSMULTIPLE_ITEM NodeTypes,
+    IN ULONG NodeIndex,
+    OUT LPMIXERCONTROLW MixerControl)
+{
+    LPGUID NodeType;
+    KSP_NODE Node;
+    ULONG BytesReturned;
+    NTSTATUS Status;
+    LPWSTR Name;
+
+
+    /* initialize mixer control */
+    MixerControl->cbStruct = sizeof(MIXERCONTROLW);
+    MixerControl->dwControlID = MixerInfo->ControlId;
+
+    /* get node type */
+    NodeType = GetNodeType(NodeTypes, NodeIndex);
+    /* store control type */
+    MixerControl->dwControlType = GetControlTypeFromTopologyNode(NodeType);
+
+    MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; //FIXME
+    MixerControl->cMultipleItems = 0; //FIXME
+
+    if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
+    {
+        MixerControl->Bounds.dwMinimum = 0;
+        MixerControl->Bounds.dwMaximum = 1;
+    }
+    else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
+    {
+        MixerControl->Bounds.dwMinimum = 0;
+        MixerControl->Bounds.dwMaximum = 0xFFFF;
+        MixerControl->Metrics.cSteps = 0xC0; //FIXME
+    }
+
+    /* setup request to retrieve name */
+    Node.NodeId = NodeIndex;
+    Node.Property.Id = KSPROPERTY_TOPOLOGY_NAME;
+    Node.Property.Flags = KSPROPERTY_TYPE_GET;
+    Node.Property.Set = KSPROPSETID_Topology;
+    Node.Reserved = 0;
+
+    /* get node name size */
+    Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
+
+    if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+        ASSERT(BytesReturned != 0);
+        Name = ExAllocatePool(NonPagedPool, BytesReturned);
+        if (!Name)
+        {
+            /* not enough memory */
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* get node name */
+        Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
+        if (NT_SUCCESS(Status))
+        {
+            RtlMoveMemory(MixerControl->szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
+            MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+
+            RtlMoveMemory(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
+            MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
+        }
+
+        /* free name buffer */
+        ExFreePool(Name);
+    }
+
+    MixerInfo->ControlId++;
+
+    DPRINT("Status %x Name %S\n", Status, MixerControl->szName);
+    return STATUS_SUCCESS;
+}
+
 NTSTATUS
 AddMixerSourceLine(
     IN OUT LPMIXER_INFO MixerInfo,
     IN PFILE_OBJECT FileObject,
+    IN PKSMULTIPLE_ITEM NodeConnections,
+    IN PKSMULTIPLE_ITEM NodeTypes,
     IN ULONG DeviceIndex,
-    IN ULONG PinId)
+    IN ULONG PinId,
+    IN ULONG bBridgePin,
+    IN ULONG bTargetPin)
 {
     LPMIXERLINE_EXT SrcLine, DstLine;
     NTSTATUS Status;
     KSP_PIN Pin;
     LPWSTR PinName;
     GUID NodeType;
-    ULONG BytesReturned;
+    ULONG BytesReturned, ControlCount, Index;
+    PULONG Nodes;
 
-    /* allocate src mixer line */
-    SrcLine = (LPMIXERLINE_EXT)ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
-    if (!SrcLine)
-        return STATUS_INSUFFICIENT_RESOURCES;
+    if (!bTargetPin)
+    {
+        /* allocate src mixer line */
+        SrcLine = (LPMIXERLINE_EXT)ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
 
-    /* zero struct */
-    RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
+        if (!SrcLine)
+            return STATUS_INSUFFICIENT_RESOURCES;
 
-    /* initialize mixer src line */
-    SrcLine->DeviceIndex = DeviceIndex;
-    SrcLine->PinId = PinId;
-    SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
+        /* zero struct */
+        RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
+
+    }
+    else
+    {
+        ASSERT(!IsListEmpty(&MixerInfo->LineList));
+        SrcLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+    }
 
     /* get destination line */
     DstLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+    ASSERT(DstLine);
 
-    /* initialize mixer destination line */
-    SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
-    SrcLine->Line.dwDestination = 0;
-    SrcLine->Line.dwSource = DstLine->Line.cConnections;
-    SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000);
-    SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
-    SrcLine->Line.dwUser = 0;
-    SrcLine->Line.cChannels = DstLine->Line.cChannels;
-    SrcLine->Line.cConnections = 0;
-    SrcLine->Line.cControls = 1; //FIXME
-
-    //HACK
-    SrcLine->LineControls = ExAllocatePool(NonPagedPool, SrcLine->Line.cControls * sizeof(MIXERCONTROLW));
-    if (!SrcLine->LineControls)
+
+    if (!bTargetPin)
+    {
+        /* initialize mixer src line */
+        SrcLine->DeviceIndex = DeviceIndex;
+        SrcLine->PinId = PinId;
+        SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
+
+        /* initialize mixer destination line */
+        SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
+        SrcLine->Line.dwDestination = 0;
+        SrcLine->Line.dwSource = DstLine->Line.cConnections;
+        SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000);
+        SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
+        SrcLine->Line.dwUser = 0;
+        SrcLine->Line.cChannels = DstLine->Line.cChannels;
+        SrcLine->Line.cConnections = 0;
+        SrcLine->Line.Target.dwType = 1;
+        SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
+        SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
+        SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
+        SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
+        wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
+
+    }
+
+    /* allocate a node arrary */
+    Nodes = ExAllocatePool(NonPagedPool, sizeof(ULONG) * NodeTypes->Count);
+
+    if (!Nodes)
     {
         /* not enough memory */
-        ExFreePool(SrcLine);
+        if (!bTargetPin)
+        {
+            ExFreePool(SrcLine);
+        }
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    /* clear line controls */
-    RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW));
+    /* clear nodes array */
+    RtlZeroMemory(Nodes, sizeof(ULONG) * NodeTypes->Count);
 
-    /* fill in pseudo mixer control */
-    SrcLine->LineControls->dwControlID = 1; //FIXME
-    SrcLine->LineControls->cbStruct = sizeof(MIXERCONTROLW);
-    SrcLine->LineControls->fdwControl = 0;
-    SrcLine->LineControls->cMultipleItems = 0;
-    wcscpy(SrcLine->LineControls->szName, L"test");
-    wcscpy(SrcLine->LineControls->szShortName, L"test");
+    Status = GetControlsFromPin(NodeConnections, NodeTypes, PinId, bTargetPin, Nodes);
+    if (!NT_SUCCESS(Status))
+    {
+        /* something went wrong */
+        if (!bTargetPin)
+        {
+            ExFreePool(SrcLine);
+        }
+        ExFreePool(Nodes);
+        return Status;
+    }
+
+    /* now count all nodes controlled by that pin */
+    ControlCount = 0;
+    for(Index = 0; Index < NodeTypes->Count; Index++)
+    {
+        if (Nodes[Index])
+            ControlCount++;
+    }
+
+    /* now allocate the line controls */
+    if (ControlCount)
+    {
+        SrcLine->LineControls = ExAllocatePool(NonPagedPool, sizeof(MIXERCONTROLW) * ControlCount);
+
+        if (!SrcLine->LineControls)
+        {
+            /* no memory available */
+            if (!bTargetPin)
+            {
+                ExFreePool(SrcLine);
+            }
+            ExFreePool(Nodes);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        SrcLine->NodeIds = ExAllocatePool(NonPagedPool, sizeof(ULONG) * ControlCount);
+        if (!SrcLine->NodeIds)
+        {
+            /* no memory available */
+            ExFreePool(SrcLine->LineControls);
+            if (!bTargetPin)
+            {
+                ExFreePool(SrcLine);
+            }
+            ExFreePool(Nodes);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* zero line controls */
+        RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount);
+        RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount);
+
+        ControlCount = 0;
+        for(Index = 0; Index < NodeTypes->Count; Index++)
+        {
+            if (Nodes[Index])
+            {
+                /* store the node index for retrieving / setting details */
+                SrcLine->NodeIds[ControlCount] = Index;
+
+                Status = AddMixerControl(MixerInfo, FileObject, NodeTypes, Index, &SrcLine->LineControls[ControlCount]);
+                if (NT_SUCCESS(Status))
+                {
+                    /* increment control count on success */
+                    ControlCount++;
+                }
+            }
+        }
+        /* store control count */
+        SrcLine->Line.cControls = ControlCount;
+    }
 
+    /* release nodes array */
+    ExFreePool(Nodes);
 
     /* get pin category */
     Pin.PinId = PinId;
@@ -831,17 +1134,12 @@ AddMixerSourceLine(
         }
     }
 
-    SrcLine->Line.Target.dwType = 1;
-    SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
-    SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
-    SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
-    SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
-    wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
-
-
     /* insert src line */
-    InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
-    DstLine->Line.cConnections++;
+    if (!bTargetPin)
+    {
+        InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
+        DstLine->Line.cConnections++;
+    }
 
     return STATUS_SUCCESS;
 }
@@ -851,8 +1149,12 @@ NTSTATUS
 AddMixerSourceLines(
     IN OUT LPMIXER_INFO MixerInfo,
     IN PFILE_OBJECT FileObject,
+    IN PKSMULTIPLE_ITEM NodeConnections,
+    IN PKSMULTIPLE_ITEM NodeTypes,
     IN ULONG DeviceIndex,
     IN ULONG PinsCount,
+    IN ULONG BridgePinIndex,
+    IN ULONG TargetPinIndex,
     IN PULONG Pins)
 {
     ULONG Index;
@@ -862,7 +1164,7 @@ AddMixerSourceLines(
     {
         if (Pins[Index-1])
         {
-            AddMixerSourceLine(MixerInfo, FileObject, DeviceIndex, Index-1);
+            AddMixerSourceLine(MixerInfo, FileObject, NodeConnections, NodeTypes, DeviceIndex, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex));
         }
     }
     return Status;
@@ -987,7 +1289,7 @@ HandlePhysicalConnection(
                 PinsSrcRef[OutConnection->Pin] = TRUE;
             }
 
-            Status = AddMixerSourceLines(MixerInfo, FileObject, DeviceIndex, PinsRefCount, PinsSrcRef);
+            Status = AddMixerSourceLines(MixerInfo, FileObject, NodeConnections, NodeTypes, DeviceIndex, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef);
 
             ExFreePool(MixerControls);
             ExFreePool(PinsSrcRef);
@@ -1045,10 +1347,6 @@ InitializeMixer(
     if (!DestinationLine)
         return STATUS_INSUFFICIENT_RESOURCES;
 
-    /* initialize mixer info */
-    MixerInfo->hMixer = hDevice;
-    MixerInfo->MixerFileObject = FileObject;
-
     /* intialize mixer caps */
     MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
     MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
@@ -1083,7 +1381,6 @@ InitializeMixer(
     DestinationLine->Line.dwUser = 0;
     DestinationLine->Line.dwComponentType = (bInput == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
     DestinationLine->Line.cChannels = 2; //FIXME
-    DestinationLine->Line.cControls = 0; //FIXME
     wcscpy(DestinationLine->Line.szShortName, L"Summe"); //FIXME
     wcscpy(DestinationLine->Line.szName, L"Summe"); //FIXME
     DestinationLine->Line.Target.dwType = (bInput == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
@@ -1411,6 +1708,7 @@ WdmAudGetLineControls(
 {
     LPMIXERLINE_EXT MixerLineSrc;
     PWDMAUD_DEVICE_EXTENSION DeviceExtension;
+    ULONG Index;
 
     /* get device extension */
     DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
@@ -1427,15 +1725,12 @@ WdmAudGetLineControls(
         ASSERT(MixerLineSrc);
         if (MixerLineSrc)
         {
-            RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, DeviceInfo->u.MixControls.cControls) * sizeof(MIXERLINECONTROLSW));
+            RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, DeviceInfo->u.MixControls.cControls) * sizeof(MIXERCONTROLW));
         }
         return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
     }
     else if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
     {
-        DPRINT1("dwLineID %u\n",DeviceInfo->u.MixControls.dwLineID);
-        UNIMPLEMENTED
-        //HACK
         if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
         {
             /* invalid parameter */
@@ -1444,11 +1739,18 @@ WdmAudGetLineControls(
 
         MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
         ASSERT(MixerLineSrc);
-        if (MixerLineSrc)
+
+        Index = 0;
+        for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
         {
-            RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, DeviceInfo->u.MixControls.cControls) * sizeof(MIXERLINECONTROLSW));
+            if (DeviceInfo->u.MixControls.dwControlType == MixerLineSrc->LineControls[Index].dwControlType)
+            {
+                RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
+                return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
+            }
         }
-        return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
+        DPRINT1("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x\n", DeviceInfo->u.MixControls.dwControlType, DeviceInfo->u.MixControls.dwLineID);
+        return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
     }
 
     UNIMPLEMENTED;
diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/sup.c b/reactos/drivers/wdm/audio/legacy/wdmaud/sup.c
new file mode 100644 (file)
index 0000000..dd61c34
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Kernel Streaming
+ * FILE:            drivers/wdm/audio/legacy/wdmaud/sup.c
+ * PURPOSE:         System Audio graph builder
+ * PROGRAMMER:      Andrew Greenwood
+ *                  Johannes Anderwald
+ */
+#include "wdmaud.h"
+
+NTSTATUS
+SetIrpIoStatus(
+    IN PIRP Irp,
+    IN NTSTATUS Status,
+    IN ULONG Length)
+{
+    Irp->IoStatus.Information = Length;
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
+
+}
+
+NTSTATUS
+ClosePin(
+    IN  PWDMAUD_CLIENT ClientInfo,
+    IN  ULONG FilterId,
+    IN  ULONG PinId,
+    IN  SOUND_DEVICE_TYPE DeviceType)
+{
+    ULONG Index;
+
+    for(Index = 0; Index < ClientInfo->NumPins; Index++)
+    {
+        if (ClientInfo->hPins[Index].FilterId == FilterId && ClientInfo->hPins[Index].PinId == PinId && ClientInfo->hPins[Index].Handle && ClientInfo->hPins[Index].Type == DeviceType)
+        {
+            if (ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
+            {
+                ZwClose(ClientInfo->hPins[Index].Handle);
+            }
+            ClientInfo->hPins[Index].Handle = NULL;
+            return Index;
+        }
+    }
+    return MAXULONG;
+}
+
+NTSTATUS
+InsertPinHandle(
+    IN  PWDMAUD_CLIENT ClientInfo,
+    IN  ULONG FilterId,
+    IN  ULONG PinId,
+    IN  SOUND_DEVICE_TYPE DeviceType,
+    IN  HANDLE PinHandle,
+    IN  ULONG FreeIndex)
+{
+    PWDMAUD_HANDLE Handles;
+
+    if (FreeIndex != MAXULONG)
+    {
+        /* re-use a free index */
+        ClientInfo->hPins[FreeIndex].Handle = PinHandle;
+        ClientInfo->hPins[FreeIndex].FilterId = FilterId;
+        ClientInfo->hPins[FreeIndex].PinId = PinId;
+        ClientInfo->hPins[FreeIndex].Type = DeviceType;
+
+        return STATUS_SUCCESS;
+    }
+
+    Handles = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
+
+    if (!Handles)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    if (ClientInfo->NumPins)
+    {
+        RtlMoveMemory(Handles, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
+        ExFreePool(ClientInfo->hPins);
+    }
+
+    ClientInfo->hPins = Handles;
+    ClientInfo->hPins[ClientInfo->NumPins].Handle = PinHandle;
+    ClientInfo->hPins[ClientInfo->NumPins].Type = DeviceType;
+    ClientInfo->hPins[ClientInfo->NumPins].FilterId = FilterId;
+    ClientInfo->hPins[ClientInfo->NumPins].PinId = PinId;
+    ClientInfo->NumPins++;
+
+    return STATUS_SUCCESS;
+}
+
+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;
+}
+
diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/wave.c b/reactos/drivers/wdm/audio/legacy/wdmaud/wave.c
new file mode 100644 (file)
index 0000000..9aac7ff
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Kernel Streaming
+ * FILE:            drivers/wdm/audio/legacy/wdmaud/wave.c
+ * PURPOSE:         Wave Out enumeration
+ * PROGRAMMER:      Andrew Greenwood
+ *                  Johannes Anderwald
+ */
+#include "wdmaud.h"
+
+
+typedef struct
+{
+    ULONG SampleRate;
+    ULONG Bit8Mono;
+    ULONG Bit8Stereo;
+    ULONG Bit16Mono;
+    ULONG Bit16Stereo;
+}AUDIO_RANGE;
+
+#define AUDIO_TEST_RANGE (5)
+
+static AUDIO_RANGE TestRange[AUDIO_TEST_RANGE] =
+{
+    {
+        11025,
+        WAVE_FORMAT_1M08,
+        WAVE_FORMAT_1S08,
+        WAVE_FORMAT_1M16,
+        WAVE_FORMAT_1S16
+    },
+    {
+        22050,
+        WAVE_FORMAT_2M08,
+        WAVE_FORMAT_2S08,
+        WAVE_FORMAT_2M16,
+        WAVE_FORMAT_2S16
+    },
+    {
+        44100,
+        WAVE_FORMAT_4M08,
+        WAVE_FORMAT_4S08,
+        WAVE_FORMAT_4M16,
+        WAVE_FORMAT_4S16
+    },
+    {
+        48000,
+        WAVE_FORMAT_48M08,
+        WAVE_FORMAT_48S08,
+        WAVE_FORMAT_48M16,
+        WAVE_FORMAT_48S16
+    },
+    {
+        96000,
+        WAVE_FORMAT_96M08,
+        WAVE_FORMAT_96S08,
+        WAVE_FORMAT_96M16,
+        WAVE_FORMAT_96S16
+    }
+};
+
+LPWAVE_INFO
+AllocateWaveInfo()
+{
+    /* allocate wav info */
+    LPWAVE_INFO WaveOutInfo = ExAllocatePool(NonPagedPool, sizeof(WAVE_INFO));
+    if (!WaveOutInfo)
+        return NULL;
+
+    /* zero wave info struct */
+    RtlZeroMemory(WaveOutInfo, sizeof(WAVE_INFO));
+
+    return WaveOutInfo;
+}
+
+PKSPIN_CONNECT
+AllocatePinConnect(
+    ULONG DataFormatSize)
+{
+    PKSPIN_CONNECT Connect = ExAllocatePool(NonPagedPool, sizeof(KSPIN_CONNECT) + DataFormatSize);
+    if (!Connect)
+        return NULL;
+
+    /* zero pin connect struct */
+    RtlZeroMemory(Connect, sizeof(KSPIN_CONNECT) + DataFormatSize);
+
+    return Connect;
+}
+
+NTSTATUS
+GetWaveInfoByIndexAndType(
+    IN  PDEVICE_OBJECT DeviceObject,
+    IN  ULONG DeviceIndex,
+    IN  SOUND_DEVICE_TYPE DeviceType,
+    OUT LPWAVE_INFO *OutWaveInfo)
+{
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
+    ULONG Index = 0;
+    PLIST_ENTRY Entry, ListHead;
+    LPWAVE_INFO WaveInfo;
+
+    /* get device extension */
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    if (DeviceType == WAVE_IN_DEVICE_TYPE)
+        ListHead = &DeviceExtension->WaveInList;
+    else
+        ListHead = &DeviceExtension->WaveOutList;
+
+    /* get first entry */
+    Entry = ListHead->Flink;
+
+    while(Entry != ListHead)
+    {
+        WaveInfo = (LPWAVE_INFO)CONTAINING_RECORD(Entry, WAVE_INFO, Entry);
+
+        if (Index == DeviceIndex)
+        {
+            *OutWaveInfo = WaveInfo;
+            return STATUS_SUCCESS;
+        }
+        Index++;
+        Entry = Entry->Flink;
+    }
+
+    return STATUS_NOT_FOUND;
+}
+
+
+VOID
+InitializePinConnect(
+    IN OUT PKSPIN_CONNECT PinConnect,
+    IN ULONG PinId)
+{
+    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->Priority.PriorityClass = KSPRIORITY_NORMAL;
+    PinConnect->Priority.PrioritySubClass = 1;
+}
+
+VOID
+InitializeDataFormat(
+    IN PKSDATAFORMAT_WAVEFORMATEX DataFormat,
+    LPWAVEFORMATEX WaveFormatEx)
+{
+
+    DataFormat->WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag;
+    DataFormat->WaveFormatEx.nChannels = WaveFormatEx->nChannels;
+    DataFormat->WaveFormatEx.nSamplesPerSec = WaveFormatEx->nSamplesPerSec;
+    DataFormat->WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign;
+    DataFormat->WaveFormatEx.nAvgBytesPerSec = WaveFormatEx->nAvgBytesPerSec;
+    DataFormat->WaveFormatEx.wBitsPerSample = WaveFormatEx->wBitsPerSample;
+    DataFormat->WaveFormatEx.cbSize = 0;
+    DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
+    DataFormat->DataFormat.Flags = 0;
+    DataFormat->DataFormat.Reserved = 0;
+    DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
+
+    DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+    DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
+    DataFormat->DataFormat.SampleSize = 4;
+}
+
+
+NTSTATUS
+AttachToVirtualAudioDevice(
+    IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
+    IN ULONG VirtualDeviceId)
+{
+    ULONG BytesReturned;
+    SYSAUDIO_INSTANCE_INFO InstanceInfo;
+
+    /* 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 = VirtualDeviceId;
+
+    /* attach to virtual device */
+   return KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
+
+}
+
+NTSTATUS
+GetAudioPinDataRanges(
+    IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
+    IN ULONG FilterId,
+    IN ULONG PinId,
+    IN OUT PKSMULTIPLE_ITEM * OutMultipleItem)
+{
+    KSP_PIN PinProperty;
+    ULONG BytesReturned = 0;
+    NTSTATUS Status;
+    PKSMULTIPLE_ITEM MultipleItem;
+
+    /* retrieve size of data ranges buffer */
+    PinProperty.Reserved = FilterId;
+    PinProperty.PinId = PinId;
+    PinProperty.Property.Set = KSPROPSETID_Pin;
+    PinProperty.Property.Id = KSPROPERTY_PIN_DATARANGES;
+    PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
+
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
+    if (Status != STATUS_MORE_ENTRIES)
+    {
+        return Status;
+    }
+
+    MultipleItem = ExAllocatePool(NonPagedPool, BytesReturned);
+    if (!MultipleItem)
+    {
+        /* not enough memory */
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
+    if (!NT_SUCCESS(Status))
+    {
+        /* failed */
+        ExFreePool(MultipleItem);
+        return Status;
+    }
+
+    /* save result */
+    *OutMultipleItem = MultipleItem;
+    return Status;
+}
+
+NTSTATUS
+FindAudioDataRange(
+    PKSMULTIPLE_ITEM MultipleItem,
+    PKSDATARANGE_AUDIO * OutDataRangeAudio)
+{
+    ULONG Index;
+    PKSDATARANGE_AUDIO DataRangeAudio;
+    PKSDATARANGE DataRange;
+
+    DataRange = (PKSDATARANGE) (MultipleItem + 1);
+    for(Index = 0; Index < MultipleItem->Count; Index++)
+    {
+        if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO))
+        {
+            DataRangeAudio = (PKSDATARANGE_AUDIO)DataRange;
+            if (IsEqualGUIDAligned(&DataRangeAudio->DataRange.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
+                IsEqualGUIDAligned(&DataRangeAudio->DataRange.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
+                IsEqualGUIDAligned(&DataRangeAudio->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
+            {
+                DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio->MinimumSampleFrequency, DataRangeAudio->MaximumSampleFrequency,
+                                                         DataRangeAudio->MinimumBitsPerSample, DataRangeAudio->MaximumBitsPerSample, DataRangeAudio->MaximumChannels);
+                *OutDataRangeAudio = DataRangeAudio;
+                return STATUS_SUCCESS;
+            }
+        }
+    }
+    return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+NTAPI
+OpenWavePin(
+    IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
+    IN ULONG FilterId,
+    IN ULONG PinId,
+    IN LPWAVEFORMATEX WaveFormatEx,
+    IN ACCESS_MASK DesiredAccess,
+    OUT PHANDLE PinHandle)
+{
+    PKSPIN_CONNECT PinConnect;
+    PKSDATAFORMAT_WAVEFORMATEX DataFormat;
+    NTSTATUS Status;
+
+    /* allocate pin connect */
+    PinConnect = AllocatePinConnect(sizeof(KSDATAFORMAT_WAVEFORMATEX));
+    if (!PinConnect)
+    {
+        /* no memory */
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* initialize pin connect struct */
+    InitializePinConnect(PinConnect, PinId);
+
+    /* get offset to dataformat */
+    DataFormat = (PKSDATAFORMAT_WAVEFORMATEX) (PinConnect + 1);
+    /* initialize with requested wave format */
+    InitializeDataFormat(DataFormat, WaveFormatEx);
+
+    /* first attach to the virtual device */
+    Status = AttachToVirtualAudioDevice(DeviceExtension, FilterId);
+
+    if (!NT_SUCCESS(Status))
+    {
+        /* failed */
+        ExFreePool(PinConnect);
+        return Status;
+    }
+
+    /* now create the pin */
+    Status = KsCreatePin(DeviceExtension->hSysAudio, PinConnect, DesiredAccess, PinHandle);
+
+    /* free create info */
+    ExFreePool(PinConnect);
+
+    return Status;
+}
+
+ULONG
+GetPinInstanceCount(
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension,
+    ULONG FilterId,
+    ULONG PinId)
+{
+    KSP_PIN PinRequest;
+    KSPIN_CINSTANCES PinInstances;
+    ULONG BytesReturned;
+    NTSTATUS Status;
+
+    /* query the instance count */
+    PinRequest.Reserved = FilterId;
+    PinRequest.PinId = PinId;
+    PinRequest.Property.Set = KSPROPSETID_Pin;
+    PinRequest.Property.Flags = KSPROPERTY_TYPE_GET;
+    PinRequest.Property.Id = KSPROPERTY_PIN_CINSTANCES;
+
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSP_PIN), (PVOID)&PinInstances, sizeof(KSPIN_CINSTANCES), &BytesReturned);
+    ASSERT(Status == STATUS_SUCCESS);
+    return PinInstances.CurrentCount;
+}
+
+
+NTSTATUS
+CheckSampleFormat(
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension,
+    LPWAVE_INFO WaveInfo,
+    ULONG SampleRate,
+    ULONG NumChannels,
+    ULONG BitsPerSample)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+#if 0
+
+    WAVEFORMATEX WaveFormat;
+    HANDLE PinHandle;
+
+    /* clear wave format */
+    RtlZeroMemory(&WaveFormat, sizeof(WAVEFORMATEX));
+
+    WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
+    WaveFormat.nChannels = NumChannels;
+    WaveFormat.nSamplesPerSec = SampleRate;
+    WaveFormat.nAvgBytesPerSec = SampleRate * NumChannels * (BitsPerSample/8);
+    WaveFormat.nBlockAlign = (NumChannels * BitsPerSample) / 8;
+    WaveFormat.wBitsPerSample = BitsPerSample;
+    WaveFormat.cbSize = sizeof(WAVEFORMATEX);
+
+    Status = OpenWavePin(DeviceExtension, WaveInfo->FilterId, WaveInfo->PinId, &WaveFormat, GENERIC_READ | GENERIC_WRITE, &PinHandle);
+
+    if (NT_SUCCESS(Status))
+    {
+        /* success */
+        ZwClose(PinHandle);
+
+        while(GetPinInstanceCount(DeviceExtension, WaveInfo->FilterId, WaveInfo->PinId))
+            KeStallExecutionProcessor(5);
+    }
+
+    DPRINT("SampleRate %u BitsPerSample %u NumChannels %u Status %x bInput %u\n", SampleRate, BitsPerSample, NumChannels, Status, WaveInfo->bInput);
+#endif
+
+
+    return Status;
+}
+
+
+NTSTATUS
+CheckFormat(
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension,
+    PKSDATARANGE_AUDIO DataRangeAudio,
+    LPWAVE_INFO WaveInfo)
+{
+    ULONG Index, SampleFrequency;
+    ULONG Result = 0;
+    NTSTATUS Status;
+
+    for(Index = 0; Index < AUDIO_TEST_RANGE; Index++)
+    {
+        SampleFrequency = TestRange[Index].SampleRate;
+
+        if (DataRangeAudio->MinimumSampleFrequency <= SampleFrequency && DataRangeAudio->MaximumSampleFrequency >= SampleFrequency)
+        {
+            /* the audio adapter supports the sample frequency */
+            if (DataRangeAudio->MinimumBitsPerSample <= 8 && DataRangeAudio->MaximumBitsPerSample >= 8)
+            {
+                /* check if pin supports the sample rate in 8-Bit Mono */
+                Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 1, 8);
+                if (NT_SUCCESS(Status))
+                {
+                    Result |= TestRange[Index].Bit8Mono;
+                }
+
+                if (DataRangeAudio->MaximumChannels > 1)
+                {
+                    /* check if pin supports the sample rate in 8-Bit Stereo */
+                    Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 2, 8);
+                    if (NT_SUCCESS(Status))
+                    {
+                        Result |= TestRange[Index].Bit8Stereo;
+                    }
+                }
+            }
+
+            if (DataRangeAudio->MinimumBitsPerSample <= 16 && DataRangeAudio->MaximumBitsPerSample >= 16)
+            {
+                /* check if pin supports the sample rate in 16-Bit Mono */
+                Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 1, 16);
+                if (NT_SUCCESS(Status))
+                {
+                    Result |= TestRange[Index].Bit16Mono;
+                }
+
+                if (DataRangeAudio->MaximumChannels > 1)
+                {
+                    /* check if pin supports the sample rate in 16-Bit Stereo */
+                    Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 2, 16);
+                    if (NT_SUCCESS(Status))
+                    {
+                        Result |= TestRange[Index].Bit16Stereo;
+                    }
+                }
+            }
+        }
+    }
+
+
+    if (WaveInfo->bInput)
+        WaveInfo->u.InCaps.dwFormats = Result;
+    else
+        WaveInfo->u.OutCaps.dwFormats = Result;
+
+    DPRINT("Format %x bInput %u\n", Result, WaveInfo->bInput);
+
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+InitializeWaveInfo(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN ULONG FilterId,
+    IN ULONG PinId,
+    IN ULONG bInput)
+{
+    KSP_PIN PinProperty;
+    KSCOMPONENTID ComponentId;
+    NTSTATUS Status;
+    ULONG BytesReturned;
+    WCHAR DeviceName[MAX_PATH];
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
+    PKSMULTIPLE_ITEM MultipleItem;
+    PKSDATARANGE_AUDIO DataRangeAudio;
+    LPWAVE_INFO WaveInfo = AllocateWaveInfo();
+
+
+    if (!WaveInfo)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* initialize wave info */
+    WaveInfo->bInput = bInput;
+    WaveInfo->FilterId = FilterId;
+    WaveInfo->PinId = PinId;
+
+    /* setup request to return component id */
+    PinProperty.PinId = FilterId;
+    PinProperty.Property.Set = KSPROPSETID_Sysaudio;
+    PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_COMPONENT_ID;
+    PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
+
+    /* get device extension */
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    /* query sysaudio for component id */
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)&ComponentId, sizeof(KSCOMPONENTID), &BytesReturned);
+    if (NT_SUCCESS(Status))
+    {
+        if (bInput)
+        {
+            WaveInfo->u.InCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
+            WaveInfo->u.InCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
+        }
+        else
+        {
+            WaveInfo->u.OutCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
+            WaveInfo->u.OutCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
+        }
+    }
+    else
+    {
+        /* set up something useful */
+        if (bInput)
+        {
+            WaveInfo->u.InCaps.wMid = MM_MICROSOFT;
+            WaveInfo->u.InCaps.wPid = MM_PID_UNMAPPED;
+            WaveInfo->u.InCaps.vDriverVersion = 1;
+        }
+        else
+        {
+            WaveInfo->u.OutCaps.wMid = MM_MICROSOFT;
+            WaveInfo->u.OutCaps.wPid = MM_PID_UNMAPPED;
+            WaveInfo->u.OutCaps.vDriverVersion = 1;
+        }
+    }
+
+    /* 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 */
+        if (bInput)
+            Status = FindProductName(DeviceName, MAXPNAMELEN, WaveInfo->u.OutCaps.szPname);
+        else
+            Status = FindProductName(DeviceName, MAXPNAMELEN, WaveInfo->u.InCaps.szPname);
+
+        /* check for success */
+        if (!NT_SUCCESS(Status))
+        {
+            if (bInput)
+                WaveInfo->u.OutCaps.szPname[0] = L'\0';
+            else
+                WaveInfo->u.InCaps.szPname[0] = L'\0';
+        }
+    }
+
+    Status = GetAudioPinDataRanges(DeviceExtension, FilterId, PinId, &MultipleItem);
+    if (NT_SUCCESS(Status))
+    {
+        /* find a audio data range */
+        Status = FindAudioDataRange(MultipleItem, &DataRangeAudio);
+
+        if (NT_SUCCESS(Status))
+        {
+            if (bInput)
+            {
+                WaveInfo->u.InCaps.wChannels = DataRangeAudio->MaximumChannels;
+            }
+            else
+            {
+                WaveInfo->u.OutCaps.wChannels = DataRangeAudio->MaximumChannels;
+            }
+            CheckFormat(DeviceExtension, DataRangeAudio, WaveInfo);
+        }
+        ExFreePool(MultipleItem);
+    }
+
+    if (bInput)
+    {
+        InsertTailList(&DeviceExtension->WaveInList, &WaveInfo->Entry);
+        DeviceExtension->WaveInDeviceCount++;
+    }
+    else
+    {
+        InsertTailList(&DeviceExtension->WaveOutList, &WaveInfo->Entry);
+        DeviceExtension->WaveOutDeviceCount++;
+    }
+
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+NTAPI
+WdmAudWaveInitialize(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    KSP_PIN Pin;
+    ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
+    NTSTATUS Status;
+    KSPIN_COMMUNICATION Communication;
+    KSPIN_DATAFLOW DataFlow;
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
+
+    Pin.Property.Set = KSPROPSETID_Sysaudio;
+    Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
+    Pin.Property.Flags = KSPROPERTY_TYPE_GET;
+
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    /* set wave count to zero */
+    DeviceExtension->WaveInDeviceCount = 0;
+    DeviceExtension->WaveOutDeviceCount = 0;
+
+    /* intialize list head */
+    InitializeListHead(&DeviceExtension->WaveInList);
+    InitializeListHead(&DeviceExtension->WaveOutList);
+
+    Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
+    if (!NT_SUCCESS(Status))
+        return STATUS_UNSUCCESSFUL;
+
+    Result = 0;
+    for(Index = 0; Index < Count; Index++)
+    {
+        /* query number of pins */
+        Pin.Reserved = Index; // see sysaudio
+        Pin.Property.Flags = KSPROPERTY_TYPE_GET;
+        Pin.Property.Set = KSPROPSETID_Pin;
+        Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
+        Pin.PinId = 0;
+
+        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 */
+            for(SubIndex = 0; SubIndex < NumPins; SubIndex++)
+            {
+                Pin.PinId = SubIndex;
+                Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
+                Communication = KSPIN_COMMUNICATION_NONE;
+
+                /* get pin communication type */
+                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(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
+
+                if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
+                {
+                    /* found a wave out device */
+                    InitializeWaveInfo(DeviceObject, Index, SubIndex, FALSE);
+                }
+                else if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
+                {
+                    /* found a wave in device */
+                    InitializeWaveInfo(DeviceObject, Index, SubIndex, TRUE);
+                }
+            }
+        }
+    }
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+WdmAudControlOpenWave(
+    IN  PDEVICE_OBJECT DeviceObject,
+    IN  PIRP Irp,
+    IN  PWDMAUD_DEVICE_INFO DeviceInfo,
+    IN  PWDMAUD_CLIENT ClientInfo)
+{
+    PWDMAUD_DEVICE_EXTENSION DeviceExtension;
+    LPWAVE_INFO WaveInfo;
+    NTSTATUS Status;
+    ACCESS_MASK DesiredAccess = 0;
+    HANDLE PinHandle;
+    ULONG FreeIndex;
+
+    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);
+    }
+
+    /* get device extension */
+    DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    /* find destination wave */
+    Status = GetWaveInfoByIndexAndType(DeviceObject, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType, &WaveInfo);
+    if (!NT_SUCCESS(Status))
+    {
+        /* failed to find wave info */
+        DbgBreakPoint();
+        return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
+    }
+
+    /* close pin handle which uses same virtual audio device id and pin id */
+    FreeIndex = ClosePin(ClientInfo, WaveInfo->FilterId, WaveInfo->PinId, DeviceInfo->DeviceType);
+
+    /* get desired access */
+    if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
+    {
+        DesiredAccess |= GENERIC_READ;
+    }
+     else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
+    {
+        DesiredAccess |= GENERIC_WRITE;
+    }
+
+    /* now try open the pin */
+    Status = OpenWavePin(DeviceExtension, WaveInfo->FilterId, WaveInfo->PinId, &DeviceInfo->u.WaveFormatEx, DesiredAccess, &PinHandle);
+
+    if (!NT_SUCCESS(Status))
+    {
+        /* failed to open the pin */
+        return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
+    }
+
+    /* store the handle */
+    Status = InsertPinHandle(ClientInfo, WaveInfo->FilterId, WaveInfo->PinId, DeviceInfo->DeviceType, PinHandle, FreeIndex);
+    if (!NT_SUCCESS(Status))
+    {
+        /* failed to insert handle */
+        ZwClose(PinHandle);
+        return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
+    }
+
+    /* store pin handle */
+    DeviceInfo->hDevice = PinHandle;
+    return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
+}
+
+NTSTATUS
+WdmAudWaveCapabilities(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PWDMAUD_DEVICE_INFO DeviceInfo,
+    IN PWDMAUD_CLIENT ClientInfo,
+    IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
+{
+    LPWAVE_INFO WaveInfo;
+    NTSTATUS Status;
+
+    /* find destination wave */
+    Status = GetWaveInfoByIndexAndType(DeviceObject, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType, &WaveInfo);
+    if (!NT_SUCCESS(Status))
+    {
+        /* failed to find wave info */
+        DbgBreakPoint();
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
+    {
+        RtlMoveMemory(&DeviceInfo->u.WaveInCaps, &WaveInfo->u.InCaps, sizeof(WAVEINCAPSW));
+    }
+    else
+    {
+        RtlMoveMemory(&DeviceInfo->u.WaveOutCaps, &WaveInfo->u.OutCaps, sizeof(WAVEOUTCAPSW));
+    }
+
+    return STATUS_SUCCESS;
+}
+
index 561336e..6941dcb 100644 (file)
@@ -40,21 +40,33 @@ typedef struct
     ULONG DeviceIndex;
     MIXERLINEW Line;
     LPMIXERCONTROLW LineControls;
+    PULONG          NodeIds;
 }MIXERLINE_EXT, *LPMIXERLINE_EXT;
 
 
 typedef struct
 {
-    HANDLE        hMixer;
-    PFILE_OBJECT  MixerFileObject;
-
     MIXERCAPSW    MixCaps;
 
     LIST_ENTRY    LineList;
-
+    ULONG ControlId;
 }MIXER_INFO, *LPMIXER_INFO;
 
 
+typedef struct
+{
+    LIST_ENTRY Entry;
+    ULONG FilterId;
+    ULONG PinId;
+    ULONG bInput;
+    union
+    {
+        WAVEOUTCAPSW OutCaps;
+        WAVEINCAPSW  InCaps;
+    }u;
+}WAVE_INFO, *LPWAVE_INFO;
+
+
 typedef struct
 {
     LIST_ENTRY Entry;
@@ -77,6 +89,12 @@ typedef struct
     ULONG MixerInfoCount;
     LPMIXER_INFO MixerInfo;
 
+    ULONG WaveInDeviceCount;
+    LIST_ENTRY WaveInList;
+
+    ULONG WaveOutDeviceCount;
+    LIST_ENTRY WaveOutList;
+
 
 }WDMAUD_DEVICE_EXTENSION, *PWDMAUD_DEVICE_EXTENSION;
 
@@ -86,6 +104,16 @@ typedef struct
     PIRP Irp;
 }CONTEXT_WRITE, *PCONTEXT_WRITE;
 
+NTSTATUS
+NTAPI
+OpenWavePin(
+    IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
+    IN ULONG FilterId,
+    IN ULONG PinId,
+    IN LPWAVEFORMATEX WaveFormatEx,
+    IN ACCESS_MASK DesiredAccess,
+    OUT PHANDLE PinHandle);
+
 NTSTATUS
 WdmAudRegisterDeviceInterface(
     IN PDEVICE_OBJECT PhysicalDeviceObject,
@@ -120,6 +148,14 @@ WdmAudControlOpenMixer(
     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
     IN  PWDMAUD_CLIENT ClientInfo);
 
+NTSTATUS
+WdmAudControlOpenWave(
+    IN  PDEVICE_OBJECT DeviceObject,
+    IN  PIRP Irp,
+    IN  PWDMAUD_DEVICE_INFO DeviceInfo,
+    IN  PWDMAUD_CLIENT ClientInfo);
+
+
 ULONG
 GetNumOfMixerDevices(
     IN  PDEVICE_OBJECT DeviceObject);
@@ -148,6 +184,13 @@ WdmAudMixerCapabilities(
     IN  PWDMAUD_CLIENT ClientInfo,
     IN PWDMAUD_DEVICE_EXTENSION DeviceExtension);
 
+NTSTATUS
+WdmAudWaveCapabilities(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN  PWDMAUD_DEVICE_INFO DeviceInfo,
+    IN  PWDMAUD_CLIENT ClientInfo,
+    IN PWDMAUD_DEVICE_EXTENSION DeviceExtension);
+
 NTSTATUS
 NTAPI
 WdmAudFrameSize(
@@ -192,5 +235,26 @@ NTSTATUS
 WdmAudMixerInitialize(
     IN PDEVICE_OBJECT DeviceObject);
 
+NTSTATUS
+NTAPI
+WdmAudWaveInitialize(
+    IN PDEVICE_OBJECT DeviceObject);
+
+NTSTATUS
+ClosePin(
+    IN  PWDMAUD_CLIENT ClientInfo,
+    IN  ULONG FilterId,
+    IN  ULONG PinId,
+    IN  SOUND_DEVICE_TYPE DeviceType);
+
+NTSTATUS
+InsertPinHandle(
+    IN  PWDMAUD_CLIENT ClientInfo,
+    IN  ULONG FilterId,
+    IN  ULONG PinId,
+    IN  SOUND_DEVICE_TYPE DeviceType,
+    IN  HANDLE PinHandle,
+    IN  ULONG FreeIndex);
+
 
 #endif
index fda6c01..1b3acd1 100644 (file)
@@ -7,9 +7,12 @@
        <library>ntoskrnl</library>
        <library>ks</library>
        <library>pseh</library>
+       <library>hal</library>
        <file>control.c</file>
        <file>deviface.c</file>
        <file>entry.c</file>
        <file>mixer.c</file>
+       <file>wave.c</file>
+       <file>sup.c</file>
        <file>wdmaud.rc</file>
 </module>