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)
|
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;
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user