[USBAUDIO]
[reactos.git] / reactos / drivers / usb / usbaudio / filter.c
index 2ff6593..062d0b5 100644 (file)
@@ -9,6 +9,71 @@
 
 #include "usbaudio.h"
 
+GUID NodeTypeMicrophone = { STATIC_KSNODETYPE_MICROPHONE };
+GUID NodeTypeDesktopMicrophone = { STATIC_KSNODETYPE_DESKTOP_MICROPHONE };
+GUID NodeTypePersonalMicrophone = { STATIC_KSNODETYPE_PERSONAL_MICROPHONE };
+GUID NodeTypeOmmniMicrophone = { STATIC_KSNODETYPE_OMNI_DIRECTIONAL_MICROPHONE };
+GUID NodeTypeArrayMicrophone = { STATIC_KSNODETYPE_MICROPHONE_ARRAY };
+GUID NodeTypeProcessingArrayMicrophone = { STATIC_KSNODETYPE_PROCESSING_MICROPHONE_ARRAY };
+GUID NodeTypeSpeaker = { STATIC_KSNODETYPE_SPEAKER };
+GUID NodeTypeHeadphonesSpeaker = { STATIC_KSNODETYPE_HEADPHONES };
+GUID NodeTypeHMDA = { STATIC_KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO };
+GUID NodeTypeDesktopSpeaker = { STATIC_KSNODETYPE_DESKTOP_SPEAKER };
+GUID NodeTypeRoomSpeaker = { STATIC_KSNODETYPE_ROOM_SPEAKER };
+GUID NodeTypeCommunicationSpeaker = { STATIC_KSNODETYPE_COMMUNICATION_SPEAKER };
+GUID NodeTypeSubwoofer = { STATIC_KSNODETYPE_LOW_FREQUENCY_EFFECTS_SPEAKER };
+GUID NodeTypeCapture = { STATIC_PINNAME_CAPTURE };
+GUID NodeTypePlayback = { STATIC_KSCATEGORY_AUDIO };
+GUID GUID_KSCATEGORY_AUDIO = { STATIC_KSCATEGORY_AUDIO };
+
+KSPIN_INTERFACE StandardPinInterface =
+{
+     {STATIC_KSINTERFACESETID_Standard},
+     KSINTERFACE_STANDARD_STREAMING,
+     0
+};
+
+KSPIN_MEDIUM StandardPinMedium =
+{
+     {STATIC_KSMEDIUMSETID_Standard},
+     KSMEDIUM_TYPE_ANYINSTANCE,
+     0
+};
+
+KSDATARANGE BridgePinAudioFormat[] =
+{
+    {
+        sizeof(KSDATAFORMAT),
+        0,
+        0,
+        0,
+        {STATIC_KSDATAFORMAT_TYPE_AUDIO},
+        {STATIC_KSDATAFORMAT_SUBTYPE_ANALOG},
+        {STATIC_KSDATAFORMAT_SPECIFIER_NONE}
+    }
+};
+
+static PKSDATARANGE BridgePinAudioFormats[] =
+{
+    &BridgePinAudioFormat[0]
+};
+
+static LPWSTR ReferenceString = L"global";
+
+NTSTATUS
+NTAPI
+USBAudioFilterCreate(
+    PKSFILTER Filter,
+    PIRP Irp);
+
+static KSFILTER_DISPATCH USBAudioFilterDispatch = 
+{
+    USBAudioFilterCreate,
+    NULL,
+    NULL,
+    NULL
+};
+
 NTSTATUS
 BuildUSBAudioFilterTopology(
     PKSDEVICE Device)
@@ -17,6 +82,17 @@ BuildUSBAudioFilterTopology(
     return STATUS_NOT_IMPLEMENTED;
 }
 
+NTSTATUS
+NTAPI
+USBAudioFilterCreate(
+    PKSFILTER Filter,
+    PIRP Irp)
+{
+    UNIMPLEMENTED
+    return STATUS_SUCCESS;
+}
+
+
 VOID
 CountTerminalUnits(
     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
@@ -51,6 +127,9 @@ CountTerminalUnits(
                         }
                         TotalTerminalCount++;
                     }
