XHCI put extended capability parsing into one function, parse USB port info
All checks were successful
Build ISO image / build-and-deploy (push) Successful in 2m36s
Build documentation / build-and-deploy (push) Successful in 3m15s

This commit is contained in:
2026-03-25 21:00:55 +01:00
parent c71b1cc97d
commit 167c0ad5fd
2 changed files with 60 additions and 5 deletions

View File

@@ -91,6 +91,17 @@
#define XHCI_TRB_DEV_NOTIF_EVNT 38
#define XHCI_TRB_MFINDEX_WRAP 39
/* extended capabilities */
#define XHCI_EXTCAP_USB_LEGACY_SUPPORT 1
#define XHCI_EXTCAP_SUPPORTED_PROTOCOL 2
#define XHCI_EXTCAP_EXT_POWER_MNGMNT 3
#define XHCI_EXTCAP_IO_VIRT 4
#define XHCI_EXTCAP_MSG_INTR 5
#define XHCI_EXTCAP_LOCAL_MEMORY 6
#define XHCI_EXTCAP_USB_DEBUG 7
#define XHCI_EXTCAP_EXT_MSG_INTR 8
#define XHCI_EXTCAP_VENDOR_DEFINED 9
/* clang-format on */
static void xhci_write8 (uintptr_t base, uint32_t reg, uint8_t value) {
@@ -235,8 +246,7 @@ void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t
spin_unlock (&xhci->device->lock, fd);
}
/* Make or break on real hardware. We need to take over ownership from the BIOS. */
static void xhci_bios_handover (struct xhci* xhci) {
static void xhci_parse_ext_cap (struct xhci* xhci) {
uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1);
uint32_t ext_offset = (hccparams1 >> 16) << 2;
@@ -247,9 +257,34 @@ static void xhci_bios_handover (struct xhci* xhci) {
uintptr_t cap_ptr = xhci->xhci_mmio_base + ext_offset;
uint32_t cap = xhci_read32 (cap_ptr, 0);
uint8_t cap_id = cap & 0xFF;
uint8_t minor = (cap >> 16) & 0xFF;
uint8_t major = (cap >> 24) & 0xFF;
if (cap_id == 1) {
DEBUG ("Found USB Legacy Support at offset 0x%x\n", ext_offset);
switch (cap_id) {
case XHCI_EXTCAP_SUPPORTED_PROTOCOL: {
uint32_t dword2 = xhci_read32 (cap_ptr, 8);
uint8_t port_off = dword2 & 0xFF;
uint8_t port_count = (dword2 >> 8) & 0xFF;
uint8_t first_port = port_off - 1;
uint8_t last_port = first_port + port_count - 1;
for (uint8_t port = first_port; port <= last_port; port++) {
struct xhci_port* xhci_port = malloc (sizeof (*xhci_port));
memset (xhci_port, 0, sizeof (*xhci_port));
if (major == 3)
xhci_port->type = XHCI_PORT_USB3;
else
xhci_port->type = XHCI_PORT_USB2;
list_append (xhci->xhci_ports, &xhci_port->ports_link);
DEBUG ("PORT %u: USB %u.%u\n", port, major, minor);
}
} break;
case XHCI_EXTCAP_USB_LEGACY_SUPPORT: {
/* Make or break on real hardware. We need to take over ownership from the BIOS. */
if (cap & (1 << 16)) {
DEBUG ("BIOS owns XHCI, requesting handover!\n");
@@ -267,6 +302,8 @@ static void xhci_bios_handover (struct xhci* xhci) {
DEBUG ("XHCI Handover OK\n");
}
} break;
default:
break;
}
@@ -320,7 +357,7 @@ DEFINE_DEVICE_INIT (xhci_init) {
stall_ms (1000);
xhci_bios_handover (xhci);
xhci_parse_ext_cap (xhci);
/* reset controller */
usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD);
@@ -434,6 +471,14 @@ DEFINE_DEVICE_FINI (xhci_fini) {
pmm_free (xhci->event_ring_phys, 1);
pmm_free (xhci->erst_phys, 1);
struct list_node_link *port_link, *tmp_port_link;
list_foreach (xhci->xhci_ports, port_link, tmp_port_link) {
struct xhci_port* port = list_entry (port_link, struct xhci_port, ports_link);
list_remove (xhci->xhci_ports, &port->ports_link);
free (port);
}
irq_detach (xhci->irq);
free (xhci);

View File

@@ -29,6 +29,14 @@ struct xhci_init {
uint8_t irq;
};
#define XHCI_PORT_USB2 0
#define XHCI_PORT_USB3 1
struct xhci_port {
struct list_node_link ports_link;
int type;
};
struct xhci {
struct device* device;
@@ -65,6 +73,8 @@ struct xhci {
uintptr_t erst_phys;
atomic_bool pending;
struct list_node_link* xhci_ports;
};
DEFINE_DEVICE_INIT (xhci_init);