XHCI put extended capability parsing into one function, parse USB port info
This commit is contained in:
@@ -91,6 +91,17 @@
|
|||||||
#define XHCI_TRB_DEV_NOTIF_EVNT 38
|
#define XHCI_TRB_DEV_NOTIF_EVNT 38
|
||||||
#define XHCI_TRB_MFINDEX_WRAP 39
|
#define XHCI_TRB_MFINDEX_WRAP 39
|
||||||
|
|
||||||
|
/* extended capabilities */
|
||||||
|
#define XHCI_EXTCAP_USB_LEGACY_SUPPORT 1
|
||||||
|
#define XHCI_EXTCAP_SUPPORTED_PROTOCOL 2
|
||||||
|
#define XHCI_EXTCAP_EXT_POWER_MNGMNT 3
|
||||||
|
#define XHCI_EXTCAP_IO_VIRT 4
|
||||||
|
#define XHCI_EXTCAP_MSG_INTR 5
|
||||||
|
#define XHCI_EXTCAP_LOCAL_MEMORY 6
|
||||||
|
#define XHCI_EXTCAP_USB_DEBUG 7
|
||||||
|
#define XHCI_EXTCAP_EXT_MSG_INTR 8
|
||||||
|
#define XHCI_EXTCAP_VENDOR_DEFINED 9
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
static void xhci_write8 (uintptr_t base, uint32_t reg, uint8_t value) {
|
static void xhci_write8 (uintptr_t base, uint32_t reg, uint8_t value) {
|
||||||
@@ -235,8 +246,7 @@ void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t
|
|||||||
spin_unlock (&xhci->device->lock, fd);
|
spin_unlock (&xhci->device->lock, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make or break on real hardware. We need to take over ownership from the BIOS. */
|
static void xhci_parse_ext_cap (struct xhci* xhci) {
|
||||||
static void xhci_bios_handover (struct xhci* xhci) {
|
|
||||||
uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1);
|
uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1);
|
||||||
uint32_t ext_offset = (hccparams1 >> 16) << 2;
|
uint32_t ext_offset = (hccparams1 >> 16) << 2;
|
||||||
|
|
||||||
@@ -247,9 +257,34 @@ static void xhci_bios_handover (struct xhci* xhci) {
|
|||||||
uintptr_t cap_ptr = xhci->xhci_mmio_base + ext_offset;
|
uintptr_t cap_ptr = xhci->xhci_mmio_base + ext_offset;
|
||||||
uint32_t cap = xhci_read32 (cap_ptr, 0);
|
uint32_t cap = xhci_read32 (cap_ptr, 0);
|
||||||
uint8_t cap_id = cap & 0xFF;
|
uint8_t cap_id = cap & 0xFF;
|
||||||
|
uint8_t minor = (cap >> 16) & 0xFF;
|
||||||
|
uint8_t major = (cap >> 24) & 0xFF;
|
||||||
|
|
||||||
if (cap_id == 1) {
|
switch (cap_id) {
|
||||||
DEBUG ("Found USB Legacy Support at offset 0x%x\n", ext_offset);
|
case XHCI_EXTCAP_SUPPORTED_PROTOCOL: {
|
||||||
|
uint32_t dword2 = xhci_read32 (cap_ptr, 8);
|
||||||
|
uint8_t port_off = dword2 & 0xFF;
|
||||||
|
uint8_t port_count = (dword2 >> 8) & 0xFF;
|
||||||
|
|
||||||
|
uint8_t first_port = port_off - 1;
|
||||||
|
uint8_t last_port = first_port + port_count - 1;
|
||||||
|
|
||||||
|
for (uint8_t port = first_port; port <= last_port; port++) {
|
||||||
|
struct xhci_port* xhci_port = malloc (sizeof (*xhci_port));
|
||||||
|
memset (xhci_port, 0, sizeof (*xhci_port));
|
||||||
|
|
||||||
|
if (major == 3)
|
||||||
|
xhci_port->type = XHCI_PORT_USB3;
|
||||||
|
else
|
||||||
|
xhci_port->type = XHCI_PORT_USB2;
|
||||||
|
|
||||||
|
list_append (xhci->xhci_ports, &xhci_port->ports_link);
|
||||||
|
|
||||||
|
DEBUG ("PORT %u: USB %u.%u\n", port, major, minor);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case XHCI_EXTCAP_USB_LEGACY_SUPPORT: {
|
||||||
|
/* Make or break on real hardware. We need to take over ownership from the BIOS. */
|
||||||
if (cap & (1 << 16)) {
|
if (cap & (1 << 16)) {
|
||||||
DEBUG ("BIOS owns XHCI, requesting handover!\n");
|
DEBUG ("BIOS owns XHCI, requesting handover!\n");
|
||||||
|
|
||||||
@@ -267,6 +302,8 @@ static void xhci_bios_handover (struct xhci* xhci) {
|
|||||||
|
|
||||||
DEBUG ("XHCI Handover OK\n");
|
DEBUG ("XHCI Handover OK\n");
|
||||||
}
|
}
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +357,7 @@ DEFINE_DEVICE_INIT (xhci_init) {
|
|||||||
|
|
||||||
stall_ms (1000);
|
stall_ms (1000);
|
||||||
|
|
||||||
xhci_bios_handover (xhci);
|
xhci_parse_ext_cap (xhci);
|
||||||
|
|
||||||
/* reset controller */
|
/* reset controller */
|
||||||
usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD);
|
usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD);
|
||||||
@@ -434,6 +471,14 @@ DEFINE_DEVICE_FINI (xhci_fini) {
|
|||||||
pmm_free (xhci->event_ring_phys, 1);
|
pmm_free (xhci->event_ring_phys, 1);
|
||||||
pmm_free (xhci->erst_phys, 1);
|
pmm_free (xhci->erst_phys, 1);
|
||||||
|
|
||||||
|
struct list_node_link *port_link, *tmp_port_link;
|
||||||
|
list_foreach (xhci->xhci_ports, port_link, tmp_port_link) {
|
||||||
|
struct xhci_port* port = list_entry (port_link, struct xhci_port, ports_link);
|
||||||
|
|
||||||
|
list_remove (xhci->xhci_ports, &port->ports_link);
|
||||||
|
free (port);
|
||||||
|
}
|
||||||
|
|
||||||
irq_detach (xhci->irq);
|
irq_detach (xhci->irq);
|
||||||
|
|
||||||
free (xhci);
|
free (xhci);
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ struct xhci_init {
|
|||||||
uint8_t irq;
|
uint8_t irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define XHCI_PORT_USB2 0
|
||||||
|
#define XHCI_PORT_USB3 1
|
||||||
|
|
||||||
|
struct xhci_port {
|
||||||
|
struct list_node_link ports_link;
|
||||||
|
int type;
|
||||||
|
};
|
||||||
|
|
||||||
struct xhci {
|
struct xhci {
|
||||||
struct device* device;
|
struct device* device;
|
||||||
|
|
||||||
@@ -65,6 +73,8 @@ struct xhci {
|
|||||||
uintptr_t erst_phys;
|
uintptr_t erst_phys;
|
||||||
|
|
||||||
atomic_bool pending;
|
atomic_bool pending;
|
||||||
|
|
||||||
|
struct list_node_link* xhci_ports;
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_DEVICE_INIT (xhci_init);
|
DEFINE_DEVICE_INIT (xhci_init);
|
||||||
|
|||||||
Reference in New Issue
Block a user