+                    CommonDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
+                    if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength))
+                        break;
                 }
             }
         }
@@ -61,9 +140,145 @@ CountTerminalUnits(
     }
     *NonStreamingTerminalDescriptorCount = NonStreamingTerminalCount;
     *TotalTerminalDescriptorCount = TotalTerminalCount;
+}
+
+LPGUID
+UsbAudioGetPinCategoryFromTerminalDescriptor(
+    IN PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor)
+{
+    if (TerminalDescriptor->wTerminalType == USB_AUDIO_MICROPHONE_TERMINAL_TYPE)
+        return &NodeTypeMicrophone;
+    else if (TerminalDescriptor->wTerminalType == USB_AUDIO_DESKTOP_MICROPHONE_TERMINAL_TYPE)
+        return &NodeTypeDesktopMicrophone;
+    else if (TerminalDescriptor->wTerminalType == USB_AUDIO_PERSONAL_MICROPHONE_TERMINAL_TYPE)
+        return &NodeTypePersonalMicrophone;
+    else if (TerminalDescriptor->wTerminalType == USB_AUDIO_OMMNI_MICROPHONE_TERMINAL_TYPE)
+        return &NodeTypeOmmniMicrophone;
+    else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ARRAY_MICROPHONE_TERMINAL_TYPE)
+        return &NodeTypeArrayMicrophone;
+    else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ARRAY_PROCESSING_MICROPHONE_TERMINAL_TYPE)
+        return &NodeTypeProcessingArrayMicrophone;
+
+    /* playback types */
+    if (TerminalDescriptor->wTerminalType == USB_AUDIO_SPEAKER_TERMINAL_TYPE)
+        return &NodeTypeSpeaker;
+    else if (TerminalDescriptor->wTerminalType == USB_HEADPHONES_SPEAKER_TERMINAL_TYPE)
+        return &NodeTypeHeadphonesSpeaker;
+    else if (TerminalDescriptor->wTerminalType == USB_AUDIO_HMDA_TERMINAL_TYPE)
+        return &NodeTypeHMDA;
+    else if (TerminalDescriptor->wTerminalType == USB_AUDIO_DESKTOP_SPEAKER_TERMINAL_TYPE)
+        return &NodeTypeDesktopSpeaker;
+    else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ROOM_SPEAKER_TERMINAL_TYPE)
+        return &NodeTypeRoomSpeaker;
+    else if (TerminalDescriptor->wTerminalType == USB_AUDIO_COMMUNICATION_SPEAKER_TERMINAL_TYPE)
+        return &NodeTypeCommunicationSpeaker;
+    else if (TerminalDescriptor->wTerminalType == USB_AUDIO_SUBWOOFER_TERMINAL_TYPE)
+        return &NodeTypeSubwoofer;
+
+    if (TerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE)
+    {
+        if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL)
+            return &NodeTypeCapture;
+        else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL)
+            return &NodeTypePlayback;
+
+    }
+    return NULL;
+}
+
+PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR
+UsbAudioGetStreamingTerminalDescriptorByIndex(
+    IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+    IN ULONG Index)
+{
+    PUSB_INTERFACE_DESCRIPTOR Descriptor;
+    PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR InterfaceHeaderDescriptor;
+    PUSB_COMMON_DESCRIPTOR CommonDescriptor;
+    PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR InputTerminalDescriptor;
+    ULONG TerminalCount = 0;
+
+    for (Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
+    Descriptor != NULL;
+        Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1))
+    {
+        if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */
+        {
+            InterfaceHeaderDescriptor = USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
+            if (InterfaceHeaderDescriptor != NULL)
+            {
+                CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
+                while (CommonDescriptor)
+                {
+                    InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor;
+                    if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/ || InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/)
+                    {
+                        if (InputTerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE)
+                        {
+                            if (TerminalCount == Index)
+                            {
+                                return InputTerminalDescriptor;
+                            }
+                            TerminalCount++;
+                        }
+                    }
+                    CommonDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
+                    if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength))
+                        break;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR
+UsbAudioGetNonStreamingTerminalDescriptorByIndex(
+    IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+    IN ULONG Index)
+{
+
+    PUSB_INTERFACE_DESCRIPTOR Descriptor;
+    PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR InterfaceHeaderDescriptor;
+    PUSB_COMMON_DESCRIPTOR CommonDescriptor;
+    PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR InputTerminalDescriptor;
+    ULONG TerminalCount = 0;
 
+    for (Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
+    Descriptor != NULL;
+        Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1))
+    {
+        if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */
+        {
+            InterfaceHeaderDescriptor = USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
+            if (InterfaceHeaderDescriptor != NULL)
+            {
+                CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
+                while (CommonDescriptor)
+                {
+                    InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor;
+                    if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/ || InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/)
+                    {
+                        if (InputTerminalDescriptor->wTerminalType != USB_AUDIO_STREAMING_TERMINAL_TYPE)
+                        {
+                            if (TerminalCount == Index)
+                            {
+                                return InputTerminalDescriptor;
+                            }
+                            TerminalCount++;
+                        }
+                    }
+                    CommonDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
+                    if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength))
+                        break;
+                }
+            }
+        }
+    }
+    return NULL;
 }
 
