Embedded Xinu Operating System
An ongoing research project and educational operating system.
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Groups Pages
Files | Enumerations | Functions
USB Host Controller Driver

Platform-dependent code to actually send and receive data over the USB. More...

Files

file  usb_dwc_hcd.c
 

Enumerations

enum  dwc_intr_status {
  XFER_COMPLETE = 0, XFER_FAILED = 1, XFER_NEEDS_DEFERRAL = 2, XFER_NEEDS_RESTART = 3,
  XFER_NEEDS_TRANS_RESTART = 4
}
 

Functions

usb_status_t hcd_start (void)
 
void hcd_stop (void)
 
usb_status_t hcd_submit_xfer_request (struct usb_xfer_request *req)
 

Detailed Description

Platform-dependent code to actually send and receive data over the USB.

USB Host Controller Driver specifies protocols for USB transfers.

This is a USB Host Controller Driver (HCD) that interfaces with the Synopsys DesignWare Hi-Speed USB 2.0 On-The-Go Controller, henceforth abbreviated as "DWC". This is the USB Host Controller used on the BCM2835 SoC used on the Raspberry Pi.

Please note that there is no publicly available official documentation for this particular piece of hardware, and it uses its own custom host controller interface rather than a standard one such as EHCI. Therefore, this driver was written on a best-effort basis using several sources to gleam the necessary hardware details, including the extremely complicated and difficult to understand vendor-provided Linux driver.

This file implements the Host Controller Driver Interface defined in usb_hcdi.h. Most importantly, it implements a function to power on and start the host controller (hcd_start()) and a function to send and receive messages over the USB (hcd_submit_xfer_request()).

The DWC is controlled by reading and writing to/from memory-mapped registers. The most important registers are the host channel registers. On this particular hardware, a "host channel", or simply "channel", is a set of registers to which software can read and write to cause transactions to take place on the USB. A fixed number of host channels exist; on the Raspberry Pi there are 8. From the software's perspective, transactions using different host channels can be executed at the same time.

Some of the host channel registers, as well as other registers, deal with interrupts. This driver makes use heavy of these and performs all USB transfers in an interrupt-driven manner. However, due to design flaws in this hardware and in USB 2.0 itself, "interrupt" and "isochronous" transfers still need to make use of software polling when checking for new data, even though each individual transfer is itself interrupt-driven. This means that, for example, if your USB mouse specifies a polling rate of 100 times per second, then it will, unfortunately, be polled 100 times per second in software. For more detail about how interrupts can be controlled on this particular hardware, see the comment above dwc_setup_interrupts().

Another important concept is the idea of "packets", "transactions", and "transfers". A USB transfer, such as a single control message or bulk request, may need to be split into multiple packets if it exceeds the endpoint's maximum packet size. Unfortunately, this has to be dealt with explicitly in this code, as this hardware doesn't do it for us. But at least, from the viewpoint of this software, a "transaction" is essentially the same as a "packet".

The "On-The-Go" in the name of this hardware means that it supports the USB On-The-Go protocol, which allows it to act either as a host or a device. However, we only are concerned with it acting as a host, which simplifies our driver.

To simplify the USB core software, a useful design technique (as recommended by the USB 2.0 standard and used in other implementations such as Linux's) is to have the HCD present the root hub as a standard USB hub, even if the root hub is integrated with the host controller and does not appear as a standard hub at the hardware level. This is the case with the DWC, and we implement this design. Therefore, some code in this file deals with faking requests sent to the root hub.

Enumeration Type Documentation

Internal transfer status codes used to simplify interrupt handling.

Function Documentation

usb_status_t hcd_start ( void  )

Implementation of hcd_start() for the DesignWare Hi-Speed USB 2.0 On-The-Go Controller. See usb_hcdi.h for the documentation of this interface of the Host Controller Driver.

Returns
::USB_STATUS_SUCCESS on successful intitialization of the HCD; otherwise, return ::USB_STATUS_HARDWARE_ERROR or ::USB_STATUS_OUT_OF_MEMORY
void hcd_stop ( void  )

Implementation of hcd_stop() for the DesignWare Hi-Speed USB 2.0 On-The-Go Controller. See usb_hcdi.h for the documentation of this interface of the Host Controller Driver.

usb_status_t hcd_submit_xfer_request ( struct usb_xfer_request *  req)

Implementation of hcd_submit_xfer_request() for the DesignWare Hi-Speed USB 2.0 On-The-Go Controller. See usb_hcdi.h for the documentation of this interface of the Host Controller Driver.

Returns
::USB_STATUS_SUCCESS after successful sending of mailbox message, ::SYSERR if failure within mailboxSend()

This Host Controller Driver implements this interface asynchronously, as intended. Furthermore, it uses a simplistic scheduling algorithm where it places transfer requests into a single queue and executes them in the order they were submitted. Transfers that need to be retried, including periodic transfers that receive a NAK reply and split transactions that receive a NYET reply when doing the Complete Split transaction, are scheduled to be retried at an appropriate time by separate code that shortcuts the main queue when the timer expires.

Jump to dwc_schedule_xfer_requests() to see what happens next.