USB
This document aims to provide an overview of the USB driver. Several USB classes, including USB audio, HID, MSC, and CDC, are supported by the USB driver. It might assist in becoming familiar with the architecture of the USB driver.
Requirements
The USB driver supports the following development kits:
Hardware Platforms |
Board Name |
Build Target |
---|---|---|
RTL87x3E HDK |
RTL87x3E EVB |
rws_4M_dual_bank0_default |
RTL87x3D HDK |
RTL87x3D EVB |
rws_16M_dual_bank0 |
When built for an xxx_4M_xxx
build target, the sample is configured to compile and run with a 4M flash map.
When built for an xxx_16M_xxx
build target, the sample is configured to compile and run with a 16M flash map.
To quickly set up the development environment, please refer to the detailed instructions provided in Quick Start.
Building and Downloading
The project of the USB driver can be found under sdk\board\evb\usb_lib
in the SDK folder structure. Take the project usb_lib.uvprojx
and target rtl87x3e
as an example, to build the lib with the keil development environment, follow the steps listed below:
Open
usb_lib.uvprojx
.Choose the build target
rtl87x3e
.Build the target.
After a successful compilation, the lib
usb.lib
will be generated in the directorybin\rtl87x3e
.Download progress can refer to USB Audio, which introduces how to set up a USB device. This document only introduces the USB driver.
Experimental Verification
This document only introduces the USB driver. Please refer to USB Audio for more test details.
Code Overview
The architecture of the USB driver is shown as follows.
USB HAL mainly provides hardware initialization and APIs for data transmission.
USB composite mainly deals with the standard requests defined in Chapter 9 of the USB specification[1]. This module does not deal with interface-related requests, but it passes interface requests to the corresponding function driver to process.
The function driver mainly handles requests defined by class specifications and some interface-related standard requests.
Bottom-up initialization HAL->composite->function driver->instance is required.
The locations of the USB modules mentioned above are listed as follows.
USB modules |
Location |
---|---|
USB HAL |
|
USB Composite |
|
Function Driver |
|
Function Instance |
|
Note
Applications such as headset and dongle can be used in function instances.
The composite and class drivers of the USB driver are introduced in this section.
USB Composite
The USB composite device defines the device descriptor and configuration descriptor, and handles and filters all the requests. The flow is shown below.
Initialize the USB device descriptor and configuration descriptor. The string needs to be added if the USB device descriptor’s or USB configuration descriptor’s string index is not zero.
Add the interfaces of the specific class.
After USB enumerates successfully, USB requests transmitted by the PC must be handled.
Interface Structure
The structure of the interface is as follows.
typedef struct _usb_interface
{
uint8_t if_num; // the number of the interface
struct usb_descriptor_header **descs_fs; // full speed descriptors
struct usb_descriptor_header **descs_hs; // high speed descriptors
T_USB_UTILS_LIST eps; // a list of endpoints belonging to the interface.
// callbacks for the interface to implement
int (*ctrl_request_proc)(struct _usb_interface *interface, T_USB_DEVICE_REQUEST *ctrl_request, T_HAL_USB_REQUEST_BLOCK *ctrl_urb);
int (*alt_get)(struct _usb_interface *interface, T_HAL_USB_REQUEST_BLOCK *ctrl_urb);
int (*alt_set)(struct _usb_interface *interface, T_HAL_USB_REQUEST_BLOCK *ctrl_urb, uint8_t alt);
int (*suspend)(struct _usb_interface *interface);
int (*resume)(struct _usb_interface *interface);
int (*create)(struct _usb_interface *interface);
int (*release)(struct _usb_interface *interface);
void *priv; // different for different interfaces
} T_USB_INTERFACE;
Request Handling
The USB request can be divided into several types. The request types are shown below.
USB commands can be divided into standard, class and vendor commands[1].
The standard commands can also be divided into several types. The USB specification[1] is followed in handling these commands.
The vendor command is designed according to specific requirements.
The class commands are divided into device, interface and endpoint. This module will not implement any class-related commands; instead, they will all be handled in class-related files.
If wishing to develop based on this layer, please refer to USB Composite in the API reference.
USB Class Driver
An overview of the USB class drivers, specifically the USB audio, USB HID, USB MSC, and USB CDC drivers, is provided in this section. Other classes will be implemented in the future.
USB Audio Driver
USB audio can be used for audio playback and recording.
The USB audio driver supports:
UAC1.0 and UAC2.0.
Multiple audio streams can work together.
A single audio stream contains multiple alternate settings.
The structure of the USB audio class is shown as follows.
The figure below illustrates the many interfaces that make up USB Audio, including the control interface, the out-streaming interface, and the in-streaming interface.
The USB audio initialization flow is shown as follows.
The USB audio instances will be initialized by
usb_audio_driver_inst_alloc
.The audio interface list items are allocated by
usb_audio_driver_desc_register
. The control entity list will be initialized for the control interface. For the streaming interface, the alternate setting with the different alternate value will be inserted into the alternate settings list. In addition to attributes, other associated resources will also be initialized.The control entity list will be registered in the control interface by
usb_audio_driver_ctrl_register
.The attributes will be registered in the alternate setting in each streaming interface by
usb_audio_driver_attr_init
.The data transmission-related callbacks will be registered by
usb_audio_driver_cb_register
.usb_audio_driver_init
will add interfaces to USB composite.
The structure of the driver is as follows.
typedef struct _usb_audio
{
T_USB_UTILS_LIST insts;
} T_USB_AUDIO;
The driver can contain multiple audio instances. There can be more than one audio instance in the driver.
typedef struct _usb_audio_inst
{
struct _usb_audio_inst *p_next;
uint8_t uac_ver; // the USB audio class version
T_USB_UTILS_LIST if_list; // the interface list belonging to the instance
T_USB_AUDIO_DRIVER_CBS cbs; // callbacks from the app to start and stop audio track, and transmit data
T_HAL_USB_ISO_REQUEST_BLOCK *iso_in_urb; // the USB isochronous request block for upstreaming
uint8_t iso_in_proc_interval; // the interval to process the isochronous packet
T_HAL_USB_ISO_REQUEST_BLOCK *iso_out_urb;
uint8_t iso_out_proc_interval;
uint16_t iso_out_max_buf_size; // the maximum size of the data transfer
uint8_t *copy_buf; // stores the received isochronous out data
} T_USB_AUDIO_INST;
The structure of the list item in the if_list
is as follows.
typedef struct _usb_audio_if
{
struct _usb_audio_if *p_next;
uint8_t dir; // the direction of the audio streaming interface (in/out)
uint8_t sub_class; // the subclass of the interface is control or streaming
uint8_t cur_alt; // the current alternate setting of the interface
T_USB_INTERFACE interface; // the interface structure in the USB composite
union
{
T_ALT_SETTINGS *alt_settings; // for streaming, alternate settings
T_USB_UTILS_LIST *ctrl_entity_list; // for control, control topology
} priv;
void *owner;
} T_USB_AUDIO_IF;
For the control interface, the control topology is as follows.
typedef struct _usb_audio_driver_ctrl
{
uint8_t type;
T_USB_AUDIO_DRIVER_CTRL_ATTR attr;
T_USB_AUDIO_CTRL_SET_FUNC set;
T_USB_AUDIO_CTRL_GET_FUNC get;
} T_USB_AUDIO_DRIVER_CTRL;
#define T_USB_AUDIO_DRIVER_CTRL_ENTITY(id, num) \
struct _usb_audio_driver_ctrl_entity##id \
{ \
uint8_t entity_id; \
uint8_t ctrl_num; \
T_USB_AUDIO_DRIVER_CTRL *ctrls[num]; \
}
typedef struct _usb_audio_driver_ctrl_entity_hdr
{
uint8_t entity_id;
uint8_t ctrl_num;
} T_USB_AUDIO_DRIVER_CTRL_ENTITY_HDR;
typedef struct _control_entity_item
{
struct _control_entity_item *p_next;
T_USB_AUDIO_DRIVER_CTRL_ENTITY_HDR *ctrl_entity;
} T_CONTROL_ENTITY_ITEM;
For each control unit, the following points need to be implemented:
The
id
inT_USB_AUDIO_DRIVER_CTRL_ENTITY(id, num)
is the unit id of the feature unit descriptor, andnum
denotes the number of attributes that the unit can control. For example, the feature unit may be able to control both volume and mute at the same time.T_USB_AUDIO_DRIVER_CTRL
controls a single attribute.
For the streaming interface, the alternate setting list is as follows.
typedef struct _alt_setting
{
struct _alt_setting *p_next;
uint8_t value; // an alternate value
T_USB_ENDPOINT_DESC *hs_ep_desc; // the high-speed endpoint descriptor
T_USB_ENDPOINT_DESC *fs_ep_desc; // the full-speed endpoint descriptor
T_USB_AUDIO_DRIVER_ATTR attr; // audio streaming parameters in the current alternate setting,
// such as sample rate, bit width, and channel number
} T_ALT_SETTING;
typedef struct _alt_settings
{
union
{
uint32_t data;
struct
{
uint32_t freq: 24;
uint32_t rsv: 8;
} uac2;
} cs; // a custom parameter for different UAC versions. For UAC 2.0, it indicates the current frequency.
T_USB_EP *ep; // the endpoints included in alternate settings (only one isochronous endpoint is supported at most)
T_ALT_SETTING *cur; // the current alternate setting
T_USB_UTILS_LIST list; // T_ALT_SETTING list
void *owner; // the audio interface to which the T_ALT_SETTINGS belong
} T_ALT_SETTINGS;
If developing based on this layer, please refer to the USB Audio Driver in the API reference.
USB HID Driver
The USB HID can be used for mouse, keyboard, CFU, etc.
USB HID driver supports:
Several interfaces.
Each interface with several endpoints.
The structure of the USB HID class is shown below.
To register the interface and its corresponding report descriptors, call the function
usb_hid_driver_if_desc_register
. After that, initialize the functions in the interface, and insert them intoif_list
in theT_USB_HID
structure.usb_hid_driver_cbs_register
can bindset_report
andget_report
callbacks to the interface. It can transmit data from the app throughset_report
andget_report
requests.usb_hid_driver_init
will add interfaces to USB composite.
The structure of the driver is as follows.
typedef struct _usb_hid
{
T_USB_UTILS_LIST if_list;
} T_USB_HID;
The driver can contain multiple HID interfaces. The structure of the interface is as follows.
typedef struct _usb_hid_if
{
struct _usb_hid_if *p_next;
T_USB_INTERFACE intf; // the interface structure of USB composite
uint8_t cur_alt; // the current alternate value
T_USB_HID_DRIVER_CBS cbs; // the get report and set report callbacks registered from the application.
} T_USB_HID_IF;
If you would like to develop based on this layer, please refer to USB HID Driver in the API reference.
USB MSC Driver
The USB mass storage can be used for USB flash disk. This driver only supports Bulk-Only Transport and does not depend on the command set specification or storage medium used.
The structure of the USB mass storage class is shown below.
The driver only includes an interface with two bulk endpoints.
To initialize an interface, call the function
usb_ms_driver_if_desc_register
, and then initialize the functions in the interface.The disk-related operations can be registered
usb_ms_driver_disk_register
. These callbacks can access the sdcard.usb_ms_driver_init
will add interfaces to USB composite.
The structure of the driver is as follows.
typedef struct _usb_ms
{
T_USB_INTERFACE intf; // the interface structure of USB composite
uint8_t cur_alt; // the current alternate value
void *pipe_tx; // pipe handle of bulk in ep
void *pipe_rx; // pipe handle of bulk out ep
uint32_t mtu_tx; // max transfer size of bulk in ep
uint32_t mtu_rx; // max transfer size of bulk out ep
T_RX_CB rx_cbs; // cbs to process CBW and data stage
uint32_t xfer_len; // current transfer length
uint32_t remaining_len; // data transfer length of PC want to recv or send in CBW stage
USB_MS_DRIVER_TX_COMPLETE tx_complete; // complete callback of bulk in ep
T_DISK_DRIVER disk; // disk-related callbacks
int cur_cbw_tag; // CSWTag of current CBW
T_USB_MS_STATUS ms_status; // status of ms
} T_USB_MS;
If you want to develop based on this layer, please refer to USB MS Driver in API reference.
USB CDC Driver
This driver supports virtual communication port to communicate with a computer. The driver completes data transmission through two bulk endpoints.
The structure of the USB mass storage class is shown as follows.
To initialize an interface, call the function
usb_cdc_driver_if_desc_register
. Then, initialize the functions in the interface, and insert them intoif_list
in theT_USB_CDC
structure.usb_cdc_driver_init
will add interfaces to the USB composite.
The structure of the driver is as follows.
typedef struct _usb_cdc
{
T_USB_UTILS_LIST if_list;
} T_USB_CDC;
The driver can contain two CDC interfaces. The structure of the interface is as follows.
typedef struct _usb_cdc_if
{
struct _usb_cdc_if *p_next;
T_USB_INTERFACE intf; // the interface structure of USB composite
uint8_t cur_alt; // the current alternate value
} T_USB_CDC_IF;
To develop based on this layer, please refer to USB CDC Driver in the API reference.
Appendix
[1] Universal Serial Bus (USB) Specification, Version 2.0.