This chapter contains a description of the high performance USBX embedded USB host stack from a functional perspective.
USBX is composed of several components:
The following diagram illustrates the USBX host stack.

In order to activate USBX, the function ux_system_initialize must be called. This function initializes the memory resources of USBX.
In order to activate USBX host facilities, the function ux_host_stack_initialize must be called. This function will in turn initialize all the resources used by the USBX host stack such as ThreadX threads, mutexes, and semaphores.
It is up to the application initialization to register one or more USB classes by function ux_host_stack_class_register. If Hub Class is registered, its ready to detect devices connected through hub port, otherwise, only devices connected to root hub ports are enumerated.
It is up to the application initialization to activate at least one USB host controller. When the host controller(s) initialization function has been called the bus is active and device discovery can start. If the root hub of the host controller detects an attached device, the USB enumeration thread, in charge of the USB topology, will be wake up and proceed to enumerate the device(s).
It is possible, due to the nature of the root hub and downstream hubs, that all attached USB devices may not have been configured completely when the host controller initialization function returns. It can take several seconds to enumerate all USB devices, especially if there are one or more hubs between the root hub and USB devices.
There are two levels of APIs in USBX.
Normally, a USBX application should not have to call any of the USB host stack API functions. Most applications will only access the USB Class API functions.
The host stack API functions are responsible for the registration of USBX components (host classes and host controllers), configuration of devices, and the transfer requests for available device endpoints.
The Class APIs are very specific to each USB class. Most of the common API functions for USB classes provide services such as opening/closing a device and reading from and writing to a device.
The CDC class is in charge of enumerating and driving connected CDC devices. Currently two functionalities are supported:
The Storage class is in charge of enumerating and driving connected mass storage devices. It is integrated with FileX, the Eclipse ThreadX file system support module, to offer services to operate the connected media through FX_MEDIA interface.
The HID class is in charge of enumerating and driving connect HID devices. The following functionalities are supported by its client services:
The hub class is in charge of driving USB hubs. A USB hub can either be a stand-alone hub or as part of a compound device such as a keyboard or a monitor. A hub can be self-powered or bus-powered. Bus-powered hubs have a maximum of four downstream ports and can only allow for the connection of devices that are either self-powered or bus-powered devices that use less than 100mA of power. Hubs can be cascaded. Up to five hubs can be connected to one another.
The USB host controller driver interoperates USB Host Stack operations to hardware actions. Normally, a USBX application should not have to call host controller APIs, except initialization function. When the host controller initialization function is called, the hardware is ready and the stack will reply to detect bus events and start communication with connected devices.
Each host controller instance has one or more USB root hubs. The number of root hubs is either determined by the nature of the controller or can be retrieved by reading specific registers from the controller.
The USB host stack is the centerpiece of USBX. It has three main functions.
The USB stack topology thread is awakened when a new device is connected or when a device has been disconnected. Either the root hub or a regular hub can accept device connections. Once a device has been connected to the USB, the topology manager will retrieve the device descriptor. This descriptor will contain the number of possible configurations available for this device. Most devices have one configuration only. Some devices can operate differently according to the available power available on the port where it is connected. If this is the case, the device will have multiple configurations that can be selected depending on the available power. When the device is configured by the topology manager, it is then allowed to draw the amount of power specified in its configuration descriptor.
When the device is configured, the topology manager will let the class manager continue the device discovery by looking at the device interface descriptors. A device can have one or more interface descriptors.
An interface represents a function in a device. For instance, a USB speaker has three interfaces, one for audio streaming, one for audio control, and one to manage the various speaker buttons.
The class manager has two mechanisms to join the device interface(s) to one or more classes. It can either use the combination of a PID/VID (product ID and vendor ID) found in the interface descriptor or the combination of Class/Subclass/Protocol.
The PID/VID combination is valid for interfaces that cannot be driven by a generic class. The Class/Subclass/Protocol combination is used by interfaces that belong to a USB-IF certified class such as a printer, hub, storage, audio, or HID.
The class manager contains a list of registered classes from the initialization of USBX. The class manager will call each class one at a time until one class accepts to manage the interface for that device. A class can only manage one interface. For the example of the USB audio speaker, the class manager will call all the classes for each of the interfaces.
Once a class accepts an interface, a new instance of that class is created. The class manager will then search for the default alternate setting for the interface. A device may have one or more alternate settings for each interface. The alternate setting 0 will be the on used by default until a class decides to change it.
For the default alternate setting, the class manager will mount all the endpoints contained in the alternate setting. If the mounting of each endpoint is successful, the class manager will complete its job by returning to the class that will finish the initialization of the interface.
The USB stack exports a certain number of APIs for the USB classes to perform interrogation on the device and USB transfers on specific endpoints. These API functions are described in detail in this reference manual.
The host controller driver is responsible for driving a specific type of USB controller. A USB host controller can have multiple controllers inside. For instance, certain Intel PC chipset contain two UHCI controllers. Some USB 2.0 controllers contain multiple instances of an OHCI controller in addition to one instance of the EHCI controller.
The Host controller will manage multiple instance of the same controller only. In order to drive most USB 2.0 host controllers, it will be required to initialize both the OCHI controller and the EHCI controller during the initialization of USBX.
The host controller is responsible for managing the following.
The root hub management is responsible for the powering up of each controller port and determining if there is a device inserted or not. This functionality is used by the USBX generic root hub to interrogate the controller downstream ports.
The power management processing provides for the handling of suspend/resume signals either in gang mode, therefore affecting all controller downstream ports at the same time, or individually if the controller offers this functionality.
The endpoint management provides for the creation or destruction of physical endpoints to the controller. The physical endpoints are memory entities that are parsed by the controller if the controller supports master DMA or that are written in the controller. The physical endpoints contain transactions information to be performed by the controller.
Transfer management provides for a class to perform a transaction on each of the endpoints that have been created. Each logical endpoint contains a component called TRANSFER REQUEST for USB transfer requests. The TRANSFER REQUEST is used by the stack to describe the transaction. This TRANSFER REQUEST is then passed to the stack and to the controller, which may divide it into several sub transactions depending on the capabilities of the controller.
A USB device is represented by a tree of descriptors. There are six main types of descriptors.
A USB device may have a very simple description and looks like this.

