2003-08-13 00:36:24 +04:00
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.
2003-08-14 21:58:13 +04:00
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).
2003-08-13 00:36:24 +04:00
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
2003-11-01 15:20:43 +03:00
USB Stack class will create an instance of the BusManager class: the class that manages a bus. This
class will continue to control the host controller and it will do the hw_start() method that it provided
via de module struct. The host controller will do the proper initialisation.
BASIC OPERATION
After all host controllers have been registered and prepared to go, the BusManager will spawn
a thread that will keep exploring the device tree. The thread called 'usb_main_thread' will continually
pull all devices and hubs in order to see if there are any changes to the device tree, and, if so, will
communicate this to the device tree.
DEVICES AND HOW THEY'RE MANAGED
The Busmanager keeps an internal tree of all the devices. A single device is represented by the
Device class. This class is inherited by the Hub class. Hubs are also devices,
but they can contain children and therefore are a special case. The root hub is represented as a
Hub too, but the host controller itself will decide on how to handle messages sent to it.
2003-08-13 00:36:24 +04:00
THE UHCI CONTROLLER
==============
BASIC THEORY OF OPERATION
2003-08-14 21:58:13 +04:00
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???