USB and USB Descriptors

USB stands for Universal Serial Bus, is a standard that deals with connecting computer peripherals with the host. These may include any device such a Human Interface Devices (HID), or printers, audio devices, mass storage devices, wireless controllers, USB hub, etc. Each device is associated with a device class that tells what type of device it is. The device class code is used to recognize what type of device it is. When these device class codes are communicated to the host, corresponding software driver modules are installed.

The advantage of USB lies in standardizing the connection as the drivers are being written by Operating System’s vendors and not the manufacturers of the device. This eliminates the scope of incompatibilities due to a manufacturer not supporting certain OSes(or actually supporting certain OS only).

The Connection

A typical USB connection takes place as follows:

  1. Device is connected.
  2. The device is detected by the hub.
  3. The hub informs the host that a new device has been connected to it.
  4. Hub determines whether the device is low speed(1.5Mbps) or full speed(12Mbps) compatible. The device is then reset.
  5. If it finds that the device is full speed, then it determines if the device is high speed compatible by sending special signals known as chirps and analyzing the responses.
  6. The hub establishes signal path.
  7. Host requests device descriptors.
  8. Host assigns an address.
  9. The host learns device capabilities from additional device descriptors.
  10. Host then loads the device drivers.
  11. Eventually, the device driver selects a configuration.

USB Descriptors

USB descriptors are used to describe various USB entities. To get more information from your system, you may try the lsusb command on terminal.

sudo lsusb --verbose -d 1b6d:0003

Execute the command as root, enabling verbose mode for a particular device by providing the vendor Id followed by the product Id. Each device can be uniquely identified by the Ids which can be themselves found out by typing simply lsusb on the terminal, which would list all the usb devices connected to the host.

For any descriptor, the first byte contains the length of the descriptor, and the second the type of descriptor. Other details then follow after these.

There are mainly 4 types of descriptors:

  • Device Descriptors
  • Configuration Descriptor
  • Interface Descriptor
  • Endpoint Descriptor

Device Descriptors

The length of device descriptors is 18 bytes. It’s descriptor type is 1(written as 0x01 in hexadecimal). It is the device descriptor which tells us about the class of the device. i.e. HID, mass storage, or whatever, and also it’s subclass, including the protocol used for talking to the device.

Device Descriptor contains information for identification of the device, like the vendor Id, product Id, and the device release number.

More importantly, the device descriptor also includes the number of configurations.

Configuration Descriptors

Corresponding to each configuration, there is a configuration descriptor. The length of the configuration descriptor varies for each configuration. The descriptor type is 0x02.

Configuration descriptors contain the configuration number and the configuration name, and the maximum power. They also contain the total length of the descriptor.

These descriptors also have some other attributes that tell whether it is self-powered, whether or not the device supports remote wakeup.

Eventually, it contains the number of interfaces. For each interface, there exists an interface descriptor.

Interface Descriptors

The interface descriptors contain the information on how to talk to the device. Interface descriptors are type 0x04 descriptors and have a length 9 of bytes.

Each interface descriptor contains the interface number and the interface name. It also includes the class, sub-class, and protocol for communication at interface level. The protocol thing may sound redundant but it is included at interface level for supporting composite devices.

Finally, each interface consists of number of endpoints, and for each endpoint, there is an endpoint descriptor.

Endpoint Descriptors

Each endpoint descriptor is 7 bytes in length. It is a type 0x05 descriptor. Endpoint descriptors tell us about the type of endpoint and the direction of communication. Here, we have a unidirectional communication channel. The direction is calculated with respect to the host. ‘1’ means into to the host and ‘0’ means outwards from the host. Endpoint descriptors have some other attributes like maximum packet size, interval for polling, etc.

Endpoint descriptors are of following types:

  • Control Endpoints are used to control the whole stuff, so they are sort of mandatory for all the devices.
  • Bulk Transport Endpoints are used by those devices that perform bulk transfer of data with the host.
  • Interrupt Endpoints are used when the USB device requires the attention of the host, so it does this by sending interrupts, but it is able to do so only when the host explicitly polls the device for the data.
  • Isochronous Endpoints are used to send periodic and continuous data. It is used for transmitting time sensitive information for example audio and video streams.

String Descriptors

String Descriptors are used to display the information of all of the above descriptors in human readable form. They are of varying length and are type 0x03 descriptors. They use Unicode strings for storage.

The above article is highly influenced by Philip Polstra’s course on Pluralsight, If you are interested on reading further, I highly recommend it.