Add basic xHCI driver and USB devices enumeration

This commit is contained in:
2026-08-07 21:11:08 +03:00
parent a2128de3e2
commit 4813725cf3
12 changed files with 721 additions and 117 deletions
+490
View File
@@ -0,0 +1,490 @@
#include "src/kernel/xhci.h"
#include "src/kernel/log.h"
#include "src/kernel/panic.h"
#include "src/kernel/pci.h"
#include "src/kernel/stream.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
#include "src/lib/util.h"
#define XHCI_PCI_CLASS 0x0C
#define XHCI_PCI_SUBCLASS 0x03
#define XHCI_PCI_INTERFACE 0x30
typedef volatile struct __attribute__((packed)) {
uint8_t caplength;
uint8_t reserved;
uint16_t hciversion;
uint32_t hcsparams1;
uint32_t hcsparams2;
uint32_t hcsparams3;
uint32_t hccparams1;
uint32_t dboff;
uint32_t rtsoff;
uint32_t hccparams2;
} xhci_cap_regs_t;
#define XHCI_CAP_REGS_MAX_SLOTS(c) BITS_R((c)->hcsparams1, 7, 0)
#define XHCI_CAP_REGS_MAX_INTRS(c) BITS_R((c)->hcsparams1, 18, 8)
#define XHCI_CAP_REGS_MAX_PORTS(c) BITS_R((c)->hcsparams1, 31, 24)
#define XHCI_CAP_REGS_MAX_ERSTS(c) BITS_R((c)->hcsparams2, 7, 4)
typedef volatile struct __attribute__((packed)) {
uint32_t usbcmd;
uint32_t usbsts;
uint32_t pagesize;
uint32_t reserved[2];
uint32_t dnctrl;
uint64_t crcr;
uint32_t reserved2[4];
uint64_t dcbaap;
uint32_t config;
} xhci_op_regs_t;
#define XHCI_OP_REGS_RS_R(o) BITS_R((o)->usbcmd, 0, 0)
#define XHCI_OP_REGS_RS_W(o, v) BITS_W((o)->usbcmd, 0, 0, v)
#define XHCI_OP_REGS_HCRST_R(o) BITS_R((o)->usbcmd, 1, 1)
#define XHCI_OP_REGS_HCRST_W(o, v) BITS_W((o)->usbcmd, 1, 1, v)
#define XHCI_OP_REGS_HCH(o) BITS_R((o)->usbsts, 0, 0)
#define XHCI_OP_REGS_HSE(o) BITS_R((o)->usbsts, 2, 2)
#define XHCI_OP_REGS_EINT_R(o) BITS_R((o)->usbsts, 3, 3)
#define XHCI_OP_REGS_EINT_W(o, v) BITS_W((o)->usbsts, 3, 3, v)
#define XHCI_OP_REGS_CNR(o) BITS_R((o)->usbsts, 11, 11)
#define XHCI_OP_REGS_HCE(o) BITS_R((o)->usbsts, 12, 12)
#define XHCI_OP_REGS_RCS(o) BITS_R((o)->crcr, 0, 0)
#define XHCI_OP_REGS_CRR(o) BITS_R((o)->crcr, 3, 3)
#define XHCI_OP_REGS_CRP(o) BITS_R((o)->crcr, 63, 6)
#define XHCI_OP_REGS_MAX_SLOTS_EN_R(o) BITS_R((o)->config, 7, 0)
#define XHCI_OP_REGS_MAX_SLOTS_EN_W(o, v) BITS_W((o)->config, 7, 0, v)
typedef volatile struct __attribute__((packed)) {
uint32_t portsc;
uint32_t portpmsc;
uint32_t portli;
uint32_t porthlpmc;
} xhci_port_regs_t;
#define XHCI_PORT_REGS_CCS(p) BITS_R((p)->portsc, 0, 0)
#define XHCI_PORT_REGS_PED(p) BITS_R((p)->portsc, 1, 1)
#define XHCI_PORT_REGS_PR_R(p) BITS_R((p)->portsc, 4, 4)
#define XHCI_PORT_REGS_PR_W(p, v) BITS_W((p)->portsc, 4, 4, v)
#define XHCI_PORT_REGS_PP(p) BITS_R((p)->portsc, 9, 9)
#define XHCI_PORT_REGS_PS(p) BITS_R((p)->portsc, 13, 10)
typedef volatile struct __attribute__((packed)) {
uint32_t iman;
uint32_t imod;
uint32_t erstsz;
uint32_t reserved;
uint64_t erstba;
uint64_t erdp;
} xhci_intr_regs_t;
static xhci_cap_regs_t *cap_regs = (xhci_cap_regs_t *)KERNEL_VIRTUAL_XHCI;
static xhci_op_regs_t *op_regs;
static xhci_port_regs_t *port_regs;
static xhci_intr_regs_t *intr_regs;
typedef volatile uint32_t xhci_db_regs;
#define XHCI_DB_REGS_TASK_ID(d) BITS_R((d), 31, 16)
#define XHCI_DB_REGS_TARGET(d) BITS_R((d), 7, 0)
static xhci_db_regs *db_regs;
#define MAX_SLOTS 32
static void *dcbaa[MAX_SLOTS + 1] __attribute__((aligned(PAGE_SIZE)));
typedef struct __attribute__((packed)) {
uint64_t base;
uint32_t size;
uint32_t reserved;
} xchi_erst_entry_t;
typedef struct __attribute__((packed)) {
uint64_t parameter;
uint32_t status;
uint32_t control;
} xhci_trb_t;
#define XHCI_TRB_CYCLE_R(t) BITS_R((t)->control, 0, 0)
#define XHCI_TRB_CYCLE_W(t, v) BITS_W((t)->control, 0, 0, v)
#define XHCI_TRB_TOGGLE_CYCLE_R(t) BITS_R((t)->control, 1, 1)
#define XHCI_TRB_TOGGLE_CYCLE_W(t, v) BITS_W((t)->control, 1, 1, v)
#define XHCI_TRB_TRB_TYPE_R(t) BITS_R((t)->control, 15, 10)
#define XHCI_TRB_TRB_TYPE_W(t, v) BITS_W((t)->control, 15, 10, v)
#define XHCI_TRB_SLOT_TYPE_R(t) BITS_R((t)->control, 20, 16)
#define XHCI_TRB_SLOT_TYPE_W(t, v) BITS_W((t)->control, 20, 16, v)
#define XHCI_TRB_COMPLETION_CODE(t) BITS_R((t)->status, 31, 24)
#define XHCI_TRB_SLOT_ID_R(t) BITS_R((t)->control, 31, 24)
#define XHCI_TRB_SLOT_ID_W(t, v) BITS_W((t)->control, 31, 24, v)
#define XHCI_TRB_TYPE_TRANSFER_SETUP_STAGE 2
#define XHCI_TRB_TYPE_TRANSFER_DATA_STAGE 3
#define XHCI_TRB_TYPE_TRANSFER_STATUS_STAGE 4
#define XHCI_TRB_TYPE_LINK 6
#define XHCI_TRB_TYPE_COMMAND_ENABLE_SLOT 9
#define XHCI_TRB_TYPE_COMMAND_DISABLE_SLOT 10
#define XHCI_TRB_TYPE_COMMAND_ADDRESS_DEVICE 11
#define XHCI_TRB_TYPE_COMMAND_NOOP 23
#define XHCI_TRB_TYPE_EVENT_TRANSFER_COMPLETION 32
#define XHCI_TRB_TYPE_EVENT_COMMAND_COMPLETION 33
#define XHCI_TRB_TYPE_EVENT_PORT_STATUS_CHANGE 34
static xchi_erst_entry_t erst[1] __attribute__((aligned(PAGE_SIZE)));
#define RING_LENGTH 32
static uint8_t cr_cycle = 1;
static uint8_t cr_i = 0;
static xhci_trb_t cr[RING_LENGTH + 1] __attribute__((aligned(PAGE_SIZE)));
static uint8_t er_cycle = 1;
static uint8_t er_i = 0;
static xhci_trb_t er[RING_LENGTH] __attribute__((aligned(PAGE_SIZE)));
typedef struct __attribute__((packed)) {
uint32_t drop_flags;
uint32_t add_flags;
uint32_t reserved[6];
} xhci_input_control_ctx_t;
typedef struct __attribute__((packed)) {
uint32_t dw0;
uint32_t dw1;
uint32_t dw2;
uint32_t dw3;
uint32_t reserved[4];
} xhci_slot_ctx_t;
#define XHCI_SLOT_CTX_SPEED_R(s) BITS_R((s)->dw0, 23, 20)
#define XHCI_SLOT_CTX_SPEED_W(s, v) BITS_W((s)->dw0, 23, 20, v)
#define XHCI_SLOT_CTX_CTX_ENTRIES_R(s) BITS_R((s)->dw0, 31, 27)
#define XHCI_SLOT_CTX_CTX_ENTRIES_W(s, v) BITS_W((s)->dw0, 31, 27, v)
#define XHCI_SLOT_CTX_ROOT_HUB_PORT_R(s) BITS_R((s)->dw1, 23, 16)
#define XHCI_SLOT_CTX_ROOT_HUB_PORT_W(s, v) BITS_W((s)->dw1, 23, 16, v)
typedef struct __attribute__((packed)) {
uint32_t dw0;
uint32_t dw1;
uint64_t dequeue;
uint32_t dw4;
uint32_t reserved[3];
} xhci_ep_ctx_t;
#define USB_EP_CTX_EP_TYPE_R(e) BITS_R((e)->dw1, 5, 3)
#define USB_EP_CTX_EP_TYPE_W(e, v) BITS_W((e)->dw1, 5, 3, v)
#define USB_EP_CTX_MAX_PACKET_SIZE_R(e) BITS_R((e)->dw1, 31, 16)
#define USB_EP_CTX_MAX_PACKET_SIZE_W(e, v) BITS_W((e)->dw1, 31, 16, v)
typedef struct __attribute__((packed)) {
xhci_input_control_ctx_t control;
xhci_slot_ctx_t slot;
xhci_ep_ctx_t ep[31];
} xhci_input_ctx_t;
static xhci_input_ctx_t input_ctx __attribute__((aligned(64)));
typedef struct __attribute__((packed)) {
xhci_slot_ctx_t slot;
xhci_ep_ctx_t endpoints[31];
} xchi_device_ctx_t;
static xchi_device_ctx_t device_ctx __attribute__((aligned(64)));
static uint8_t tr_attached_slot = 0;
static uint8_t tr_cycle = 1;
static uint8_t tr_i = 0;
static xhci_trb_t tr[RING_LENGTH + 1] __attribute__((aligned(PAGE_SIZE)));
static const xhci_trb_t *command_exec_sync(const xhci_trb_t *cmd) {
LOG_LN("Queueing command TRB...");
LOG_VAL_F(cmd->parameter, "%lx");
LOG_VAL_F(cmd->status, "%x");
LOG_VAL_F(cmd->control, "%x");
xhci_trb_t *cre = &cr[cr_i];
memory_copy(cmd, sizeof(xhci_trb_t), cre);
XHCI_TRB_CYCLE_W(cre, cr_cycle);
cr_i = (cr_i + 1) % RING_LENGTH;
XHCI_TRB_CYCLE_W((&cr[RING_LENGTH]), cr_cycle);
cr_cycle ^= (cr_i == 0);
LOG_LN("Ringing command doorbell...");
LOG_VAL_F(op_regs->usbsts, "%x");
db_regs[0] = 0;
LOG_VAL_F(op_regs->usbsts, "%x");
LOG_LN("Waiting for completion...");
while (1) {
xhci_trb_t *cmp = &er[er_i];
while (XHCI_TRB_CYCLE_R(cmp) != er_cycle)
;
er_i = (er_i + 1) % RING_LENGTH;
intr_regs->erdp = (uint64_t)(VIRT_TO_PHYS(&er[er_i]));
er_cycle ^= (er_i == 0);
if (XHCI_TRB_TRB_TYPE_R(cmp) != XHCI_TRB_TYPE_EVENT_COMMAND_COMPLETION || (void *)cmp->parameter != VIRT_TO_PHYS(cre)) {
LOG_LN("Received irrelevant event, skipping...");
} else {
LOG_LN("Received command completion event...");
LOG_VAL_F(cmp->parameter, "%lx");
LOG_VAL_F(cmp->status, "%x");
LOG_VAL_F(cmp->control, "%x");
ASSERT(XHCI_TRB_COMPLETION_CODE(cmp) == 1, "command_exec_sync: Command failed.");
return cmp;
}
}
}
void xhci_init() {
TRACE_LN("Searching for suitable controller...");
pci_bdf_t bdf = pci_find_by_class(XHCI_PCI_CLASS, XHCI_PCI_SUBCLASS, XHCI_PCI_INTERFACE);
ASSERT(bdf, "xhci_init: No suitable controllers found.");
TRACE_LN("Mapping controller to virtual memory...");
pci_map(bdf, cap_regs, 4);
op_regs = (xhci_op_regs_t *)((uint8_t *)cap_regs + cap_regs->caplength);
port_regs = (xhci_port_regs_t *)((uint8_t *)cap_regs + cap_regs->caplength + 0x400);
intr_regs = (xhci_intr_regs_t *)((uint8_t *)cap_regs + cap_regs->rtsoff + 0x20);
db_regs = (uint32_t *)((uint8_t *)cap_regs + cap_regs->dboff);
TRACE_VAL_F(cap_regs->caplength, "%hhx");
TRACE_VAL_F(cap_regs->hciversion, "%hx");
TRACE_VAL_F(cap_regs->hcsparams1, "%x");
TRACE_VAL_F(cap_regs->hcsparams2, "%x");
TRACE_VAL_F(cap_regs->hcsparams3, "%x");
TRACE_VAL_F(cap_regs->hccparams1, "%x");
TRACE_VAL_F(cap_regs->dboff, "%x");
TRACE_VAL_F(cap_regs->rtsoff, "%x");
TRACE_VAL_F(cap_regs->hccparams2, "%x");
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
TRACE_VAL_F(op_regs->pagesize, "%x");
TRACE_VAL_F(op_regs->dnctrl, "%x");
TRACE_VAL_F(op_regs->crcr, "%lx");
TRACE_VAL_F(op_regs->dcbaap, "%lx");
TRACE_VAL_F(op_regs->config, "%x");
TRACE_LN("Stopping controller...");
XHCI_OP_REGS_RS_W(op_regs, 0);
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
while (!XHCI_OP_REGS_HCH(op_regs))
;
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
TRACE_LN("Resetting controller...");
XHCI_OP_REGS_EINT_W(op_regs, 0);
XHCI_OP_REGS_HCRST_W(op_regs, 1);
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
while (XHCI_OP_REGS_HCRST_R(op_regs))
;
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
while (XHCI_OP_REGS_CNR(op_regs))
;
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
TRACE_LN("Setting up command ring...");
xhci_trb_t *wrapper = &cr[RING_LENGTH];
wrapper->parameter = (uint64_t)VIRT_TO_PHYS(cr);
wrapper->status = 0;
XHCI_TRB_TRB_TYPE_W(wrapper, XHCI_TRB_TYPE_LINK);
XHCI_TRB_TOGGLE_CYCLE_W(wrapper, 1);
XHCI_TRB_CYCLE_W(wrapper, cr_cycle);
TRACE_LN("Configuring controller...");
XHCI_OP_REGS_MAX_SLOTS_EN_W(op_regs, MAX_SLOTS);
op_regs->dcbaap = (uint64_t)VIRT_TO_PHYS(dcbaa);
op_regs->crcr = (uint64_t)VIRT_TO_PHYS(cr) | cr_cycle;
erst[0].size = RING_LENGTH;
erst[0].base = (uint64_t)VIRT_TO_PHYS(er);
intr_regs->erstsz = sizeof(erst) / sizeof(xchi_erst_entry_t);
intr_regs->erstba = (uint64_t)VIRT_TO_PHYS(erst);
intr_regs->erdp = erst[0].base;
TRACE_VAL_F(op_regs->config, "%x");
TRACE_VAL_F(op_regs->dcbaap, "%lx");
TRACE_VAL_F(op_regs->crcr, "%lx");
TRACE_VAL_F(intr_regs->erstba, "%lx");
TRACE_VAL_F(intr_regs->erstsz, "%x");
TRACE_VAL_F(intr_regs->erdp, "%lx");
TRACE_VAL_F(erst[0].size, "%hx");
TRACE_VAL_F(erst[0].base, "%lx");
TRACE_LN("Starting controller...");
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
XHCI_OP_REGS_RS_W(op_regs, 1);
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
while (XHCI_OP_REGS_HCH(op_regs))
;
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
LOG_LN("Enumerating ports...");
xhci_enumerate(kernel_log);
LOG_LN("Done.");
}
void xhci_enumerate(stream_t *out) {
for (uint8_t i = 0; i < XHCI_CAP_REGS_MAX_PORTS(cap_regs); i++) {
PRINT_LN(out, "port=%d CCS=%d PED=%d PP=%d PS=%d", i, XHCI_PORT_REGS_CCS(&port_regs[i]), XHCI_PORT_REGS_PED(&port_regs[i]),
XHCI_PORT_REGS_PP(&port_regs[i]), XHCI_PORT_REGS_PS(&port_regs[i]));
}
}
uint8_t xhci_port_count() {
return XHCI_CAP_REGS_MAX_PORTS(cap_regs);
}
uint8_t xhci_port_connected(uint8_t port) {
return XHCI_PORT_REGS_CCS(&port_regs[port]);
}
xhci_slot_t xhci_attach(uint8_t port) {
ASSERT(!tr_attached_slot, "xhci_attach: Can only attach one port at a time.")
ASSERT(XHCI_PORT_REGS_CCS(&port_regs[port]), "xhci_attach: Port is not connected.");
memory_set(0, sizeof(tr), tr);
tr_i = 0;
tr_cycle = 1;
LOG_LN("Resetting device...");
port_regs[port].portsc = 1 << 4;
while (XHCI_PORT_REGS_PR_R(&port_regs[port]))
;
while (!XHCI_PORT_REGS_PED(&port_regs[port]))
;
TRACE_VAL_F(XHCI_PORT_REGS_PED(&port_regs[port]), "%hhx");
LOG_LN("Enabling a slot...");
xhci_trb_t cmd_es;
memory_set(0, sizeof(xhci_trb_t), &cmd_es);
XHCI_TRB_TRB_TYPE_W(&cmd_es, XHCI_TRB_TYPE_COMMAND_ENABLE_SLOT);
xhci_slot_t slot = XHCI_TRB_SLOT_ID_R(command_exec_sync(&cmd_es));
LOG_LN("Addressing device...");
memory_set(0, sizeof(input_ctx), &input_ctx);
input_ctx.control.add_flags = 0b11;
XHCI_SLOT_CTX_CTX_ENTRIES_W(&input_ctx.slot, 1);
XHCI_SLOT_CTX_ROOT_HUB_PORT_W(&input_ctx.slot, port + 1);
XHCI_SLOT_CTX_SPEED_W(&input_ctx.slot, XHCI_PORT_REGS_PS((&port_regs[port])));
USB_EP_CTX_EP_TYPE_W(&input_ctx.ep[0], 4);
USB_EP_CTX_MAX_PACKET_SIZE_W(&input_ctx.ep[0], 64);
input_ctx.ep[0].dequeue = (uint64_t)VIRT_TO_PHYS(tr) | tr_cycle;
dcbaa[slot] = VIRT_TO_PHYS(&device_ctx);
xhci_trb_t cmd_ad;
memory_set(0, sizeof(xhci_trb_t), &cmd_ad);
cmd_ad.parameter = (uint64_t)VIRT_TO_PHYS(&input_ctx);
XHCI_TRB_TRB_TYPE_W(&cmd_ad, XHCI_TRB_TYPE_COMMAND_ADDRESS_DEVICE);
XHCI_TRB_SLOT_ID_W(&cmd_ad, slot);
command_exec_sync(&cmd_ad);
tr_attached_slot = slot;
return slot;
}
uint64_t xhci_control_transfer(xhci_slot_t slot, uint64_t setup, void *data, uint16_t length) {
ASSERT(tr_attached_slot == slot, "xhci_control_transfer: Can only attach one port at a time.");
LOG_LN("Queueing transfer TRBs...");
tr[tr_i].parameter = setup;
tr[tr_i].status = sizeof(setup);
XHCI_TRB_TRB_TYPE_W(&tr[tr_i], XHCI_TRB_TYPE_TRANSFER_SETUP_STAGE);
BITS_W(tr[tr_i].control, 17, 16, 3);
BITS_W(tr[tr_i].control, 6, 6, 1);
XHCI_TRB_CYCLE_W(&tr[tr_i], tr_cycle);
LOG_VAL_F(tr[tr_i].parameter, "%lx");
LOG_VAL_F(tr[tr_i].status, "%x");
LOG_VAL_F(tr[tr_i].control, "%x");
tr_i = (tr_i + 1) % RING_LENGTH;
XHCI_TRB_CYCLE_W(&tr[RING_LENGTH], tr_cycle);
tr_cycle ^= (tr_i == 0);
tr[tr_i].parameter = (uint64_t)VIRT_TO_PHYS(data);
tr[tr_i].status = length;
XHCI_TRB_TRB_TYPE_W(&tr[tr_i], XHCI_TRB_TYPE_TRANSFER_DATA_STAGE);
BITS_W(tr[tr_i].control, 16, 16, 1);
XHCI_TRB_CYCLE_W(&tr[tr_i], tr_cycle);
LOG_VAL_F(tr[tr_i].parameter, "%lx");
LOG_VAL_F(tr[tr_i].status, "%x");
LOG_VAL_F(tr[tr_i].control, "%x");
tr_i = (tr_i + 1) % RING_LENGTH;
XHCI_TRB_CYCLE_W(&tr[RING_LENGTH], tr_cycle);
tr_cycle ^= (tr_i == 0);
xhci_trb_t *tre = &tr[tr_i];
XHCI_TRB_TRB_TYPE_W(&tr[tr_i], XHCI_TRB_TYPE_TRANSFER_STATUS_STAGE);
BITS_W(tr[tr_i].control, 16, 16, 0);
BITS_W(tr[tr_i].control, 5, 5, 1);
XHCI_TRB_CYCLE_W(&tr[tr_i], tr_cycle);
tr_i = (tr_i + 1) % RING_LENGTH;
XHCI_TRB_CYCLE_W(&tr[RING_LENGTH], tr_cycle);
tr_cycle ^= (tr_i == 0);
LOG_LN("Ringing slot doorbell...");
db_regs[tr_attached_slot] = 1;
LOG_LN("Waiting for completion...");
while (1) {
xhci_trb_t *cmp = &er[er_i];
while (XHCI_TRB_CYCLE_R(cmp) != er_cycle)
;
er_i = (er_i + 1) % RING_LENGTH;
intr_regs->erdp = (uint64_t)(VIRT_TO_PHYS(&er[er_i]));
er_cycle ^= (er_i == 0);
if (XHCI_TRB_TRB_TYPE_R(cmp) != XHCI_TRB_TYPE_EVENT_TRANSFER_COMPLETION || (void *)cmp->parameter != VIRT_TO_PHYS(tre)) {
LOG_LN("Received irrelevant event, skipping...");
} else {
LOG_LN("Received transfer completion event...");
LOG_VAL_F(cmp->parameter, "%lx");
LOG_VAL_F(cmp->status, "%x");
LOG_VAL_F(cmp->control, "%x");
ASSERT(XHCI_TRB_COMPLETION_CODE(cmp) == 1, "xhci_control_transfer: Transfer failed.");
return length - (cmp->status & 0xFFFFFF);
}
}
}
void xhci_detach(xhci_slot_t slot) {
ASSERT(tr_attached_slot == slot, "xhci_detach: Slot not attached.");
xhci_trb_t cmd_ds;
memory_set(0, sizeof(xhci_trb_t), &cmd_ds);
XHCI_TRB_TRB_TYPE_W(&cmd_ds, XHCI_TRB_TYPE_COMMAND_DISABLE_SLOT);
XHCI_TRB_SLOT_ID_W(&cmd_ds, slot);
command_exec_sync(&cmd_ds);
dcbaa[slot] = 0;
tr_attached_slot = 0;
}