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)
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;

View File

@@ -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;
};