USB Device Descriptors

There’s been a bit of confusion concerning the USB Device Descriptors, so I thought I’d do another informational post to clear things up a bit.

All USB devices contain descriptors. These descriptors describe the important aspects of the device to the host, and are read during enumeration so that the appropriate drivers can be loaded for each connected device. There are many types of descriptors, but for basic devices only a few are used; Device Descriptors, Configuration Descriptors, Interface Descriptors and Endpoint Descriptors.

Let’s consider a canned example, that of a USB still camera. Such a camera might have two different USB connection modes; Mass Storage (for drag-drop access like a USB flash disk) and Still Image (for use with supporting camera software). It might also allow the host to use the microphone on the camera, and use the camera element as a low resolution webcam.

We’ll now be designing the descriptors required for such a device, starting with the Device Descriptor.


Device Descriptor
The Device Descriptor is mandatory, and only one is allowed for each USB device. It contains important information about the device, including the manufacturer/product IDs (assigned via USB.org, and provide a unique combination which can identify a device and indicate driver compatibility), Class and Protocol values, total configurations and power requirements.

Some devices (e.g. most Mice and Keyboards) are pretty simple, and only provide one function. These sorts of devices can declare their overall function in the device descriptor’s Class/Protocol values – which should be sourced off the list of defined classes at USB.org – which the host can read. For more complex devices which do not belong to one clear class, these are set as 0x00, which indicates to the host that the classes should be sourced from the interface descriptors of the current configuration.

Descriptors So Far:

  • Device Descriptor


Configuration Descriptor
USB devices may have multiple configurations, although these are uncommonly used in practice. Each configuration descriptor completely defines a set of interfaces for the available functions. Configurations are mutually exclusive to one-another; the host may select any one of the configurations at any one time, but cannot use multiple configurations at once.

The Configuration Descriptor contains a set of Interface and Endpoint descriptors, in a flat structure. The actual layout of the configuration descriptor is hierarchical but when transmitted to the host it is sent as a flat datastream.

Our USB camera would have two configurations, one with the Video (camera), Audio (microphone) and Mass Storage features, and another containing Video (camera), Audio (microphone) and Still Image features. As the configurations are separate the common features between configurations need to be repeated inside each independent configuration descriptor.

Descriptors So Far:

  • Device Descriptor
  • Configuration Descriptor (0)
  • Configuration Descriptor (1)


Interface Descriptor
Each device function has one or more interface descriptors associated with it. For example, with our hypothetical USB camera, we would have one interface for the Mass Storage (or Still Image) feature, another for the Video (camera) feature and a third for the Audio (microphone). The interface descriptors indicate the interface’s class and protocol and number of associated endpoints. One other interesting feature of the Interface Descriptors is the Alternate Setting value; like the Configuration descriptor each interface can have multiple entries which can change the interface’s function depending on which one is selected.

Our USB camera will have an alternate setting interface for the audio class; even if a device’s features is not selected, bandwidth is still used by the host for checking the interface’s endpoints. Thus, for audio interfaces (which use up a lot of data), an alternate setting with no endpoints is added so that when the microphone is unused, the host can turn off the endpoint and save on USB bandwidth.

Each interface descriptor will have its Class and Protocol values filled out with the values defined at USB.org for the appropriate functions of each interface.

We’ll assume that the Mass Storage/Still Image class requires two endpoints, and the Video class uses a single endpoint for the purposes of this demonstration.

Descriptors So Far:

  • Device Descriptor
  • Configuration Descriptor (0)
    • Interface Descriptor (Mass Storage Class, Alternate Settings 0, Alternate Setting 0, 2 Endpoints)
    • Interface Descriptor (Video Class, Alternate Settings 0, Alternate Setting 0, 1 Endpoint)
    • Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 0, 1 Endpoint)
    • Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 1, 0 Endpoints)
  • Configuration Descriptor (1)
    • Interface Descriptor (Still Image Class, Alternate Settings 0, Alternate Setting 0, 2 Endpoints)
    • Interface Descriptor (Video Class, Alternate Settings 0, Alternate Setting 0, 1 Endpoint)
    • Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 0, 1 Endpoint)
    • Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 1, 0 Endpoints)


Endpoint Descriptor

Lastly for our simple device, we have the Endpoint Descriptor. Each interface will have 0 or more endpoints, each of which allow for the exchange of data between the device and the host. Each endpoint descriptor indicates the type of endpoint (BULK, CONTROL, INTERRUPT, ISOCHRONOUS), address and (for INTERRUPT endpoints) the polling interval between endpoint interrupts.

