USBCCGP 获取USB设备描述符

USB设备的描述符是通过函数USBCCGP_GetDescriptors来获取的。
descriptor.c

    /* Get descriptors */
    Status = USBCCGP_GetDescriptors(DeviceObject);
    if (!NT_SUCCESS(Status))
    {
        /* Failed to start lower device */
        DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status);
        return Status;
    }

USB描述符主要是获取设备描述符配置描述符
两种设备描述符分别存储于FDO扩展结构体的DeviceDescriptor和ConfigurationDescriptor指向的内存中。

typedef struct
{
...
    PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;                 // usb device descriptor
    PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;   // usb configuration descriptor
    ...
    }FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;

获取设备描述符

设备描述符是标准的数据结构,且数据大小已知,可一次性获取。数据结构定义如下:

//
// USB 1.1: 9.6.1 Device, Table 9-7. Standard Device Descriptor
// USB 2.0: 9.6.1 Device, Table 9-8. Standard Device Descriptor
// USB 3.0: 9.6.1 Device, Table 9-8. Standard Device Descriptor
//
typedef struct _USB_DEVICE_DESCRIPTOR {
    UCHAR   bLength;
    UCHAR   bDescriptorType;
    USHORT  bcdUSB;
    UCHAR   bDeviceClass;
    UCHAR   bDeviceSubClass;
    UCHAR   bDeviceProtocol;
    UCHAR   bMaxPacketSize0;
    USHORT  idVendor;
    USHORT  idProduct;
    USHORT  bcdDevice;
    UCHAR   iManufacturer;
    UCHAR   iProduct;
    UCHAR   iSerialNumber;
    UCHAR   bNumConfigurations;
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;

描述符的获取通过一个通用函数USBCCGP_GetDescriptors来实现,而获取设备描述符的代码如下:

     Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_DEVICE_DESCRIPTOR_TYPE, sizeof(USB_DEVICE_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->DeviceDescriptor);
     if (!NT_SUCCESS(Status))
     {
         //
         // failed to get device descriptor
         //
         DeviceExtension->DeviceDescriptor = NULL;
         return Status;
     }

可以看到,获取设备描述符需要提定数据类型:

#define USB_DEVICE_DESCRIPTOR_TYPE                          0x01

获取配置描述符

配置描述符里面不光有配置描述符,还包括可能多个接口描述符端点描述符,在UVC设备中,甚至还包括接口关联描述符等其它接口描述符
配置描述符的总大小因硬件设备的不同而不同,但在配置描述符的头有一个成员指定了配置描述符的总大小。所在在获取配配描述符就需要通过二次来获取,第一次只获取配置描述符的基本大小,从基本数据结构中解析出总大小后,再次获取全部的描述符。

  //
    // 2.0 now get basic configuration descriptor
    //
    Status = BulkUsbGetDescriptor(DeviceExtension->TopOfStackDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, sizeof(USB_CONFIGURATION_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
    if (!NT_SUCCESS(Status))
    {
        ExFreePool(DeviceExtension->DeviceDescriptor);
        DeviceExtension->DeviceDescriptor = NULL;
        return Status;
    }

    DescriptorLength = DeviceExtension->ConfigurationDescriptor->wTotalLength;

    //
    // release basic descriptor
    //
    ExFreePool(DeviceExtension->ConfigurationDescriptor);
    DeviceExtension->ConfigurationDescriptor = NULL;

    //
    // 2.1 allocate full descriptor
    //
    Status = BulkUsbGetDescriptor(DeviceExtension->TopOfStackDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, DescriptorLength, 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
    if (!NT_SUCCESS(Status))
    {
        ExFreePool(DeviceExtension->DeviceDescriptor);
        DeviceExtension->DeviceDescriptor = NULL;
        return Status;
    }

BulkUsbGetDescriptor的实现

从BulkUsbGetDescriptor的实现可以看出,其还是按照USB的规范,创建URB,然后再下发到PDO中,由PDO实现数据的组织返回。

NTSTATUS BulkUsbGetDescriptor(
    IN PDEVICE_OBJECT DeviceObject,
    IN UCHAR DescriptorType,
    IN ULONG DescriptorLength,
    IN UCHAR DescriptorIndex,
    IN LANGID LanguageId,
    OUT PVOID* OutDescriptor)
{
    PURB Urb;
    NTSTATUS Status;
    PVOID Descriptor;

    ASSERT(DeviceObject);
    ASSERT(OutDescriptor);
    ASSERT(DescriptorLength);

    Descriptor = ExAllocatePool(NonPagedPool, DescriptorLength);
    if (!Descriptor)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    Urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(URB));
    if (!Urb)
    {
        ExFreePool(Descriptor);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    UsbBuildGetDescriptorRequest(Urb,
        sizeof(Urb->UrbControlDescriptorRequest),
        DescriptorType,
        DescriptorIndex,
        LanguageId,
        Descriptor,
        NULL,
        DescriptorLength,
        NULL);

   // Status = CallUSBD(DeviceObject, Urb);
    Status = USBCCGP_SyncUrbRequest(DeviceObject, Urb);
    ExFreePool(Urb);
    if (NT_SUCCESS(Status))
    {
        *OutDescriptor = Descriptor;
    }

    return Status;
}

IPR和URB的关系

IRP是WINDOWS定义的设备之间通讯的请求包,而IO_STACK_LOCATION是各层设备之间的数据栈,而URB一般用于上下层设备之间的传输,故在WINDOWS中,其作为IO_STACK_LOCATION的一个指针存在。
这点在USBCCGP_SyncUrbRequest可以得到很明显的体现。


NTSTATUS
USBCCGP_SyncUrbRequest(
    IN PDEVICE_OBJECT DeviceObject,
    OUT PURB UrbRequest)
{
    PIRP Irp;
    PIO_STACK_LOCATION IoStack;
    KEVENT Event;
    NTSTATUS Status;

    /* Allocate irp */
    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
    if (!Irp)
    {
        /* No memory */
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    /* Initialize event */
    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    /* Get next stack location */
    IoStack = IoGetNextIrpStackLocation(Irp);

    /* Initialize stack location */
    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
    IoStack->Parameters.Others.Argument1 = (PVOID)UrbRequest;
    IoStack->Parameters.DeviceIoControl.InputBufferLength = UrbRequest->UrbHeader.Length;
    Irp->IoStatus.Status = STATUS_SUCCESS;

    /* Setup completion routine */
    IoSetCompletionRoutine(Irp,
                           USBSTOR_SyncForwardIrpCompletionRoutine,
                           &Event,
                           TRUE,
                           TRUE,
                           TRUE);

    /* Call driver */
    Status = IoCallDriver(DeviceObject, Irp);

    /* Check if request is pending */
    if (Status == STATUS_PENDING)
    {
        /* Wait for completion */
        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);

        /* Update status */
        Status = Irp->IoStatus.Status;
    }

    /* Free irp */
    IoFreeIrp(Irp);

    /* Done */
    return Status;
}

而函数数据返回的成功,也是通过完成函数来实现的,这点和上一节中USBCCGP_SyncForwardIrp的实现大同小异,请大家注意类比,只是这里多了一个创建URB,并设备URB指针的过程。

取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

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

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