Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / drivers / usb / usbccgp / function.c
diff --git a/drivers/usb/usbccgp/function.c b/drivers/usb/usbccgp/function.c
new file mode 100644 (file)
index 0000000..63817c5
--- /dev/null
@@ -0,0 +1,895 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbccgp/descriptor.c
+ * PURPOSE:     USB  device driver.
+ * PROGRAMMERS:
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ *              Cameron Gutman
+ */
+
+#include "usbccgp.h"
+
+#define NDEBUG
+#include <debug.h>
+
+NTSTATUS
+USBCCGP_QueryInterface(
+    IN PDEVICE_OBJECT DeviceObject,
+    OUT PUSBC_DEVICE_CONFIGURATION_INTERFACE_V1 BusInterface)
+{
+    KEVENT Event;
+    NTSTATUS Status;
+    PIRP Irp;
+    IO_STATUS_BLOCK IoStatus;
+    PIO_STACK_LOCATION Stack;
+
+    /* Sanity checks */
+    ASSERT(DeviceObject);
+
+    /* Initialize event */
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    /* Init interface */
+    RtlZeroMemory(BusInterface, sizeof(USBC_DEVICE_CONFIGURATION_INTERFACE_V1));
+    BusInterface->Version = USBC_DEVICE_CONFIGURATION_INTERFACE_VERSION_1;
+    BusInterface->Size = sizeof(USBC_DEVICE_CONFIGURATION_INTERFACE_V1);
+
+    /* Create irp */
+    Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
+                                       DeviceObject,
+                                       NULL,
+                                       0,
+                                       NULL,
+                                       &Event,
+                                       &IoStatus);
+
+    //
+    // was irp built
+    //
+    if (Irp == NULL)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // initialize request
+    //
+    Stack = IoGetNextIrpStackLocation(Irp);
+    Stack->MajorFunction = IRP_MJ_PNP;
+    Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
+    Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
+    Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&USB_BUS_INTERFACE_USBC_CONFIGURATION_GUID;
+    Stack->Parameters.QueryInterface.Version = 2;
+    Stack->Parameters.QueryInterface.Interface = (PINTERFACE)&BusInterface;
+    Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
+    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+
+    //
+    // call driver
+    //
+    Status = IoCallDriver(DeviceObject, Irp);
+
+    //
+    // did operation complete
+    //
+    if (Status == STATUS_PENDING)
+    {
+        //
+        // wait for completion
+        //
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+
+        //
+        // collect status
+        //
+        Status = IoStatus.Status;
+    }
+
+    return Status;
+}
+
+NTSTATUS
+USBCCGP_CustomEnumWithInterface(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    ULONG FunctionDescriptorBufferLength = 0;
+    NTSTATUS Status;
+    PUSBC_FUNCTION_DESCRIPTOR  FunctionDescriptorBuffer = NULL;
+
+    //
+    // get device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    if (FDODeviceExtension->BusInterface.StartDeviceCallback == NULL)
+    {
+        //
+        // not supported
+        //
+        return STATUS_NOT_SUPPORTED;
+    }
+
+    //
+    // invoke callback
+    //
+    Status = FDODeviceExtension->BusInterface.StartDeviceCallback(FDODeviceExtension->DeviceDescriptor,
+                                                                  FDODeviceExtension->ConfigurationDescriptor,
+                                                                  &FunctionDescriptorBuffer,
+                                                                  &FunctionDescriptorBufferLength,
+                                                                  DeviceObject,
+                                                                  FDODeviceExtension->PhysicalDeviceObject);
+
+    DPRINT("USBCCGP_CustomEnumWithInterface Status %lx\n", Status);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed
+        //
+        return Status;
+    }
+
+    DPRINT("FunctionDescriptorBufferLength %lu\n", FunctionDescriptorBufferLength);
+    DPRINT("FunctionDescriptorBuffer %p\n", FunctionDescriptorBuffer);
+
+    //
+    // assume length % function buffer size
+    //
+    ASSERT(FunctionDescriptorBufferLength);
+    ASSERT(FunctionDescriptorBufferLength % sizeof(USBC_FUNCTION_DESCRIPTOR) == 0);
+
+    //
+    // store result
+    //
+    FDODeviceExtension->FunctionDescriptor = FunctionDescriptorBuffer;
+    FDODeviceExtension->FunctionDescriptorCount = FunctionDescriptorBufferLength / sizeof(USBC_FUNCTION_DESCRIPTOR);
+
+    //
+    // success
+    //
+    return STATUS_SUCCESS;
+}
+
+ULONG
+USBCCGP_CountAssociationDescriptors(
+    IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
+{
+    PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR Descriptor;
+    PUCHAR Offset, End;
+    ULONG Count = 0;
+
+    //
+    // init offsets
+    //
+    Offset = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->bLength;
+    End = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength;
+
+    while (Offset < End)
+    {
+        //
+        // get association descriptor
+        //
+        Descriptor = (PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR)Offset;
+
+        if (Descriptor->bLength == sizeof(USB_INTERFACE_ASSOCIATION_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
+        {
+            //
+            // found descriptor
+            //
+            Count++;
+        }
+
+        //
+        // move to next descriptor
+        //
+        Offset += Descriptor->bLength;
+    }
+
+    //
+    // done
+    //
+    return Count;
+}
+
+PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR
+USBCCGP_GetAssociationDescriptorAtIndex(
+    IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+    IN ULONG Index)
+{
+    PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR Descriptor;
+    PUCHAR Offset, End;
+    ULONG Count = 0;
+
+    //
+    // init offsets
+    //
+    Offset = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->bLength;
+    End = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength;
+
+    while (Offset < End)
+    {
+        //
+        // get association descriptor
+        //
+        Descriptor = (PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR)Offset;
+
+        if (Descriptor->bLength == sizeof(USB_INTERFACE_ASSOCIATION_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
+        {
+            if (Index == Count)
+            {
+                //
+                // found descriptor
+                //
+                return Descriptor;
+            }
+
+            //
+            // not the searched one
+            //
+            Count++;
+        }
+
+        //
+        // move to next descriptor
+        //
+        Offset += Descriptor->bLength;
+    }
+
+    //
+    // failed to find descriptor at the specified index
+    //
+    return NULL;
+}
+
+NTSTATUS
+USBCCGP_InitInterfaceListOfFunctionDescriptor(
+    IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+    IN PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR AssociationDescriptor,
+    OUT PUSBC_FUNCTION_DESCRIPTOR FunctionDescriptor)
+{
+    PUSB_INTERFACE_DESCRIPTOR Descriptor;
+    PUCHAR Offset, End;
+    ULONG Count = 0;
+
+    //
+    // init offsets
+    //
+    Offset = (PUCHAR)AssociationDescriptor + AssociationDescriptor->bLength;
+    End = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength;
+
+    while (Offset < End)
+    {
+        //
+        // get association descriptor
+        //
+        Descriptor = (PUSB_INTERFACE_DESCRIPTOR)Offset;
+
+        if (Descriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
+        {
+            //
+            // store interface descriptor
+            //
+            FunctionDescriptor->InterfaceDescriptorList[Count] = Descriptor;
+            Count++;
+
+            if (Count == AssociationDescriptor->bInterfaceCount)
+            {
+                //
+                // got all interfaces
+                //
+                return STATUS_SUCCESS;
+            }
+        }
+
+        if (Descriptor->bLength == sizeof(USB_INTERFACE_ASSOCIATION_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
+        {
+            //
+            // WTF? a association descriptor which overlaps the next association descriptor
+            //
+            DPRINT1("Invalid association descriptor\n");
+            ASSERT(FALSE);
+            return STATUS_UNSUCCESSFUL;
+        }
+
+        //
+        // move to next descriptor
+        //
+        Offset += Descriptor->bLength;
+    }
+
+    //
+    // invalid association descriptor
+    //
+    DPRINT1("Invalid association descriptor\n");
+    return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+USBCCGP_InitFunctionDescriptor(
+    IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
+    IN ULONG FunctionNumber,
+    OUT PUSBC_FUNCTION_DESCRIPTOR FunctionDescriptor)
+{
+    PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR Descriptor;
+    NTSTATUS Status;
+    LPWSTR DescriptionBuffer;
+    WCHAR Buffer[100];
+    ULONG Index;
+
+    // init function number
+    FunctionDescriptor->FunctionNumber = (UCHAR)FunctionNumber;
+
+    // get association descriptor
+    Descriptor = USBCCGP_GetAssociationDescriptorAtIndex(FDODeviceExtension->ConfigurationDescriptor, FunctionNumber);
+    ASSERT(Descriptor);
+
+    // store number interfaces
+    FunctionDescriptor->NumberOfInterfaces = Descriptor->bInterfaceCount;
+
+    // allocate array for interface count
+    FunctionDescriptor->InterfaceDescriptorList = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * Descriptor->bInterfaceCount);
+    if (!FunctionDescriptor->InterfaceDescriptorList)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    // init interface list
+    Status = USBCCGP_InitInterfaceListOfFunctionDescriptor(FDODeviceExtension->ConfigurationDescriptor, Descriptor, FunctionDescriptor);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed
+        //
+        return Status;
+    }
+
+    //
+    // now init interface description
+    //
+    if (Descriptor->iFunction)
+    {
+        //
+        // get interface description
+        //
+         Status = USBCCGP_GetStringDescriptor(FDODeviceExtension->NextDeviceObject,
+                                              100 * sizeof(WCHAR),
+                                              Descriptor->iFunction,
+                                              0x0409, //FIXME
+                                              (PVOID*)&DescriptionBuffer);
+        if (!NT_SUCCESS(Status))
+        {
+            //
+            // no description
+            //
+            RtlInitUnicodeString(&FunctionDescriptor->FunctionDescription, L"");
+        }
+        else
+        {
+            //
+            // init description
+            //
+            RtlInitUnicodeString(&FunctionDescriptor->FunctionDescription, DescriptionBuffer);
+        }
+        DPRINT1("FunctionDescription %wZ\n", &FunctionDescriptor->FunctionDescription);
+    }
+
+    //
+    // now init hardware id
+    //
+    Index = swprintf(Buffer, L"USB\\VID_%04x&PID_%04x&Rev_%04x&MI_%02x", FDODeviceExtension->DeviceDescriptor->idVendor,
+                                                                         FDODeviceExtension->DeviceDescriptor->idProduct,
+                                                                         FDODeviceExtension->DeviceDescriptor->bcdDevice,
+                                                                         Descriptor->bFirstInterface) + 1;
+    Index += swprintf(&Buffer[Index], L"USB\\VID_%04x&PID_%04x&MI_%02x", FDODeviceExtension->DeviceDescriptor->idVendor,
+                                                                         FDODeviceExtension->DeviceDescriptor->idProduct,
+                                                                         Descriptor->bFirstInterface) + 1;
+
+    // allocate result buffer
+    DescriptionBuffer = AllocateItem(NonPagedPool, (Index + 1) * sizeof(WCHAR));
+    if (!DescriptionBuffer)
+    {
+        //
+        // failed to allocate memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    // copy description
+    RtlCopyMemory(DescriptionBuffer, Buffer, (Index + 1) * sizeof(WCHAR));
+    FunctionDescriptor->HardwareId.Buffer = DescriptionBuffer;
+    FunctionDescriptor->HardwareId.Length = Index * sizeof(WCHAR);
+    FunctionDescriptor->HardwareId.MaximumLength = (Index + 1) * sizeof(WCHAR);
+
+    //
+    // now init the compatible id
+    //
+    Index = swprintf(Buffer, L"USB\\Class_%02x&SubClass_%02x&Prot_%02x", Descriptor->bFunctionClass, Descriptor->bFunctionSubClass, Descriptor->bFunctionProtocol) + 1;
+    Index += swprintf(&Buffer[Index], L"USB\\Class_%02x&SubClass_%02x",  Descriptor->bFunctionClass, Descriptor->bFunctionSubClass) + 1;
+    Index += swprintf(&Buffer[Index], L"USB\\Class_%02x", Descriptor->bFunctionClass) + 1;
+
+    // allocate result buffer
+    DescriptionBuffer = AllocateItem(NonPagedPool, (Index + 1) * sizeof(WCHAR));
+    if (!DescriptionBuffer)
+    {
+        //
+        // failed to allocate memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    // copy description
+    RtlCopyMemory(DescriptionBuffer, Buffer, (Index + 1) * sizeof(WCHAR));
+    FunctionDescriptor->CompatibleId.Buffer = DescriptionBuffer;
+    FunctionDescriptor->CompatibleId.Length = Index * sizeof(WCHAR);
+    FunctionDescriptor->CompatibleId.MaximumLength = (Index + 1) * sizeof(WCHAR);
+
+    //
+    // done
+    //
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+USBCCGP_EnumWithAssociationDescriptor(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    ULONG DescriptorCount, Index;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    //
+    // get device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // count association descriptors
+    //
+    DescriptorCount = USBCCGP_CountAssociationDescriptors(FDODeviceExtension->ConfigurationDescriptor);
+    if (!DescriptorCount)
+    {
+        //
+        // no descriptors found
+        //
+        return STATUS_NOT_SUPPORTED;
+    }
+
+    //
+    // allocate function descriptor array
+    //
+    FDODeviceExtension->FunctionDescriptor = AllocateItem(NonPagedPool, sizeof(USBC_FUNCTION_DESCRIPTOR) * DescriptorCount);
+    if (!FDODeviceExtension->FunctionDescriptor)
+    {
+        //
+        // no memory
+        //
+        DPRINT1("USBCCGP_EnumWithAssociationDescriptor failed to allocate function descriptor count %x\n", DescriptorCount);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    for (Index = 0; Index < DescriptorCount; Index++)
+    {
+        //
+        // init function descriptors
+        //
+        Status = USBCCGP_InitFunctionDescriptor(FDODeviceExtension, Index, &FDODeviceExtension->FunctionDescriptor[Index]);
+        if (!NT_SUCCESS(Status))
+        {
+            //
+            // failed
+            //
+            return Status;
+        }
+    }
+
+    //
+    // store function descriptor count
+    //
+    FDODeviceExtension->FunctionDescriptorCount = DescriptorCount;
+
+    //
+    // done
+    //
+    return Status;
+}
+
+NTSTATUS
+USBCCG_InitIdsWithInterfaceDescriptor(
+    IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
+    IN PUSB_INTERFACE_DESCRIPTOR Descriptor,
+    IN ULONG FunctionIndex,
+    OUT PUSBC_FUNCTION_DESCRIPTOR FunctionDescriptor)
+{
+    ULONG Index;
+    WCHAR Buffer[200];
+    LPWSTR DescriptionBuffer;
+    NTSTATUS Status;
+
+    //
+    // now init interface description
+    //
+    if (Descriptor->iInterface)
+    {
+        //
+        // get interface description
+        //
+         Status = USBCCGP_GetStringDescriptor(FDODeviceExtension->NextDeviceObject,
+                                              100 * sizeof(WCHAR),
+                                              Descriptor->iInterface,
+                                              0x0409, //FIXME
+                                              (PVOID*)&DescriptionBuffer);
+        if (!NT_SUCCESS(Status))
+        {
+            //
+            // no description
+            //
+            RtlInitUnicodeString(&FunctionDescriptor->FunctionDescription, L"");
+        }
+        else
+        {
+            //
+            // init description
+            //
+            RtlInitUnicodeString(&FunctionDescriptor->FunctionDescription, DescriptionBuffer);
+        }
+        DPRINT1("FunctionDescription %wZ\n", &FunctionDescriptor->FunctionDescription);
+    }
+
+
+    //
+    // now init hardware id
+    //
+    Index = swprintf(Buffer, L"USB\\VID_%04x&PID_%04x&Rev_%04x&MI_%02x", FDODeviceExtension->DeviceDescriptor->idVendor,
+                                                                         FDODeviceExtension->DeviceDescriptor->idProduct,
+                                                                         FDODeviceExtension->DeviceDescriptor->bcdDevice,
+                                                                         FunctionIndex) + 1;
+    Index += swprintf(&Buffer[Index], L"USB\\VID_%04x&PID_%04x&MI_%02x", FDODeviceExtension->DeviceDescriptor->idVendor,
+                                                                         FDODeviceExtension->DeviceDescriptor->idProduct,
+                                                                         FunctionIndex) + 1;
+
+    // allocate result buffer
+    DescriptionBuffer = AllocateItem(NonPagedPool, (Index + 1) * sizeof(WCHAR));
+    if (!DescriptionBuffer)
+    {
+        //
+        // failed to allocate memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    // copy description
+    RtlCopyMemory(DescriptionBuffer, Buffer, (Index + 1) * sizeof(WCHAR));
+    FunctionDescriptor->HardwareId.Buffer = DescriptionBuffer;
+    FunctionDescriptor->HardwareId.Length = Index * sizeof(WCHAR);
+    FunctionDescriptor->HardwareId.MaximumLength = (Index + 1) * sizeof(WCHAR);
+
+    //
+    // now init the compatible id
+    //
+    Index = swprintf(Buffer, L"USB\\Class_%02x&SubClass_%02x&Prot_%02x", Descriptor->bInterfaceClass, Descriptor->bInterfaceSubClass, Descriptor->bInterfaceProtocol) + 1;
+    Index += swprintf(&Buffer[Index], L"USB\\Class_%02x&SubClass_%02x",  Descriptor->bInterfaceClass, Descriptor->bInterfaceSubClass) + 1;
+    Index += swprintf(&Buffer[Index], L"USB\\Class_%02x", Descriptor->bInterfaceClass) + 1;
+
+    // allocate result buffer
+    DescriptionBuffer = AllocateItem(NonPagedPool, (Index + 1) * sizeof(WCHAR));
+    if (!DescriptionBuffer)
+    {
+        //
+        // failed to allocate memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    // copy description
+    RtlCopyMemory(DescriptionBuffer, Buffer, (Index + 1) * sizeof(WCHAR));
+    FunctionDescriptor->CompatibleId.Buffer = DescriptionBuffer;
+    FunctionDescriptor->CompatibleId.Length = Index * sizeof(WCHAR);
+    FunctionDescriptor->CompatibleId.MaximumLength = (Index + 1) * sizeof(WCHAR);
+
+    //
+    // done
+    //
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+USBCCGP_LegacyEnum(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    ULONG Index;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+    //
+    // get device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // sanity check
+    //
+    ASSERT(FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces);
+
+    //
+    // allocate function array
+    //
+    FDODeviceExtension->FunctionDescriptor = AllocateItem(NonPagedPool, sizeof(USBC_FUNCTION_DESCRIPTOR) * FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces);
+    if (!FDODeviceExtension->FunctionDescriptor)
+    {
+        //
+        // no memory
+        //
+        DPRINT1("USBCCGP_EnumWithAssociationDescriptor failed to allocate function descriptor %lu\n", FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // init function descriptors
+    //
+    FDODeviceExtension->FunctionDescriptorCount = 0;
+    for (Index = 0; Index < FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces; Index++)
+    {
+        // get interface descriptor
+        InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(FDODeviceExtension->ConfigurationDescriptor, FDODeviceExtension->ConfigurationDescriptor, Index, 0, -1, -1, -1);
+        if (InterfaceDescriptor == NULL)
+        {
+            //
+            // failed to find interface descriptor
+            //
+            DPRINT1("[USBCCGP] Failed to find interface descriptor index %lu\n", Index);
+            ASSERT(FALSE);
+            return STATUS_UNSUCCESSFUL;
+        }
+
+        //
+        // init function descriptor
+        //
+        FDODeviceExtension->FunctionDescriptor[Index].FunctionNumber = Index;
+        FDODeviceExtension->FunctionDescriptor[Index].NumberOfInterfaces = 1;
+        FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * 1);
+        if (!FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList)
+        {
+            //
+            // no memory
+            //
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        //
+        // store interface descriptor
+        //
+        FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList[0] = InterfaceDescriptor;
+
+        //
+        // now init the device ids
+        //
+        Status = USBCCG_InitIdsWithInterfaceDescriptor(FDODeviceExtension, InterfaceDescriptor, Index, &FDODeviceExtension->FunctionDescriptor[Index]);
+        if (!NT_SUCCESS(Status))
+        {
+            //
+            // failed to init ids
+            //
+            DPRINT1("[USBCCGP] Failed to init ids with %lx\n", Status);
+            return Status;
+        }
+
+        //
+        // store function count
+        //
+        FDODeviceExtension->FunctionDescriptorCount++;
+    }
+
+    //
+    // done
+    //
+    return Status;
+}
+
+NTSTATUS
+USBCCGP_EnumWithUnionFunctionDescriptors(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+USBCCGP_EnumWithAudioLegacy(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    ULONG Index;
+    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor, FirstDescriptor = NULL;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    //
+    // get device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+
+    //
+    // first check if all interfaces belong to the same audio class
+    //
+    for (Index = 0; Index < FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces; Index++)
+    {
+        //
+        // get interface descriptor
+        //
+        InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(FDODeviceExtension->ConfigurationDescriptor, FDODeviceExtension->ConfigurationDescriptor, Index, 0, -1, -1, -1);
+        DPRINT1("Index %lu Descriptor %p\n", Index, InterfaceDescriptor);
+        ASSERT(InterfaceDescriptor);
+
+        if (InterfaceDescriptor->bInterfaceClass != 0x1)
+        {
+            //
+            // collection contains non audio class
+            //
+            return STATUS_UNSUCCESSFUL;
+        }
+
+        if (FirstDescriptor == NULL)
+        {
+            //
+            // store interface descriptor
+            //
+            FirstDescriptor = InterfaceDescriptor;
+            continue;
+        }
+
+        if (FirstDescriptor->bInterfaceSubClass == InterfaceDescriptor->bInterfaceSubClass)
+        {
+            //
+            // interface subclass must be different from the first interface
+            //
+            return STATUS_UNSUCCESSFUL;
+        }
+    }
+
+    //
+    // this is an composite audio device
+    //
+    DPRINT("[USBCCGP] Audio Composite Device detected\n");
+
+    //
+    // audio interfaces are all grouped into one single function
+    //
+    FDODeviceExtension->FunctionDescriptor = AllocateItem(NonPagedPool, sizeof(USBC_FUNCTION_DESCRIPTOR));
+    if (!FDODeviceExtension->FunctionDescriptor)
+    {
+        //
+        // no memory
+        //
+        DPRINT1("USBCCGP_EnumWithAssociationDescriptor failed to allocate function descriptor count\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // init function number
+    //
+    FDODeviceExtension->FunctionDescriptor[0].FunctionNumber = 0;
+
+    //
+    // store interfaces
+    //
+    Status = AllocateInterfaceDescriptorsArray(FDODeviceExtension->ConfigurationDescriptor, &FDODeviceExtension->FunctionDescriptor[0].InterfaceDescriptorList);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to allocate descriptor array
+        //
+        DPRINT1("[USBCCGP] Failed to allocate descriptor array %lx\n", Status);
+        return Status;
+    }
+
+    //
+    // now init the device ids
+    //
+    Status = USBCCG_InitIdsWithInterfaceDescriptor(FDODeviceExtension, FirstDescriptor, 0, &FDODeviceExtension->FunctionDescriptor[0]);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to init ids
+        //
+        DPRINT1("[USBCCGP] Failed to init ids with %lx\n", Status);
+        return Status;
+    }
+
+    //
+    // number of interfaces
+    //
+    FDODeviceExtension->FunctionDescriptor[0].NumberOfInterfaces = FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces;
+
+    //
+    // store function count
+    //
+    FDODeviceExtension->FunctionDescriptorCount = 1;
+
+    //
+    // done
+    //
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+USBCCGP_EnumerateFunctions(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    NTSTATUS Status;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+
+    //
+    // get device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // first try with filter driver
+    //
+    Status = USBCCGP_CustomEnumWithInterface(DeviceObject);
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // succeeded
+        //
+        return Status;
+    }
+
+    //
+    // enumerate functions with interface association descriptor
+    //
+    Status = USBCCGP_EnumWithAssociationDescriptor(DeviceObject);
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // succeeded
+        //
+        return Status;
+    }
+
+#if 0
+    //
+    // try with union function descriptors
+    //
+    Status = USBCCGP_EnumWithUnionFunctionDescriptors(DeviceObject);
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // succeeded
+        //
+        return Status;
+    }
+#endif
+
+    //
+    // try with legacy audio methods
+    //
+    Status = USBCCGP_EnumWithAudioLegacy(DeviceObject);
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // succeeded
+        //
+        return Status;
+    }
+
+    //
+    // try with legacy enumeration
+    //
+    return USBCCGP_LegacyEnum(DeviceObject);
+}