USB Host stack
The USB Host stack server -
usb provides the generic core functionality, including abstraction of Host Controller Device, managing devices enumeration and communication with device drivers. The USB Host stack is accessible to other processes through a port
Host Controller Devices
The USB Host stack allows using different types and multiple instances of HCDs. It provides generic types
hcd_ops_t. Specific drivers for different types of HCDs such as
ohci etc. are a part of the
phoenix-rtos-devices repository in the form of a static library named, e.g.
libusbehci. When building the USB Host stack, one should set the environmental variable
USB_HCD_LIBS to an appropriate value denoting host controllers available on the platform. Each Host Controlller driver library should register its
hcd_ops_t instance using a GCC constructor. It allows the USB Host stack to communicate with an HCD driver using callbacks within an
The USB Host stack during initialization first fetches the platform-dependent information on the available HCD instances using
hcd_info_t structure. (At this moment it is done using
hcd_getInfo() function. In the future it should be done using a device tree.) Then it matches instances with previously registered HCD ops and creates
hcd_t instances, with which it would then communicate in terms of scheduling transfers and detecting devices connection/disconnection.
Hubs are the basis of the USB devices tree. Each HCD has its own Root Hub with at least one port. Both Root Hubs and additional physical hub devices are managed using the hub driver, which is the only USB class driver implemented as a part of the USB stack, while other USB classes are implemented as separate processes. The hub driver is responsible for managing port status changes, e.g. devices connection or disconnection. When a new device is connected the hub module performs the enumeration process and binds a device with appropriate drivers. On the device disconnection, it shall unbind a device from drivers, destroy a device and all its resources.
Drivers are seperate processes, which communicate with the Host stack using messages and are represented in the USB Host stack as
usb_drv_t instances. A driver first registers itself using a
connect USB message (implemented in
usb_connect() function). It then waits for events such as
deletion sent by the USB Host stack.
insertion message is sent, once the USB Host stack binds the newly connected device to a particular driver. A device can be a composite device containing multiple interfaces. Each interface can be bound to a different driver. An
insertion message is sent for every interface seperately. It works the same with
Drivers are bound to interfaces after matching device or interface descriptors with driver filters described by one or many
usb_device_id_t structures. An array of those structures is provided to the USB Host stack, when registering a driver using
usb_connect() function. It consists of the following fields (from most specific to most general):
Each of those fields can have a fixed value or a wildcard value
USBDRV_ANY. An interface can match multiple drivers, but the host stack shall choose the most specific one to bind the interface to. For example it shall prefer a driver, which matches
vid fields over a driver that matches
It's the driver's responsibility to create ports in order to give other processes access to resources of a particular device, e.g.
Pipes are a software abstraction of a USB endpoint. Drivers communicate with specific endpoints using pipes. A pipe is characterized with a direction (in or out) and type (control, bulk, interrupt isochronous). A device driver first opens a pipe by sending a USB
open message (implemented in
usb_open() function). A driver gives details on a pipe it requests to open. If the USB Host stack finds an endpoint on a given device interface with given direction and type, it creates a pipe, allocates an
id unique in the context of the driver and returns the id to the driver. The driver can then send transfers using this pipe id. A pipe id can be thought as a UN*X-like file descriptors - it is a key to communicate with a specific endpoint.
A driver writes or reads data using a pipe by sending
urb messages. The USB Host stack schedules a transfer on a corresponding Host Controller Device, once it processes an
urb. It then informs a driver, that a transfer has been finished either in a synchronous way (calling
msgRespond() to the
urb message - bulk and control transfers) or asynchronous (a new event message - interrupt and isochronous message).