# USB An xHCI host controller driver, a device-independent core, and three class drivers. Written from the specification. --- ## Why not ported from BSD "Take the USB stack from BSD" is the obvious plan and it does not survive contact with the code. FreeBSD's `sys/dev/usb` is roughly 100k lines welded to newbus, devclass, `bus_dma`, callouts, taskqueues and FreeBSD's locking primitives, none of which exist here. **Porting it means porting FreeBSD's device framework first and then discovering the USB stack underneath.** NetBSD's is more portable and the same argument applies with a smaller multiplier. The specification is public and the controller is not complicated. > BSD is much more valuable as the reference you check yourself against than as > the code you paste. Licensing points the same way: the BSD stacks are BSD-2/3-clause and compatible, Linux's drivers are GPL-2.0-only and are not — see [../licensing.md](../licensing.md). ## What the spec gives you for free Everything in [`include/usb.h`](../../include/usb.h) comes from USB 2.0 chapter 9, which every device implements regardless of speed, class or vendor. **That is what makes enumeration possible at all:** before you know anything about a device you can still ask it what it is, because the question is standardised. ## The controller `kernel/drivers/bus/xhci/`. The full bring-up path: ``` reset → DCBAA → command ring → event ring → scratchpad → port enumeration → Enable Slot → Address Device → control transfers → configuration and interface descriptors → SET_CONFIGURATION → interrupt and bulk endpoints ``` Rings are producer rings: the driver writes TRBs and the controller reads them, with a Link TRB as the last entry pointing back at the start — which is how a fixed-size buffer becomes an endless queue. 64 TRBs per ring, 16 device slots. ### Enumeration polls; data uses interrupts **And that is not laziness.** `pci_bind_all()` runs from `kmain()` with interrupts disabled and no scheduler, so a driver that waited for an interrupt during probe would wait forever. Interrupts are registered afterwards, for when a device is actually delivering data. ## Class drivers | | | |---|---| | **HID** (`usb/hid/`) | Boot protocol keyboard and mouse, driven from the IRQ handler, feeding the same input paths as PS/2. | | **Mass storage** (`usb/storage/`) | Bulk-only transport and SCSI, presenting a block device. A superblock reads back through `bread()`. | | **Hub** (`usb/hub/`) | Route strings, hub slot contexts, per-port reset and power. | Class drivers are offered a device by the core once its interface descriptor has been read, from the list in `kernel/drivers/registry.c`. Whichever claims it publishes a `struct device` in the bus-agnostic list, **with the class the driver chose rather than the one the descriptor claimed** — the descriptor says what the device says it is, and the driver knows what it made of it. ### What proves the hub works A mouse behind a hub enumerating a tier deep. Hubs are the part of USB where route strings and slot contexts stop being theoretical, and a hub driver that handles only directly-attached devices looks identical to a working one until something is plugged into it. ### The USB HID grab detail The HID path updates its `prev[]` key state **before returning** even when the device is grabbed — otherwise the next report looks like every held key had just been pressed again. See [graphics.md](graphics.md#input) for the grab itself. ## Testing `bootcheck -Usb` attaches an xHCI controller with a keyboard, a mouse and a mass-storage device. **Nothing on the default machine has a USB port**, so without that switch the driver is never asked to do anything and a broken one looks exactly like a working one. `echo u > /proc/sysrq` and `echo s > /proc/sysrq` drive the storage path. --- ## What it does not do - **A USB disk cannot be mounted or booted from.** The block device works and `bread()` reads a superblock off it; the root device is compiled in rather than selectable, so nothing can be told to use it. This is the largest single gap and it is item 1 of [../plan/roadmap.md](../plan/roadmap.md). - **Boot protocol only** for HID. No report descriptor parsing, so anything that is not a plain keyboard or mouse is not understood. - **No isochronous transfers**, so no audio and no cameras. - **No USB 3 SuperSpeed-specific features** beyond what enumeration needs — the USB2 and USB3 descriptor paths both work, the rest of the difference is unused. - **16 device slots**, compile-time. - **No hot-unplug.** A device removed is not noticed; the device model has no removal path either. - **One controller.** A second xHCI card would bind and then contend for state the driver keeps per-driver rather than per-instance.