USB device descriptors

The device descriptor contains information about a USB device as a whole. This article describes the USB_DEVICE_DESCRIPTOR structure and includes information about how a client driver can send a get-descriptor request to obtain the device descriptor.

Every Universal Serial Bus (USB) device must be able to provide a single device descriptor that contains relevant information about the device. The USB_DEVICE_DESCRIPTOR structure describes a device descriptor. Windows uses that information to derive various sets of information. For example, the idVendor and idProduct fields specify vendor and product identifiers, respectively. Windows uses those field values to construct a hardware ID for the device. To view the hardware ID of a particular device:

  1. Open Device Manager.
  2. Right-click on the USB device and select Properties.
  3. Select the Details tab in the properties dialog box.
  4. Drop down the Property list.
  5. Select the Hardware Ids property

The values indicate the hardware IDs ("USB\XXX") that Windows generates.

The bcdUSB field of the USB_DEVICE_DESCRIPTOR structure indicates the version of the USB specification to which the device conforms. For example, 0x0200 indicates that the device is designed as per the USB 2.0 specification. The bcdDevice value indicates the device-defined revision number.

The USB driver stack uses bcdDevice, along with idVendor and idProduct, to generate hardware and compatible IDs for the device. You can view those identifiers in Device Manager. The device descriptor also indicates the total number of configurations that the device supports.

A device might report different information in its device descriptor when the device connects to the host computer in a high speed capacity than when it connects in a full speed capacity. A device must not change the information contained in the device descriptor during the lifetime of a connection, including during power state changes.

The host obtains the device descriptor through a control transfer. In the transfer, the request type is GET DESCRIPTOR and the recipient is the device. The client driver can initiate that transfer in either of two ways: by using the framework USB target device object or by sending an URB with the request information.

Getting the device descriptor

A Windows Driver Frameworks (WDF) client driver can obtain the device descriptor only after the framework USB target device object is created.

A Kernel-Mode Driver Framework (KMDF) driver must obtain a WDFUSBDEVICE handle to the USB target device object by calling WdfUsbTargetDeviceCreate. Typically, a client driver calls WdfUsbTargetDeviceCreate in the driver's EvtDevicePrepareHardware callback implementation. After that, the client driver must call the WdfUsbTargetDeviceGetDeviceDescriptor method. After the call completes, the device descriptor is received in the caller-allocated USB_DEVICE_DESCRIPTOR structure.

A User-Mode Driver Framework (UMDF) driver must query the framework device object for an IWDFUsbTargetDevice pointer and then call the IWDFUsbTargetDevice::RetrieveDescriptor method and specify USB_DEVICE_DESCRIPTOR_TYPE as the descriptor type.

The host can also obtain the device descriptor by sending an URB. This method only applies to kernel-mode drivers. However, a client driver should never have to send an URB for this type of request unless the driver is based on Windows Driver Model (WDM). Such a driver must allocate an URB structure and then call the UsbBuildGetDescriptorRequest macro to specify format the URB for the request. The driver can then send the request by submitting the URB to the USB driver stack. For more information, see How to Submit an URB.

This code example shows a UsbBuildGetDescriptorRequest call that formats the buffer pointed to by pURB with the appropriate URB:

UsbBuildGetDescriptorRequest(
    pURB,                                                 // Points to the URB to be formatted
    sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
    USB_DEVICE_DESCRIPTOR_TYPE,
    0,                                                    // Not used for device descriptors
    0,                                                    // Not used for device descriptors
    pDescriptor,                                          // Points to a USB_DEVICE_DESCRIPTOR structure
    NULL,
    sizeof(USB_DEVICE_DESCRIPTOR),
    NULL
);

Sample device descriptor

This example shows the device descriptor for a USB webcam device (see USB Device Layout), obtained by using the USBView application:

Device Descriptor:
bcdUSB:             0x0200
bDeviceClass:         0xEF
bDeviceSubClass:      0x02
bDeviceProtocol:      0x01
bMaxPacketSize0:      0x40 (64)
idVendor:           0x045E (Microsoft Corporation)
idProduct:          0x0728
bcdDevice:          0x0100
iManufacturer:        0x01
0x0409: "Microsoft"
iProduct:             0x02
0x0409: "Microsoft LifeCam VX-5000"
0x0409: "Microsoft LifeCam VX-5000"
iSerialNumber:        0x00
bNumConfigurations:   0x01

In the preceding example, the device was developed as per USB Specification, version 2.0. Note the bDeviceClass, bDeviceSubClass, and bDeviceProtocol values. Those values indicate that the device contains one or more USB interface association descriptors that can be used to group multiple interfaces per function. For more information, see USB Interface Association Descriptor.

Next, see the value of bMaxPacketSize0. This value indicates the maximum packet size of the default endpoint. This sample device can transfer up to 64 bytes of data through its default endpoint.

Typically, to configure the device, the client driver gets information about the supported configurations in the device after getting the device descriptor. To determine the number of configurations that the device supports, inspect the bNumConfigurations member of the returned structure. This device supports one configuration. To get information about a USB configuration, the driver must get USB Configuration Descriptors.