How USB works

The USB protocol

USB is a polled bus, meaning, the device can't initiate any communication to the host, no, not even interrupts. On being asked by the host, the device responds. There are four ways in which devices can communicate, given in the order in which they are handled.

* Isochronous Transfer - Meant of streaming devices like Video Cameras. (unreliable) * Interrupt Transfer - Short, low latency reliable delivery. * Control Transfer - Meant for configuring the device, etc. * Bulk Transfer - Bulk Transfers.

We'll be mostly dealing with Bulk Transfers as USB NICs use only that.

USB Device Addressing

Every device in a USB bus is given a device address during its configuration time (the time when its detected to be present on the bus). A USB device is made up of a certain number of endpoints. An endpoint is a simplex communication channel that is a source, or sink. It is a unique addressable portion of a USB device. An endpoint is associated with a direction and a type of data transfer. The tuple {device number, end point number, direction} uniquely identifies a source or sink of data. These endpoints have certain characteristics such as MaxPacketSize etc. The endpoints are configured during device probe.

USB NICs are expected to have at least one Bulk IN endpoint and a Bulk OUT endpoint in addition to the Control Endpoint (Number 0) which every device is expected to provide as a basic requirement.

USB Software mainly exists in two places, on a PC (called host) and on a device (called device). We will be mainly deailing with the host part here, in the document.

The host part of the USB mainly revolves around a piece of hardware known as a Host Controller. It is the host controller who sends out bits on the serial bus in the format specified in the USB Specification. Now, the host controller specifications are not covered in the USB specification, whose implementation is left to the hardware vendors, who in turn create specifications for their own product. Examples of Host Controllers are UHCI, EHCI, OHCI among other very less known ones.

We'll look at the UHCI host controller to begin with. It is a simple host controller suporting only Low Speed (1.5 Mbps) and Full Speed (12 Mbps) devices (The other being High Speed operating at 480 Mbps). For a PC, it is mostly available as a PCI device. As usual the UCHI documentation lists all the registers used by the card.

Now, lets see how a Host Controller works. For now, I'll be dealing with UHCI host controller only. So, as we understand, our job, is to tell the host controller to transfer certain data from a memory location to some USB Address on the bus. Here's how we do it with the UHCI host controller.

Working of the UHCI host controller. ( Works with Full Speed (12 Mbps) and Low Speed (1.5 Mbps) only )

Telling what to transfer whom to transfer, and in what direction is done using a data structure called a TD (Trasnfer Descriptor). The structure of a TD is quite obvious looking the schedule shown below in Fig. 4. It points to other TDs and QHs (described ahead).

As seen above, a host controller maintains a list of 'Frames' in system memory, whose address is pointed to by a register called 'Frame List Base Address register'. The list of 'Frames' occupies a page (4K ) space. with each 'Frame' entry being 32 bits wide, we have 1024 'Frame' entries.

The USB defines the idea of a 'Frame'. A frame is a one millisecond time window on the bus which can be used to transfer data. Another register called 'Frame Counter' indexes into the list of Frames to select a particular frame for transfer. In RAM, a Frame is a data structure (32 bits long) which point to a list of TDs (Transfer Descriptors - which contain what, whom, and in which direction to transfer data).

There's the Queue Head (QHs) that remain to be explained. It is a data structure just to organise TDs. It looks like this. It contains feilds which point to a QH or a TD.

Finally, once we know how TDs and QHs are arranged in memory, we'll get to how the Host Controller processes them.The Frame Counter register is incremented every second. It indexes into the Frame list and selects a frame. From the frame, TDs one by one are executed, and their status marked in the TD itself. The TDs can be optionally marked to generate Interrupts on Completion (IOCs). This goes on and on. When interrupts are not available, we can poll for their status and recognize their completion.

How do use this in a USB NIC

Packet Transmission is fairly straight forward. Wrap it in a Device specific header and create a TD for it and put in the host controller schedule.

Packet Reception is not very straight forward. One way I think this can be done is, in the poll method, create as much IN TDs( for receiving data) as the rx queue of the device can accumulate frames . When poll is called again we check for exectued TDs and pass the packet to higher layers, and again we create TDs upto the brim.

And in the poll method itself, we can look at the status of transmitted packets and signal the upper layers about the status of the transaction.

For reading registers related to the NIC, we can use the control endpoint with device specific command and we wait for them to finish.

QR Code
QR Code playground:balajirrao (generated for current page)