feat(usb): every xHCI controller is driven, not only the first

boards/BRINGUP.md A1, FABRIC-3 SXLII.  xhci.c keeps a table of controllers
(up to 8) and services each; kernel_main brings up index 0, 1, ... until
there is none.  repl.c's and blkio_usb.c's per-slot state is per
controller now (a slot ID is a controller's own), and each USB keyboard
keeps its own last report and lights; an unplugged keyboard releases what
it held.

Test first: keyboard and identity on a second controller behind a bridge,
Zuse on the first -- before, only Zuse; after, all three, on all three
ISAs.  Hot-plug and unplug on the second controller.  Acceptance unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-14 14:27:38 -04:00
co-authored by Claude Opus 5.5
parent 739cb9c163
commit e729c64ba3
27 changed files with 81701 additions and 260 deletions
+30
View File
@@ -5823,3 +5823,33 @@ not reach the device, records the enumeration working).
not its keyboard is not used; no key repeat (a boot keyboard does not repeat, and nothing here
does it for it); the lights are sent on the next report after a lock key, not at once.
## XLII. Every USB controller, not the first (`boards/BRINGUP.md` A1, the rest) (2026-10-14)
Captain Bob, 2026-10-14: "do multiple controllers" -- §XL's open item. A PC has several xHCI
controllers, each with its own ports; only the first found was driven, so a stick or keyboard in
another's ports was never seen.
**What assumed one controller, and now does not:**
- `xhci.c`: one latched `g_xhci_dev` → a table of up to `XHCI_MAX_CONTROLLERS` (8);
`xhci_poll_events()` services each in turn; `xhci_get_dev()` → `xhci_dev_count()` /
`xhci_dev_at(i)`; `xhci_find_and_map(dev, index)` finds the index-th controller (1 when there is
none). Everything per device was already per controller (`msc_slots`, the rings, the connect
state machine, the BOT state).
- `kernel_main.c`: brings up controller 0, 1, ... until there is none; one that fails is skipped.
- `repl.c` and `blkio_usb.c`: their per-slot arrays were indexed by slot ID alone -- but a slot ID is
a controller's own, so slot 1 on two controllers would have been one entry. Now one set per
controller (`g_usb_ctrl[]`; `blkio_usb.c` finds its set by the controller's pointer); the attach
acknowledgement looks the device up across all of them.
- `usb_kbd.c`: one "previous report" and one "lights sent" for every keyboard would have diffed two
keyboards against each other. Both are each keyboard's own now (in its slot); a keyboard that
goes releases whatever it still held (no Shift stuck down after unplugging).
**Verified.** Test first: amd64, no PS/2, Zuse's drive on the usual controller, a second (NEC,
behind a root port) with the USB keyboard and identity `00` -- before, only Zuse attached
(`logs/20261014-140826`); after, the keyboard types (`3`, `3`, `AB`), `00` attaches, Zuse is confirmed
(`-141442`) -- both controllers with a device in slot 1, the collision case. Four identities
hot-plugged onto the second controller all attach, and unplugging one detaches that one
(`-141621`). aarch64 and riscv64, the same two-controller boot: all the same results (`-141756`,
`-141953`). Standard acceptance, all three: POST 1052, hash unchanged (`-142120`, `-142237`,
`-142449`); five identities hot-plugged on the first controller, all attached (`-142606`).