USBD ROM Stack
2.0
ROM based USB device stack
|
A USB device provides information about itself in data structures called USB descriptors. This section provides information about various descriptors that a USB device should provide to host during enumeration process.
The host obtains descriptors from an attached device by sending various standard control requests (GET_DESCRIPTOR requests) to the default endpoint. Those requests specify the type of descriptor to retrieve. In response to such requests, the device sends descriptors that include information about the device, its configurations, interfaces and the related endpoints. Device descriptors contain information about the whole device. Configuration descriptors contain information about each device configuration. String descriptors contain Unicode text strings. The USB ROM stack handles all these standard requests eliminating the complexity from user application, as long as the user application provides the proper descriptor arrays to stack initialization routine.
Every USB device exposes a device descriptor that indicates the device's class information, vendor and product identifiers, and number of configurations. Each configuration exposes its configuration descriptor that indicates number of interfaces and power characteristics. Each interface exposes an interface descriptor for each of its alternate settings that contain information about the class and the number of endpoints. Each endpoint within each interface exposes endpoint descriptors that indicate the endpoint type and the maximum packet size. User application should provide these descriptors to the ROM stack for proper handling of standard requests.
The device descriptor contains information about a USB device as a whole. The pointer to the memory containing device descriptor should be provided by application through device_desc field of USB_CORE_DESCS_T structure, whose address is passed to stack initialization routine usbapi->hw->init(). The user application can create an instance of _USB_DEVICE_DESCRIPTOR structure in global scope (defined in memory accessible by USB bus master) and pass the address of the instance in device_desc field. Or the application can define the descriptor as character array as shown below:
The device_qualifier descriptor describes information about a high-speed capable device that would change if the device were operating at the other speed (see _USB_DEVICE_QUALIFIER_DESCRIPTOR structure). For example, if the device is currently operating at full-speed, the device_qualifier returns information about how it would operate at high-speed and vice-versa. The pointer to the memory containing device qualifier descriptor should be provided by application through device_qualifier field of USB_CORE_DESCS_T structure, whose address is passed to stack initialization routine usbapi->hw->init().
A USB device exposes its capabilities in the form of a series of interfaces called a USB configuration. A USB configuration is described in a configuration descriptor (see _USB_CONFIGURATION_DESCRIPTOR structure). A configuration descriptor contains information about the configuration and its interfaces, alternate settings, and their endpoints. Each interface descriptor or alternate setting is described in a _USB_INTERFACE_DESCRIPTOR structure. In a configuration, each interface descriptor is followed in memory by all of the endpoint descriptors for the interface and alternate setting. Each endpoint descriptor is stored in a _USB_ENDPOINT_DESCRIPTOR structure.
The ROM stack assumes that all the descriptors associated with the configuration are arranged as a consecutive byte array in memory. The address to this array is passed to the stack through full_speed_desc and high_speed_desc field of USB_CORE_DESCS_T structure, whose address is passed to usbapi->hw->init() routine. The following diagram illustrates how configuration information should be laid out in memory.
The following example shows the configuration descriptor for the USB Mass storage class device:
The other_speed_configuration describes a configuration of a high-speed capable device if it were operating at its other possible speed. The structure _USB_OTHER_SPEED_CONFIGURATION is identical to a configuration descriptor. Except the bDescriptorType field which is set to 0x07. To optimize application data memory usage the ROM stack reuses the meory pointed by full_speed_desc and high_speed_desc fields when reporting other speed configuration descriptor.
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, the host sends Get BOS Descriptor request to the device. The device should prepare for a BOS descriptor once LPM is enabled.
The BOS descriptor contains:
For a USB device, which reports a bcdUSB value greater than 0x0200 in their device descriptor, the host sends Get BOS Descriptor request to the device. The device should report both BOS descriptor and Device Capability Descriptor(s) information back to the host.
The Device Capability descriptor contains:
Device, configuration, and interface descriptors may contain references to string descriptors. String descriptors are referenced by their one-based index number. A string descriptor contains one or more Unicode strings; each string is a translation of the others into another language.
A string descriptor contains:
String index zero for all languages should return a string descriptor that contains an array of two-byte LANGID codes supported by the device. Current implementation of ROM stack assumes single language support. For applications using US English strings this descriptor should be:
The ROM stack assumes that all USB strings referenced in various descriptors are provided to stack as a single character array containing multiple string descriptors. ROM stack traverses to the next descriptor in array by adding the value of bLength field to current index. Hence it is important to construct this descriptor array properly with bLength fields reflecting the exact size of its string descriptor.