From b35fc5545c88cbd0199e1c481ef48aa3947f8aca Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Sun, 22 Mar 2026 23:09:21 +0100 Subject: [PATCH] XHCI test sending noop command --- kernel/amd64/apic.c | 6 +- kernel/amd64/bootmain.c | 4 +- kernel/amd64/intr.c | 6 +- kernel/amd64/intr_defs.h | 13 +- kernel/amd64/intr_stub.S | 6 +- kernel/amd64/smp.c | 2 +- kernel/device/pci_ide.c | 9 +- kernel/device/pci_xhci.c | 32 ++++- kernel/device/ps2_kb.c | 6 +- kernel/device/xhci.c | 265 ++++++++++++++++++++++++++++++++++++++- kernel/device/xhci.h | 42 +++++++ 11 files changed, 360 insertions(+), 31 deletions(-) diff --git a/kernel/amd64/apic.c b/kernel/amd64/apic.c index 3e16e59..4100106 100644 --- a/kernel/amd64/apic.c +++ b/kernel/amd64/apic.c @@ -239,12 +239,12 @@ static uint32_t lapic_calibrate (uint32_t us) { lapic_write (LAPIC_DCR, DIVIDER_VALUE); - lapic_write (LAPIC_LVTTR, SCHED_PREEMPT_TIMER | (1 << 16)); + lapic_write (LAPIC_LVTTR, INTR_SCHED_PREEMPT_TIMER | (1 << 16)); lapic_write (LAPIC_TIMICT, 0xFFFFFFFF); sleep_micro (us); - lapic_write (LAPIC_LVTTR, SCHED_PREEMPT_TIMER | (0 << 16)); + lapic_write (LAPIC_LVTTR, INTR_SCHED_PREEMPT_TIMER | (0 << 16)); uint32_t ticks = 0xFFFFFFFF - lapic_read (LAPIC_TIMCCT); DEBUG ("timer ticks = %u\n", ticks); @@ -261,7 +261,7 @@ static uint32_t lapic_calibrate (uint32_t us) { static void lapic_start (uint32_t ticks) { lapic_write (LAPIC_DCR, DIVIDER_VALUE); lapic_write (LAPIC_TIMICT, ticks); - lapic_write (LAPIC_LVTTR, SCHED_PREEMPT_TIMER | (1 << 17)); + lapic_write (LAPIC_LVTTR, INTR_SCHED_PREEMPT_TIMER | (1 << 17)); } /* diff --git a/kernel/amd64/bootmain.c b/kernel/amd64/bootmain.c index ab66e5b..5e2c816 100644 --- a/kernel/amd64/bootmain.c +++ b/kernel/amd64/bootmain.c @@ -78,8 +78,8 @@ void bootmain (void) { struct device* temp0 = device_find ("temp0"); vfs_create_volume (thiscpu->kproc, &rctx, "temp", FS_FAT16, temp0, true); - irq_attach (&proc_irq_sched, NULL, SCHED_PREEMPT_TIMER); - irq_attach (&proc_irq_sched, NULL, CPU_REQUEST_SCHED); + irq_attach (&proc_irq_sched, NULL, INTR_SCHED_PREEMPT_TIMER); + irq_attach (&proc_irq_sched, NULL, INTR_CPU_REQUEST_SCHED); smp_init (); diff --git a/kernel/amd64/intr.c b/kernel/amd64/intr.c index 56c7fd0..a803bb8 100644 --- a/kernel/amd64/intr.c +++ b/kernel/amd64/intr.c @@ -126,9 +126,9 @@ static void idt_init (void) { IDT_ENTRY (40, 2); IDT_ENTRY (41, 2); IDT_ENTRY (42, 2); IDT_ENTRY (43, 2); IDT_ENTRY (44, 2); IDT_ENTRY (45, 2); IDT_ENTRY (46, 2); IDT_ENTRY (47, 2); - IDT_ENTRY (SCHED_PREEMPT_TIMER, 2); - IDT_ENTRY (CPU_REQUEST_SCHED, 2); - IDT_ENTRY (CPU_SPURIOUS, 2); + IDT_ENTRY (INTR_SCHED_PREEMPT_TIMER, 2); + IDT_ENTRY (INTR_CPU_REQUEST_SCHED, 2); + IDT_ENTRY (INTR_CPU_SPURIOUS, 2); /* clang-format on */ #undef IDT_ENTRY diff --git a/kernel/amd64/intr_defs.h b/kernel/amd64/intr_defs.h index 2390ef8..185a930 100644 --- a/kernel/amd64/intr_defs.h +++ b/kernel/amd64/intr_defs.h @@ -1,12 +1,13 @@ #ifndef _KERNEL_AMD64_INTR_DEFS_H #define _KERNEL_AMD64_INTR_DEFS_H -#define PS2KB 32 -#define IDE_DRIVE_PRIM 33 -#define IDE_DRIVE_SCND 34 +#define INTR_PS2KB 32 +#define INTR_IDE_DRIVE_PRIM 33 +#define INTR_IDE_DRIVE_SCND 34 +#define INTR_XHCI 35 -#define SCHED_PREEMPT_TIMER 80 -#define CPU_REQUEST_SCHED 82 -#define CPU_SPURIOUS 255 +#define INTR_SCHED_PREEMPT_TIMER 80 +#define INTR_CPU_REQUEST_SCHED 82 +#define INTR_CPU_SPURIOUS 255 #endif // _KERNEL_AMD64_INTR_DEFS_H diff --git a/kernel/amd64/intr_stub.S b/kernel/amd64/intr_stub.S index 6fa6b09..014c13e 100644 --- a/kernel/amd64/intr_stub.S +++ b/kernel/amd64/intr_stub.S @@ -91,6 +91,6 @@ make_intr_stub(no_err, 45) make_intr_stub(no_err, 46) make_intr_stub(no_err, 47) -make_intr_stub(no_err, SCHED_PREEMPT_TIMER) -make_intr_stub(no_err, CPU_REQUEST_SCHED) -make_intr_stub(no_err, CPU_SPURIOUS) +make_intr_stub(no_err, INTR_SCHED_PREEMPT_TIMER) +make_intr_stub(no_err, INTR_CPU_REQUEST_SCHED) +make_intr_stub(no_err, INTR_CPU_SPURIOUS) diff --git a/kernel/amd64/smp.c b/kernel/amd64/smp.c index d25d39b..eed790e 100644 --- a/kernel/amd64/smp.c +++ b/kernel/amd64/smp.c @@ -52,7 +52,7 @@ void cpu_request_sched (struct cpu* cpu, bool user) { return; } - lapic_ipi (cpu->lapic_id, CPU_REQUEST_SCHED); + lapic_ipi (cpu->lapic_id, INTR_CPU_REQUEST_SCHED); } struct cpu* cpu_find_lightest (void) { diff --git a/kernel/device/pci_ide.c b/kernel/device/pci_ide.c index 5b6dcd9..5584ad4 100644 --- a/kernel/device/pci_ide.c +++ b/kernel/device/pci_ide.c @@ -124,10 +124,10 @@ bool pci_ide_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_in } else { irqs_support = true; - if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, IDE_DRIVE_PRIM, + if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, INTR_IDE_DRIVE_PRIM, thiscpu->lapic_id)) { - ioapic_route_irq (IDE_DRIVE_PRIM, 14, 0, thiscpu->lapic_id); - ioapic_route_irq (IDE_DRIVE_SCND, 15, 0, thiscpu->lapic_id); + ioapic_route_irq (INTR_IDE_DRIVE_PRIM, 14, 0, thiscpu->lapic_id); + ioapic_route_irq (INTR_IDE_DRIVE_SCND, 15, 0, thiscpu->lapic_id); DEBUG ("Fallback to IOAPIC interrupt routing\n"); } } @@ -136,7 +136,8 @@ bool pci_ide_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_in DEBUG ("scmd=%x, sctrl=%x\n", scmd, sctrl); DEBUG ("IRQ support=%d\n", irqs_support); - uint16_t channels[2][3] = {{pcmd, pctrl, IDE_DRIVE_PRIM}, {scmd, sctrl, IDE_DRIVE_SCND}}; + uint16_t channels[2][3] = {{pcmd, pctrl, INTR_IDE_DRIVE_PRIM}, + {scmd, sctrl, INTR_IDE_DRIVE_SCND}}; for (size_t i = 0; i < lengthof (channels); i++) { uint16_t cmd = channels[i][0]; diff --git a/kernel/device/pci_xhci.c b/kernel/device/pci_xhci.c index 2bea411..9527e6a 100644 --- a/kernel/device/pci_xhci.c +++ b/kernel/device/pci_xhci.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -28,7 +30,7 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i uint16_t pci_cmd = pci_read16 (pci_info.bus, pci_info.slot, pci_info.func, PCI_COMMAND); - uint16_t new_cmd = (pci_cmd | (1 << 1) | (1 << 2)); + uint16_t new_cmd = (pci_cmd | (1 << 1) | (1 << 2)) & ~(1 << 10); if (pci_cmd != new_cmd) { pci_write16 (pci_info.bus, pci_info.slot, pci_info.func, PCI_COMMAND, new_cmd); @@ -55,13 +57,35 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i uintptr_t xhci_base = xhci_phys + (uintptr_t)hhdm->offset; /* 2 pages should cover the mmio space */ - mm_map_kernel_page (xhci_phys, xhci_base, MM_PG_RW | MM_PG_PRESENT); - mm_map_kernel_page (xhci_phys + PAGE_SIZE, xhci_base + PAGE_SIZE, MM_PG_RW | MM_PG_PRESENT); + for (size_t page = 0; page < 8; page++) { + mm_map_kernel_page (xhci_phys + page * PAGE_SIZE, xhci_base + page * PAGE_SIZE, + MM_PG_RW | MM_PG_PRESENT); + } + + bool irqs_support = false; + + if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, INTR_XHCI, thiscpu->lapic_id)) { + uint8_t intr_line = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_INTERRUPT_LINE); + uint8_t intr_pin = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_INTERRUPT_PIN); + + if (intr_pin != 0) { + irqs_support = true; + ioapic_route_irq (INTR_XHCI, intr_line, 0, thiscpu->lapic_id); + } + } else { + irqs_support = true; + } + + DEBUG ("IRQ support=%d\n", irqs_support); char key[32]; snprintf (key, sizeof (key), "xhci%d", xhci_counter++); - struct xhci_init init = {.xhci_mmio_base = xhci_base}; + struct xhci_init init = { + .xhci_mmio_base = xhci_base, + .irqs_support = irqs_support, + .irq = INTR_XHCI, + }; device_op_func_t ops[] = {0}; diff --git a/kernel/device/ps2_kb.c b/kernel/device/ps2_kb.c index d524328..e1eeeca 100644 --- a/kernel/device/ps2_kb.c +++ b/kernel/device/ps2_kb.c @@ -226,8 +226,8 @@ static void ps2kb_set_typematic (uint8_t delay, uint8_t rate) { } DEFINE_DEVICE_INIT (ps2kb_init) { - ioapic_route_irq (PS2KB, 1, 0, thiscpu->lapic_id); - irq_attach (&ps2kb_irq, NULL, PS2KB); + ioapic_route_irq (INTR_PS2KB, 1, 0, thiscpu->lapic_id); + irq_attach (&ps2kb_irq, NULL, INTR_PS2KB); ringbuffer_init (&ps2kb_ringbuffer, PS2KB_RINGBUFFER_MAX, sizeof (uint8_t)); @@ -252,6 +252,6 @@ DEFINE_DEVICE_INIT (ps2kb_init) { DEFINE_DEVICE_FINI (ps2kb_fini) { (void)device, (void)proc, (void)rctx; - irq_detach (PS2KB); + irq_detach (INTR_PS2KB); ringbuffer_fini (&ps2kb_ringbuffer); } diff --git a/kernel/device/xhci.c b/kernel/device/xhci.c index 197656d..b037e8f 100644 --- a/kernel/device/xhci.c +++ b/kernel/device/xhci.c @@ -1,10 +1,13 @@ #include #include #include +#include #include #include #include +#include #include +#include #include #include #include @@ -52,6 +55,41 @@ #define XHCI_ERSTBA 0x10 #define XHCI_ERDP 0x18 +/* event types */ +#define XHCI_TRB_NORMAL 1 +#define XHCI_TRB_SETUP_STAGE 2 +#define XHCI_TRB_DATA_STAGE 3 +#define XHCI_TRB_STATUS_STAGE 4 +#define XHCI_TRB_ISOCH 5 +#define XHCI_TRB_LINK 6 +#define XHCI_TRB_EVENT_DATA 7 +#define XHCI_TRB_NOOP 8 +#define XHCI_TRB_SLOT_ENAB_CMD 9 +#define XHCI_TRB_SLOT_DISB_CMD 10 +#define XHCI_TRB_ADDR_DEV_CMD 11 +#define XHCI_TRB_CFG_ENDP_CMD 12 +#define XHCI_TRB_EVAL_CTX_CMD 13 +#define XHCI_TRB_RESET_ENDP_CMD 14 +#define XHCI_TRB_STOP_ENDP_CMD 15 +#define XHCI_TRB_SET_DRDQP_CMD 16 +#define XHCI_TRB_RESET_DEV_CMD 17 +#define XHCI_TRB_FORCE_EVT_CMD 18 +#define XHCI_TRB_NEGO_BANDW_CMD 19 +#define XHCI_TRB_SET_LTV_CMD 20 +#define XHCI_TRB_PORT_BANDW_CMD 21 +#define XHCI_TRB_FORCE_HEADER 22 +#define XHCI_TRB_NOOP_CMD 23 +#define XHCI_TRB_GET_EXTPRP_CMD 24 +#define XHCI_TRB_SET_EXTPRP_CMD 25 +#define XHCI_TRB_TRANSFER_EVENT 32 +#define XHCI_TRB_CMD_CMPL_EVENT 33 +#define XHCI_TRB_PORT_STS_CHNG 34 +#define XHCI_TRB_BANDW_RQ_EVENT 35 +#define XHCI_TRB_DOORBELL_EVENT 36 +#define XHCI_TRB_HOST_CTRL_EVNT 37 +#define XHCI_TRB_DEV_NOTIF_EVNT 38 +#define XHCI_TRB_MFINDEX_WRAP 39 + /* clang-format on */ static void xhci_write8 (uintptr_t base, uint32_t reg, uint8_t value) { @@ -78,7 +116,130 @@ static uint32_t xhci_read32 (uintptr_t base, uint32_t reg) { return *(volatile uint32_t*)(base + reg); } +static void xhci_event_dispatch (struct xhci* xhci, struct xhci_trb* event, uint8_t type) { + switch (type) { + case XHCI_TRB_CMD_CMPL_EVENT: { + uintptr_t cmd_trb_phys = event->param; + uint8_t cmpl_code = (event->status >> 24) & 0xFF; + uint8_t slot_id = (event->ctrl >> 24) & 0xFF; + + DEBUG ("cmd completion: phys=%p,code=%u,slot=%u\n", cmd_trb_phys, cmpl_code, slot_id); + } break; + default: + DEBUG ("Unhandled event type %u at %u\n", type, xhci->event_ring_idx); + break; + } +} + +static void xhci_poll_events (struct xhci* xhci) { + uintptr_t ir_base = xhci->xhci_runtime_base + 0x20; + + bool serviced = false; + for (;;) { + struct xhci_trb* event = &xhci->event_ring[xhci->event_ring_idx]; + + if ((event->ctrl & 0x1) != xhci->event_cycle_bit) { + break; + } + + serviced = true; + + uint8_t type = (event->ctrl >> 10) & 0x3F; + + xhci_event_dispatch (xhci, event, type); + + xhci->event_ring_idx++; + + if (xhci->event_ring_idx >= xhci->event_ring_size) { + xhci->event_ring_idx = 0; + xhci->event_cycle_bit ^= 1; + } + } + + if (serviced) { + uintptr_t dequeue_ptr = + xhci->event_ring_phys + (xhci->event_ring_idx * sizeof (struct xhci_trb)); + + xhci_write32 (ir_base, XHCI_ERDP, (uint32_t)dequeue_ptr | (1 << 3)); + xhci_write32 (ir_base, XHCI_ERDP + 4, (uint32_t)(dequeue_ptr >> 32)); + + atomic_store (&xhci->pending, false); + } +} + +static void xhci_irq (void* arg, void* regs, bool user, struct reschedule_ctx* rctx) { + (void)user, (void)regs, (void)rctx; + + uint64_t fd; + + struct xhci* xhci = arg; + + spin_lock (&xhci->device->lock, &fd); + + uintptr_t ir_base = xhci->xhci_runtime_base + 0x20; + + /* ack */ + + uint32_t iman = xhci_read32 (ir_base, XHCI_IMAN); + xhci_write32 (ir_base, XHCI_IMAN, iman | 0x01); + + uint32_t usbsts = xhci_read32 (xhci->xhci_oper_base, XHCI_USBSTS); + xhci_write32 (xhci->xhci_oper_base, XHCI_USBSTS, usbsts | (1 << 3)); + + /* clear event busy */ + uint64_t erdp = (uint64_t)xhci_read32 (ir_base, XHCI_ERDP) | + ((uint64_t)xhci_read32 (ir_base, XHCI_ERDP + 4) << 32); + xhci_write32 (ir_base, XHCI_ERDP, (uint32_t)erdp | (1 << 3)); + + xhci_poll_events (xhci); + + spin_unlock (&xhci->device->lock, fd); +} + +void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t ctrl) { + uint64_t fd; + + spin_lock (&xhci->device->lock, &fd); + + if (xhci->irqs_support) { + if (xhci->cmd_ring_idx == (xhci->cmd_ring_size - 1)) { + struct xhci_trb* link = &xhci->cmd_ring[xhci->cmd_ring_idx]; + link->param = xhci->cmd_ring_phys; + link->status = 0; + link->ctrl = (6 << 10) | (1 << 1) | xhci->cmd_cycle_bit; + + xhci->cmd_ring_idx = 0; + xhci->cmd_cycle_bit ^= 1; + } + + struct xhci_trb* trb = &xhci->cmd_ring[xhci->cmd_ring_idx]; + trb->param = param; + trb->status = status; + trb->ctrl = (ctrl & ~0x1) | xhci->cmd_cycle_bit; + + xhci->cmd_ring_idx++; + + atomic_store (&xhci->pending, true); + + xhci_write32 (xhci->xhci_doorbell_base, 0, 0); + + spin_unlock (&xhci->device->lock, fd); + while (atomic_load (&xhci->pending)) + spin_lock_relax (); + spin_lock (&xhci->device->lock, &fd); + } else { + while (atomic_load (&xhci->pending)) { + xhci_poll_events (xhci); + spin_lock_relax (); + } + } + + spin_unlock (&xhci->device->lock, fd); +} + DEFINE_DEVICE_INIT (xhci_init) { + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + struct xhci* xhci = malloc (sizeof (*xhci)); if (xhci == NULL) @@ -89,6 +250,8 @@ DEFINE_DEVICE_INIT (xhci_init) { memset (xhci, 0, sizeof (*xhci)); xhci->device = device; xhci->xhci_mmio_base = init->xhci_mmio_base; + xhci->irqs_support = init->irqs_support; + xhci->irq = init->irq; device->udata = xhci; @@ -109,8 +272,7 @@ DEFINE_DEVICE_INIT (xhci_init) { spin_lock_relax (); /* STOP */ - uint32_t usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD); - xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, usbcmd & ~0x01); + xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, 0); /* wait for HCH bit */ int timeout = 100000; @@ -133,11 +295,110 @@ DEFINE_DEVICE_INIT (xhci_init) { DEBUG ("XHCI init done\n"); + uint32_t hcsparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCSPARAMS1); + uint8_t max_slots = (uint8_t)(hcsparams1 & 0xFF); + + /* enable slots */ + uint32_t config = xhci_read32 (xhci->xhci_oper_base, XHCI_CONFIG); + xhci_write32 (xhci->xhci_oper_base, XHCI_CONFIG, (config & ~0xFF) | max_slots); + + DEBUG ("enabled %u slots\n", max_slots); + + uint32_t hcsparams2 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCSPARAMS2); + xhci->max_scratchpad = (hcsparams2 >> 27) & 0x1F; + + uintptr_t dcbaa_phys = pmm_alloc (1); + + xhci->xhci_dcbaa_phys = dcbaa_phys; + + xhci->xhci_dcbaa = (uintptr_t*)(dcbaa_phys + (uintptr_t)hhdm->offset); + memset (xhci->xhci_dcbaa, 0, PAGE_SIZE); + + if (xhci->max_scratchpad > 0) { + uintptr_t dev_array_phys = pmm_alloc (1); + + uintptr_t* dev_array = (uintptr_t*)(dev_array_phys + (uintptr_t)hhdm->offset); + memset (dev_array, 0, PAGE_SIZE); + + for (size_t i = 0; i < xhci->max_scratchpad; i++) + dev_array[i] = pmm_alloc (1); + + xhci->xhci_dcbaa[0] = dev_array_phys; + } + + xhci_write32 (xhci->xhci_oper_base, XHCI_DCBAAP, (uint32_t)xhci->xhci_dcbaa_phys); + xhci_write32 (xhci->xhci_oper_base, XHCI_DCBAAP + 4, (uint32_t)(xhci->xhci_dcbaa_phys >> 32)); + + xhci->cmd_ring_phys = pmm_alloc (1); + xhci->cmd_ring = (struct xhci_trb*)(xhci->cmd_ring_phys + (uintptr_t)hhdm->offset); + xhci->cmd_ring_size = PAGE_SIZE / sizeof (struct xhci_trb); + xhci->cmd_ring_idx = 0; + xhci->cmd_cycle_bit = 1; + memset (xhci->cmd_ring, 0, PAGE_SIZE); + + uint64_t crcr = xhci->cmd_ring_phys | xhci->cmd_cycle_bit; + xhci_write32 (xhci->xhci_oper_base, XHCI_CRCR, (uint32_t)crcr); + xhci_write32 (xhci->xhci_oper_base, XHCI_CRCR + 4, (uint32_t)(crcr >> 32)); + + xhci->event_ring_phys = pmm_alloc (1); + xhci->event_ring = (struct xhci_trb*)(xhci->event_ring_phys + (uintptr_t)hhdm->offset); + xhci->event_ring_size = PAGE_SIZE / sizeof (struct xhci_trb); + xhci->event_ring_idx = 0; + xhci->event_cycle_bit = 1; + memset (xhci->event_ring, 0, PAGE_SIZE); + + xhci->erst_phys = pmm_alloc (1); + xhci->erst = (struct xhci_erst_entry*)(xhci->erst_phys + (uintptr_t)hhdm->offset); + xhci->erst[0].ptr = xhci->event_ring_phys; + xhci->erst[0].size = xhci->event_ring_size; + xhci->erst[0]._rsvd = 0; + + uintptr_t ir_base = xhci->xhci_runtime_base + 0x20; + xhci_write32 (ir_base, XHCI_ERSTSZ, 1); + xhci_write32 (ir_base, XHCI_ERSTBA, (uint32_t)xhci->erst_phys); + xhci_write32 (ir_base, XHCI_ERSTBA + 4, (uint32_t)(xhci->erst_phys >> 32)); + + xhci_write32 (ir_base, XHCI_ERDP, (uint32_t)xhci->event_ring_phys | (1 << 3)); + xhci_write32 (ir_base, XHCI_ERDP + 4, (uint32_t)(xhci->event_ring_phys >> 32)); + + if (xhci->irqs_support) { + /* enable interrupter */ + irq_attach (&xhci_irq, xhci, xhci->irq); + xhci_write32 (ir_base, XHCI_IMAN, xhci_read32 (ir_base, XHCI_IMAN) | 0x02); + } + + uint32_t usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD); + xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, usbcmd | 0x01 | (1 << 2)); + + xhci_send_cmd (xhci, 0, 0, (23 << 10)); + return true; } DEFINE_DEVICE_FINI (xhci_fini) { + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + struct xhci* xhci = device->udata; + if (xhci->max_scratchpad > 0) { + uintptr_t dev_array_phys = xhci->xhci_dcbaa[0]; + + uintptr_t* dev_array = (uintptr_t*)(dev_array_phys + (uintptr_t)hhdm->offset); + + for (size_t i = 0; i < xhci->max_scratchpad; i++) { + if (dev_array[i] != 0) + pmm_free (dev_array[i], 1); + } + + pmm_free (dev_array_phys, 1); + } + + pmm_free (xhci->xhci_dcbaa_phys, 1); + pmm_free (xhci->cmd_ring_phys, 1); + pmm_free (xhci->event_ring_phys, 1); + pmm_free (xhci->erst_phys, 1); + + irq_detach (xhci->irq); + free (xhci); } diff --git a/kernel/device/xhci.h b/kernel/device/xhci.h index e4092d0..6e06846 100644 --- a/kernel/device/xhci.h +++ b/kernel/device/xhci.h @@ -1,6 +1,7 @@ #ifndef _KERNEL_DEVICE_XHCI_H #define _KERNEL_DEVICE_XHCI_H +#include #include #include #include @@ -8,16 +9,57 @@ #include #include +/* event ring segment table entry */ +struct xhci_erst_entry { + uint64_t ptr; + uint32_t size; + uint32_t _rsvd; +} PACKED; + +/* transfer request block */ +struct xhci_trb { + uint64_t param; + uint32_t status; + uint32_t ctrl; +} PACKED; + struct xhci_init { uintptr_t xhci_mmio_base; + bool irqs_support; + uint8_t irq; }; struct xhci { struct device* device; + + bool irqs_support; + uint8_t irq; + uintptr_t xhci_mmio_base; uintptr_t xhci_oper_base; uintptr_t xhci_runtime_base; uintptr_t xhci_doorbell_base; + + uintptr_t* xhci_dcbaa; + uintptr_t xhci_dcbaa_phys; + uint32_t max_scratchpad; + + struct xhci_trb* cmd_ring; + uintptr_t cmd_ring_phys; + uint32_t cmd_ring_idx; + uint32_t cmd_ring_size; + uint8_t cmd_cycle_bit; + + struct xhci_trb* event_ring; + uintptr_t event_ring_phys; + uint32_t event_ring_idx; + uint32_t event_ring_size; + uint8_t event_cycle_bit; + + struct xhci_erst_entry* erst; + uintptr_t erst_phys; + + atomic_bool pending; }; DEFINE_DEVICE_INIT (xhci_init);