haiku/docs/develop/kernel/USB_stack_design

77 lines
5.6 KiB
Plaintext

THE USB STACK
==========
The USB stack will follow the same design as the BeOS R5 stack. This implies that:
- There's a bus manager called the 'usb' manager - this file also contains the usb module
- This usb module will control other modules that implement the communication with the host controller
- These modules are the UHCI, EHCI and OHCI modules
- There will be support for RAW usb device handling in later stages of development
- The public API (for drivers) will be compatible with the API of BeOS R5
THE CORE OF THE MATTER: THE USB BUS MODULE
==============================
I'm a little confused whether or not to make the internals of the USB stack in C++, but eventually
I decided to do that, because it makes the whole thing clearer. This does mean that there still needs
to be some C-glue between the modules of the stack, because the OBOS kernel doesn't support
dynamic libraries. The core data of the USB stack is stored in a class called 'Stack'. On init of the
stack one global variable is created with the name 'data'.
The data struct is protected by one master lock called 'master'. This lock should be gained by
every thread that reads or writes in the 'data' struct.
The USB stack will support multiple host controllers. The USB specification says this is enough, however, there will possibly systems with more controllers. Between the usb core and the host controller driver (essentially another module), is a private api (that will be documented for future additions of host controllers).
DEVICES AND HOW THEY'RE MANAGED
The stack keeps an internal tree of all the devices. A single device is represented by the Device
class. This class is inherited by the RootHub and Hub classes. Hubs are also devices,
but they can contain children and therefore are a special case. The root hub is even more special,
because there are nonstandard ways of accessing information on these ports.
THE INITIALISATION PHASE
As soon as a device driver calls the usb module, and the module isn't loaded before, a single instance
of the stack class is made. The constructor initialises the object, and it starts the search for host
controllers. All the host controller modules are called, and if there is no hardware present, or the
hardware corresponding to that host controller is malfunctioning, the controller returns B_ERROR. If
there is no controller that works, the USB module will fail to initialise.
If a controller succeeds in initialising the hardware, and the module initialisation succeeds, the
USB Stack class will call the hw_start() call. One of the arguments is a structure with some pointers to
functions that the host controller needs. The host controller will register it's root hub. using the function
register_roothub() and the supplied argument will be a struct that holds some functions (see later what
these functions do).
THE UHCI CONTROLLER
==============
BASIC THEORY OF OPERATION
From: FreeBSD developers handbook
Written by Nick Hibma,. © 2000, 2001, 2002, 2003 by The FreeBSD Documentation Project
"The UHCI host controller maintains a framelist with 1024 pointers to per frame data structures.
It understands two different data types: transfer descriptors (TD) and queue heads (QH). Each TD
represents a packet to be communicated to or from a device endpoint. QHs are a means to
groupTDs (and QHs) together. Each transfer consists of one or more packets. The UHCI driver splits
large transfers into multiple packets. For every transfer, apart from isochronous transfers, a QH is
allocated. For every type of transfer these QHs are collected at a QH for that type. Isochronous
transfers have to be executed first because of the fixed latency requirement and are directly
referred to by the pointer in the framelist. The last isochronous TD refers to the QH for interrupt
transfers for that frame. All QHs for interrupt transfers point at the QH for control transfers, which in
turn points at the QH for bulk transfers.
This results in the following schedule being run in each frame. After fetching the pointer for the
current frame from the framelist the controller first executes the TDs for all the isochronous packets
in that frame. The last of these TDs refers to the QH for the interrupt transfers for thatframe. The
host controller will then descend from that QH to the QHs for the individual interrupt transfers. After
finishing that queue, the QH for the interrupt transfers will refer the controller to the QH for all control
transfers. It will execute all the subqueues scheduled there, followed by all the transfers queued at the
bulk QH. To facilitate the handling of finished or failed transfers different types of interrupts are
generated by the hardware at the end of each frame. In the last TD for a transfer the Interrupt-On
Completion bit is set by the HC driver to flag an interrupt when the transfer has completed. An error
interrupt is flagged if a TD reaches its maximum error count. If the short packet detect bit is set in a
TD and less than the set packet length is transferred this interrupt is flagged to notify the controller
driver of the completed transfer. It is the host controller driver's task to find out which transfer has
completed or produced an error. When called the interrupt service routine will locate all the finished
transfers and call their callbacks."
INITIALISATION
- Reset the host controller (USBCMD)
- Turn on all interrupts( USBINTR)
- Start at frame 0 (FRBNUM)
- Set frame base pointer (FLBASEDDR)
- Start the host controller (USBCMD)
Also, several data structures need to be made:
- Frame list, one page (4096), contains 1024 frame list pointers.
- TODO: what else???