XHCI fix device hotplug, introduce xhci port status change queue
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user