+
+
 NTSTATUS
 USBAudioPinBuildDescriptors(
     PKSDEVICE Device,
@@ -71,8 +286,83 @@ USBAudioPinBuildDescriptors(
     PULONG PinDescriptorsCount,
     PULONG PinDescriptorSize)
 {
-    UNIMPLEMENTED
-    return STATUS_NOT_IMPLEMENTED;
+    PDEVICE_EXTENSION DeviceExtension;
+    PKSPIN_DESCRIPTOR_EX Pins;
+    ULONG TotalTerminalDescriptorCount = 0;
+    ULONG NonStreamingTerminalDescriptorCount = 0;
+    ULONG Index = 0;
+    PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor = NULL;
+
+    /* get device extension */
+    DeviceExtension = Device->Context;
+
+    CountTerminalUnits(DeviceExtension->ConfigurationDescriptor, &NonStreamingTerminalDescriptorCount, &TotalTerminalDescriptorCount);
+    DPRINT1("TotalTerminalDescriptorCount %lu NonStreamingTerminalDescriptorCount %lu", TotalTerminalDescriptorCount, NonStreamingTerminalDescriptorCount);
+
+    /* allocate pins */
+    Pins = AllocFunction(sizeof(KSPIN_DESCRIPTOR_EX) * TotalTerminalDescriptorCount);
+    if (!Pins)
+    {
+        /* no memory*/
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    for (Index = 0; Index < TotalTerminalDescriptorCount; Index++)
+    {
+        if (Index < (TotalTerminalDescriptorCount - NonStreamingTerminalDescriptorCount))
+        {
+            /* irp sink pins*/
+            TerminalDescriptor = UsbAudioGetStreamingTerminalDescriptorByIndex(DeviceExtension->ConfigurationDescriptor, Index);
+            Pins[Index].PinDescriptor.InterfacesCount = 1;
+            Pins[Index].PinDescriptor.Interfaces = &StandardPinInterface;
+            Pins[Index].PinDescriptor.MediumsCount = 1;
+            Pins[Index].PinDescriptor.Mediums = &StandardPinMedium;
+            Pins[Index].PinDescriptor.Category = UsbAudioGetPinCategoryFromTerminalDescriptor(TerminalDescriptor);
+
+            if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL)
+            {
+                Pins[Index].PinDescriptor.Communication = KSPIN_COMMUNICATION_BOTH;
+                Pins[Index].PinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT;
+            }
+            else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL)
+            {
+                Pins[Index].PinDescriptor.Communication = KSPIN_COMMUNICATION_SINK;
+                Pins[Index].PinDescriptor.DataFlow = KSPIN_DATAFLOW_IN;
+            }
+
+            /* irp sinks / sources can be instantiated */
+            Pins[Index].InstancesPossible = 1;
+        }
+        else
+        {
+            /* bridge pins */
+            TerminalDescriptor = UsbAudioGetNonStreamingTerminalDescriptorByIndex(DeviceExtension->ConfigurationDescriptor, Index - (TotalTerminalDescriptorCount - NonStreamingTerminalDescriptorCount));
+            Pins[Index].PinDescriptor.InterfacesCount = 1;
+            Pins[Index].PinDescriptor.Interfaces = &StandardPinInterface;
+            Pins[Index].PinDescriptor.MediumsCount = 1;
+            Pins[Index].PinDescriptor.Mediums = &StandardPinMedium;
+            Pins[Index].PinDescriptor.DataRanges = BridgePinAudioFormats;
+            Pins[Index].PinDescriptor.DataRangesCount = 1;
+            Pins[Index].PinDescriptor.Communication = KSPIN_COMMUNICATION_BRIDGE;
+            Pins[Index].PinDescriptor.Category = UsbAudioGetPinCategoryFromTerminalDescriptor(TerminalDescriptor);
+
+            if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL)
+            {
+                Pins[Index].PinDescriptor.DataFlow = KSPIN_DATAFLOW_IN;
+            }
+            else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL)
+            {
+                Pins[Index].PinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT;
+            }
+        }
+
+    }
+
+    *PinDescriptors = Pins;
+    *PinDescriptorSize = sizeof(KSPIN_DESCRIPTOR_EX);
+    *PinDescriptorsCount = TotalTerminalDescriptorCount;
+
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
@@ -88,6 +378,7 @@ USBAudioInitComponentId(
     INIT_USBAUDIO_MID(&ComponentId->Manufacturer, DeviceExtension->DeviceDescriptor->idVendor);
     INIT_USBAUDIO_PID(&ComponentId->Product, DeviceExtension->DeviceDescriptor->idProduct);
 
+    //ComponentId->Component = KSCOMPONENTID_USBAUDIO;
     UNIMPLEMENTED
     return STATUS_NOT_IMPLEMENTED;
 }