Each endpoint must be given a unique address. The value of each address is actually not important, except for the most significant bit, which when set indicates to the host that the endpoint is of the IN type, for sending data from the device into the host. Address 0 is reserved, and is used for the control endpoint that is present on all USB devices for host-device control requests. Endpoint 0 does not need an explicit Endpoint Descriptor — it is mandatory and thus does not need to be described.

We must place each endpoint after the interface to which it belongs. This is how interface-endpoint relationships are established; if an interface declares it has three endpoints, three Endpoint Descriptors must be placed directly after the Interface Descriptor. This is why the address is not important to anything other than the device (which then uses the address to read data in and out of the appropriate endpoints).

Descriptors So Far:

  • Device Descriptor
  • Configuration Descriptor (0)
    • Interface Descriptor (Mass Storage Class, Alternate Settings 0, Alternate Setting 0, 2 Endpoints)
      • Endpoint Descriptor (BULK, OUT, Address 1, 64 Bytes)
      • Endpoint Descriptor (BULK, IN, Address 2, 64 Bytes)
    • Interface Descriptor (Video Class, Alternate Settings 0, Alternate Setting 0, 1 Endpoint)
      • Endpoint Descriptor (BULK, IN, Address 3, 64 Bytes)
    • Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 0, 1 Endpoint)
      • Endpoint Descriptor (ISOCHRONOUS, IN, Address 4, 128 Bytes)
    • Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 1, 0 Endpoints)

  • Configuration Descriptor (1)
    • Interface Descriptor (Still Image Class, Alternate Settings 0, Alternate Setting 0, 2 Endpoints)
      • Endpoint Descriptor (BULK, OUT, Address 1, 64 Bytes)
      • Endpoint Descriptor (BULK, IN, Address 2, 64 Bytes)
    • Interface Descriptor (Video Class, Alternate Settings 0, Alternate Setting 0, 1 Endpoint)
      • Endpoint Descriptor (BULK, IN, Address 3, 64 Bytes)
    • Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 0, 1 Endpoint)
      • Endpoint Descriptor (ISOCHRONOUS, IN, Address 4, 128 Bytes)
    • Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 1, 0 Endpoints)

Putting them all together

Now we have the basic hierarchical structure of our descriptors for our USB camera. We need to flatten them into three structures – one Device, two Configuration. To do that, we just add the items to the struct in the order of the above, with children following parents:

Device Descriptor

Configuration Descriptor (0)

Interface Descriptor (Mass Storage Class, Alternate Settings 0, Alternate Setting 0, 2 Endpoints)
Endpoint Descriptor (BULK, OUT, Address 1, 64 Bytes)
Endpoint Descriptor (BULK, IN, Address 2, 64 Bytes)
Interface Descriptor (Video Class, Alternate Settings 0, Alternate Setting 0, 1 Endpoint)
Endpoint Descriptor (BULK, IN, Address 3, 64 Bytes)
Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 0, 1 Endpoint)
Endpoint Descriptor (ISOCHRONOUS, IN, Address 4, 128 Bytes)
Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 1, 0 Endpoints)

Configuration Descriptor (1)

Interface Descriptor (Still Image Class, Alternate Settings 0, Alternate Setting 0, 2 Endpoints)
Endpoint Descriptor (BULK, OUT, Address 1, 64 Bytes)
Endpoint Descriptor (BULK, IN, Address 2, 64 Bytes)
Interface Descriptor (Video Class, Alternate Settings 0, Alternate Setting 0, 1 Endpoint)
Endpoint Descriptor (BULK, IN, Address 3, 64 Bytes)
Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 0, 1 Endpoint)
Endpoint Descriptor (ISOCHRONOUS, IN, Address 4, 128 Bytes)
Interface Descriptor (Audio Class, Alternate Settings 1, Alternate Setting 1, 0 Endpoints)

Nothing to it. Of course, there are plenty of details about descriptors not covered here, but I just wanted to clear up the general confusion about what to change to create the desired behaviour.

 

Comments: 2

Leave a reply »

 
 
 

Greetings,
I’m a newbie trying to understand USB. My task is to convert an existing product to USB. So I’m doing a lot of research and studying. Needless to say it can get very confusing. I find Atmel’s USB examples only a little helpful. Thanks for making your project available.

My question is: Why did you choose to use bit fields to pack the descriptor structures? Is it for memory saving?

Thanks.

Edd

 

[…] USB Device Descriptors […]

 

Leave a Reply

 
(will not be published)
 
 
Comment
 
 

 

Vital Stats

  • 35 Years Old
  • Australian
  • Lover of embedded systems
  • Firmware engineer
  • Self-Proclaimed Geek

Latest Blog Posts

RSS