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:
co-authored by
Claude Opus 5.5
parent
739cb9c163
commit
e729c64ba3
+33
-17
@@ -88,15 +88,14 @@ static void xhci_take_from_bios(xhci_dev_t *dev)
|
||||
}
|
||||
}
|
||||
|
||||
int xhci_find_and_map(xhci_dev_t *dev)
|
||||
int xhci_find_and_map(xhci_dev_t *dev, unsigned index)
|
||||
{
|
||||
uint64_t map_size;
|
||||
|
||||
if (!dev) return -1;
|
||||
|
||||
if (pci_find_class(XHCI_PCI_CLASS, XHCI_PCI_SUBCLASS, XHCI_PCI_PROG_IF, 0, &dev->pci) != 0) {
|
||||
log_message(LOG_DEBUG, "xhci: no xHCI controller on any PCI bus");
|
||||
return -1;
|
||||
if (pci_find_class(XHCI_PCI_CLASS, XHCI_PCI_SUBCLASS, XHCI_PCI_PROG_IF, index, &dev->pci) != 0) {
|
||||
return 1; /* no index-th controller: there are fewer */
|
||||
}
|
||||
xhci_log_hex32("xhci: controller vendor/device=",
|
||||
((uint32_t)dev->pci.vendor_id << 16) | dev->pci.device_id);
|
||||
@@ -188,10 +187,12 @@ static void xhci_log_hex32(const char *label, uint32_t val)
|
||||
log_message(LOG_DEBUG, "%s%s", label, buf);
|
||||
}
|
||||
|
||||
/* Only one controller is supported (matches xhci_dev_t's own doc comment);
|
||||
* latched at the end of a successful xhci_bringup() for
|
||||
* xhci_poll_events()'s use. */
|
||||
static xhci_dev_t *g_xhci_dev = NULL;
|
||||
/* Every controller brought up, in the order found (2026-10-14: a PC has
|
||||
* several, and a stick or keyboard may be in any of their ports -- until
|
||||
* then only the first was ever driven). Latched at the end of a
|
||||
* successful xhci_bringup(); xhci_poll_events() services each in turn. */
|
||||
static xhci_dev_t *g_xhci_devs[XHCI_MAX_CONTROLLERS];
|
||||
static uint32_t g_xhci_dev_count;
|
||||
|
||||
/* Forward declaration -- xhci_bringup() below issues one Enable Slot as a
|
||||
* command-ring smoke test; the implementation lives after xhci_bringup()
|
||||
@@ -428,7 +429,7 @@ int xhci_bringup(xhci_dev_t *dev)
|
||||
? "xhci: context size = 64 bytes"
|
||||
: "xhci: context size = 32 bytes");
|
||||
|
||||
g_xhci_dev = dev;
|
||||
if (g_xhci_dev_count < XHCI_MAX_CONTROLLERS) g_xhci_devs[g_xhci_dev_count++] = dev;
|
||||
|
||||
/* Catch a device already connected at launch -- xhci_poll_events() is
|
||||
* purely event-ring-driven (Port Status Change events only), and a
|
||||
@@ -442,9 +443,14 @@ int xhci_bringup(xhci_dev_t *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
xhci_dev_t *xhci_get_dev(void)
|
||||
uint32_t xhci_dev_count(void)
|
||||
{
|
||||
return g_xhci_dev;
|
||||
return g_xhci_dev_count;
|
||||
}
|
||||
|
||||
xhci_dev_t *xhci_dev_at(uint32_t i)
|
||||
{
|
||||
return i < g_xhci_dev_count ? g_xhci_devs[i] : NULL;
|
||||
}
|
||||
|
||||
xhci_msc_slot_t *xhci_msc_slot_for(xhci_dev_t *dev, uint32_t slot_id)
|
||||
@@ -1510,7 +1516,7 @@ static int xhci_ep0_hid_set_leds(xhci_dev_t *dev, uint32_t slot_id, uint8_t leds
|
||||
XHCI_TRB_CONTROL_DIR_IN);
|
||||
|
||||
ms->transfer_purpose = XHCI_XFER_HID_SET_LEDS;
|
||||
usb_kbd_leds_sent(leds); /* once asked: a keyboard that refuses is not asked again and again */
|
||||
ms->hid_leds_sent = leds; /* once asked: a keyboard that refuses is not asked again and again */
|
||||
dev->doorbell[slot_id] = XHCI_DB_TARGET(1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1859,9 +1865,17 @@ static void xhci_handle_bulk_stall(xhci_dev_t *dev, uint32_t slot_id,
|
||||
static uint32_t g_xhci_keyboards;
|
||||
int xhci_keyboard_running(void) { return g_xhci_keyboards != 0; }
|
||||
|
||||
static void xhci_poll_one(xhci_dev_t *dev);
|
||||
|
||||
void xhci_poll_events(void)
|
||||
{
|
||||
xhci_dev_t *dev = g_xhci_dev;
|
||||
uint32_t i;
|
||||
for (i = 0; i < g_xhci_dev_count; i++) xhci_poll_one(g_xhci_devs[i]);
|
||||
}
|
||||
|
||||
/* One controller's Event Ring -- everything below, per controller. */
|
||||
static void xhci_poll_one(xhci_dev_t *dev)
|
||||
{
|
||||
if (!dev) return;
|
||||
|
||||
uint32_t evt_processed = 0;
|
||||
@@ -2004,7 +2018,7 @@ void xhci_poll_events(void)
|
||||
{
|
||||
xhci_msc_slot_t *dms2 = xhci_msc_slot_for(dev, dev->pending_disable_slot_id);
|
||||
if (dms2) {
|
||||
if (dms2->hid_kbd) usb_kbd_reset(); /* A3: no key stays held */
|
||||
if (dms2->hid_kbd) usb_kbd_forget(dms2->hid_prev); /* A3: no key stays held */
|
||||
if (dms2->hid_running && g_xhci_keyboards) g_xhci_keyboards--;
|
||||
dms2->hid_kbd = 0;
|
||||
dms2->hid_running = 0;
|
||||
@@ -2134,7 +2148,7 @@ void xhci_poll_events(void)
|
||||
uint32_t asked = xms->hid_max_packet ? xms->hid_max_packet : 8u;
|
||||
uint32_t left = trb->status & 0xFFFFFFu;
|
||||
if (asked > 64u) asked = 64u;
|
||||
usb_kbd_report(xms->hid_buf, left < asked ? asked - left : 0u);
|
||||
usb_kbd_report(xms->hid_prev, xms->hid_buf, left < asked ? asked - left : 0u);
|
||||
xms->next_action = XHCI_NEXT_ACTION_HID_POLL;
|
||||
} else {
|
||||
console_println("USB keyboard: report failed -- keyboard stopped");
|
||||
@@ -2361,7 +2375,8 @@ void xhci_poll_events(void)
|
||||
case XHCI_XFER_HID_SET_PROTOCOL: {
|
||||
xms->hid_running = 1;
|
||||
g_xhci_keyboards++;
|
||||
usb_kbd_reset();
|
||||
memset(xms->hid_prev, 0, sizeof(xms->hid_prev));
|
||||
xms->hid_leds_sent = 0xFFu; /* tell it the lights at once */
|
||||
console_println("USB keyboard ready");
|
||||
xms->next_action = XHCI_NEXT_ACTION_HID_POLL;
|
||||
break;
|
||||
@@ -2669,7 +2684,8 @@ void xhci_poll_events(void)
|
||||
uint8_t leds;
|
||||
if (!nms->hid_running) break;
|
||||
xhci_hid_queue_report(dev, next_slot_id, nms);
|
||||
if (nms->transfer_purpose == XHCI_XFER_NONE && usb_kbd_leds_pending(&leds))
|
||||
leds = usb_kbd_leds_wanted();
|
||||
if (nms->transfer_purpose == XHCI_XFER_NONE && leds != nms->hid_leds_sent)
|
||||
(void)xhci_ep0_hid_set_leds(dev, next_slot_id, leds);
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user