USB Subsystem
The USB subsystem provides support for Universal Serial Bus devices across all major host controller standards. It handles controller enumeration, device discovery, descriptor parsing, class driver management, and data transfers for keyboards, mice, storage devices, and more.
Architecture Overview
The USB subsystem is organized into three layers:
- USB Core (
usb_core.c) — Device enumeration, address allocation, descriptor parsing, and class driver matching. - Host Controller Drivers (HCDs) — UHCI, OHCI, EHCI, and xHCI drivers that translate generic USB operations into controller-specific hardware register programming.
- Class Drivers — USB HID (keyboards, mice) and USB Mass Storage (flash drives, external HDDs).
Initialization Flow
usb_init()
→ pci_enumerate() // Scan PCI bus for USB controllers
→ usb_probe_controller() // Allocate controller, map MMIO, call HCD init
→ usb_enumerate_ports() // For each port: detect device, reset, enumerate
→ usb_enumerate_device() // Assign address, read descriptors, set config
→ usb_match_class_driver() // Match interface to HID/MSC/other driver
Key Data Structures
The core structures are defined in fern/src/include/usb/usb.h:
usb_controller_t— Represents a USB host controller. Contains the PCI device, base address, port count, device table, and an ops vtable (usb_controller_ops_t) for controller-specific operations.usb_device_t— Represents an enumerated USB device. Holds vendor/product IDs, speed, configurations, endpoints, and HCD-specific data.usb_class_driver_t— A class driver registered with the core, matched by class/subclass/protocol.usb_controller_ops_t— Function pointer table (vtable) that each HCD implements:init,shutdown,reset_port,control_transfer,bulk_transfer,interrupt_transfer,poll.
PCI Discovery
The USB core scans the PCI bus during initialization looking for devices with class code 0x0C (Serial Bus Controller) and subclass 0x03 (USB). The programming interface byte identifies the controller type:
| prog_if | Controller |
|---|---|
| 0x00 | UHCI |
| 0x10 | OHCI |
| 0x20 | EHCI |
| 0x30 | xHCI |
Build Configuration
USB components are gated by ENABLE_USB and per-controller flags in fern/build/features/usb.mk. Setting ENABLE_USB=no excludes the entire USB subsystem. Individual controllers and class drivers can also be excluded independently. QEMU support is available via QEMU_USB=yes, which appends -device usb-ehci to the QEMU options.
UHCI (Universal Host Controller Interface)
Source: fern/src/usb/uhci.c · Header: fern/src/include/usb/uhci.h
UHCI is the simplest USB controller standard, designed for USB 1.0/1.1. It was created by Intel and uses an I/O port-based interface with a software-managed frame list.
Register Layout
UHCI uses 16-bit I/O ports at a base address read from PCI BAR4. Key registers:
| Register | Offset | Size | Purpose |
|---|---|---|---|
| USBCMD | 0x00 | 16 | Run/Stop, Host Controller Reset |
| USBSTS | 0x02 | 16 | Interrupt status, halted state |
| USBINTR | 0x04 | 16 | Interrupt enable bits |
| FRNUM | 0x06 | 16 | Current frame number |
| FRBASEADD | 0x08 | 32 | Frame list physical address |
| SOFMOD | 0x0C | 8 | Start-of-Frame timing |
| PORTSC1 | 0x10 | 16 | Port 1 status/control |
| PORTSC2 | 0x12 | 16 | Port 2 status/control |
Initialization
uhci_init() performs:
- Allocates
uhci_data_t(controller-specific state). - Disables BIOS legacy support by writing to PCI config register 0xC0.
- Performs a global reset followed by a host controller reset.
- Allocates a 1024-entry frame list (4KB aligned).
- Allocates a pool of 256 Transfer Descriptors (TDs) from a pre-allocated pool.
- Programs the frame list base address and enables interrupts.
- Starts the controller by setting the Run bit.
- Auto-detects the number of ports by probing port status registers.
Transfer Mechanism
UHCI uses Transfer Descriptors (TDs) linked into a frame list. Each TD is 16 bytes and 16-byte aligned. The controller processes one TD per frame (1ms interval).
Control transfers are implemented as a three-phase operation:
- SETUP stage — TD with SETUP PID (0x2D), 8-byte setup packet.
- DATA stage — One or more TDs with IN/OUT PID, data toggle alternates.
- STATUS stage — Final TD in the opposite direction of data.
For each phase, a TD is placed into frame list entry 0, polled until the Active bit clears, then freed. The driver checks error bits (Stall, Babble, CRC/Timeout, etc.) to determine transfer success.
Bulk transfers follow the same pattern but without the SETUP phase. Data is chunked into max-packet-size segments with alternating data toggles.
Interrupt transfers are currently implemented as bulk transfers (a TODO note indicates proper periodic scheduling should be added).
Speed Detection
UHCI only supports low-speed (1.5 Mbps) and full-speed (12 Mbps) devices. The LSDA (Low Speed Device Attached) bit in the port status register determines the speed.
OHCI (Open Host Controller Interface)
Source: fern/src/usb/ohci.c · Header: fern/src/include/usb/ohci.h
OHCI is a more hardware-assisted USB 1.0 controller interface. Unlike UHCI, OHCI manages its own scheduling via a Host Controller Communication Area (HCCA) in memory.
Memory-Mapped Interface
OHCI uses MMIO registers at the base address read from PCI BAR0. The register space is divided into a revision register, control/status registers, and a root hub section.
HCCA (Host Controller Communication Area)
The HCCA is a 256-byte, 256-byte aligned structure containing:
- Interrupt table — 32 Endpoint Descriptor (ED) pointers for periodic interrupt transfers.
- Frame number — Current frame number written by hardware.
- Done head — Completed Transfer Descriptors (TDs) linked by hardware.
Endpoint and Transfer Descriptors
OHCI separates endpoint configuration from transfer descriptors:
- Endpoint Descriptor (ED) — 16 bytes, 16-byte aligned. Contains device address, endpoint number, direction, speed, max packet size, and head/tail TD pointers.
- Transfer Descriptor (TD) — 16 bytes, 16-byte aligned. Contains buffer pointer, transfer length, condition code, and next-TD pointer.
EDs are organized into three lists:
- Control list — For control transfers (head pointer in HcControlHeadED).
- Bulk list — For bulk transfers (head pointer in HcBulkHeadED).
- Periodic list — For interrupt transfers (EDs linked through the interrupt table in the HCCA).
Initialization
ohci_init() performs:
- Maps MMIO registers.
- Reads the OHCI revision register (expects 1.0a).
- Allocates the HCCA (256-byte aligned).
- Allocates ED and TD pools (16-byte aligned).
- Takes ownership from SMM (System Management Mode) if needed.
- Performs a hardware reset (sets HCFS to Reset, issues HCR).
- Programs the frame interval (default 11999 bit times for 1ms frames).
- Enables control, bulk, and periodic lists.
- Powers on root hub ports.
- Reads port count from HcRhDescriptorA.
Transfer Execution
For control transfers:
- Allocate an ED and chain of TDs: setup, data (optional), status, and a dummy TD as the tail.
- Program the ED with device address, endpoint, max packet size, and speed.
- Link TDs: setup → data → status → dummy.
- Write the ED address to HcControlHeadED and set the Control List Filled bit.
- Poll the HCCA done head until the status TD's condition code is no longer
NOTACCESSED.
For bulk transfers, the same pattern uses the bulk list (HcBulkHeadED).
Condition Codes
OHCI reports transfer completion via condition codes in the TD status field:
| Code | Meaning |
|---|---|
| 0 | No Error |
| 1 | CRC Check Error |
| 2 | Bit Stuffing Error |
| 3 | Data Toggle Mismatch |
| 4 | Stall |
| 5 | Device Not Responding |
| 6-9 | PID/Data errors |
| 14 | Not Accessed (pending) |
EHCI (Enhanced Host Controller Interface)
Source: fern/src/usb/ehci.c · Header: fern/src/include/usb/ehci.h
EHCI provides USB 2.0 High-Speed (480 Mbps) support. It introduces two scheduling mechanisms: an asynchronous schedule for control and bulk transfers, and a periodic schedule for interrupt and isochronous transfers.
Register Layout
EHCI uses a capability/operational register split. The capability registers at BAR0 provide basic parameters, and the operational registers at BAR0 + CAPLENGTH provide control.
Capability registers:
| Register | Offset | Purpose |
|---|---|---|
| CAPLENGTH | 0x00 | Operational register offset |
| HCSPARAMS | 0x04 | Port count, companion controllers |
| HCCPARAMS | 0x08 | 64-bit capable, extended capabilities |
Operational registers:
| Register | Offset | Purpose |
|---|---|---|
| USBCMD | 0x00 | Run/Stop, Schedule enables |
| USBSTS | 0x04 | Status, Halted |
| USBINTR | 0x08 | Interrupt enables |
| FRINDEX | 0x0C | Frame index |
| PERIODICLISTBASE | 0x14 | Frame list physical address |
| ASYNCLISTADDR | 0x18 | Async schedule head |
| CONFIGFLAG | 0x40 | Port routing |
| PORTSC+4*n | 0x44+ | Port status/control |
Initialization
ehci_init() performs:
- Reads capability registers to determine port count, companion controllers, and extended capabilities.
- Takes ownership from BIOS via the USB Legacy Support extended capability (EECP).
- Performs a host controller reset.
- Allocates a 1024-entry frame list (4KB aligned).
- Allocates QH and QTD pools (32-byte aligned) using a custom aligned allocation helper.
- Sets up the async schedule head (a QH pointing to itself, configured as the Head of Reclamation).
- Initializes the periodic frame list with terminated entries.
- Programs the frame list base and async list address.
- Enables periodic and async schedules, then starts the controller.
- Sets the Configure Flag to route ports to EHCI.
- Powers on all ports.
Queue Heads and Transfer Descriptors
EHCI uses Queue Heads (QHs) and Queue Transfer Descriptors (QTDs), both 32-byte aligned:
- QH (48 bytes) — Contains endpoint characteristics, endpoint capabilities, and a transfer overlay area that mirrors the currently executing QTD.
- QTD (32 bytes) — Contains next/alternate TD pointers, token (PID, byte count, status), and up to 5 buffer pointers for page-spanning transfers.
Scheduling
Async schedule (control and bulk):
- A circular linked list of QHs.
- The async head is a special QH with the Head of Reclamation flag, pointing to itself.
- New transfers are inserted into the circular list by updating the horizontal link pointers.
- The controller processes QHs in round-robin fashion.
Periodic schedule (interrupt and isochronous):
- A 1024-entry frame list where each entry points to a QH or ITD.
- Interrupt transfers are currently implemented as bulk transfers (TODO: proper periodic scheduling).
BIOS Ownership Handoff
EHCI implements the BIOS/OS handoff protocol via the USB Legacy Support extended capability. The driver:
- Reads the legacy support register at the EECP offset in PCI config space.
- If the BIOS-owned bit is set, writes the OS-owned bit.
- Polls until the BIOS-owned bit clears (with a timeout).
Companion Controller
EHCI only handles high-speed devices. Low-speed and full-speed devices are handed to companion controllers (UHCI/OHCI) by setting the Port Owner bit in the port status register.
xHCI (eXtensible Host Controller Interface)
Source: fern/src/usb/xhci.c · Header: fern/src/include/usb/xhci.h
xHCI is the modern USB 3.0/3.1 host controller interface, supporting SuperSpeed (5 Gbps) and SuperSpeed+ (10 Gbps). It uses a ring-based architecture instead of linked lists.
Register Layout
xHCI has four register spaces:
- Capability registers (BAR0) — Controller parameters.
- Operational registers (BAR0 + CAPLENGTH) — Controller control.
- Runtime registers (BAR0 + RTSOFF) — Interrupter management.
- Doorbell registers (BAR0 + DBOFF) — Per-slot doorbells for ringing the host controller.
Memory Structures
xHCI requires several memory-mapped data structures:
- DCBAA (Device Context Base Address Array) — 64-byte aligned array of pointers to device contexts.
- Command Ring — Circular ring of Transfer Request Blocks (TRBs) for host commands.
- Event Ring — Circular ring of TRBs for host events (command completion, transfer events, port changes).
- ERST (Event Ring Segment Table) — Describes event ring segments.
- Transfer Rings — Per-endpoint rings for data transfers.
- Device Contexts — Per-device structures containing slot and endpoint contexts.
- Scratchpad Buffers — Optional buffers for controller use (allocated if required by HCSPARAMS2).
Initialization
xhci_init() performs:
- Reads capability registers for max slots, ports, interrupters, context size, and page size.
- Performs a host controller reset (stop, wait for halt, set HCRST, wait for clear).
- Sets the number of enabled device slots.
- Allocates the DCBAA (64-byte aligned).
- Allocates scratchpad buffers if required.
- Allocates command and event rings with link TRBs.
- Sets up the Event Ring Segment Table and interrupter 0.
- Starts the controller and enables interrupts.
Device Addressing
xHCI uses a slot-based model instead of simple USB addresses:
- Enable Slot — Send an Enable Slot command to allocate a device slot.
- Address Device — Build an input context with slot and EP0 endpoint contexts, then send an Address Device command. The DCBAA[slot] is updated with the output device context.
- Configure Endpoint — Send a Configure Endpoint command to enable additional endpoints.
Transfer Rings
Each endpoint gets its own transfer ring. Transfers are described by TRBs:
- Normal TRB — Bulk and interrupt transfers.
- Setup Stage TRB — Control setup phase.
- Data Stage TRB — Control data phase.
- Status Stage TRB — Control status phase.
- Link TRB — Wraps around the ring.
TRBs are 16 bytes and 16-byte aligned. The ring uses a cycle bit to distinguish new TRBs from old ones.
Command and Event Processing
Commands are submitted by writing a TRB to the command ring and ringing doorbell 0. The driver polls the event ring for command completion events.
Events are consumed by checking the cycle bit, then dispatching based on the TRB type (Transfer Event, Command Completion, Port Status Change, etc.).
Port Reset
xHCI supports both standard reset (USB 2.0) and warm reset (USB 3.0). The driver detects the port speed from the port status register and issues the appropriate reset type.
USB HID (Human Interface Device)
Source: fern/src/usb/usb_hid.c · Header: fern/src/include/usb/usb_hid.h
The HID driver supports USB keyboards and mice using the boot protocol. It translates USB HID scancodes into Linux input event codes and integrates with the input event subsystem.
Driver Registration
The HID class driver registers with class code 0x03 (HID) and matches all subclasses and protocols. During probe, it detects the device type from the interface descriptor's subclass (Boot) and protocol (Keyboard=0x01, Mouse=0x02).
Keyboard Support
Boot protocol report (8 bytes):
| Offset | Field | Description |
|---|---|---|
| 0 | modifiers | Modifier key bitmap (Ctrl, Shift, Alt, GUI) |
| 1 | reserved | Always 0 |
| 2-7 | keycodes | Up to 6 simultaneous keycodes |
The driver maintains a keys_pressed[256] array to track key state across reports. When a keycode appears in the current report but not the previous, it's a key press. When a keycode disappears, it's a release.
Modifier handling:
- The driver emits separate modifier change events when the modifier byte changes between reports.
- Modifiers are mapped to Linux keycodes (e.g., Left Ctrl = 29, Left Shift = 42).
LED control:
- Caps Lock, Num Lock, and Scroll Lock toggle LEDs via
SET_REPORT. - LED state is maintained per-device and sent to the keyboard when toggled.
Scancode conversion:
- USB HID usage codes (0x04-0x65) are mapped to Linux keycodes via the
hid_usage_to_linuxtable. - ASCII conversion uses
scancode_to_ascii_lower/uppertables, accounting for Shift and Caps Lock.
Mouse Support
Boot protocol report (3+ bytes):
| Offset | Field | Description |
|---|---|---|
| 0 | buttons | Left, Right, Middle button bits |
| 1 | x | X movement (-127 to 127) |
| 2 | y | Y movement (-127 to 127) |
| 3 | wheel | Scroll wheel (IntelliMouse extension) |
The driver maintains absolute mouse position clamped to screen bounds (configurable via usb_hid_mouse_set_bounds). Movement deltas are computed and dispatched as EV_REL events.
Input Event Integration
Events are dispatched through two paths:
- devfs —
devfs_kbd_queue_eventanddevfs_mouse_queue_eventfor userspace consumption via/dev/input. - input_mux —
input_mux_dispatch_eventfor kernel-level input routing. - Hotkey system — F1-F12 keys are forwarded to
hotkey_process_key_eventfor media keys and system shortcuts.
Polling
usb_hid_poll() is called from the USB core's usb_poll() function. For each registered HID device, it performs an interrupt transfer on the interrupt IN endpoint and processes the report.
USB Mass Storage
Source: fern/src/usb/usb_mass_storage.c · Header: fern/src/include/usb/usb_mass_storage.h
The Mass Storage driver implements the USB Mass Storage Class Bulk-Only (BBB) Transport protocol, supporting flash drives, external HDDs, and optical drives.
BBB Protocol
The Bulk-Only Transport uses three phases:
- Command Phase — Host sends a 31-byte Command Block Wrapper (CBW) containing the SCSI command.
- Data Phase — Optional data transfer via bulk IN or OUT endpoint.
- Status Phase — Host reads a 13-byte Command Status Wrapper (CSW) indicating success/failure.
CBW and CSW Structures
Command Block Wrapper (31 bytes):
| Field | Size | Description |
|---|---|---|
| Signature | 4 | Magic: 0x43425355 ("USBC") |
| Tag | 4 | Transaction tag (matched in CSW) |
| DataTransferLength | 4 | Bytes to transfer in data phase |
| Flags | 1 | Direction (bit 7: 0=OUT, 1=IN) |
| LUN | 1 | Logical Unit Number (bits 0-3) |
| CBLength | 1 | Command block length (1-16) |
| CB | 16 | SCSI command block |
Command Status Wrapper (13 bytes):
| Field | Size | Description |
|---|---|---|
| Signature | 4 | Magic: 0x53425355 ("USBS") |
| Tag | 4 | Must match CBW tag |
| DataResidue | 4 | Difference between expected and actual transfer |
| Status | 1 | 0=Passed, 1=Failed, 2=Phase Error |
SCSI Command Set
The driver translates high-level block I/O operations into SCSI commands sent via the BBB protocol:
| Operation | SCSI Command |
|---|---|
| Test Unit Ready | TEST UNIT READY (0x00) |
| Inquiry | INQUIRY (0x12) |
| Read Capacity (10) | READ CAPACITY(10) (0x25) |
| Read Capacity (16) | SERVICE ACTION IN(16) (0x9E) |
| Read Blocks (10) | READ(10) (0x28) |
| Read Blocks (16) | READ(16) (0x88) |
| Write Blocks (10) | WRITE(10) (0x2A) |
| Write Blocks (16) | WRITE(16) (0x8A) |
| Request Sense | REQUEST SENSE (0x03) |
| Synchronize Cache | SYNCHRONIZE CACHE(10) (0x35) |
Device Initialization
usb_msc_configure_device() probes each LUN (up to max_lun):
- Issue TEST UNIT READY (retry up to 3 times, with REQUEST SENSE between retries).
- Issue INQUIRY to get vendor, product, and device type.
- Wait for the device to become ready.
- Issue READ CAPACITY to determine total blocks and block size.
- For drives reporting 0xFFFFFFFF last LBA, fall back to READ CAPACITY(16).
LUN Support
The driver supports up to 16 LUNs per device. Each LUN is tracked independently with its own capacity, block size, vendor/product strings, and present/removable status.
Error Recovery
If a CSW indicates a phase error or the transfer fails, the driver performs a Bulk-Only Mass Storage Reset Recovery:
- Issue Bulk-Only Mass Storage Reset (class request 0xFF).
- Clear HALT on the bulk IN endpoint.
- Clear HALT on the bulk OUT endpoint.
USB Device Enumeration
Device enumeration is handled by usb_enumerate_device() in usb_core.c. The process:
- Read device descriptor (8 bytes) — Gets the max packet size for endpoint 0.
- Set address — Assigns a unique address (1-127) via
SET_ADDRESS. - Read full device descriptor — Gets vendor ID, product ID, class, subclass, protocol, and configuration count.
- Read configuration descriptors — Reads the first configuration, including all interface and endpoint descriptors.
- Set configuration — Activates the first configuration via
SET_CONFIGURATION. - Match class drivers — Iterates registered class drivers, matching on class/subclass/protocol. The first matching driver's
probe()function is called.
Descriptor Parsing
Descriptor types are defined as:
| Type | Value | Description |
|---|---|---|
| Device | 0x01 | Device descriptor (18 bytes) |
| Configuration | 0x02 | Configuration descriptor (9 bytes header + interfaces) |
| String | 0x03 | String descriptor (variable length UTF-16) |
| Interface | 0x04 | Interface descriptor (9 bytes) |
| Endpoint | 0x05 | Endpoint descriptor (7 bytes) |
| HID | 0x21 | HID descriptor |
| Report | 0x22 | HID Report descriptor |
Setup Packet
All control transfers use a standard 8-byte setup packet:
| Field | Size | Description |
|---|---|---|
| bmRequestType | 1 | Direction, type, recipient |
| bRequest | 1 | Request code |
| wValue | 2 | Request-specific value |
| wIndex | 2 | Request-specific index |
| wLength | 2 | Data transfer length |
Transfer Types
Control Transfers
Used for device configuration and standard requests. Always on endpoint 0. Three phases: SETUP, DATA (optional), STATUS. All HCDs implement control_transfer().
Bulk Transfers
Used for large, non-time-critical data (e.g., mass storage). No guaranteed bandwidth. Transfers are chunked into max-packet-size segments. HCDs implement bulk_transfer().
Interrupt Transfers
Used for periodic, low-latency data (e.g., HID devices). The HID driver polls interrupt IN endpoints periodically. In UHCI/OHCI/EHCI, interrupt transfers are currently implemented as bulk transfers (with TODO notes for proper periodic scheduling). xHCI handles them similarly to bulk.
Isochronous Transfers
Used for streaming data (e.g., audio, video). Guarantees bandwidth but no error correction. Currently not implemented in the driver (marked as TODO).
Host Controller Management
Controller Linked List
Controllers are stored in a singly-linked list (g_controllers). Each controller's next pointer links to the next controller. The USB core traverses this list during usb_poll() and usb_shutdown().
MMIO Mapping
For MMIO-based controllers (OHCI, EHCI, xHCI), the base address is identity-mapped into both the kernel page directory and the active page directory. During usb_poll(), the driver ensures MMIO mappings are present in the active page directory, handling task switches correctly.
Pointer Validation
The USB core validates controller pointers before operations to detect corruption:
- Checks that the pointer falls within the kernel heap range.
- Verifies alignment.
- Validates the controller type enum.
- Caps port count at 64.
If corruption is detected, the poll loop is quarantined to prevent cascading failures.
Ops Repair
If a controller's ops pointer becomes corrupted or points to the wrong type, the core repairs it by looking up the correct ops based on the controller type. This is logged and counted.
Root Hub Management
Each host controller has an integrated root hub with one or more ports. Port operations are delegated to the HCD:
- Reset port — Asserts reset signal for 10-50ms, waits for completion.
- Enable/Disable port — Controls port power and enable state.
- Get port speed — Returns Low/Full/High/Super speed based on line status.
- Port connected — Checks current connect status bit.
EHCI Companion Controller Handoff
EHCI only handles high-speed devices. When a port reset reveals a low-speed or full-speed device, the Port Owner bit is set to hand the port to the companion UHCI/OHCI controller.
xHCI Warm Reset
xHCI distinguishes between USB 2.0 standard reset and USB 3.0 warm reset. The driver reads the port speed to determine which reset type to issue.
Hot-Plug Support
Hot-plug is handled through the USB core's polling mechanism:
Polling
usb_poll() is called periodically (from the timer IRQ context). It:
- Validates all controller pointers and MMIO mappings.
- Calls each controller's
poll()function. - Calls
usb_hid_poll()to read input reports.
Port Change Detection
Each HCD's poll() function checks for port status changes:
- UHCI — Checks Connect Status Change (CSC) bit in port status register.
- OHCI — Checks Root Hub Status Change interrupt and per-port CSC.
- EHCI — Checks Port Change Detect (PCD) status bit and per-port CSC.
- xHCI — Processes Port Status Change events from the event ring.
When a device is detected:
- Port status change bits are cleared (write-1-to-clear).
- The driver logs the connection event.
- The USB core's enumeration flow is triggered.
Device Disconnect
Disconnect detection follows the same path — the CSC bit clears when a device is removed. The driver logs the event. Full disconnect cleanup (class driver disconnect, resource freeing) is a work in progress.
Timer-Context Safety
Since usb_poll() runs from timer IRQ context, the driver takes care to:
- Sync kernel page directory entries to the active task's page directory.
- Validate all pointers before dereferencing.
- Quarantine the USB subsystem if corruption is detected, preventing kernel crashes.
Summary of File Locations
| Component | Source | Header |
|---|---|---|
| USB Core | fern/src/usb/usb_core.c |
fern/src/include/usb/usb.h |
| UHCI | fern/src/usb/uhci.c |
fern/src/include/usb/uhci.h |
| OHCI | fern/src/usb/ohci.c |
fern/src/include/usb/ohci.h |
| EHCI | fern/src/usb/ehci.c |
fern/src/include/usb/ehci.h |
| xHCI | fern/src/usb/xhci.c |
fern/src/include/usb/xhci.h |
| HID | fern/src/usb/usb_hid.c |
fern/src/include/usb/usb_hid.h |
| Mass Storage | fern/src/usb/usb_mass_storage.c |
fern/src/include/usb/usb_mass_storage.h |
| Hub | — | fern/src/include/usb/usb_hub.h |
| Build | fern/build/features/usb.mk |
— |