@@ -99,6 +390,7 @@ USBAudioCreateFilterContext(
     PKSDEVICE Device)
 {
     KSFILTER_DESCRIPTOR FilterDescriptor;
+    PDEVICE_EXTENSION DeviceExtension;
     PKSCOMPONENTID ComponentId;
     NTSTATUS Status;
 
@@ -107,7 +399,11 @@ USBAudioCreateFilterContext(
 
     /* init filter descriptor*/
     FilterDescriptor.Version = KSFILTER_DESCRIPTOR_VERSION;
+    FilterDescriptor.Flags = 0;
     FilterDescriptor.ReferenceGuid = &KSNAME_Filter;
+    FilterDescriptor.Dispatch = &USBAudioFilterDispatch;
+    FilterDescriptor.CategoriesCount = 1;
+    FilterDescriptor.Categories = &GUID_KSCATEGORY_AUDIO;
 
     /* init component id*/
     ComponentId = AllocFunction(sizeof(KSCOMPONENTID));
@@ -134,15 +430,21 @@ USBAudioCreateFilterContext(
         return Status;
     }
 
+    DbgBreakPoint();
     /* build topology */
     Status = BuildUSBAudioFilterTopology(Device);
     if (!NT_SUCCESS(Status))
     {
         /* failed*/
-        FreeFunction(ComponentId);
-        return Status;
+        //FreeFunction(ComponentId);
+        //return Status;
     }
 
+    /* lets create the filter */
+    DeviceExtension = Device->Context;
+    Status = KsCreateFilterFactory(Device->FunctionalDeviceObject, &FilterDescriptor, ReferenceString, NULL, KSCREATE_ITEM_FREEONSTOP, NULL, NULL, NULL);
+    DPRINT1("KsCreateFilterFactory: %x\n", Status);
+
     return Status;
 }