From 482afb47d79499f6b4f51f8d30926a8911f7e3b4 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Sun, 29 Mar 2026 18:59:20 +0200 Subject: [PATCH] USB driver polling user app, handle only one XHCI controller for now, Implement USB device addressing --- OVMF/OVMF_VARS.fd | Bin 540672 -> 540672 bytes include/device_info.h | 9 +++ include/devices.h | 9 +++ include/syscall_defs.h | 1 + kernel/amd64/intr_defs.h | 5 +- kernel/device/device.c | 57 ++++++++++--- kernel/device/device.h | 6 +- kernel/device/partitions.c | 3 +- kernel/device/pci_ide.c | 4 +- kernel/device/pci_xhci.c | 36 ++++----- kernel/device/xhci.c | 159 +++++++++++++++++++++++++++++++++---- kernel/device/xhci.h | 39 ++++++++- kernel/syscall/syscall.c | 22 +++++ libsystem/system.c | 4 + libsystem/system.h | 4 + make/apps.mk | 3 +- sdutil/Makefile | 1 - usb/.gitignore | 6 ++ usb/Makefile | 10 +++ usb/app.mk | 1 + usb/src.mk | 3 + usb/usb.c | 57 +++++++++++++ 22 files changed, 383 insertions(+), 56 deletions(-) create mode 100644 include/device_info.h create mode 100644 usb/.gitignore create mode 100644 usb/Makefile create mode 100644 usb/app.mk create mode 100644 usb/src.mk create mode 100644 usb/usb.c diff --git a/OVMF/OVMF_VARS.fd b/OVMF/OVMF_VARS.fd index 8894f9850d46c32b39d14944783525cb3a123b30..8cd0488b3df456b6bdb9ec90ca4a841195a875bf 100644 GIT binary patch delta 568 zcmY+>%}T>S5CGuWX7j7jHLXpe780pSL8MxbiV7l15u)N%@LojUAR@$bohR_(!Gk~K zAoLv+!58o#zD7)!nlQ{|zx|up**Fg4IDBzDwu#R?#C30g19vg4`M=Bf#OLv{6{H(` zA7*;i`BDC7n3nciuXaJ5(x5a8_CGm(yDJqAxUDvacQdP4lpHH5{56w<0$KKWDvMJc z0O;YBAF>X1-A1?%J8%rUc^tqAbRmEvIE3~nRw2N1t*SGoFarSZU6*CJr7p-s<7J{@ z88+nvUa?=k(WjiDoTZ%0 j`DM#PN#_bQ5GCc@v6JTi*U~Lm%YZG8!Cct3;0B~*`p#T5? diff --git a/include/device_info.h b/include/device_info.h new file mode 100644 index 0000000..72c12a3 --- /dev/null +++ b/include/device_info.h @@ -0,0 +1,9 @@ +#ifndef _DEVICE_INFO_H +#define _DEVICE_INFO_H + +struct device_info { + int type; + char key[0x100]; +}; + +#endif // _DEVICE_INFO_H diff --git a/include/devices.h b/include/devices.h index 2e7acaf..8d31ea9 100644 --- a/include/devices.h +++ b/include/devices.h @@ -1,6 +1,12 @@ #ifndef _DEVICES_H #define _DEVICES_H +#define DEVICE_TYPE_DEBUGCONSOLE 0 +#define DEVICE_TYPE_TERMINAL 1 +#define DEVICE_TYPE_KEYBOARD 2 +#define DEVICE_TYPE_DRIVE 3 +#define DEVICE_TYPE_USB_CTRL 4 + /* debugconsole device */ #define DEBUGCONSOLE_PUTSTR 0 @@ -21,4 +27,7 @@ #define XDRV_READ 3 #define XDRV_WRITE 4 +/* usb controller devices */ +#define XUSBCTRL_POLL_DRIVER 0 + #endif // _DEVICES_H diff --git a/include/syscall_defs.h b/include/syscall_defs.h index c379c96..c3ebaf1 100644 --- a/include/syscall_defs.h +++ b/include/syscall_defs.h @@ -38,5 +38,6 @@ #define SYS_STREAM_WRITE 35 #define SYS_STREAM_READ 36 #define SYS_GET_PROC_INFO 37 +#define SYS_GET_DEVICE_INFO 38 #endif // _M_SYSCALL_DEFS_H diff --git a/kernel/amd64/intr_defs.h b/kernel/amd64/intr_defs.h index efe1cdb..185a930 100644 --- a/kernel/amd64/intr_defs.h +++ b/kernel/amd64/intr_defs.h @@ -4,10 +4,7 @@ #define INTR_PS2KB 32 #define INTR_IDE_DRIVE_PRIM 33 #define INTR_IDE_DRIVE_SCND 34 -#define INTR_XHCI0 35 -#define INTR_XHCI1 36 -#define INTR_XHCI2 37 -#define INTR_XHCI3 38 +#define INTR_XHCI 35 #define INTR_SCHED_PREEMPT_TIMER 80 #define INTR_CPU_REQUEST_SCHED 82 diff --git a/kernel/device/device.c b/kernel/device/device.c index 302190f..8f40542 100644 --- a/kernel/device/device.c +++ b/kernel/device/device.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,7 @@ struct device* device_find (const char* key) { return hash_entry (found_link, struct device, device_table_link); } -struct device* device_create (const char* key, device_op_func_t* ops, size_t ops_len, +struct device* device_create (int type, const char* key, device_op_func_t* ops, size_t ops_len, device_init_func_t init, device_fini_func_t fini, void* arg, struct proc* proc, struct reschedule_ctx* rctx) { uint64_t fdt; @@ -68,6 +69,7 @@ struct device* device_create (const char* key, device_op_func_t* ops, size_t ops device->init = init; device->fini = fini; memcpy (device->key, key, strlen_null (key)); + device->type = type; if (ops != NULL) memcpy (device->ops, ops, ops_len * sizeof (device_op_func_t)); @@ -91,6 +93,40 @@ struct device* device_create (const char* key, device_op_func_t* ops, size_t ops return device; } +size_t device_populate_device_infos (struct device_info* infos, size_t count) { + uint64_t fdt, fd; + + if (count >= DEVICES_MAX) + count = DEVICES_MAX; + + size_t j = 0; + + spin_lock (&device_table.lock, &fdt); + + for (size_t i = 0; i < lengthof (device_table.device_buckets); i++) { + struct hash_node_link* hash_link = device_table.device_buckets[i]; + + while (hash_link != NULL && j < count) { + struct device* device = hash_entry (hash_link, struct device, device_table_link); + struct device_info* info = &infos[j]; + + spin_lock (&device->lock, &fd); + + memcpy (info->key, device->key, sizeof (info->key)); + info->type = device->type; + + spin_unlock (&device->lock, fd); + + hash_link = hash_link->next; + j++; + } + } + + spin_unlock (&device_table.lock, fdt); + + return j; +} + static void debugconsole_device_init (void) { struct reschedule_ctx rctx; memset (&rctx, 0, sizeof (rctx)); @@ -98,8 +134,8 @@ static void debugconsole_device_init (void) { device_op_func_t ops[] = { [DEBUGCONSOLE_PUTSTR] = &debugconsole_putstr, }; - device_create ("debugconsole", ops, lengthof (ops), &debugconsole_init, &debugconsole_fini, NULL, - thiscpu->kproc, &rctx); + device_create (DEVICE_TYPE_DEBUGCONSOLE, "debugconsole", ops, lengthof (ops), &debugconsole_init, + &debugconsole_fini, NULL, thiscpu->kproc, &rctx); } static void terminal_device_init (void) { @@ -110,8 +146,8 @@ static void terminal_device_init (void) { [TERMINAL_PUTSTR] = &terminal_putstr, [TERMINAL_DIMENSIONS] = &terminal_dimensions, }; - device_create ("terminal", ops, lengthof (ops), &terminal_init, &terminal_fini, NULL, - thiscpu->kproc, &rctx); + device_create (DEVICE_TYPE_TERMINAL, "terminal", ops, lengthof (ops), &terminal_init, + &terminal_fini, NULL, thiscpu->kproc, &rctx); } static void sys_device_init (void) { @@ -155,8 +191,8 @@ static void sys_device_init (void) { .sector_size = 512, .buffer = unpack_buffer, }; - device_create ("sys0", ops, lengthof (ops), &ramdrv_init, &ramdrv_fini, &init, thiscpu->kproc, - &rctx); + device_create (DEVICE_TYPE_DRIVE, "sys0", ops, lengthof (ops), &ramdrv_init, &ramdrv_fini, &init, + thiscpu->kproc, &rctx); LZ4F_freeDecompressionContext (dctx); } @@ -177,8 +213,8 @@ static void temp_device_init (void) { .total_size = 1024 * 1024 * 20, .sector_size = 512, }; - device_create ("temp0", ops, lengthof (ops), &ramdrv_init, &ramdrv_fini, &init, thiscpu->kproc, - &rctx); + device_create (DEVICE_TYPE_DRIVE, "temp0", ops, lengthof (ops), &ramdrv_init, &ramdrv_fini, &init, + thiscpu->kproc, &rctx); } #if defined(__x86_64__) @@ -189,7 +225,8 @@ static void ps2kb_device_init (void) { device_op_func_t ops[] = { [KB_READ_KEY] = &ps2kb_read_key, }; - device_create ("kb", ops, lengthof (ops), &ps2kb_init, &ps2kb_fini, NULL, thiscpu->kproc, &rctx); + device_create (DEVICE_TYPE_KEYBOARD, "kb", ops, lengthof (ops), &ps2kb_init, &ps2kb_fini, NULL, + thiscpu->kproc, &rctx); } #endif diff --git a/kernel/device/device.h b/kernel/device/device.h index 7f25631..794e4a2 100644 --- a/kernel/device/device.h +++ b/kernel/device/device.h @@ -1,6 +1,7 @@ #ifndef _KERNEL_DEVICE_DEVICE_H #define _KERNEL_DEVICE_DEVICE_H +#include #include #include #include @@ -35,14 +36,17 @@ struct device { device_init_func_t init; device_fini_func_t fini; void* udata; + int type; }; -struct device* device_create (const char* key, device_op_func_t* ops, size_t ops_len, +struct device* device_create (int type, const char* key, device_op_func_t* ops, size_t ops_len, device_init_func_t init, device_fini_func_t fini, void* arg, struct proc* proc, struct reschedule_ctx* rctx); struct device* device_find (const char* key); +size_t device_populate_device_infos (struct device_info* infos, size_t count); + void devices_init (void); #endif // _KERNEL_DEVICE_DEVICE_H diff --git a/kernel/device/partitions.c b/kernel/device/partitions.c index df5b43d..bd1b2c5 100644 --- a/kernel/device/partitions.c +++ b/kernel/device/partitions.c @@ -59,7 +59,8 @@ static int device_probe_partitions_dos (struct proc* proc, struct reschedule_ctx memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "%sp%zu", device->key, i); - device_create (key, ops, lengthof (ops), &partdrv_init, &partdrv_fini, &init, proc, rctx); + device_create (DEVICE_TYPE_DRIVE, key, ops, lengthof (ops), &partdrv_init, &partdrv_fini, &init, + proc, rctx); } spin_unlock (&device->lock, fd); diff --git a/kernel/device/pci_ide.c b/kernel/device/pci_ide.c index 5584ad4..6cec005 100644 --- a/kernel/device/pci_ide.c +++ b/kernel/device/pci_ide.c @@ -58,8 +58,8 @@ static void ide_make_device (struct proc* proc, struct reschedule_ctx* rctx, .irq = probe.irq, .irqs_support = probe.irqs_support, }; - struct device* ide = device_create (device_key, ops, lengthof (ops), &idedrv_init, &idedrv_fini, - &init, proc, rctx); + struct device* ide = device_create (DEVICE_TYPE_DRIVE, device_key, ops, lengthof (ops), + &idedrv_init, &idedrv_fini, &init, proc, rctx); device_probe_partitions (proc, rctx, ide); } diff --git a/kernel/device/pci_xhci.c b/kernel/device/pci_xhci.c index 30a9b2f..18e9b0d 100644 --- a/kernel/device/pci_xhci.c +++ b/kernel/device/pci_xhci.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -16,16 +17,11 @@ #include #include -static int xhci_counter = 0; +static bool xhci_init_done = false; bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_info pci_info) { struct limine_hhdm_response* hhdm = limine_hhdm_request.response; - if (xhci_counter == 3) { - DEBUG ("Cannot initialize more XHCI controllers\n"); - return false; - } - uint8_t progif = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_PROG_IF); /* not an XHCI controller */ @@ -33,6 +29,11 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i return true; } + if (xhci_init_done) { + DEBUG ("Cannot initialize more XHCI controllers\n"); + return false; + } + 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)) & ~(1 << 10); @@ -48,7 +49,7 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i map_pages = pci_get_bar_size (pci_info.bus, pci_info.slot, pci_info.func, PCI_BAR0); map_pages = div_align_up (map_pages, PAGE_SIZE); - if ((bar0 & PCI_BAR_MEM64)) { + if ((bar0 & 0x6) == 0x4) { uint32_t bar1 = pci_read32 (pci_info.bus, pci_info.slot, pci_info.func, PCI_BAR1); xhci_phys = ((uint64_t)bar1 << 32) | (bar0 & ~0xF); DEBUG ("XHCI phys base addr=%p (64 bit)\n", xhci_phys); @@ -73,15 +74,13 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i bool irqs_support = false; - uint32_t irq = INTR_XHCI0 + xhci_counter; - - if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, irq, thiscpu->lapic_id)) { + 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 (irq, intr_line, 0, thiscpu->lapic_id); + ioapic_route_irq (INTR_XHCI, intr_line, 0, thiscpu->lapic_id); } } else { irqs_support = true; @@ -89,19 +88,20 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i 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, .irqs_support = irqs_support, - .irq = irq, + .irq = INTR_XHCI, }; - device_op_func_t ops[] = {0}; + device_op_func_t ops[] = { + [XUSBCTRL_POLL_DRIVER] = &xhci_poll_driver, + }; - struct device* xhci = - device_create (key, ops, lengthof (ops), &xhci_init, &xhci_fini, &init, proc, rctx); + device_create (DEVICE_TYPE_USB_CTRL, "xhci", ops, lengthof (ops), &xhci_init, &xhci_fini, &init, + proc, rctx); + + xhci_init_done = true; return true; } diff --git a/kernel/device/xhci.c b/kernel/device/xhci.c index f46d672..c2049b7 100644 --- a/kernel/device/xhci.c +++ b/kernel/device/xhci.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -180,6 +181,37 @@ static void xhci_port_reset (struct xhci* xhci, uint8_t port) { stall_ms (100); } +static void xhci_create_plugged_device (struct xhci* xhci, uint8_t port) { + struct xhci_plugged_device* pdevice; + + list_find (struct xhci_plugged_device, xhci->xhci_plugged_devices, pdevice, port_value, port, + plugged_devices_link); + + if (pdevice != NULL) + return; + + pdevice = malloc (sizeof (*pdevice)); + memset (pdevice, 0, sizeof (*pdevice)); + pdevice->port_value = port; + pdevice->slot_id = -1; + + list_append (xhci->xhci_plugged_devices, &pdevice->plugged_devices_link); +} + +static void xhci_delete_plugged_device (struct xhci* xhci, uint8_t port) { + struct xhci_plugged_device* pdevice; + + list_find (struct xhci_plugged_device, xhci->xhci_plugged_devices, pdevice, port_value, port, + plugged_devices_link); + + list_remove (xhci->xhci_plugged_devices, &pdevice->plugged_devices_link); + + if (pdevice->endpoint0_ring_phys != 0) + pmm_free (pdevice->endpoint0_ring_phys, 1); + + free (pdevice); +} + static void xhci_event_dispatch (struct xhci* xhci, struct xhci_trb* event, uint8_t type) { switch (type) { case XHCI_TRB_CMD_CMPL_EVENT: { @@ -187,6 +219,8 @@ static void xhci_event_dispatch (struct xhci* xhci, struct xhci_trb* event, uint uint8_t slot_id = (event->ctrl >> 24) & 0xFF; DEBUG ("cmd completion: code=%u,slot=%u\n", cmpl_code, slot_id); + + xhci->last_slot_id = slot_id; } break; case XHCI_TRB_PORT_STS_CHNG: { uint8_t port = ((event->param >> 24) & 0xFF) - 1; @@ -200,10 +234,15 @@ 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))) + if ((portsc & (1 << 0))) { DEBUG ("Device attached to port %u!\n", port); - else + + xhci_create_plugged_device (xhci, port); + } else { DEBUG ("Device detached from port %u!\n", port); + + xhci_delete_plugged_device (xhci, port); + } } if ((portsc & (1 << 21))) @@ -271,11 +310,8 @@ static void xhci_irq (void* arg, void* regs, bool user, struct reschedule_ctx* r 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); - +static void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t ctrl, + uint64_t* lockflags) { 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]; @@ -298,14 +334,14 @@ void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t xhci_write32 (xhci->xhci_doorbell_base, 0, 0); - spin_unlock (&xhci->device->lock, fd); - int timeout = 100; - while (atomic_load (&xhci->pending) && --timeout > 0) - stall_ms (1); + spin_unlock (&xhci->device->lock, *lockflags); - spin_lock (&xhci->device->lock, &fd); + while (atomic_load (&xhci->pending) && --timeout > 0) + stall_ms (10); + + spin_lock (&xhci->device->lock, lockflags); if (timeout == 0) DEBUG ("timed out\n"); @@ -315,8 +351,6 @@ void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t spin_lock_relax (); } } - - spin_unlock (&xhci->device->lock, fd); } static void xhci_bios_handover (struct xhci* xhci) { @@ -406,8 +440,6 @@ static void xhci_reset_ports (struct xhci* xhci) { DEBUG ("PORT %u: USB %u.%u\n", port, major, minor); } - - break; } uint8_t next = (cap >> 8) & 0xFF; @@ -451,6 +483,9 @@ DEFINE_DEVICE_INIT (xhci_init) { uint32_t hcsparams2 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCSPARAMS2); xhci->max_scratchpad = (((hcsparams2 >> 21) & 0x1F) << 5) | ((hcsparams2 >> 27) & 0x1F); + uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1); + xhci->xhci_ctx_size = (hccparams1 & (1 << 2)) ? 64 : 32; + DEBUG ("starting init sequence\n"); /* stop running / clear Run/Stop bit */ @@ -544,7 +579,7 @@ DEFINE_DEVICE_INIT (xhci_init) { usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD); xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, usbcmd | (1 << 0) | (1 << 2)); - xhci_send_cmd (xhci, 0, 0, XHCI_TRB_SLOT_ENAB_CMD << 10); + stall_ms (500); xhci_reset_ports (xhci); @@ -569,6 +604,13 @@ DEFINE_DEVICE_FINI (xhci_fini) { pmm_free (scratchpads_phys, 1); } + for (size_t i = 0; i < PAGE_SIZE / sizeof (xhci->xhci_dcbaa[0]); i++) { + uintptr_t out_ctx = xhci->xhci_dcbaa[i]; + + if (out_ctx != 0) + pmm_free (out_ctx, 1); + } + pmm_free (xhci->xhci_dcbaa_phys, 1); pmm_free (xhci->cmd_ring_phys, 1); pmm_free (xhci->event_ring_phys, 1); @@ -586,3 +628,86 @@ DEFINE_DEVICE_FINI (xhci_fini) { free (xhci); } + +static void xhci_poll_setup_devices (struct xhci* xhci, uint64_t* lockflags) { + struct list_node_link *pdevice_link, *tmp_pdevice_link; + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + + list_foreach (xhci->xhci_plugged_devices, pdevice_link, tmp_pdevice_link) { + struct xhci_plugged_device* pdevice = + list_entry (pdevice_link, struct xhci_plugged_device, plugged_devices_link); + + /* slot assigned */ + if (pdevice->slot_id != -1) + continue; + + struct xhci_port* xhci_port; + list_find (struct xhci_port, xhci->xhci_ports, xhci_port, port_value, pdevice->port_value, + ports_link); + + xhci_send_cmd (xhci, 0, 0, XHCI_TRB_SLOT_ENAB_CMD << 10, lockflags); + uint8_t slot_id = xhci->last_slot_id; + + pdevice->slot_id = slot_id; + + uintptr_t out_ctx_phys = pmm_alloc (1); + void* out_ctx_virt = (void*)(out_ctx_phys + (uintptr_t)hhdm->offset); + memset (out_ctx_virt, 0, PAGE_SIZE); + xhci->xhci_dcbaa[pdevice->slot_id] = out_ctx_phys; + + pdevice->endpoint0_ring_phys = pmm_alloc (1); + pdevice->endpoint0_ring = + (struct xhci_trb*)(pdevice->endpoint0_ring_phys + (uintptr_t)hhdm->offset); + memset (pdevice->endpoint0_ring, 0, PAGE_SIZE); + + uintptr_t input_ctx_phys = pmm_alloc (1); + void* input_ctx_virt = (void*)(input_ctx_phys + (uintptr_t)hhdm->offset); + memset (input_ctx_virt, 0, PAGE_SIZE); + + if (xhci->xhci_ctx_size == 64) { + struct xhci_input_ctx64* ctx64 = input_ctx_virt; + + size_t max_packet_size = (xhci_port->type == XHCI_PORT_USB3) ? 512 : 64; + + /* Add slot and endpoint 0 */ + ctx64->ctrl.dw[1] = (1 << 0) | (1 << 1); + + ctx64->slot.dw[0] = (1 << 27); + ctx64->slot.dw[1] = ((pdevice->port_value + 1) << 16); + + ctx64->endpoints[0].dw[1] = (3 << 1) | (4 << 3) | (max_packet_size << 16); + ctx64->endpoints[0].dw[2] = (uint32_t)pdevice->endpoint0_ring_phys | (1 << 0); + ctx64->endpoints[0].dw[3] = (uint32_t)(pdevice->endpoint0_ring_phys >> 32); + } else { + struct xhci_input_ctx32* ctx32 = input_ctx_virt; + + size_t max_packet_size = (xhci_port->type == XHCI_PORT_USB3) ? 512 : 64; + + ctx32->ctrl.dw[1] = (1 << 0) | (1 << 1); + + ctx32->slot.dw[0] = (1 << 27); + ctx32->slot.dw[1] = ((pdevice->port_value + 1) << 16); + + ctx32->endpoints[0].dw[1] = (3 << 1) | (4 << 3) | (max_packet_size << 16); + ctx32->endpoints[0].dw[2] = (uint32_t)pdevice->endpoint0_ring_phys | (1 << 0); + ctx32->endpoints[0].dw[3] = (uint32_t)(pdevice->endpoint0_ring_phys >> 32); + } + + uint32_t ctrl = (pdevice->slot_id << 24) | (XHCI_TRB_ADDR_DEV_CMD << 10); + xhci_send_cmd (xhci, input_ctx_phys, 0, ctrl, lockflags); + + stall_ms (500); + + DEBUG ("Device on port %u addressed on slot %u!\n", pdevice->port_value, pdevice->slot_id); + + pmm_free (input_ctx_phys, 1); + } +} + +DEFINE_DEVICE_OP (xhci_poll_driver) { + struct xhci* xhci = device->udata; + + xhci_poll_setup_devices (xhci, lockflags); + + return ST_OK; +} diff --git a/kernel/device/xhci.h b/kernel/device/xhci.h index 0d9b7f0..29b0e21 100644 --- a/kernel/device/xhci.h +++ b/kernel/device/xhci.h @@ -23,6 +23,26 @@ struct xhci_trb { uint32_t ctrl; } PACKED; +struct xhci_ctx32 { + uint32_t dw[8]; +} PACKED; + +struct xhci_ctx64 { + uint32_t dw[16]; +} PACKED; + +struct xhci_input_ctx32 { + struct xhci_ctx32 ctrl; + struct xhci_ctx32 slot; + struct xhci_ctx32 endpoints[31]; +}; + +struct xhci_input_ctx64 { + struct xhci_ctx64 ctrl; + struct xhci_ctx64 slot; + struct xhci_ctx64 endpoints[31]; +}; + struct xhci_init { uintptr_t xhci_mmio_base; bool irqs_support; @@ -38,6 +58,15 @@ struct xhci_port { int type; }; +struct xhci_plugged_device { + struct list_node_link plugged_devices_link; + uint8_t port_value; + int slot_id; + + struct xhci_trb* endpoint0_ring; + uintptr_t endpoint0_ring_phys; +}; + struct xhci { struct device* device; @@ -73,13 +102,21 @@ struct xhci { struct xhci_erst_entry* erst; uintptr_t erst_phys; - atomic_bool pending; + size_t xhci_ctx_size; struct list_node_link* xhci_ports; + struct list_node_link* xhci_plugged_devices; + + atomic_bool pending; + uint8_t last_slot_id; + + spin_lock_t setup_lock; }; DEFINE_DEVICE_INIT (xhci_init); DEFINE_DEVICE_FINI (xhci_fini); +DEFINE_DEVICE_OP (xhci_poll_driver); + #endif // _KERNEL_DEVICE_XHCI_H diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index 5352409..f32e7f2 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -1076,6 +1077,26 @@ DEFINE_SYSCALL (sys_get_proc_info) { return SYSRESULT (proc_populate_proc_infos (infos, infos_count)); } +/* int get_device_info (struct device_info* infos, size_t count) */ +DEFINE_SYSCALL (sys_get_device_info) { + uint64_t fp; + + uintptr_t uvaddr_infos = a1; + size_t infos_count = (size_t)a2; + + spin_lock (&proc->lock, &fp); + struct procgroup* procgroup = proc->procgroup; + spin_unlock (&proc->lock, fp); + + struct device_info* infos = + sys_get_user_buffer (procgroup, uvaddr_infos, infos_count * sizeof (struct device_info)); + + if (infos == NULL) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + return SYSRESULT (device_populate_device_infos (infos, infos_count)); +} + static syscall_handler_func_t handler_table[] = { [SYS_QUIT] = &sys_quit, [SYS_TEST] = &sys_test, @@ -1114,6 +1135,7 @@ static syscall_handler_func_t handler_table[] = { [SYS_STREAM_WRITE] = &sys_stream_write, [SYS_STREAM_READ] = &sys_stream_read, [SYS_GET_PROC_INFO] = &sys_get_proc_info, + [SYS_GET_DEVICE_INFO] = &sys_get_device_info, }; syscall_handler_func_t syscall_find_handler (int syscall_num) { diff --git a/libsystem/system.c b/libsystem/system.c index b3557a0..246daba 100644 --- a/libsystem/system.c +++ b/libsystem/system.c @@ -114,3 +114,7 @@ int stream_read (int pgid, int rid, void* buffer, size_t size) { int get_proc_info (struct proc_info* infos, size_t count) { return (int)do_syscall (SYS_GET_PROC_INFO, infos, count); } + +int get_device_info (struct device_info* infos, size_t count) { + return (int)do_syscall (SYS_GET_DEVICE_INFO, infos, count); +} diff --git a/libsystem/system.h b/libsystem/system.h index 3c79b1f..1a31575 100644 --- a/libsystem/system.h +++ b/libsystem/system.h @@ -2,6 +2,7 @@ #define _LIBMSL_M_SYSTEM_H #include +#include #include #include #include @@ -118,4 +119,7 @@ int stream_read (int pgid, int rid, void* buffer, size_t size); /* get process information */ int get_proc_info (struct proc_info* infos, size_t count); +/* get device information */ +int get_device_info (struct device_info* infos, size_t count); + #endif // _LIBMSL_M_SYSTEM_H diff --git a/make/apps.mk b/make/apps.mk index 5663637..b295126 100644 --- a/make/apps.mk +++ b/make/apps.mk @@ -2,7 +2,8 @@ apps := \ init \ spin \ ce \ - sdutil + sdutil \ + usb all_apps: @for d in $(apps); do make -C $$d platform=$(platform) all; done diff --git a/sdutil/Makefile b/sdutil/Makefile index 23c4adf..4d978ab 100644 --- a/sdutil/Makefile +++ b/sdutil/Makefile @@ -5,7 +5,6 @@ $(eval $(call add_lib,libprocess)) $(eval $(call add_lib,libaux)) $(eval $(call add_lib,libmalloc)) $(eval $(call add_lib,libdebugconsole)) -$(eval $(call add_lib,libmalloc)) $(eval $(call add_lib,libinput)) $(eval $(call add_lib,libfat)) $(eval $(call add_include,libterminal)) diff --git a/usb/.gitignore b/usb/.gitignore new file mode 100644 index 0000000..bbca1b9 --- /dev/null +++ b/usb/.gitignore @@ -0,0 +1,6 @@ +*.o +*.json +docs/ +.cache/ +*.map +usb diff --git a/usb/Makefile b/usb/Makefile new file mode 100644 index 0000000..117cc7d --- /dev/null +++ b/usb/Makefile @@ -0,0 +1,10 @@ +include ../make/ufuncs.mk + +$(eval $(call add_lib,libstring)) +$(eval $(call add_lib,libprocess)) +$(eval $(call add_lib,libaux)) +$(eval $(call add_lib,libmalloc)) + +cflags += -DPRINTF_INCLUDE_CONFIG_H=1 + +include ../make/user.mk diff --git a/usb/app.mk b/usb/app.mk new file mode 100644 index 0000000..bdb30ae --- /dev/null +++ b/usb/app.mk @@ -0,0 +1 @@ +app := usb diff --git a/usb/src.mk b/usb/src.mk new file mode 100644 index 0000000..08b69ac --- /dev/null +++ b/usb/src.mk @@ -0,0 +1,3 @@ +c += usb.c + +o += usb.o diff --git a/usb/usb.c b/usb/usb.c new file mode 100644 index 0000000..049c273 --- /dev/null +++ b/usb/usb.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void usb_poll_driver_proc (void* arg) { + struct device_info* info = arg; + + mprintf ("Polling device %s\n", info->key); + + for (;;) { + device_do (info->key, XUSBCTRL_POLL_DRIVER, NULL, NULL, NULL, NULL); + + sched (); + } +} + +void app_main (void) { + libprocess_self_init (); + + char commandbuf[32]; + memset (commandbuf, 0, sizeof (commandbuf)); + + if (env_get (process_get_pgid (), "C", (void*)commandbuf, sizeof (commandbuf)) != ST_OK) { + mprintf ("ERROR C=???. No command provided\n"); + return; + } + + if (strcmp (commandbuf, "poll") == 0) { + struct device_info* infos = malloc (sizeof (struct device_info) * 1024); + memset (infos, 0, sizeof (struct device_info) * 1024); + + int device_count = get_device_info (infos, 1024); + + for (int dev = 0; dev < device_count; dev++) { + struct device_info* info = &infos[dev]; + + if (info->type != DEVICE_TYPE_USB_CTRL) { + continue; + } + + struct process_data* pdata = process_spawn (&usb_poll_driver_proc, info); + + mprintf ("Started USB poller process: PID %d\n", pdata->pid); + } + + for (;;) + ; + } else { + mprintf ("ERROR unknown command %s\n", commandbuf); + } +}