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
+19 -6
View File
@@ -30,20 +30,33 @@ typedef struct {
* controller's own max_slots, allocated once on first use here since this
* file has no bringup-time hook of its own to do it earlier). Indexed
* directly by xHCI slot ID, index 0 unused, matching msc_slots[]. */
static BlkioUsbState *g_usb_blk_slots = NULL;
static uint32_t g_usb_blk_slot_count = 0;
/* One registry per controller (2026-10-14: every xHCI controller is now
* driven, and a slot ID is a controller's own -- slot 1 on two
* controllers is two devices). Found by the controller's own pointer. */
static struct {
xhci_dev_t *xdev;
BlkioUsbState *slots;
uint32_t count;
} g_usb_blk[XHCI_MAX_CONTROLLERS];
static BlkioUsbState *usb_blk_state_for(xhci_dev_t *xdev, uint32_t slot_id) {
uint32_t c;
if (!xdev || slot_id < 1 || slot_id > xdev->max_slots) return NULL;
if (!g_usb_blk_slots || g_usb_blk_slot_count < xdev->max_slots + 1) {
for (c = 0; c < XHCI_MAX_CONTROLLERS; c++) {
if (g_usb_blk[c].xdev == xdev || !g_usb_blk[c].xdev) break;
}
if (c == XHCI_MAX_CONTROLLERS) return NULL;
if (!g_usb_blk[c].slots || g_usb_blk[c].count < xdev->max_slots + 1) {
size_t bytes = (size_t)(xdev->max_slots + 1) * sizeof(BlkioUsbState);
BlkioUsbState *fresh = (BlkioUsbState *)kmalloc_aligned(bytes, 64);
if (!fresh) return NULL;
memset(fresh, 0, bytes);
g_usb_blk_slots = fresh;
g_usb_blk_slot_count = xdev->max_slots + 1;
g_usb_blk[c].xdev = xdev;
g_usb_blk[c].slots = fresh;
g_usb_blk[c].count = xdev->max_slots + 1;
}
return &g_usb_blk_slots[slot_id];
return &g_usb_blk[c].slots[slot_id];
}
static int usb_blk_open(blkio_dev_t *dev, const blkio_params_t *p) {