In the above illustration, the device has only one configuration. A single interface is attached to this configuration, indicating that the device has only one function, and it has one endpoint only. Attached to the device descriptor is a string descriptor providing a visible identification of the device.
However, a device may be more complex and may appear as follows.

In the above illustration, the device has two configuration descriptors attached to the device descriptor. This device may indicate that it has two power modes or can be driven by either standard classes or proprietary classes.
Attached to the first configuration are two interfaces indicating that the device has two logical functions. The first function has 3 endpoint descriptors and a functional descriptor. The functional descriptor may be used by the class responsible to drive the interface to obtain further information about this interface normally not found by a generic descriptor.
Each USB device has one single device descriptor. This descriptor contains the device identification, the number of configurations supported, and the characteristics of the default control endpoint used for configuring the device.
| Offset | Field | Size | Value | Description |
|---|---|---|---|---|
| 0 | BLength | 1 | Number | Size of this descriptor in bytes |
| 1 | bDescriptorType | 1 | Constant | DEVICE Descriptor Type |
| 2 | bcdUSB | 2 | BCD | USB Specification Release Number in BinaryCoded Dec Example: 2.10 is equivalent to 0x210. This field identifies the release of the USB Specification that the device and its descriptors are compliant with. |
| 4 | bDeviceClass | 1 | Class | Class code (assigned by USB-IF). If this field is reset to 0, each interface within a configuration specifies its own class information and the various interfaces operate independently. If this field is set to a value between 1 and 0xFE, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. If this field is set to 0xFF, the device class is vendor specific. |
| 5 | bDeviceSubClass | 1 | SubClass | Subclass code (assigned by USB-IF). These codes are qualified by the value of the bDeviceClass field. If the bDeviceClass field is reset to 0, this field must also be reset to 0. If the bDeviceClass field is not set to 0xFF, all values are reserved for assignment by USB. |
| 6 | bDeviceProtocol | 1 | Protocol | Protocol code (assigned by USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. If this field is reset to 0, the device does not use class specific protocols on a device basis. However, it may use class specific protocols on an interface basis. If this field is set to 0xFF, the device uses a vendor specific protocol on a device basis. |
| 7 | bMaxPacketSize0 | 1 | Number | Maximum packet size for endpoint zero (only byte sizes of 8, 16, 32, or 64 are valid) |
| 8 | idVendor | 2 | ID | Vendor ID (assigned by USB-IF) |
| 10 | idProduct | 2 | ID | Product ID (assigned by the Manufacturer) |
| 12 | bcdDevice | 2 | BCD | Device release number in binary-coded decimal |
| 14 | iManufacturer | 1 | Index | Index of string descriptor describing manufacturer |
| 15 | iProduct | 1 | Index | Index of string descriptor describing product |
| 16 | iSerialNumber | 1 | Index | Index of string descriptor describing the device’s serial number |
| 17 | bNumConfigurations | 1 | Number | Number of possible configurations |
USBX defines a USB device descriptor as follows:
typedef struct UX_DEVICE_DESCRIPTOR_STRUCT
{
UINT bLength;
UINT bDescriptorType;
USHORT bcdUSB;
UINT bDeviceClass;
UINT bDeviceSubClass;
UINT bDeviceProtocol;
UINT bMaxPacketSize0;
USHORT idVendor;
USHORT idProduct;
USHORT bcdDevice;
UINT iManufacturer;
UINT iProduct;
UINT iSerialNumber;
UINT bNumConfigurations;
} UX_DEVICE_DESCRIPTOR;
The USB device descriptor is part of a device container described as:
typedef struct UX_DEVICE_STRUCT
{
ULONG ux_device_handle;
ULONG ux_device_type;
ULONG ux_device_state;
ULONG ux_device_address;
ULONG ux_device_speed;
ULONG ux_device_port_location;
ULONG ux_device_max_power;
ULONG ux_device_power_source;
UINT ux_device_current_configuration;
TX_SEMAPHORE ux_device_protection_semaphore;
struct UX_DEVICE_STRUCT *ux_device_parent;
struct UX_HOST_CLASS_STRUCT *ux_device_class;
VOID *ux_device_class_instance;
struct UX_HCD_STRUCT *ux_device_hcd;
struct UX_CONFIGURATION_STRUCT *ux_device_first_configuration;
struct UX_DEVICE_STRUCT *ux_device_next_device;
struct UX_DEVICE_DESCRIPTOR_STRUCT ux_device_descriptor;
struct UX_ENDPOINT_STRUCT ux_device_control_endpoint;
struct UX_HUB_TT_STRUCT ux_device_hub_tt[UX_MAX_TT];
} UX_DEVICE;
The configuration descriptor describes information about a specific device configuration. A USB device may contain one or more configuration descriptors. The bNumConfigurations field in the device descriptor indicates the number of configuration descriptors. The descriptor contains a bConfigurationValue field with a value that, when used as a parameter to the Set Configuration request, causes the device to assume the described configuration.
The descriptor describes the number of interfaces provided by the configuration. Each interface represents a logical function within the device and may operate independently. For instance a USB audio speaker may have three interfaces, one for audio streaming, one for audio control, and one HID interface to manage the speaker’s buttons.
When the host issues a GET_DESCRIPTOR request for the configuration descriptor, all related interface and endpoint descriptors are returned.
| Offset | Field | Size | Value | Description |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | Size of this descriptor in bytes. |
| 1 | bDescriptorType | 1 | Constant | CONFIGURATION |
| 2 | wTotalLength | 2 | Number | Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class or vendor specific) returned for this configuration. |
| 4 | bNumInterfaces | 1 | Number | Number of interfaces supported by this configuration. |
| 5 | bConfigurationValue | 1 | Number | Value to use as an argument to Set Configuration to select this configuration. |
| 6 | iConfiguration | 1 | Index | Index of string descriptor describing this configuration. |
| 7 | bMAttributes | 1 | Bitmap | Configuration characteristics D7 Bus Powered D6 Self Powered D5 Remote Wakeup D4..0 Reserved (reset to 0) A device configuration that uses power from the bus and a local source sets both D7 and D6. The actual power source at runtime may be determined using the Get Status device request. If a device configuration supports remote wakeup, D5 is set to 1. |
| 8 | MaxPower | 1 | mA | Maximum power consumption of USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (e.g., 50 = 100 mA). Note: A device configuration reports whether the configuration is bus-powered or self-powered. Device status reports whether the device is currently self-powered. If a device is disconnected from its external power source, it updates device status to indicate that it is no longer self-powered. |
USBX defines a USB configuration descriptor as follows.
typedef struct UX_CONFIGURATION_DESCRIPTOR_STRUCT
{
UINT bLength;
UINT bDescriptorType;
USHORT wTotalLength;
UINT bNumInterfaces;
UINT bConfigurationValue;
UINT iConfiguration;
UINT bmAttributes;
UINT MaxPower;
} UX_CONFIGURATION_DESCRIPTOR;
The USB configuration descriptor is part of a configuration container described as shown below.
typedef struct UX_CONFIGURATION_STRUCT
{
ULONG ux_configuration_handle;
ULONG ux_configuration_state;
struct UX_CONFIGURATION_DESCRIPTOR_STRUCT ux_configuration_descriptor;
struct UX_INTERFACE_STRUCT *ux_configuration_first_interface;
struct UX_CONFIGURATION_STRUCT *ux_configuration_next_configuration;
struct UX_DEVICE_STRUCT *ux_configuration_device;
} UX_CONFIGURATION;
The interface descriptor describes a specific interface within a configuration. An interface is a logical function within a USB device. A configuration provides one or more interfaces, each with zero or more endpoint descriptors describing a unique set of endpoints within the configuration. When a configuration supports more than one interface, the endpoint descriptors for a particular interface follow the interface descriptor in the data returned by the GET_DESCRIPTOR request for the specified configuration.
An interface descriptor is always returned as part of a configuration descriptor. An interface descriptor cannot be directly access by a GET_DESCRIPTOR request.
An interface may include alternate settings that allow the endpoints and/or their characteristics to be varied after the device has been configured. The default setting for an interface is always alternate setting zero. A class can select to change the current alternate setting to change the interface behavior and the characteristics of the associated endpoints. The SET_INTERFACE request is used to select an alternate setting or to return to the default setting.
Alternate settings allow a portion of the device configuration to be varied while other interfaces remain in operation. If a configuration has alternate settings for one or more of its interfaces, a separate interface descriptor and its associated endpoints are included for each setting.
If a device configuration contains a single interface with two alternate settings, the GET_DESCRIPTOR request for the configuration would return the configuration descriptor, then the interface descriptor with the bInterfaceNumber and bAlternateSetting fields set to zero and then the endpoint descriptors for that setting, followed by another interface descriptor and its associated endpoint descriptors. The second interface descriptor’s bInterfaceNumber field would also be set to zero, but the bAlternateSetting field of the second interface descriptor would be set to 1 indicating that this alternate setting belongs to the first interface.
An interface may not have any endpoints associated with it, in which case only the default control endpoint is valid for that interface.
Alternate settings are used mainly to change the requested bandwidth for periodic endpoints associated with the interface. For example, a USB speaker streaming interface should have the first alternate setting with a 0 bandwidth demand on its isochronous endpoint. Other alternate settings may select different bandwidth requirements depending on the audio streaming frequency.
The USB descriptor for the interface is as follows:
| Offset | Field | Size | Value | Descriptor |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | Size of this descriptor in bytes. |
| 1 | bDescriptorType | 1 | Constant | INTERFACE Descriptor Type |
| 2 | bInterfaceNumber | 1 | Number | Number of interface. Zero-based value identifying the index in the array of concurrent interfaces supported by this configuration. |
| 3 | bAlternateSetting | 1 | Number | Value used to select alternate setting for the interface identified in the prior field. |
| 4 | bNumEndpoints | 1 | Number | Number of endpoints used by this interface (excluding endpoint zero). If this value is 0, this interface only uses endpoint zero. |
| 5 | bInterfaceClass | 1 | Class | Class code (assigned by USB) If this field is reset to 0, the interface does not belong to any USB specified device class. If this field is set to 0xFF, the interface class is vendor specific. All other values are reserved for assignment by USB. |
| 6 | bInterfaceSubClass | 1 | SubClass | Subclass code (assigned by USB). These codes are qualified by the value of the bInterfaceClass field. If the bInterfaceClass field is reset to 0, this field must also be reset to 0. If the bInterfaceClass field is not set to 0xFF, all values are reserved for assignment by USB. |
| 7 | bInterfaceProtocol | 1 | Protocol | Protocol code (assigned by USB). These codes are qualified by the value of the bInterfaceClass and the bInterfaceSubClass fields. If an interface supports class-specific requests, this code identifies the protocols that the device uses as defined by the specification of the device class. If this field is reset to 0, the device does not use a class specific protocol on this interface. If this field is set to 0xFF, the device uses a vendor specific protocol for this interface. |
| 8 | iInterface | 1 | Index | Index of string descriptor describing this interface. |
USBX defines a USB interface descriptor as follows.
typedef struct UX_INTERFACE_DESCRIPTOR_STRUCT
{
UINT bLength;
UINT bDescriptorType;
UINT bInterfaceNumber;
UINT bAlternateSetting;
UINT bNumEndpoints;
UINT bInterfaceClass
UINT bInterfaceSubClass;
UINT bInterfaceProtocol;
UINT iInterface;
} UX_INTERFACE_DESCRIPTOR;
The USB interface descriptor is part of an interface container described as follows.
typedef struct UX_INTERFACE_STRUCT
{
ULONG ux_interface_handle;
ULONG ux_interface_state;
ULONG ux_interface_current_alternate_setting;
struct UX_INTERFACE_DESCRIPTOR_STRUCT ux_interface_descriptor;
struct UX_HOST_CLASS_STRUCT *ux_interface_class;
VOID *ux_interface_class_instance;
struct UX_ENDPOINT_STRUCT *ux_interface_first_endpoint;
struct UX_INTERFACE_STRUCT *ux_interface_next_interface;
struct UX_CONFIGURATION_STRUCT *ux_interface_configuration;
} UX_INTERFACE;
Each endpoint associated with an interface has its own endpoint descriptor. This descriptor contains the information required by the host stack to determine the bandwidth requirements of each endpoint, the maximum payload associated with the endpoint, its periodicity, and its direction. An endpoint descriptor is always returned by a GET_DESCRIPTOR command for the configuration.
The default control endpoint associated with the device descriptor is not counted as part of the endpoint(s) associated with the interface and therefore not returned in this descriptor.
When the host software requests a change of the alternate setting for an interface, all the associated endpoints and their USB resources are modified according to the new alternate setting.
Except for the default control endpoints, endpoints cannot be share between interfaces.
| Offset | Field | Size | Value | Description |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | Size of this descriptor in bytes. |
| 1 | bDescriptorType | 1 | Constant | ENDPOINT Descriptor Type. |
| 2 | bEndpointAddress | 1 | Endpoint | The address of the endpoint on the USB device described by this descriptor. The address is encoded as follows: Bit 3…0: The endpoint number Bit 6…4: Reserved, reset to zero Bit 7: Direction, ignored for control endpoints 0 = OUT endpoint 1 = IN endpoint |
| 3 | bmAttributes | 1 | Bitmap | This field describes the endpoint’s attributes when it is configured using the bConfigurationValue field. Bits 1..0: Transfer Type 00 = Control 01 = Isochronous 10 = Bulk 11 = Interrupt If not an isochronous endpoint, bits 5..2 are reserved and must be set to zero. If isochronous, they are defined as follows: Bits 3..2: Synchronization Type 00 = No Synchronization 01 = Asynchronous 10 = Adaptive 11 = Synchronous Bits 5..4: Usage Type 00 = Data endpoint 01 = Feedback endpoint 10 = Implicit feedback data endpoint 11 = Reserved |
| 4 | wMaxPacketSize | 2 | Number | Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. For isochronous endpoints, this value is used to reserve the bus time in the schedule, required for the per-(micro)frame data payloads. The pipe may, on an ongoing basis, actually use less bandwidth than that reserved. The device reports, if necessary, the actual bandwidth used via its normal, non-USB defined mechanisms. For all endpoints, bits 10..0 specify the maximum packet size (in bytes). For high-speed isochronous and interrupt endpoints: Bits 12..11 specify the number of additional transaction opportunities per microframe: 00 = None (1 transaction per microframe) 01 = 1 additional (2 per microframe) 10 = 2 additional (3 per microframe) 11 = Reserved Bits 15..13 are reserved and must be set to zero. |
| 6 | bInterval | 1 | Number | Number interval for polling endpoint for data transfers. Expressed in frames or microframes depending on the device operating speed (i.e., either 1 millisecond or 125 µs units). For full-/high-speed isochronous endpoints, this value must be in the range from 1 to 16. The bInterval is used as the exponent for a 2bInterval-1 value; e.g., a bInterval 4 means a period of 8 (24-1). For full-/low-speed interrupt endpoints, the value of this field may be from 1 to 255. For high-speed interrupt endpoints, the bInterval is used as the exponent for a 2bInterval-1 value; e.g., a bInterval 4 means a period of 8 (24-1). This value must be from 1 to 16. For high-speed bulk/control OUT endpoints, the bInterval specify the maximum NAK rate of the endpoint. A value of 0 indicates the endpoint never NAKs. Other values indicate at most one NAK each bInterval of microframes. This value must be in the range from 0 to 255. |
USBX defines a USB endpoint descriptor as follows:
typedef struct UX_ENDPOINT_DESCRIPTOR_STRUCT
{
UINT bLength;
UINT bDescriptorType;
UINT bEndpointAddress;
UINT bmAttributes;
USHORT wMaxPacketSize;
UINT bInterval;
} UX_ENDPOINT_DESCRIPTOR;
The USB endpoint descriptor is part of an endpoint container, which is described as follows.
typedef struct UX_ENDPOINT_STRUCT {
ULONG ux_endpoint_handle;
ULONG ux_endpoint_state;
VOID *ux_endpoint_ed;
struct UX_ENDPOINT_DESCRIPTOR_STRUCT ux_endpoint_descriptor;
struct UX_ENDPOINT_STRUCT *ux_endpoint_next_endpoint;
struct UX_INTERFACE_STRUCT *ux_endpoint_interface;
struct UX_DEVICE_STRUCT *ux_endpoint_device;
struct UX_TRANSFER REQUEST_STRUCT ux_endpoint_transfer request;
} UX_ENDPOINT;
String descriptors are optional. If a device does not support string descriptors, all references to string descriptors within device, configuration, and interface descriptors must be reset to zero.
String descriptors use UNICODE encoding, thus allowing the support for several character sets. The strings in a USB device may support multiple languages. When requesting a string descriptor, the requester specifies the desired language using a language ID defined by the USB-IF. The list of currently defined USB LANGIDs can be found in the USBX appendix ??. String index zero for all languages returns a string descriptor that contains an array of two-byte LANGID codes supported by the device. It should be noted that the UNICODE string is not 0 terminated. Instead, the size of the string array is computed by subtracting two from the size of the array contained in the first byte of the descriptor.
The USB string descriptor 0 is encoded as follows.
| Offset | Field | Size | Value | Description |
|---|---|---|---|---|
| 0 | bLength | 1 | N+2 | Size of this descriptor in bytes |
| 1 | bDescriptorType | 1 | Constant | STRING Descriptor Type |
| 2 | wLANGID[0] | 2 | Number | LANGID code 0 |
| … | …] | … | … | … |
| N | wLANGID[n] | 2 | Number | LANGID code n |
Other USB string descriptors are encoded as follows.
| Offset | Field | Size | Value | Description |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | Size of this descriptor in bytes |
| 1 | bDescriptorType | 1 | Constant | STRING Descriptor Type |
| 2 | bString | n | Number | UNICODE encoded string |
USBX defines a non-zero length USB string descriptor as follows:
typedef struct UX_STRING_DESCRIPTOR_STRUCT
{
UINT bLength;
UINT bDescriptorType;
USHORT bString[1];
} UX_STRING_DESCRIPTOR;
Functional descriptors are also known as class-specific descriptors. They normally use the same basic structures as generic descriptors and allow for additional information to be available to the class. For example, in the case of the USB audio speaker, class specific descriptors allow the audio class to retrieve for each alternate setting the type of audio frequency supported.
USBX maintains most device descriptors in memory, that is, all descriptors except the string and functional descriptors. The following diagram shows how these descriptors are stored and related.
