XHCI fix device hotplug, introduce xhci port status change queue
All checks were successful
Build ISO image / build-and-deploy (push) Successful in 4m1s
Build documentation / build-and-deploy (push) Successful in 2m47s

This commit is contained in:
2026-03-31 17:16:58 +02:00
parent e41e62af38
commit 8f1e24653d
2 changed files with 43 additions and 16 deletions

View File

@@ -208,6 +208,9 @@ static void xhci_delete_pdevice (struct xhci* xhci, uint8_t port) {
if (pdevice->endpoint0_ring_phys != 0) if (pdevice->endpoint0_ring_phys != 0)
pmm_free (pdevice->endpoint0_ring_phys, 1); pmm_free (pdevice->endpoint0_ring_phys, 1);
pmm_free (xhci->xhci_dcbaa[pdevice->slot_id], 1);
xhci->xhci_dcbaa[pdevice->slot_id] = 0;
free (pdevice); free (pdevice);
} }
@@ -233,20 +236,10 @@ static void xhci_event_dispatch (struct xhci* xhci, struct xhci_trb* event, uint
xhci_portsc_write (xhci, port, portsc); xhci_portsc_write (xhci, port, portsc);
if ((portsc & (1 << 17))) { struct xhci_port_status_change* change = malloc (sizeof (*change));
if ((portsc & (1 << 0))) { change->port = port;
DEBUG ("Device attached to port %u!\n", port); change->portsc = portsc;
list_append (xhci->port_changes, &change->port_changes_link);
xhci_create_pdevice (xhci, port);
} else {
DEBUG ("Device detached from port %u!\n", port);
xhci_delete_pdevice (xhci, port);
}
}
if ((portsc & (1 << 21)))
DEBUG ("Port %u reset done\n", port);
} break; } break;
case XHCI_TRB_TRANSFER_EVENT: { case XHCI_TRB_TRANSFER_EVENT: {
uint8_t cmpl_code = (event->status >> 24) & 0xFF; uint8_t cmpl_code = (event->status >> 24) & 0xFF;
@@ -625,8 +618,8 @@ static bool xhci_pdevice_setup_get_info (struct xhci* xhci, struct xhci_pdevice*
void* response_buf = (void*)(response_buf_phys + (uintptr_t)hhdm->offset); void* response_buf = (void*)(response_buf_phys + (uintptr_t)hhdm->offset);
memset (response_buf, 0, PAGE_SIZE); memset (response_buf, 0, PAGE_SIZE);
bool ok = xhci_endpoint0_ctrl_in (xhci, pdevice, 0x80, 6, (1 << 8), 0, response_buf_phys, bool ok = xhci_endpoint0_ctrl_in (xhci, pdevice, 0x80, 6, (1 << 8), 0, response_buf_phys, 18,
sizeof (struct usb_device_desc), lockflags); lockflags);
if (!ok) { if (!ok) {
pmm_free (response_buf_phys, 1); pmm_free (response_buf_phys, 1);
@@ -659,9 +652,36 @@ static void xhci_poll_setup_devices (struct xhci* xhci, uint64_t* lockflags) {
} }
} }
static void xhci_poll_port_changes (struct xhci* xhci) {
struct list_node_link *port_change_link, *tmp_port_change_link;
list_foreach (xhci->port_changes, port_change_link, tmp_port_change_link) {
struct xhci_port_status_change* change =
list_entry (port_change_link, struct xhci_port_status_change, port_changes_link);
list_remove (xhci->port_changes, &change->port_changes_link);
if ((change->portsc & (1 << 17))) {
if ((change->portsc & (1 << 0))) {
DEBUG ("Device attached to port %u!\n", change->port);
xhci_port_reset (xhci, change->port);
xhci_create_pdevice (xhci, change->port);
} else {
DEBUG ("Device detached from port %u!\n", change->port);
xhci_delete_pdevice (xhci, change->port);
}
}
free (change);
}
}
DEFINE_DEVICE_OP (xhci_poll_driver) { DEFINE_DEVICE_OP (xhci_poll_driver) {
struct xhci* xhci = device->udata; struct xhci* xhci = device->udata;
xhci_poll_port_changes (xhci);
xhci_poll_setup_devices (xhci, lockflags); xhci_poll_setup_devices (xhci, lockflags);
return ST_OK; return ST_OK;

View File

@@ -70,6 +70,12 @@ struct xhci_pdevice {
uint8_t endpoint0_cycle_bit; uint8_t endpoint0_cycle_bit;
}; };
struct xhci_port_status_change {
struct list_node_link port_changes_link;
uint8_t port;
uint32_t portsc;
};
struct xhci { struct xhci {
struct device* device; struct device* device;
@@ -113,6 +119,7 @@ struct xhci {
atomic_bool pending; atomic_bool pending;
uint8_t last_slot_id; uint8_t last_slot_id;
uint8_t last_cmpl_code; uint8_t last_cmpl_code;
struct list_node_link* port_changes;
spin_lock_t setup_lock; spin_lock_t setup_lock;
}; };