Files
RedBear-OS/local/docs/USB-IMPLEMENTATION-PLAN.md
T
vasilito 05bb9095ce docs: USB-IMPLEMENTATION-PLAN.md v2 — mark P0-A1 done + P0-A2..B2 handoff
Update §5 phases table: P0-A1  committed (base fork cbd40e0d, parent
a2998c2d).

Update §6 validation table: test-xhci-irq-qemu.sh now greps for actual
reactor log lines (not fictitious strings).

Update §7 durability log: base fork now has two USB commits (one from
P0-A1), not one.  The "first USB-focused commit since dd08b76" is
now cbd40e0d.

Add §11 — implementation handoff appendix with per-phase concrete
targets: upstream commit SHAs, files to touch per phase, git-landing
rules, validation scripts to write, and dependency graph (P0-B2 depends
on P0-B1; P0-A2 through P0-A4 are independent of B; P0-B1 is unblocked).
2026-07-07 00:44:31 +03:00

555 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 against `local/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 from `archived/`); the older
> `archived/USB-BOOT-INPUT-PLAN.md` and `archived/XHCID-DEVICE-IMPROVEMENT-PLAN.md` are
> 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:
1. **What is built?** — every host controller, class driver, scheme, and observability tool
that actually exists in `local/sources/base/` and `local/recipes/drivers/`. Status is
derived from the current source tree, not from prior memory or from patch carriers.
2. **What was patched?** — every durable Red Bear modification, with file paths
(`local/patches/base/P*.patch` for the base module, dedicated local recipes or forks
otherwise).
3. **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.
4. **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 P0P5 (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:141` hardcodes polling:
```rust
let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle);
//TODO: Fix interrupts.
```
The `get_int_method` function 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:101115` defines a complete
`get_int_method()` that returns MSI-X, MSI, INTx, or Polling based on PCI capabilities.
`main.rs:141` then **disables it**:
```rust
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, SepOct 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.** `xhcid` returns `ENOSYS` for 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**:
1. **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>/...`, no `usbhidd` is started for any
device on that scheme. The keyboard is reachable by userland but the input pipeline
never builds.
2. **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.
3. **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`).
4. **No real-hardware validation matrix** — there is no `hardware-validation.md` table
enumerating which physical controller families have been exercised on bare metal.
QEMU `qemu-xhci` is one fixed emulation target; it is not representative.
5. **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.
6. **Strict-boot mode exists but is not bound** — `uhcid`/`ohcid`/`ehcid` accept
`--strict-boot`, but no initfs entry enables it; the policy lives in operator
knowledge, not in the artifact.
7. **LED state is a weak health signal** — `usbhidd` keyboard LEDs are bounded,
per-device, best-effort; they are not a system-global lock-state authority. A dead
`Caps Lock` indicator 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.
8. **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`). | QEMU lifecycle + full-stack pass |
| **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** | USB 3.x hub correctness upstream commits (`cbbcbc9e`, `f58625b0`, `8dcd85b5`, `ba0ca4ce`); review alt-setting handling (`a5f87735`) against our `active_ifaces`. | One USB 3 hub brought up in QEMU with descriptor walk end-to-end |
| **P2-A** | Storage data path: in-guest write verification on the `disk.usb-*` scheme; multi-LUN if it is tractable. | `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:**
1. `test-xhci-irq-qemu.sh --check` must 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.
2. Add `test-xhci-regression-qemu.sh` for the upstream reset-procedure fix.
3. Add `test-uhci-runtime-qemu.sh` and `test-ohci-runtime-qemu.sh` after P0-B2 — same
shape as the xHCI lifecycle test.
4. Add `test-ehci-class-autospawn-qemu.sh` after P0-B1.
Proofs must:
- run on `redbear-mini` from a clean `make clean` build;
- keep the boot log under `local/docs/boot-logs/` with a `REDBEAR-...-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:
1. The base *recipe* (`recipes/core/base/recipe.toml`) actually applies those patches on
`repo cook`. Verify by running `repo validate-patches base` after every edit and by
checking that `recipes/core/base/source/drivers/usb/xhcid/...` contains the Red Bear
state, not the upstream state.
2. No "live-edit" of `recipes/core/base/source/...` ever escapes into the next build
without an immediate patch mirror. `local/AGENTS.md` enforces this; the rule stands.
3. 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/base` branch — 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/base`** since `dd08b76`
(commit `cbd40e0d`, 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.toml` should track the `submodule/base` branch as upstream
(currently it does, per the source-of-truth rules in `local/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*.patch` and `local/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
1. **Rebase cadence** — when `submodule/base` upstream lands the
`simplify xHCI` commit (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.
2. **Cross-process class driver spawn** — the class spawn path is currently xhcid-driven
(via the scheme). Should the spawn helper live in `usb-core` and be reused by
`ehcid`/`uhcid`/`ohcid`? Yes (P0-B1, P0-B2) — and that requires `usb-core` to grow
`spawn_class_driver`, which it does not yet have. The migration is the natural unit
of P0-B1.
3. **Strict-boot mode** — should `pcid-spawner` always pass `--strict-boot` to USB host
daemons? Operators can set `REDBEAR_STRICT_USB_BOOT=1` today; the default is off.
Recommend leaving the default off but documenting the env var in
`USB-VALIDATION-RUNBOOK.md` (P0-A4 documentation step).
4. **Whether to keep `usbscsid` enabled after upstream disabled it** — adopt the upside
(bounded in-guest write proof) and the downside (occasional stalls). Defer to P2-A
evaluation.
5. **Hardware validation entries** — the matrix in `local/docs/HARDWARE-VALIDATION-MATRIX.md`
is 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-btusb` consumes 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)
```