Name
Host Controller Drivers — Structure and Interface
Description
This section is mainly of interest to developers who want to write a new host controller driver. It describes the interface used by the USB stack to initiate HCD operations and the API that an HCD can use to interact with the USB stack.
HCD Object
The main interface between the USB stack and each type of HCD is the usb_hcd object:
struct usb_hcd { const char *name; // Driver name // Initialization etc. void (*init)( void ); // Initialize controller(s) int (*attach)( usb_bus *bus ); // Attach to hardware int (*detach)( usb_bus *bus ); // Detach from hardware // Endpoint handling int (*endpoint_attach)( usb_device *dev, usb_device_endpoint *dep ); int (*endpoint_detach)( usb_device *dev, void *hcd_endpoint ); // Transfer handling int (*submit)( usb_device *dev, usb_tfr *tfr ); // Submit transfer (chain) int (*cancel)( usb_device *dev, usb_tfr *tfr ); // Cancel transfer // Controller operation void (*poll)( usb_bus *bus ); // Poll controller for events int (*frame_number)( usb_bus *bus ); // Get current frame number // Root hub support int (*port_status)( usb_bus *bus, int port, usb_hub_port_status *status); int (*set_port_feature)(usb_bus *bus, int port, usb_uint16 feature ); int (*clear_port_feature)(usb_bus *bus, int port, usb_uint16 feature ); // TODO: Bandwidth support } CYG_HAL_TABLE_TYPE;
The fields are as follows:
- name
- This is a pointer to a string that names this device. It is mainly used for debugging.
- init
This is called once by the USB stack to initialize all HCDs of this type. In combination with platform code this function should enumerate all the HCDs of the supported type and eventually call
usb_hcd_register()
to make the controller available to the USB stack.The call to
usb_hcd_register()
is passed a hcd_bus object that the HCD should allocate in its private data structures. Within this object thehcd
field should be set to this HCDs usb_hcd object. Thehcd_priv
field should be set to point to the HCDs per-controller private data structure; this value will be copied to thehcd_priv
field of any device attached to this bus. Thehcd_ep0
field should be set to point to an HCD control endpoint for device 0; this will be used to communicate with a newly attached device before its ID has been set. The second argument tousb_hcd_register()
is a count of the number of downstream, ports the root hub contains.While this function should locate the devices and initialize the HCD data structures it should not access the Host Controller hardware at this point.
- attach
- This is called to attach the HCD to the hardware. This is when the hardware should be initialized, interrupt handlers registered and everything made ready for transfers to occur.
- detach
This is called to detach the HCD from the hardware. It should undo the initialization done by the attach function, leaving the device free for other software to take control.
The main reason for this attach/detach mechanism is to allow OTG devices to be shared between host and peripheral drivers.
- endpoint_attach
This is called to create an endpoint in the host controller. The HCD should use the id of the device plus the endpoint descriptor in the usb_device_endpoint object to create an endpoint of the correct type and direction for the device.
The HCD will typically allocate controller and driver data structures to represent this endpoint. If the underlying controller only supports a limited number of endpoints, then the driver should either fail excess endpoint attachments, or arrange to share the physical endpoints between a larger number of virtual endpoints. If the HCD endpoint is created successfully the it should assign a pointer to it to the hcd field in the usb_device_endpoint object.
- endpoint_detach
-
This is called when the device is detached, or changes its
active interface. It undoes the resource allocation made in
endpoint_attach
. Additionally, this function must cancel any transfers that are pending on the endpoint. Depending on the nature of the controller, these transfer cancellations and the eventual deallocation of the endpoint may happen after this function returns. - submit
-
This is called to submit a transfer to a device. Internally,
this function should extract the HCD private data from the
device
hcd_priv
and the endpoint from the device's usb_device_endpoint object for the transfer's endpoint address. The HCD is free to use thehcd_endpoint
andhcd_list
fields in the usb_tfr object; the latter should be initialized before use. - cancel
-
This is called to cancel a pending transfer. In general this is
only necessary for interrupt or isochronous transfers, control
and bulk transfers will always terminate within a finite
time. The transfer will not necessarily be available for reuse
once this function returns. This is only guaranteed once the
transfer's callback is invoked, either with a
USB_TFR_CANCELLED
status, some other error, or evenUSB_OK
. - poll
This is called from the main USB handling loop to give the HCD the chance to service the hardware. In general all controller operations should be handled in this function rather than the ISR or DSR. The HCD should test the hardware for transfer completion, device attach/detach and errors and handle them here.
If a transfer completes in this polling routine its callback may either be invoked directly by calling
usb_tfr_callback_pop()
or may be deferred for later processing by callingusb_tfr_complete_async()
. The latter is preferable since it avoids any problems of recursion if the callback submits another transfer.The simplest way to write an HCD is to do all device event handling in the
poll()
routine. If the controller supports interrupts then the HCD can callusb_signal_poll()
to cause the poll routine to be called. If it makes sense to handle device events in the ISR or DSR, callbacks, such as returning transfers, should still happen in the poll routine.- frame_number
- This simply returns the current USB frame number.
- port_status
-
This call fills in the
status
buffer with information on the state of the given port. This routine should query the port in the host controller's root hub registers and translate the results into the standard format expected in the status result, which should be returned in little endian order. - set_port_feature
-
This is called to set a port feature. The
feature
argument is a standard hub port feature code as defined in the USB standard. Only the subset of features relevant to a root hub are supported. - clear_port_feature
-
This is called to clear a port feature. The
feature
argument is a standard hub port feature code as defined in the USB standard. Only the subset of features relevant to a root hub are supported.
2024-03-18 | eCosPro Non-Commercial Public License |