Open Host Controller Interface

From OSDev Wiki
Jump to navigation Jump to search

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.

Technical Details

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:

Offset (Hex) Name
00 HcRevision
04 HcControl
08 HcCommandStatus
0c HcInterruptStatus
10 HcInterruptEnable
14 HcInterruptDisable
18 HcHCCA
1c HcPeriodCurrentED
20 HcControlHeadED
24 HcControlCurrentED
28 HcBulkHeadED
2c HcBulkCurrentED
30 HcDoneHead
34 HcFmInterval
38 HcFmRemaining
3c HcFmNumber
40 HcPeriodicStart
44 HcLSThreshold
48 HcRhDescriptorA
4c HcRhDescriptorB
50 HcRhStatus

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.

PCI Configuration

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.

Shared Memory Linked Lists

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

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.

Bulk Messages

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.

Endpoint Descriptors

An Endpoint Descriptor is a memory structure that contains information used to communicate with a specific endpoint on a specific device address.

Offset (Hex) Name
00 Control
04 Tail TD Address
08 Head TD Address
0c Next ED Address

Transfer Descriptors

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.)

Offset (Hex) Name
00 Control
04 First Byte Address
08 Next TD Address
0c Last Byte Address