USBCCGP 关联接口功能设备枚举

从上节可知,所有的功能设备都存储在FDO_DEVICE_EXTENSION中的FunctionDescriptor中的,而FunctionDescriptorCount成员记录着子功能数量。

typedef struct _USBC_FUNCTION_DESCRIPTOR{
    // The 0-based index of the function described
    UCHAR FunctionNumber;

    // The number of interfaces contained in this function
    UCHAR NumberOfInterfaces;

    // A callee allocated array of pointers into the config desc buffer passed as an input
    PUSB_INTERFACE_DESCRIPTOR *InterfaceDescriptorList;

    // Callee allocated PNP IDs for this PDO
    UNICODE_STRING HardwareId;
    UNICODE_STRING CompatibleId;
    UNICODE_STRING FunctionDescription;

    // Custom Flags
    ULONG FunctionFlags;
    PVOID Reserved;
} USBC_FUNCTION_DESCRIPTOR, *PUSBC_FUNCTION_DESCRIPTOR;

关联接口功能设备的枚举是通过USBCCGP_EnumWithAssociationDescriptor实现的。
function.c


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;
}

1.首选获取关联描述符的数量

有几个关联描述符就应该有几个功能设备,这个是通过接口描述符类型来判断的。

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;
}

2.根据关联调备的描述符数量分配USBC_FUNCTION_DESCRIPTOR内存空间

3.使用函数USBCCGP_InitFunctionDescriptor找到各个对应的关联描述符,并分析相关信息,实现各个子功能设备USBC_FUNCTION_DESCRIPTOR结构体数据信息的填充。


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;
}

3.1.在各个关联调备中可能有多个接口描述符,如UVC中就会有VC和VC,所以对于各个关联接口描述符中,需要初始化FUNCTION_DESCRIPTOR中的 PUSB_INTERFACE_DESCRIPTOR *InterfaceDescriptorList;成员。并使用函数USBCCGP_InitInterfaceListOfFunctionDescriptor来初始化。


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;
}

在上面的USBCCGP_GetAssociationDescriptorAtIndex函数中,获取的接口描述符并非是关联描述符的指针,而是其下一个接口描述符的指针。

3.2最后,如果功能调备有设置字符描述符,通过函数USBCCGP_GetStringDescriptor获取它。


NTSTATUS
NTAPI
USBCCGP_GetStringDescriptor(
    IN PDEVICE_OBJECT DeviceObject,
    IN ULONG DescriptorLength,
    IN UCHAR DescriptorIndex,
    IN LANGID LanguageId,
    OUT PVOID *OutDescriptor)
{
    NTSTATUS Status;
    PUSB_STRING_DESCRIPTOR StringDescriptor;
    ULONG Size;
    PVOID Buffer;

    // retrieve descriptor
    Status = USBCCGP_GetDescriptor(DeviceObject, USB_STRING_DESCRIPTOR_TYPE, DescriptorLength, DescriptorIndex, LanguageId, OutDescriptor);
    if (!NT_SUCCESS(Status))
    {
        // failed
        return Status;
    }

    // get descriptor structure
    StringDescriptor = (PUSB_STRING_DESCRIPTOR)*OutDescriptor;

    // sanity check
    ASSERT(StringDescriptor->bLength < DescriptorLength - 2);

    if (StringDescriptor->bLength == 2)
    {
        // invalid descriptor
        FreeItem(StringDescriptor);
        return STATUS_DEVICE_DATA_ERROR;
    }

    // calculate size
    Size = StringDescriptor->bLength + sizeof(WCHAR);

    // allocate buffer
    Buffer = AllocateItem(NonPagedPool, Size);
    if (!Buffer)
    {
        // no memory
        FreeItem(StringDescriptor);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    // copy result
    RtlCopyMemory(Buffer, StringDescriptor->bString, Size - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString));

    // free buffer
    FreeItem(StringDescriptor);

    // store result
    *OutDescriptor = (PVOID)Buffer;
    return STATUS_SUCCESS;
}
  • USB基础
  • USB摄像头UVC
  • USB人机交互HID
  • USB音频UAC
  • Windows基础
  • 磁盘与文件系统
  • Windows编程
  • Windows驱动
  • 开发模块
  • Windows运维
  • Linux相关
  • C语言学习
  • 高级语言
  • 前端开发
  • 服务器开发
  • 数据库
  • 字节流笔记
  • 字节流
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

    打开支付宝扫一扫,即可进行扫码打赏哦

    Powered by bytekits.com,汇天下文字,成非凡梦想!!!