Open Host Controller Interface
The Open Host Controller Interface (OHCI) is an open standard that defines the interfaces between certain USB and Firewire drivers, hardware controllers, and devices. It was originally published by Compaq, Microsoft and National Semiconductor in 1999. Along with the Universal Host Controller Interface (UHCI), the OHCI makes up the USB 1.0 hardware controller interface standard.
According to the OHCI standard, the OHCI driver communicates with the OHCI controller using two primary methods: Memory Mapped Registers, and Shared Memory Linked Lists.
The OHCI defines 21 memory mapped registers, exposed through BAR0:
In addition to these registers, starting at offset 54h, each USB port on the root hub is assigned an HcRhPortStatus register that denotes the current status of the port.
The memory mapped registers listed above are not fixed in memory, and may be located at any 32-bit address regardless of how much memory is installed on the machine. To find the base register address, the PCI bus can be searched for a specific vendor/device id, or a specific Class ID to find any OHCI controllers. All OHCI controllers will have a Class ID of 0x0Ch, a subclass of 0x03h, and a program interface value of 0x10h. The PCI device configuration area contains a single Base Address that points to the memory mapped register block.
All commands and data packets are supplied to the controller via a shared memory area containing tables and linked lists. The USB protocol defines 4 different message types: Interrupt, Isochronous, Control and Bulk. Each message type is given its own linked list of outgoing messages. As the controller processes these messages, they are moved to a corresponding "done" list, along with information concerning any errors encountered by the controller while delivering the message.
Control messages are used to initialize and configure a device that has been detected by a hub. Devices that have not been initialized will not respond to any control messages. To initialize a device, the hub port that the device is connected to must be reset. Upon reset, the device will default to address 0, and will begin responding to any control messages sent to that address. You should ensure that only one device is initialized at a time, and once the device's port has been reset, you should immediately send a SetAddress command to assign an unused address between 1 and 127 to the device. Once this command has been sent, the device will begin responding to its new address, and will no longer respond to address 0.
The HcControlHead register points to the first control Endpoint Descriptor (ED) in a linked list of Endpoint Descriptors. Each Endpoint Descriptor describes one endpoint on the USB bus that can be communicated with by the operating system. To send or receive data from an endpoint, a Transfer Descriptor is added to an Endpoint Descriptor by the operating system. Once the data has been transferred, the controller will move the Transfer Descriptor from the Endpoint Descriptor to the Done Queue.
Each Endpoint Descriptor has a "head" Transfer Descriptor field and a "tail" Transfer Descriptor field, as well as a "next" Endpoint Descriptor field. The final Endpoint Descriptor in the Endpoint Descriptor chain will have a "next" Endpoint Descriptor value of zero. When the "head" Transfer Descriptor matches the "tail" Transfer Descriptor, the Endpoint Descriptor is empty, and no more data will be sent.
The Endpoint Descriptors in the HcControlHead list can only be used to communicate with Control endpoints. All devices have a control endpoint 0 that is used to configure the device.
The HcBulkHeadED register points to the first bulk Endpoint Descriptor in the bulk endpoint descriptor list, and is used to send and receive bulk data packets. Otherwise, it is functionally identical to the HcControlHead register.
An Endpoint Descriptor is a memory structure that contains information used to communicate with a specific endpoint on a specific device address.
|04||Tail TD Address|
|08||Head TD Address|
|0c||Next ED Address|
Transfer Descriptors describe a memory buffer to be sent to, or read from, a (non-isochronous) USB endpoint. (Isochronous endpoints use a different descriptor structure.)
|04||First Byte Address|
|08||Next TD Address|
|0c||Last Byte Address|