Authored by Martin Borve [MSFT]

In 2009 we posted a detailed description of how Windows 7 enumerates a USB device. In Windows 8, we’ve made modifications in the USB driver stack on how the stack enumerates USB 2.1, 2.0, and 1.1 devices. Those modifications support new USB features and improve device enumeration performance. The purpose of this article is to bring awareness to these subtle changes and enable device/firmware builders to easily determine the root cause of enumeration failures.

Reduced Timing Delays

Before Windows 8, the timing for delays were approximately 15-30 milliseconds longer than delays required by the official USB 2.0 specification. Cumulatively, those delays added several 100 milliseconds to the device enumeration time. In Windows 8, we’ve reduced the timing delays to 0-15 milliseconds resulting in faster enumeration.

Elimination of Second-Port Reset for High-Speed Devices

Before Windows 8, the USB driver stack reset the device’s upstream port twice. That behavior was to support legacy USB devices that were confused by the second request for the Device Descriptor. To allow those devices to enumerate successfully, the driver stack had to reset the upstream port between the first and second requests for the Device Descriptor. This second reset was expensive in terms of enumeration time.

Because that second reset was required just to support legacy low and full-speed devices, we’ve removed it for high-speed devices in Windows 8. Just in case the first attempt to enumerate a high-speed device fails, the driver stack reverts to resetting the port twice when it retries enumeration for the device.

BOS Descriptor Query and Validation

The USB 3.0 and USB 2.0 LPM specifications define a new USB descriptor called the Binary Device Object Store (BOS). The BOS descriptor returns a set of device-level capability descriptors for the USB device. For a USB device, which reports a bcdUSB value greater than 0x0200 in their device descriptor, in Windows 8, the USB driver stack requests for the BOS descriptor header immediately after the Language ID query request. If that request fails, the driver stack proceeds to the Product ID String query request.

If the request for the BOS descriptor header succeeds, the driver stack requests the entire BOS descriptor set by using the value returned in the BOS descriptor’s wTotalLength field as the request length. If that request fails, the driver stack will fail enumeration of the device.

Note: To make sure your device enumerates on Windows 8 and future versions of Windows, do not rely on the sequence in which the USB driver stack queries for the BOS descriptor. Instead, make sure that the device reports correct values to pass validation checks as described in these sections.

BOS Descriptor Validation

The USB driver stack validates the retrieved BOS descriptor. Make sure that in your device:

  • The number of bytes greater than or equal to the size of the BOS descriptor.
  • bDescriptorType indicates the BOS Descriptor type (0x0F).
  • bLength is the correct size of the BOS descriptor.
  • wTotalLength is greater than or equal to the size of the BOS descriptor.
  • wTotalLength is large enough to contain the number of capability descriptors reported in bNumDeviceCaps. The device computes the value by assuming a minimal 2-byte capability descriptor containing bLength and bDescriptorType fields, multiplied by the bNumDeviceCaps value, and added to the size of the BOS descriptor.
  • bNumDeviceCaps is not zero.

If any of those validation checks fail, the driver stack will fail enumeration of the device. Otherwise the stack validates each Device Capability Descriptor.

Device Capability Descriptors Validation

Generic Device Capability Descriptor Validation

For each device capability descriptor returned within the BOS descriptor set, the USB driver stack validates these conditions:

  • There is enough space left in the descriptor set for a capability descriptor.
  • The capability descriptor’s bLength value does not overrun the end of the descriptor set.
  • The capability descriptor’s bLength value is non-zero.

If any of those validations fail, the driver stack discards the BOS descriptor and proceeds to the Product ID String query.

Validation of USB 2.0 Extension Capability Descriptor

The driver stack validates the USB 2.0 Extension Capability Descriptor. If your device has that descriptor, make sure that:

  • bLength is set to the size of the USB 2.0 Extension Descriptor.
  • The reserved bits of the bmAttributes field are zero.

If any of those validation checks fail, the driver stack discards the BOS descriptor and proceeds to the Product ID String query.

Validation of SuperSpeed USB Device Capability Descriptor

The driver stack validates the USB 2.0 Extension Capability Descriptor. If your device has that descriptor, make sure that:

  • bLength is set to the size of the SuperSpeed USB Device Capability Descriptor.
  • The reserved bits of the bmAttributes field are zero.
  • The wSpeedsSupported field is non-zero.
  • wU2DevExitLat is less than 0x0800.

If any of those validations fail, the driver stack discards the BOS descriptor and proceeds to the Product ID String query.

Validation of Container ID Descriptor

The USB driver stack validates the Container ID Descriptor. If your device has that descriptor, make sure that:

  • bLength is set to the size of the Container ID Capability Descriptor.
  • bReserved field is zero.

If any of those validations fail, the driver stack discards the BOS descriptor and proceeds to the Product ID String query.

Other Capability Descriptors

The USB driver stack performs generic validation checks on any other capability descriptors found. Beyond that they are ignored.