http://blogs.msdn.com/b/usbcoreblog/archive/2010/09/11/9915562.aspx
Device enumeration for a USB port begins when the hub indicate a connect status change via the hub’s interrupt endpoint. If the port status indicates a newly connected device, the USB hub driver will use the following sequences of steps to enumerate the device:
Let us find out in detail how the software stack interacts with the device in each of these steps by describing which hardware events are handled, which ones are ignored, how long the software waits for the next event to occur, when does the software attempt reenumeration, how many times it reattempts, what constitutes a broken device, what leads to enumeration failure, etc.
The steps 1 through 7 are required for the device to be enumerated and reported to the system. In the next blog post, I will summarize all the hardware issues during enumeration that can either cause the software stack to not report the device at all or report to the system as “Unknown Device” by providing “USB\VID_0000&PID_0000” as the Device ID.
NOTE: Enumeration information provided here applies to 1.1 and 2.0 devices. The sequence and timing of various operations may change for 2.1+ and 3.0+ devices.
Port Stabilization Debounce
The hub driver must observe a period of at least 100ms where there are no port connect changes (USB 2.0 spec, 7.1.7.3, TATTDB). If the port has not stabilized after 200ms, the hub driver will disable the port and cancel enumeration. No device will be reported to PnP.
First Port Reset
Once the port debounce has completed successfully, the hub driver will issue a reset request for the port. In normal operation this will result in the port status transitioning to a connected and enabled state, and the device itself will respond to the default USB address of 0.
Port resets of all USB devices are serialized via an “enumeration lock” on a per host controller basis, as only one USB device can be enabled with the default USB address 0 at a any one time. The hub driver will acquire the enumeration lock prior to issuing the first port reset request, and will release it when the device has been assigned a non-default USB address, or when enumeration has been cancelled. The hub driver uses a 5 second timeout for the port reset request in case it never completes.
While waiting for the first port reset to complete, the hub driver must be able to deal with the following events:
Device Disconnect
Enumeration is cancelled. No device is reported to PnP.
Overcurrent Change
Enumeration is normally cancelled in this case, unless the over-current is determined to be spurious. No device is reported to PnP.
Timeout of Port Reset
In the case of a timeout of the first reset request, the hub driver will attempt to retry enumeration up to 3 times by returning to the beginning of the “First Port Reset” state. A delay of 500ms occurs between each retry to allow the device to settle. If the port reset times out on the 3rd retry, enumeration will be cancelled and an “Unknown Device” will be reported to PnP.
If the port reset request completes successfully, the hub driver will proceed based on the current port state as follows:
Device Disconnected
Enumeration is cancelled. No device is reported to PnP.
Port Connected and Disabled
Port reset completion is ignored. Reset timeout will be allowed to run, and port reset will be retried as appropriate.
Port Connected and Suspended
Enumeration is cancelled. No device is reported to PnP.
Port Overcurrent
Port reset completion is ignored. Reset timeout will be allowed to run, and port reset will be retried as appropriate.
Port Enabled and Connected
This indicates a successful reset of the port. The hub driver delays at least 10ms to allow for reset recovery (USB 2.0 spec, 7.1.7.3, TRSTRCY). The hub driver moves to the “First Device Descriptor Request" state.
First Device Descriptor Request
The USB driver stack issues a request for the USB Device Descriptor (GET_DESCRIPTOR for Descriptor Type DEVICE), using the default USB address of 0, and a maximum packet size of 8 bytes for low-speed devices and 64 bytes for full and high-speed devices.
This descriptor request is used solely to determine the correct maximum packet size for the default control endpoint, as specified in the Device Descriptor’sbMaxPacketSize0 field at offset 7. USB devices are required to return at least the first 8 bytes of the Device Descriptor when they are at the default USB address (USB 2.0 spec, 5.5.3).
When requesting the device descriptor the hub driver will specify a transfer size of 64 bytes. This is done because some older USB devices will behave badly if the request size is smaller. We’ve also found some USB devices will babble when returning the device descriptor, but will still return valid data in at least the first 8 bytes. For this reason transfer errors will be ignored if at least 8 bytes of data were returned by the device.
If the request for the device descriptor fails, the hub driver will retry enumeration up to three times by returning to the “First Port Reset” state. If the hub driver has already retried enumeration 3 times, enumeration will be cancelled and an “Unknown Device” will be reported to PnP.
If the device descriptor request succeeds, the hub driver will move to the “Second Port Reset” step. All further control transfers for the default endpoint will use the maximum packet size specified in the Device Descriptor.
Second Port Reset
In the early days of USB some USB devices would become confused by a second request for the Device Descriptor if they did not return the complete Device Descriptor for the first request. To allow these devices to enumerate successfully it was necessary to reset the port between the first and second requests for the Device Descriptor.
The hub driver uses a 5 second timeout for the second port reset request in case it never completes. While waiting for the second port reset to complete, the hub driver must be able to deal with the following events (this is essentially identical to the handling in the first reset request):
Device Disconnect
Enumeration is cancelled. No device is reported to PnP.
Overcurrent Change
Enumeration is cancelled. No device is reported to PnP.
Timeout of Port Reset
In the case of a timeout of the second reset request, the hub driver will attempt to retry enumeration up to 3 times by returning to the beginning of the “First Port Reset” state. If the port reset times out on the 3rd retry, enumeration will be cancelled and an “Unknown Device” will be reported to PnP.
If the port reset request completes successfully, the hub driver will proceed based on the current port state as follows:
Device Disconnected
Enumeration is cancelled. No device is reported to PnP.
Port Connected and Disabled
Port reset completion is ignored. Reset timeout will be allowed to run, and port reset will be retried as appropriate.
Port Connected and Suspended
Enumeration is cancelled. No device is reported to PnP.
Port Overcurrent
Port reset completion is ignored. Reset timeout will be allowed to run, and port reset will be retried as appropriate.
Port Enabled and Connected
This indicates a successful reset of the port. The hub driver delays at least 10ms to allow for reset recovery (USB 2.0 spec, 7.1.7.3, TRSTRCY). The hub driver moves to the next enumeration state “Set USB Address". The hub driver will delay 100ms after successfully resetting the port if enumeration had to be retried at least once.
Set USB Address
The USB driver stack allocates a unique (per-controller) USB device address and issues a SET_ADDRESS request to the device. If the SET_ADDRESS request fails or times out, enumeration is cancelled and an “Unknown Device” is reported to PnP.
If the SET_ADDRESS is successful, the hub driver will wait for at least 10ms to allow for device stabilization before moving to the “Second Device Descriptor Request” state.
Second Device Descriptor Request
The USB driver stack will issue a second request for the full USB Device Descriptor (GET_DESCRIPTOR for Descriptor Type DEVICE). If the request fails or times out, the port is disabled and enumeration is retried by returning to the “First Port Reset” state. If the hub driver has already retried enumeration 3 times, enumeration is cancelled and an “Unknown Device” is reported to PnP.
Upon successful completion of the second request for the Device Descriptor, the hub driver will validate the Device Descriptor as follows:
If the validation fails, the port is disabled and enumeration is retried by returning to the “First Port Reset” state. If the hub driver has already retried enumeration 3 times, enumeration is cancelled and an “Unknown Device” is reported to PnP.
Upon successful validation of the Device Descriptor, the hub driver will cache the descriptor, release the enumeration lock, and move to the “Configuration Descriptor Request” state.
Configuration Descriptor Request
The USB driver stack will issue a request for the device’s USB Configuration Descriptor (GET_DESCRIPTOR for Descriptor Type CONFIGURATION). For compatibility reasons the configuration descriptor request will specify a length of 255 bytes.
If the Configuration Descriptor request completes with an error or times out, the hub driver will disable the port and retry enumeration by returning to the “First Port Reset” state. If the hub driver has already retried enumeration 3 times, enumeration is cancelled and an “Unknown Device” is reported to PnP.
If the Configuration Descriptor request completes successfully, the hub driver will verify that the number of bytes returned for the request is greater than or equal to the Configuration Descriptor’s wTotalLength value. If it is not greater than or equal to wTotalLength, the hub driver will retry the Configuration Descriptor request once to insure the device is not returning invalid data in the descriptor.
Upon successful completion of the Configuration Descriptor request, the USB driver stack will validate the descriptor as follows:
If the validation fails the hub driver will disable the port and retry enumeration by returning to the “First Port Reset” state. If the hub driver has already retried enumeration 3 times, enumeration is cancelled and an “Unknown Device” is reported to PnP.
If the validation is successful, the Configuration Descriptor is cached and the hub driver moves on to the “MS OS Descriptor Query” state.
MS OS Descriptor Query
Microsoft has defined a set of vendor specific USB descriptors called Microsoft OS Feature Descriptors, which are queried for at the time of device enumeration.
If the USB Device Descriptor’s bcdUSB field is equal to 0x0100 or 0x0110, the hub driver will skip the query for the MS OS Descriptor and move to the “Serial Number String Descriptor Query” state.
If the hub driver has never before enumerated a device with the same VID/PID/Revision as the device being enumerated, it will query the device for the MS OS String Descriptor (GET_DESCRIPTOR for Descriptor Type STRING), which uses index 0xEE. It will specify a language ID of 0x00.
If the device returns an MS OS Descriptor, the hub driver will validate the descriptor as follows:
Once validated, the value in the descriptor’s bVendorCode field will be stored in the registry on a per VID/PID/Revision basis, under the USBFLAGS registry subkey in the “osvc” registry value. Subsequent enumerations of any device with the same VID/PID/Revision will read the bVendorCode from this registry value rather than querying the device.
The hub driver will then move to the “Serial Number String Descriptor Query” state.
Serial Number String Descriptor Query
If the USB Device Descriptor reports a non-zero serial number string index, the hub driver will query for the serial number string descriptor (GET_DESCRIPTOR for Descriptor Type STRING) using the American English language ID (0x409) and the serial number string index.
The hub driver performs the following validation on all string descriptors:
If this validation passes, the hub driver performs the following validation specifically for the serial number string descriptor:
If any of the above validation fails the serial number will be discarded, otherwise it will be cached.
Regardless of the results of the serial number query and validation, the hub driver will move on to the “MS OS Extended Configuration Descriptor Request” state if the device supports the MS OS Descriptor, otherwise it will move to the “Language ID Query”.
MS OS Extended Configuration Descriptor Request
If the device is not a composite device the hub driver will issue a request for the MS OS Extended Configuration Descriptor.
Software will issue an initial request for this descriptor by specifying a data size equal to the descriptor’s header. This will be used to determine the existence of the descriptor, and to determine its size. If the request is successful the hub driver will validate the header as follows:
Once the descriptor header is validated, the hub driver will re-issue the request for the descriptor using the size of the entire descriptor as returned by the device in the descriptor’s header.
If a device successfully returns an MS OS Extended Configuration Descriptor, the hub driver will validate the descriptor as follows:
Software will move to the “MS OS Container ID Descriptor Query” state.
MS OS Container ID Descriptor Query
Windows 7 introduces the concept of a Container ID, which is used to group all functions that are part of a physical device. For details on how USB generates Container IDs, please refer to this whitepaper.
If the VID/PID/Revision of the device has been previously flagged as not supporting the Container ID Descriptor via the registry, the hub driver will move to the “Language ID Query” state.
If neither the hub descriptor nor the ACPI namespace describes the device as non-removable, and the device supports the MS OS Descriptor, the USB stack will query the device for the MS OS Container ID, otherwise the hub driver will move to the “Language ID Query” state.
A device must indicate support for the container ID by setting bit 1 of the bFlags flag of the MS OS Descriptor. If this bit is set, software will issue a request for the MS OS Container ID Descriptor header. The setup packet will specify a wIndex of 6, and the Device as the recipient. If a descriptor is successfully returned, the hub driver will validate the descriptor as follows:
If the header is successfully validated, software will issue a request for the entire MS OS Container ID Descriptor. The setup packet will again specify a wIndex of 6, and the Device as the recipient.
If the descriptor is successfully returned, the hub driver will validate the descriptor as follows:
If the request for the Container ID Descriptor fails for any reason, a registry value will be set to indicate the hub driver should skip this request in future enumerations of devices with the same VID/PID/Revision. The hub driver will then disable the port and retry enumeration by returning to the “First Port Reset” state. If the hub driver has already retried enumeration 3 times, enumeration is cancelled and an “Unknown Device” is reported to PnP.
Language ID Query
The USB hub driver will query the device for the array of supported language IDs. The hub driver will issue a query for the string descriptor at index 0, which is an array of 2-byte LANGID codes supported by the device, as defined in section 9.6.7 of the USB 2.0 specification.
The hub driver will perform standard string descriptor validation on the Language ID string descriptor, as described previously in the description of the “Serial Number String Descriptor Query” state. If the string is found to be valid, the hub driver will cache the data returned in the string. It will then move to the “Product ID String Query” state.
Product ID String Query
If the USB Device Descriptor’s iProduct field is non zero the hub driver will issue a request for the Product ID string using the string index specified in the iProduct field and the English language ID of 0x409.
If the string descriptor request completes successfully, the hub driver will perform standard string descriptor validation on the Product ID string descriptor. If the validation is successful, the hub driver will cache the string. It will then move to the “Device Qualifier Descriptor Query” state.
Device Qualifier Descriptor Query
If the device is attached to a USB 1.1 hub, is operating at Full-Speed, and its USB Device Descriptor bcdUSB field is greater than or equal to 0x200, the hub driver will issue a GET_DESCRIPTOR for descriptor type DEVICE_QUALIFIER (6).
The successful completion of the request indicates the device can support USB 2.0 high-speed operation.
Duplicate Device Detection
The USB driver stack must deal with an artifact of the EHCI companion controller design where a device can move quickly between the USB 2.0 EHCI host controller and a companion USB 1.1 controller when the USB 2.0 controller is enabled or disabled. This creates a scenario where the new instance of a USB device can be reported to the PnP Manager before its previous instance on the other host controller had been reported as removed to PnP Manager. This results in a bugcheck if the device has a serial number, as PnP Manager would see two device nodes reporting the same unique instance IDs. This behavior can also occur when a USB device is moved to a different port while the system is suspended.
The USB hub driver maintains a list of all USB devices currently attached to the system and have been reported to the PnP Manager. If the currently enumerating device has a serial number, software will search this list for any device that has the same vendor ID, product ID, revision number, and serial number. If no matching device is found, the hub driver will move to the “Report New Device To PnP Manager” state.
If a matching device is found the hub driver will handle it based the following logic:
Report New Device to PnP Manager
At this point the USB device has been successfully enumerated and the hub driver will report the new device to PnP. This involves calling IoInvalidateDeviceRelations and reporting then new device when handling IRP_MN_QUERY_DEVICE_RELATIONS/BusRelations.