From 8f1e24653d0effffa6a0a29e2922e135f84b7074 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Tue, 31 Mar 2026 17:16:58 +0200 Subject: [PATCH] XHCI fix device hotplug, introduce xhci port status change queue --- kernel/device/usb/xhci.c | 52 +++++++++++++++++++++++++++------------- kernel/device/usb/xhci.h | 7 ++++++ 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/kernel/device/usb/xhci.c b/kernel/device/usb/xhci.c index 9d374ec..b914c58 100644 --- a/kernel/device/usb/xhci.c +++ b/kernel/device/usb/xhci.c @@ -208,6 +208,9 @@ static void xhci_delete_pdevice (struct xhci* xhci, uint8_t port) { if (pdevice->endpoint0_ring_phys != 0) 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); } @@ -233,20 +236,10 @@ static void xhci_event_dispatch (struct xhci* xhci, struct xhci_trb* event, uint xhci_portsc_write (xhci, port, portsc); - if ((portsc & (1 << 17))) { - if ((portsc & (1 << 0))) { - DEBUG ("Device attached to port %u!\n", port); - - 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); + struct xhci_port_status_change* change = malloc (sizeof (*change)); + change->port = port; + change->portsc = portsc; + list_append (xhci->port_changes, &change->port_changes_link); } break; case XHCI_TRB_TRANSFER_EVENT: { 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); memset (response_buf, 0, PAGE_SIZE); - bool ok = xhci_endpoint0_ctrl_in (xhci, pdevice, 0x80, 6, (1 << 8), 0, response_buf_phys, - sizeof (struct usb_device_desc), lockflags); + bool ok = xhci_endpoint0_ctrl_in (xhci, pdevice, 0x80, 6, (1 << 8), 0, response_buf_phys, 18, + lockflags); if (!ok) { 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) { struct xhci* xhci = device->udata; + xhci_poll_port_changes (xhci); xhci_poll_setup_devices (xhci, lockflags); return ST_OK; diff --git a/kernel/device/usb/xhci.h b/kernel/device/usb/xhci.h index a480862..707675c 100644 --- a/kernel/device/usb/xhci.h +++ b/kernel/device/usb/xhci.h @@ -70,6 +70,12 @@ struct xhci_pdevice { 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 device* device; @@ -113,6 +119,7 @@ struct xhci { atomic_bool pending; uint8_t last_slot_id; uint8_t last_cmpl_code; + struct list_node_link* port_changes; spin_lock_t setup_lock; };