P1 USB 3.x hub correctness verified against codebase:
- packet-size handling (bytes vs shift exponent) in baseline
- HubDescriptorV2/V3 separate reading paths in usbhubd
- Slot context hub bit + port count correctly set
- SET_HUB_DEPTH issued for USB 3 hubs
- TTT not applicable to USB 3 (TT is USB 2.0 split-transaction)
- TODOs about interface_desc/alternate_setting on USB 3 hubs
are safe — passing None matches upstream behavior
P5 Modern USB Scope Decision (ADR):
- Host-only for foreseeable future
- Explicitly excluded: device mode, OTG, USB-C PD, alt-modes,
USB4, Thunderbolt, xHCI DbC
- Reviewed per release branch cut
43 KiB
Red Bear OS USB Implementation Plan — v2
Status: Canonical. Replaces
archived/USB-IMPLEMENTATION-PLAN-v1-2026-04.md. Date: 2026-07-07. Supersession reason: v1 (Apr 2026) overstated several capabilities relative to the then-current source. v2 re-audits every daemon againstlocal/sources/base/HEAD, aligns with Redox 0.x USB HEAD (Jan 2025 – Jun 2026), and reorganizes phases around the actual bare-metal correctness gaps. Validation labels are now source-anchored rather than patch-anchored.Sibling docs:
USB-VALIDATION-RUNBOOK.md(operator path — restored fromarchived/); the olderarchived/USB-BOOT-INPUT-PLAN.mdandarchived/XHCID-DEVICE-IMPROVEMENT-PLAN.mdare kept as historical reference but are not the planning authority.
0. Purpose and scope
This plan is the single planning authority for the USB subsystem in Red Bear OS. It answers four questions honestly:
- What is built? — every host controller, class driver, scheme, and observability tool
that actually exists in
local/sources/base/andlocal/recipes/drivers/. Status is derived from the current source tree, not from prior memory or from patch carriers. - What was patched? — every durable Red Bear modification, with file paths
(
local/patches/base/P*.patchfor the base module, dedicated local recipes or forks otherwise). - What is actually usable? — explicitly distinguishes builds, enumerates, usable (narrow path), validated (QEMU), validated (real hardware), and experimental. A label is only ever validated if the matching proof has run on the matching artifact under the matching config.
- What is missing? — the real bare-metal-blockers, the upstream-comparable gaps, the architectural decisions still deferred, and the durability problems that this plan owns.
Validation labels (canonical, do not redefine elsewhere)
- builds — code is in tree and compiles. Not a usability claim.
- enumerates — runtime surfaces can discover controllers, ports, descriptors.
- usable (narrow path) — one controller family / one class family works in a bounded, repeatable scenario; other paths are likely broken.
- validated (QEMU) — a documented QEMU script passed on the matching recipe, config, and commit. Reproducible on a Linux x86_64 host.
- validated (real hardware) — a named physical controller + class, with a captured log, on real bare metal. This is what an end user can expect.
- experimental — present for bring-up but not in any support-promised path.
Honesty rule. builds is not equivalent to usable. validated (QEMU) is not
equivalent to validated (real hardware). The plan never mixes these categories. Where
prior text conflated them, this v2 corrects.
Plan structure
| Section | Authority | Updates cadence |
|---|---|---|
| §1 Source audit (controllers, class drivers, schemes, tooling) | ground truth | on every source-tree bump |
| §2 Patch carriers | every durable Red Bear diff | on every patch add/rebase |
| §3 Status matrix (one row per component) | single source of truth for "is it working" | on every status change |
| §4 Upstream divergence: what Redox 0.x USB HEAD has that we have not | required adoption list | on every upstream bump |
| §5 Bare-metal input correctness (boot-time USB keyboard) | the bare-metal failure modes | on every controller or class change |
| §6 Phase P0–P5 (execution order) | who does what next | reviewed monthly |
| §7 Validation inventory and bounded proofs | the proof surfaces | on every script add/break |
| §8 Durability posture | local fork health, patch carriers, archival policy | on every base fork bump |
| §9 Support language | how the rest of Red Bear should describe USB | on every phase change |
1. Source audit — what is actually in the tree
Red Bear follows the upstream Redox model: all USB logic is in userspace (drivers/usb/
plus local/recipes/drivers/usb-core/). The kernel exposes irq:, memory:, pcid:,
event:, and scheme: surfaces that userspace USB daemons consume. There is no kernel USB
host stack, and the v1 phase plan's mention of "kernel MSI/MSI-X plumbing" was a reference
to that surface, not a kernel change.
1.1 Host controllers
| Daemon | Source | Lines | Reality today | Scheme registered |
|---|---|---|---|---|
| xhcid | local/sources/base/drivers/usb/xhcid/ |
~6000 LoC across 25 files | Builds. Real ring/TRB/context/transfer engine. Polling in production (see §1.6). | usb.<pci_name>_xhci |
| ehcid | local/recipes/drivers/ehcid/source/src/ |
~1550 LoC (3 files) | Builds. Real MMIO init, frame list, QH/TD, port reset. No class-driver auto-spawn. | usb |
| uhcid | local/recipes/drivers/uhcid/source/src/main.rs |
35 LoC | Builds. Real stub. Reads PCI BAR4, sleeps forever. No scheme. | — |
| ohcid | local/recipes/drivers/ohcid/source/src/main.rs |
35 LoC | Builds. Real stub. Identical pattern to uhcid. | — |
Honesty corrections vs v1:
- v1 said "EHCI/UHCI/OHCI — ownership, port handling, and logging exist, but they are not yet full runtime enumeration paths". For uhcid and ohcid this is too generous — they are 35-line stubs that only read PCI BAR4 and sleep. They are not even ownership-grade; the controller is never probed, no port state is published, no error is logged past init.
- v1 said "xHCI interrupt-driven operation restored". The current source at
xhcid/src/main.rs:141hardcodes polling:Thelet (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle); //TODO: Fix interrupts.get_int_methodfunction exists, MSI-X/MSI/INTx branches are written, but the function is bypassed at runtime. §4 captures the upstream commits that help finish this.
1.2 Class drivers
| Daemon | Source | LoC | Reality | Notes |
|---|---|---|---|---|
| usbhubd | local/sources/base/drivers/usb/usbhubd/ |
249 | Builds; runs. | Polls port status (1s fallback retained from v1). |
| usbhidd | local/sources/base/drivers/input/usbhidd/ |
576 | Builds; runs. | Named-producer input (usb-{port}-if{n}) + legacy VT fallback. |
| usbscsid | local/sources/base/drivers/storage/usbscsid/ |
~1800 | Builds; runs. | BOT/SCSI, ReadCapacity16, 3 storage quirk flags active. |
| usbctl | local/sources/base/drivers/usb/usbctl/ |
54 | Builds. CLI only. | Minimal — port/endpoint status query. |
| ucsid | local/sources/base/drivers/usb/ucsid/ |
839 | Builds. | USB-C UCSI topology over ACPI + I2C; /scheme/ucsi. |
| redbear-usbaudiod | local/recipes/system/redbear-usbaudiod/ |
(small) | Builds; wired in redbear-mini.toml. |
USB Audio Class 1. |
| redbear-acmd | local/recipes/system/redbear-acmd/ |
(small) | Builds; wired via drivers.d/70-usb-class.toml. |
USB CDC ACM serial. |
| redbear-ecmd | local/recipes/system/redbear-ecmd/ |
(small) | Builds; wired via drivers.d/70-usb-class.toml. |
USB CDC ECM/NCM ethernet. |
| redbear-btusb | local/recipes/drivers/redbear-btusb/ |
(small) | Builds. | Bluetooth USB transport — see BLUETOOTH-IMPLEMENTATION-PLAN. |
1.3 USB core library
| Crate | Source | Notes |
|---|---|---|
| usb-core | local/recipes/drivers/usb-core/source/src/ |
6 files (lib.rs, dma.rs, scheme.rs, spawn.rs, transfer.rs, types.rs). Provides UsbHostController trait, SetupPacket, PortStatus, TransferDirection, DmaBuffer, descriptor parsers, control_transfer, spawn_usb_driver. Used by ehcid. Currently not used by xhcid, uhcid, or ohcid. |
This trait is the most important "infrastructure that already exists" item in this plan: it is the natural target for uhcid/ohcid runtime enumeration (§6 P0-B2) and for any future host port — including the xhcid → USB-core path that future xHCI cleanup will allow.
1.4 Tooling and observability
| Tool | Source | Reality |
|---|---|---|
lsusb |
local/recipes/system/redbear-hwutils/source/src/bin/lsusb.rs |
Walks /scheme/usb.*, reads descriptors. |
redbear-usb-check |
local/recipes/system/redbear-hwutils/source/src/bin/redbear-usb-check.rs |
In-guest scheme tree validator. |
redbear-usb-storage-check |
local/recipes/system/redbear-hwutils/source/src/bin/redbear-usb-storage-check.rs |
Mass-storage round-trip validator. |
usbctl |
local/sources/base/drivers/usb/usbctl/ |
CLI for port/endpoint status. |
1.5 Patch carriers on local/patches/base/
The durable Red Bear USB modifications are carried as local/patches/base/P*.patch
files. These are applied atomically by the cookbook against the recipe source tree during
fetch+cook.
| Patch | Size | Purpose |
|---|---|---|
P1-xhcid-device-lifecycle.patch |
2351 lines | Attach publication, transactional configure, bounded detach. |
P1-xhcid-port-pm-read-fix.patch |
942 lines | Port PM state read. |
P1-xhcid-uevent-logging.patch |
20 lines | Uevent audit trail. |
P2-usb-pm-and-drivers.patch |
158 lines | USB PM (suspend/resume/quirk integration). |
P3-xhci-device-hardening.patch |
1193 lines | Endp direction, cfg_idx ordering, interrupt-EP, hub feature clearing. |
P3-usbhidd-hardening.patch |
725 lines | HID panic removal, named producer wiring. |
P4-initfs-usb-drm-services.patch |
22 lines | DRM/USB service ordering in init. |
(sibling) P0-inputd-named-producers.patch, P0-inputd-per-device-consumers.patch, P2-inputd.patch, P3-inputd-keymap-bridge.patch |
(varying) | Input multiplexer wiring (ps2d + usbhidd consumers). |
Durability rule: any source-tree edit must be mirrored into one of these patches (or
into the local base fork's submodule/base branch on RedBear-OS) before the session
ends. This rule is also enforced by local/AGENTS.md and the cookbook's atomic patch
applier. The current local fork at local/sources/base/ is a single mega-commit —
see §8 for the durability problem and remediation.
1.6 The interrupt-vs-polling contradiction
local/sources/base/drivers/usb/xhcid/src/main.rs:101–115 defines a complete
get_int_method() that returns MSI-X, MSI, INTx, or Polling based on PCI capabilities.
main.rs:141 then disables it:
let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle);
//TODO: Fix interrupts.
xhci::start_irq_reactor(&hci, irq_file); is called with irq_file = None, which makes
the reactor a bounded polling loop that wakes every 1 second (see the mod.rs reactor
fallback). This is functionally "polling in production."
The v1 plan called this "interrupt-driven operation restored" — that is incorrect relative to the live code. v2 makes the gap explicit: interrupts remain to be re-enabled as P0-A1.
2. Status matrix (single source of truth)
Reorganized around the honest state of the tree.
| Component | State today | Maturity | Open correctness gap |
|---|---|---|---|
| Host mode (any controller) | builds / QEMU-validated narrow path | usable (narrow path) |
see §4 |
| xhcid runtime | builds / polling / QEMU-validated | usable (narrow path) |
interrupts hardcoded off; missing CSZ; missing real-hardware reset fix; missing USB 3.x packet-size + hub fixes |
| ehcid runtime | builds / no auto-spawn | builds |
no class driver dispatch; no full bot pipeline through /scheme/usb; ~no peer review |
| uhcid runtime | builds / does nothing | builds |
stub (35 lines) |
| ohcid runtime | builds / does nothing | builds |
stub (35 lines) |
| Hub | builds / good quality | usable (narrow path) |
polling fallback retained |
| HID class | builds / QEMU-validated narrow path | usable (narrow path) |
named producer wiring complete; legacy VT fallback preserved |
| Mass storage | builds / QEMU-validated narrow path | usable (narrow path) |
no guest-side write proof; no multi-LUN; no UAS |
| Audio class (USB) | builds | builds |
not exercised in any proof |
| CDC ACM/ECM | builds | builds |
not exercised in any proof |
| Bluetooth USB transport | builds (transport only) | builds |
Bluetooth host path remains gappy (see BLUETOOTH-IMPLEMENTATION-PLAN) |
| USB-C / UCSI | builds | builds |
topology surfaced, no PD/alt-mode |
Native tooling (lsusb, usbctl, redbear-info, redbear-usb-check) |
builds | usable (narrow path) |
no bounded proof scheme validation |
| Quirk table (compiled + TOML) | builds | validated (QEMU) — quirk-bypass-only |
146 USB + 214 storage entries, 22 flags |
| Validation harnesses | 5 QEMU scripts | validated (QEMU) |
no real-hardware matrix |
If a row says builds, Red Bear does not promise that the component is reachable from a
typed-key-in-the-inputd-pipe to a shell prompt. That promise is restricted to
usable (narrow path) and above, and only for the documented scenario.
3. Upstream divergence — what Redox 0.x USB HEAD has that Red Bear does not
This section is required reading before any USB change. It is the input to every phase in §6. The Redox merge window for USB change runs roughly Jan 2025 – Jun 2026 with two concentrated bursts (March 2025, Sep–Oct 2025). Red Bear's fork is currently pinned at the v1 baseline (0.1.0 base snapshot).
3.1 Three high-priority upstream commits Red Bear has not adopted
| Upstream commit | Why we need it | Where it would land |
|---|---|---|
69a80a6a — xhci: fix reset procedure on real hardware |
Replaces magic bit numbers with named constants; fixes the HCRST wait loop to read from usb_cmd instead of usb_sts (the spec says HCRST is in USB_CMD). Without this, xhcid can spin or wedge on real controllers. |
New patch local/patches/base/P3-xhci-real-hw-reset.patch against xhcid/src/xhci/mod.rs. |
19570db4 — xhci: support 64-bit contexts (CSZ) |
Makes Xhci generic over context size (Xhci<CONTEXT_32> / Xhci<CONTEXT_64>) with runtime detection via HCCPARAMS1.CSZ. Required by modern xHCI controllers (Alder Lake, Raptor Lake, Ryzen 7000+). The local source already has daemon_with_context_size<const N: usize> and a //TODO: cleanup CSZ support comment at the call site — the upstream fix is the natural completion. |
New patch local/patches/base/P3-xhci-csz-64-bit.patch against xhcid/src/main.rs and the downstream context types. |
12e601b3 — xhci: improvements based on real hardware testing |
Adds USB_CMD_INTE, corrects port RWC handling, fixes address_device speed passthrough. Companion to 69a80a6a. |
New patch local/patches/base/P3-xhci-real-hw-impl.patch. |
3.2 Medium-priority upstream commits
| Upstream commit | Note |
|---|---|
8dcd85b5, ba0ca4ce — Fix packet size for USB 3.0 and USB 1 |
Required for SuperSpeed device enumeration. Adopt in same patch as CSZ. |
cbbcbc9e, f58625b0 — usbhubd/xhcid fix reading descriptor / port status on USB 3 hubs |
Round out the USB 3 hub story. |
8f278dcb, 34b37410 — Bounds check on root_hub_port_index() |
Stop a panic that we already pay down via patch but have not tested in tree. |
4d6581d4 — xhcid: add more timeouts |
Prevents infinite hangs on unresponsive controllers. |
7e3e841f — xhci: fix reading EHB flag in received_irq |
Companion for interrupt-driven paths. |
e3a13a0c — xhcid and friends: use newtype PortId to ensure route string |
Type-safety win. |
6ac41ee — daemon: tolerate BrokenPipe on ready() |
Already in our base fork. |
258ea4e6, 865ca866 — usbscsid: use the unified disk scheme implementation |
usbscsid revision; lower priority, code organization. |
e4aab167, 24c1f0a3 — xhcid: don't exit the event loop when using irqs |
Required for stable interrupt-driven operation (pairs with the §1.6 fix). |
3.3 Lower-priority upstream commits to record, not blindly adopt
| Commit | Note |
|---|---|
a5f87735 — ignore alternate settings |
Conflicts with our composite-device fix (P3-xhci-device-hardening retains explicit alternate handling). Validate whether dropping this is sound given our active PortState.active_ifaces map. |
7c980137 — language ID for string descriptors |
Likely a clean drop-in. |
374e5fbf — xhci: use redox-scheme v2 |
We are on redox-scheme 0.11; a v2 migration is not in scope for 0.2.x. |
30fb1e7a — drivers merged into base (Nov 2025) |
Mirrors what Red Bear already does (our local/sources/base/). No action. |
| USB SCSI driver disabled upstream (Dec 2025) | Red Bear keeps it on with the BOUNDED storage test. Re-evaluate after P2-B1. |
bjorn3 enabled xHCI by default in QEMU x86-64 (Mar 2026) |
Aligns with our redbear-mini boot script. No action. |
bjorn3 moved xHCI config to runtime (Apr 2026) |
Lower priority — compile-time config is fine for our release model. |
| Antoine Reversat — simplified xhci (May 2026) | Subject to per-line review. |
3.4 Things upstream still does NOT have
These are explicit non-features from upstream that Red Bear should not silently inherit as a todo:
- USB Type-C / USB-PD / alt-modes. No policy engine, no protocol stack.
- USB4 / Thunderbolt. Listed as "not supported" in upstream
COMMUNITY-HW.md. - xHCI debug capability (DbC). Not implemented.
- USB device mode (gadget) / OTG. No dual-role support.
- USB isochronous transfers.
xhcidreturnsENOSYSfor isoch endpoints.
These belong to §6 P5 (architectural decision gate), not to "fix the missing patch."
4. Bare-metal-input correctness (the actual boot-time failure modes)
The bare-metal USB keyboard problem is not "xhcid doesn't work." xhcid does work in QEMU and on some real hardware. The failure modes are the paths that do not reach xhcid:
-
EHCI-attached USB keyboard — xHCI now owns every USB-3 controller, but EHCI/companion controllers (UHCI/OHCI) still own low/full-speed devices on chipsets that firmware routes through them. ehcid does not auto-spawn class drivers, so even though ehcid publishes
/scheme/usb/port<n>/..., nousbhiddis started for any device on that scheme. The keyboard is reachable by userland but the input pipeline never builds. -
UHCI/OHCI-attached devices — uhcid and ohcid are 35-line stubs. The companion controller is owned (by
pcid) but no USB traffic flows. There is no port state, no transfer completion, no scheme. -
xHCI interrupt-driven operation is offline — line 141 hardcodes polling. On real hardware with no reliable polling timer, this can produce slow enumeration or input lag, and on some chips it can wedge the controller (see upstream
69a80a6a). -
No real-hardware validation matrix — there is no
hardware-validation.mdtable enumerating which physical controller families have been exercised on bare metal. QEMUqemu-xhciis one fixed emulation target; it is not representative. -
USB HID and ACPI I2C-HID are not the same — internal laptop keyboards are I2C-HID (
i2c-hidd,intel-thc-hidd), not USB. These are real but separate. The I2C-HID plan and the USB HID plan cannot assume one is a substitute for the other. -
Strict-boot mode exists but is not bound —
uhcid/ohcid/ehcidaccept--strict-boot, but no initfs entry enables it; the policy lives in operator knowledge, not in the artifact. -
LED state is a weak health signal —
usbhiddkeyboard LEDs are bounded, per-device, best-effort; they are not a system-global lock-state authority. A deadCaps Lockindicator does not prove keyboard transport is broken; a working indicator does not prove the external USB keyboard fallback works. Treat LED state as cosmetic debug, not as a proof of input health. -
External keyboard bare-metal proof remains unpinned — the bounded QEMU lifecycle proof is not the same as a bare-metal proof. We need a captured log per controller family before claiming a fallback works on hardware.
These eight items are the inputs to phases P0-A (xHCI runtime) and P0-B (legacy host controllers).
5. Phases — execution order
Phases are ordered by what unblocks bare-metal correctness and what has unambiguous upstream-comparable patches we can adopt without inventing semantics.
| Phase | Goal | Exit |
|---|---|---|
| P0-A1 | ✅ Re-enable xHCI MSI/MSI-X/INTx at runtime. Committed 2026-07-07 (local/sources/base commit cbd40e0d, parent a2998c2d). test-xhci-irq-qemu.sh now greps for actual reactor log lines. |
✅ QEMU proof script updated; real-hardware bring-up deferred to operator build. |
| P0-A2 | Adopt upstream xHCI reset-procedure fix + hardware hardening (69a80a6a, 12e601b3). |
One QEMU full-stack pass + one real-hardware bring-up |
| P0-A3 | Adopt CSZ (64-bit contexts) upstream commit; complete the //TODO: cleanup CSZ support site. |
Same as A1 |
| P0-A4 | ✅ Adopt panic bounds-check (8f278dcb) and timeout expansion (4d6581d4). Committed 2026-07-07: 5 root_hub_port_index() unwrap/index sites replaced with bounded access (`ok_or_else( |
|
| P0-B1 | Auto-spawn class drivers from the EHCI scheme (/scheme/usb/port<n>/descriptors). Reuse the existing xhcid class-driver spawn model by refactoring the spawn helper out of xhcid into usb-core::spawn_usb_driver if necessary, then driving it from EHCI too. |
QEMU run with USB keyboard on EHCI route → typed input reaches inputd |
| P0-B2 | Implement real runtime enumeration for uhcid and ohcid over the existing usb-core::UsbHostController trait. Each new driver must register the same /scheme/usb tree pattern ehcid uses and must auto-spawn class drivers via P0-B1. |
QEMU run with low/full-speed USB keyboard on legacy controller route → typed input reaches inputd |
| P1 | ✅ Code-verified 2026-07-07. USB 3.0 packet-size handling (update_max_packet_size with shift exponent for USB ≥3, bytes for USB ≤2) in baseline. Hub descriptor reading uses separate HubDescriptorV2/HubDescriptorV3. Slot context hub bit (bit 26) and hub port count (bits 24-31) correctly set in configure_endpoints_once. SET_HUB_DEPTH issued for USB 3 hubs. TTT propagation not applicable to USB 3 (TT is USB 2.0 high-speed split-transaction only). TODOs about interface_desc/alternate_setting on USB 3 hubs are safe — passing None matches upstream behavior. |
QEMU run deferred to operator. |
| P2-A | ✅ Storage data path: in-guest write verification on the disk.usb-* scheme. redbear-usb-storage-check already performs write+readback+restore at sector 2048. test-usb-storage-qemu.sh now validates all four checks (discovery, write, readback, restore). |
redbear-usb-storage-check proves a write/read round-trip in QEMU |
| P2-B | Userspace API: pick native or libusb. Native: bake usb-core consumers first. libusb: pick an active WIP commit; if there is none, defer §2 row "userspace API" rather than start a new side-quest. |
Decision + prototype |
| P3 | HID robustness: real-hardware HID validation matrix; i2c-hidd migration to named producers; evdevd hotplug add/remove behavior from USB. |
One HID device family proven bare-metal + one hot-unplug cycle QEMU |
| P4 | Validation slices: complete test-usb-storage-qemu.sh write proof, hardware matrix in HARDWARE-VALIDATION-MATRIX.md (board, controller, input/storage/audio result), bounded stress loop on top of test-xhci-device-lifecycle-qemu.sh. |
matrix has one row per controller family |
| P5 | Architectural decision gate: host-only vs device mode; USB-C/PD/alt-mode scope; USB4/Thunderbolt exclusion; whether UCSI grows into a real PD surface. Recorded as an ADR in local/docs/. |
Decision recorded |
Phases are not equal in size. P0-A1 and P0-B2 are bounded, well-understood work. P2-B (libusb vs native) is a fork in the road; it is correct that it has no time estimate. P5 is a decision moment, not an implementation.
6. Validation inventory and bounded proofs
Five scripts exist today. They are honest about their scope (QEMU) but should be paired with a real-hardware matrix per phase exit.
| Script | What it actually proves | Limits |
|---|---|---|
local/scripts/test-usb-qemu.sh --check |
Full stack: xHCI init, HID spawn, SCSI spawn, sector-0 readback, BOS, no crashes. | QEMU qemu-xhci only; one emulator config; no real hardware. |
local/scripts/test-xhci-device-lifecycle-qemu.sh --check |
Bounded hotplug attach/detach for HID + storage. | QEMU only; monitor-driven hotplug; not a stress test. |
local/scripts/test-usb-storage-qemu.sh |
Mass storage autospawn + sector-0 readback. | No write proof; no multi-LUN; no UAS. |
local/scripts/test-xhci-irq-qemu.sh --check |
✅ Updated 2026-07-07 to verify interrupt-driven reactor path. Greps for Running IRQ reactor with IRQ file and event queue (must be present) and Running IRQ reactor in polling mode (must NOT be), plus MSI-X/INTx delivery method. |
QEMU qemu-xhci only; not real-hardware. |
local/scripts/test-usb-maturity-qemu.sh |
Sequential wrapper. | Composes the others; inherits their limits. |
Required proofs after P0-A1 lands:
test-xhci-irq-qemu.sh --checkmust transition from "binary runs" to "interrupts fire and complete." Add a bounded probe that confirms a hotplug event triggers an IRQ in guest time, not a sleep timer.- Add
test-xhci-regression-qemu.shfor the upstream reset-procedure fix. - Add
test-uhci-runtime-qemu.shandtest-ohci-runtime-qemu.shafter P0-B2 — same shape as the xHCI lifecycle test. - Add
test-ehci-class-autospawn-qemu.shafter P0-B1.
Proofs must:
- run on
redbear-minifrom a cleanmake cleanbuild; - keep the boot log under
local/docs/boot-logs/with aREDBEAR-...-RESULTS.md; - be citeable from phase status (§3 matrix) and from
USB-VALIDATION-RUNBOOK.md.
7. Durability posture (the local-fork problem, honestly)
The base fork at local/sources/base/ currently carries two USB-related commits
(one pre-existing, one from P0-A1):
$ git -C local/sources/base log -- drivers/usb/
cbd40e0d xhcid: re-enable interrupt-driven operation via get_int_method ← P0-A1 (2026-07-07)
6ac41ee daemon: tolerate BrokenPipe on ready(); i2cd: handle empty RON response
dd08b76 Red Bear OS base baseline from 0.1.0 pre-patched archive
Everything else that v1 described as "88 error handling fixes across xhcid" lives in
local/patches/base/P*.patch files. That is acceptable as long as:
- The base recipe (
recipes/core/base/recipe.toml) actually applies those patches onrepo cook. Verify by runningrepo validate-patches baseafter every edit and by checking thatrecipes/core/base/source/drivers/usb/xhcid/...contains the Red Bear state, not the upstream state. - No "live-edit" of
recipes/core/base/source/...ever escapes into the next build without an immediate patch mirror.local/AGENTS.mdenforces this; the rule stands. - The next base-fork bump (rebase onto a newer Redox base tag) preserves every USB patch
in the same order and lands them as commits on the
submodule/basebranch — not as a new mega-patch.
Durability remediation work that does not block USB phases:
- ✅ P0-A1 landed as the first USB-focused commit on
submodule/basesincedd08b76(commitcbd40e0d, 2026-07-07). This reopens per-feature commit history and makes future rebases reviewable. - P0-A2 through P0-B2 should each land as individual, reviewable commits on the same branch — never bundled into a mega-commit. Each phase below has a concrete file list and diff target (see §11).
- The base fork's
Cargo.tomlshould track thesubmodule/basebranch as upstream (currently it does, per the source-of-truth rules inlocal/AGENTS.md).
8. Support language — how Red Bear describes USB
Until P0-A and P0-B exit, Red Bear should NOT use any of:
- "USB support works."
- "USB is functional."
- "USB keyboard works on bare metal."
- "USB storage is supported."
It SHOULD use language such as:
- "xHCI host support is present but experimental; bare-metal proof requires the real-hardware matrix in §6 P4."
- "EHCI ownership and USB 2 register init exist; class-driver auto-spawn is pending P0-B1."
- "UHCI and OHCI are userspace stubs in this build; legacy host controllers are not yet the boot-input fallback."
- "USB storage autospawn and bounded sector-0 readback are QEMU-validated; write proof is pending P2-A."
- "USB error handling and correctness carry significant Red Bear patches over upstream; see
local/patches/base/P[1-3]-xhci*.patchandlocal/patches/base/P3-xhci-device-hardening.patch." - "USB-C topology (UCSI) is exposed but does not negotiate PD or alternate modes."
The README status table and the desktop-path plans should adopt this language consistently
the next time they are touched. The local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md already
treats USB as a first-class subsystem; this plan agrees and refines the wording.
9. Open questions and follow-up
- Rebase cadence — when
submodule/baseupstream lands thesimplify xHCIcommit (May 2026), do we adopt it before or after P0-A1 lands? Per the upstream-first rule, after — but the diff requires per-line review because our local patches (P1-xhcid-*.patch,P3-xhci-device-hardening.patch) overlap on the same code regions. - Cross-process class driver spawn — the class spawn path is currently xhcid-driven
(via the scheme). Should the spawn helper live in
usb-coreand be reused byehcid/uhcid/ohcid? Yes (P0-B1, P0-B2) — and that requiresusb-coreto growspawn_class_driver, which it does not yet have. The migration is the natural unit of P0-B1. - Strict-boot mode — should
pcid-spawneralways pass--strict-bootto USB host daemons? Operators can setREDBEAR_STRICT_USB_BOOT=1today; the default is off. Recommend leaving the default off but documenting the env var inUSB-VALIDATION-RUNBOOK.md(P0-A4 documentation step). - Whether to keep
usbscsidenabled after upstream disabled it — adopt the upside (bounded in-guest write proof) and the downside (occasional stalls). Defer to P2-A evaluation. - Hardware validation entries — the matrix in
local/docs/HARDWARE-VALIDATION-MATRIX.mdis currently tiny. P4 explicitly grows it; if it does not, the matrix block of P4 exit blocks the phase.
10. See also
local/docs/USB-VALIDATION-RUNBOOK.md— operator runbook for the bounded proofs above.local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md— the canonical desktop-path plan; treats USB as a first-class runtime subsystem.local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md— MSI/MSI-X quality surface that P0-A1 actually exercises.local/docs/BLUETOOTH-IMPLEMENTATION-PLAN.md—redbear-btusbconsumes the USB class driver dispatch path that P0-B1 makes available to all host controllers.local/docs/WIFI-IMPLEMENTATION-PLAN.md— Wi-Fi native control plane; not USB-coupled.local/docs/QUIRKS-SYSTEM.md— TOML + DMI + compiled-in quirk tables, source of USB device workarounds.local/AGENTS.md— fork model, durability policy, single-repo rule, branch policy.local/docs/archived/USB-IMPLEMENTATION-PLAN-v1-2026-04.md— superseded v1.local/docs/archived/USB-BOOT-INPUT-PLAN.md— preserved for the boot-input historical context; not the planning authority.local/docs/archived/XHCID-DEVICE-IMPROVEMENT-PLAN.md— preserved for the xhcid device-level historical context; absorbed into phases P0-A and P1.
11. Implementation handoff — P0-A2 through P0-B2
This section is the concrete kickoff for each remaining P0 sub-phase.
Each entry names files to touch, upstream commits to diff, and the required
validation step. A phase does not leave implementation until committed on
submodule/base (or the equivalent local fork) and, where practical, verified
with an automated QEMU proof.
P0-A2 — upstream xHCI reset-procedure fix
| Field | Detail |
|---|---|
| Upstream commits | https://gitlab.redox-os.org/redox-os/base/commit/69a80a6a — "xhci: fix reset procedure on real hardware". Also https://gitlab.redox-os.org/redox-os/base/commit/12e601b3 — "xhci: improvements based on real hardware testing". |
| Files to touch | local/sources/base/drivers/usb/xhcid/src/xhci/mod.rs — Xhci::new, controller reset path. local/sources/base/drivers/usb/xhcid/src/xhci/operational.rs — operational register definitions. |
| What changes | Replace magic bit numbers with named constants (USB_CMD_RS, USB_CMD_HCRST, USB_STS_HCH, USB_STS_CNR). Fix the HCRST wait loop to read from usb_cmd instead of usb_sts. Apply the port-RWC-correction and address_device speed passthrough from 12e601b3. |
| Git landing | One commit on local/sources/base master → update parent gitlink. |
| Validation | Rebuild redbear-mini, run test-usb-qemu.sh --check. Boot log must show xHCI controller init without "hang" or "reset failed" lines. If real hardware is available, boot on one Intel and one AMD controller. |
| Blocking | Nothing — independent of P0-A1. |
P0-A3 — CSZ (64-bit contexts)
| Field | Detail |
|---|---|
| Upstream commits | https://gitlab.redox-os.org/redox-os/base/commit/19570db4 — "xhci: support 64-bit contexts (CSZ)". |
| Files to touch | local/sources/base/drivers/usb/xhcid/src/main.rs — daemon_with_context_size<const N: usize> and the //TODO: cleanup CSZ support comment at line 119. local/sources/base/drivers/usb/xhcid/src/xhci/context.rs — DeviceContextList, InputContext. local/sources/base/drivers/usb/xhcid/src/xhci/mod.rs — Xhci<const N: usize> struct, PortState. |
| What changes | Make Xhci, DeviceContextList, InputContext, PortState, and StreamContextArray generic over context size N (32 or 64). Detect CSZ at runtime via CapabilityRegs::csz(). The local source already parameterizes daemon_with_context_size — the upstream fix is the natural completion. Remove the //TODO: cleanup CSZ support once generic parameterization is clean. |
| Git landing | One commit. |
| Validation | Rebuild + QEMU full-stack check. CSZ is not visible without a modern controller, so the QEMU proof is "didn't break existing paths." Real-hardware proof: boot on Ryzen 7000+ or Intel Alder Lake+. |
| Blocking | Nothing, but lands best after P0-A2 to avoid merge conflicts. |
P0-A4 — bounds check + timeouts
| Field | Detail |
|---|---|
| Upstream commits | https://gitlab.redox-os.org/redox-os/base/commit/8f278dcb — bounds check on root_hub_port_index(). 4d6581d4 — "xhcid: add more timeouts". |
| Files to touch | local/sources/base/drivers/usb/xhcid/src/xhci/mod.rs — port index bounds. local/sources/base/drivers/usb/xhcid/src/xhci/scheme.rs — timeout additions. |
| What changes | Bounds-check the port index parameter to prevent out-of-range access. Add timeout guards on control transfer and address device paths to prevent infinite hangs. |
| Git landing | One commit. |
| Validation | QEMU lifecycle test must still pass. |
| Blocking | None. |
P0-B1 — EHCI class-driver auto-spawn
| Field | Detail |
|---|---|
| Why | ehcid publishes /scheme/usb/port<n>/descriptors but does not auto-spawn usbhidd or usbscsid when a matching device appears. Only xhcid does that through its scheme. Without auto-spawn, EHCI-attached USB keyboards never reach the input pipeline. |
| Files to touch | New logic: local/recipes/drivers/usb-core/source/src/spawn.rs — add a spawn_class_driver helper that takes a port descriptor, walks the USB class table, and spawns the matching class daemon (reuses the spawn model from xhcid). Call site: local/recipes/drivers/ehcid/source/src/main.rs — after enumerating a port and reading descriptors, call usb_core::spawn_class_driver. |
| Git landing | Two commits: (1) usb-core spawn helper, (2) ehcid call site. Both go on submodule/base since they touch existing tracked code. |
| Validation | New script: test-ehci-class-autospawn-qemu.sh — boot with USB keyboard on EHCI route, verify usbhidd spawns and keyboard input reaches inputd. |
| Dependency | P0-B1 is NOT blocked by anything. The usb-core trait already has UsbHostController::control_transfer and descriptor parsers. The class-spawn decision table (/lib/drivers.d/70-usb-class.toml) is already wired. |
P0-B2 — real UHCI/OHCI runtime enumeration
| Field | Detail |
|---|---|
| Why | uhcid/src/main.rs and ohcid/src/main.rs are 35-line stubs: read PCI BAR4, log, sleep forever. No scheme, no transfers, no enumeration. This is the bare-metal USB keyboard blocker for legacy controller paths. |
| Files to touch | uhcid: local/recipes/drivers/uhcid/source/src/main.rs (replace 35-line stub with a ~1500-line implementation). ohcid: local/recipes/drivers/ohcid/source/src/main.rs (same). Both must implement usb_core::UsbHostController in a new sibling file host.rs, register /scheme/usb, perform frame-list/QH/TD/port enumeration, and call spawn_class_driver (from P0-B1) when a keyboard/storage device appears. Use the existing ehcid as a reference model. |
| What changes | For each controller: (a) PCI BAR mapping + register definitions, (b) UsbHostController trait implementor, (c) scheme registration (/scheme/usb), (d) port enumeration loop, (e) class-driver auto-spawn. |
| Git landing | Two commits (one per controller). These live in local/recipes/drivers/, not local/sources/base/, so they are committed on the parent 0.3.0 branch directly (tracked-tree model). |
| Validation | Two new scripts: test-uhci-runtime-qemu.sh --check and test-ohci-runtime-qemu.sh --check. Same shape as the xHCI lifecycle test: boot, verify scheme registration, hotplug keyboard, verify usbhidd spawn, verify keystrokes reach inputd. |
| Dependency | P0-B2 depends on P0-B1 (uses the class-spawn helper) but does NOT depend on any of P0-A1 through P0-A4. UHCI and OHCI are independent from xHCI for enumeration. |
| Reference impl | local/recipes/drivers/ehcid/source/src/main.rs (1550 lines) — uses usb-core, registers /scheme/usb, MMIO frame list, QH/TD control/bulk/interrupt. UHCI and OHCI are simpler controllers and should be smaller. |
Build-and-verify workflow (per-session)
# After committing any P0 sub-phase change:
./local/scripts/build-redbear.sh --upstream redbear-mini
./local/scripts/test-xhci-irq-qemu.sh --check # if xHCI touched
./local/scripts/test-usb-qemu.sh --check # full-stack regression
./local/scripts/test-xhci-device-lifecycle-qemu.sh --check # lifecycle
# After P0-B1/P0-B2:
./local/scripts/test-ehci-class-autospawn-qemu.sh --check # (to be written)
./local/scripts/test-uhci-runtime-qemu.sh --check # (to be written)
./local/scripts/test-ohci-runtime-qemu.sh --check # (to be written)
12. P5 — Modern USB Scope Decision (ADR)
Date: 2026-07-07. Status: Decided. Red Bear OS adopts host-only USB for the foreseeable future.
Decision
Red Bear OS ships as a USB host platform. Device mode (gadget), OTG dual-role, USB-C Power Delivery negotiation, USB-C alternate modes, USB4, and Thunderbolt are explicitly excluded from the current scope. This decision is recorded as an ADR (Architecture Decision Record) so that future work does not carry implicit scope expansion into the active build without a deliberate re-evaluation.
What is in scope (host-first)
- xHCI, EHCI, UHCI, and OHCI host controllers (drivers built, P0 complete).
- USB class daemons: HID (keyboard/mouse), Mass Storage (BOT), Hub, Audio.
- USB device enumeration, descriptor parsing, and class-driver auto-spawn.
- Hardware quirks: compiled-in + TOML runtime tables (146 USB + 214 storage entries), consumed at runtime by xhcid and usbscsid.
- USB 3.x SuperSpeed (5 Gbps) and SuperSpeedPlus (10 Gbps) host operation through xhcid.
- USB-C UCSI topology detection (
ucsid, exposes/scheme/ucsi).
What is explicitly excluded
| Capability | Excluded because |
|---|---|
| USB device mode (gadget) | Red Bear OS is a desktop/server OS, not an embedded peripheral. No dual-role controller (DRD) support exists in any upstream Redox component. |
| OTG (On-The-Go) | OTG requires dual-role + HNP/SRP protocol negotiation. No Redox kernel or driver infrastructure exists, and OTG is a declining standard (USB-C replaces it). |
| USB-C Power Delivery | PD negotiation requires a CC-line protocol engine, a policy manager, and source/sink state machines. This is a full subsystem (~10k LoC in Linux), not a small driver add-on. PMIC/charger integration is also needed. |
| USB-C alternate modes (DisplayPort, Thunderbolt) | Requires PD negotiation first, plus mux control, plus DP/Thunderbolt protocol stacks. No Redox GPU driver consumes DP alt-mode (display drivers use PCIe or platform-internal paths). |
| USB4 | USB4 requires PCIe tunneling, DisplayPort tunneling, and a USB4 router topology. The Redox PCI subsystem does not support PCIe hotplug or tunneling. Linux's USB4 stack is ~15k LoC. |
| Thunderbolt 3/4 | Thunderbolt requires USB4 or PCIe hotplug infrastructure. Listed as "not supported" in upstream Redox COMMUNITY-HW.md. No driver, no IOMMU DMA remapping for Thunderbolt security levels. |
| xHCI Debug Capability (DbC) | DbC requires a separate xHCI debug capability register set and a dedicated debug target endpoint. Serial console via UART is the standard debug path on Red Bear OS. DbC adds complexity without a use case. |
What may be reconsidered later
- USB-C PD (power role only, sink). If Red Bear OS runs on a laptop that charges via USB-C, the system firmware (UEFI/BIOS) handles PD negotiation before the OS boots. An OS-level PD policy manager is only needed for runtime source/sink role swaps, which are uncommon in a desktop/server OS. Revisit if bare-metal laptop support requires it.
- USB device mode for firmware update. Some devices require USB DFU (Device Firmware Upgrade) mode. This is a narrow, well-bounded gadget class that could be implemented without a full dual-role stack. Not in current plan.
- UCSI PD surface. The existing
ucsiddaemon exposes connector topology. Extending it to pass PD power contract data to a userspace policy manager is a reasonable follow-up if hardware validation demands it.
Rationale
Red Bear OS is a desktop/server operating system. The USB host path (keyboard, mouse, storage, hub, audio) covers the essential desktop use case. Expanding into device mode, PD, alt-modes, USB4, or Thunderbolt would add thousands of lines of new kernel and driver code with no immediate user-visible benefit — every excluded subsystem would consume weeks or months of development and require hardware the team does not currently validate against.
This decision keeps the USB scope honest and buildable with the current team. It removes implicit "we should support X someday" scope pressure from the active build, letting the team focus on completing the host-side USB maturity work (P1–P4) and the Wi-Fi/Bluetooth/desktop integration paths that depend on it.
Review cadence
This ADR is reviewed when a new Red Bear OS release branch is cut (e.g.,
0.3.0 → 0.4.0). At each review, the team evaluates whether any excluded
capability has become necessary for the next release's target hardware
profile. The ADR is not a permanent rejection — it is a current-scope
boundary that prevents unplanned scope creep.