Proper USB system + moved into userspace

This commit is contained in:
rwusmm 2026-05-11 20:58:38 +03:00
parent 3392b56aab
commit 8e805938a1
20 changed files with 735 additions and 232 deletions

View file

@ -46,7 +46,6 @@ C_SOURCES = $(wildcard $(SRC_DIR)/core/*.c) \
$(wildcard $(SRC_DIR)/net/nic/*.c) \ $(wildcard $(SRC_DIR)/net/nic/*.c) \
$(wildcard $(SRC_DIR)/fs/*.c) \ $(wildcard $(SRC_DIR)/fs/*.c) \
$(wildcard $(SRC_DIR)/wm/*.c) \ $(wildcard $(SRC_DIR)/wm/*.c) \
$(wildcard $(SRC_DIR)/usb/*.c) \
$(wildcard $(SRC_DIR)/net/third_party/lwip/core/*.c) \ $(wildcard $(SRC_DIR)/net/third_party/lwip/core/*.c) \
$(wildcard $(SRC_DIR)/net/third_party/lwip/core/ipv4/*.c) \ $(wildcard $(SRC_DIR)/net/third_party/lwip/core/ipv4/*.c) \
$(SRC_DIR)/net/third_party/lwip/netif/ethernet.c \ $(SRC_DIR)/net/third_party/lwip/netif/ethernet.c \
@ -63,7 +62,6 @@ OBJ_FILES = $(patsubst $(SRC_DIR)/core/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_D
$(patsubst $(SRC_DIR)/net/nic/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/nic/*.c)) \ $(patsubst $(SRC_DIR)/net/nic/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/nic/*.c)) \
$(patsubst $(SRC_DIR)/fs/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/fs/*.c)) \ $(patsubst $(SRC_DIR)/fs/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/fs/*.c)) \
$(patsubst $(SRC_DIR)/wm/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/wm/*.c)) \ $(patsubst $(SRC_DIR)/wm/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/wm/*.c)) \
$(patsubst $(SRC_DIR)/usb/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/usb/*.c)) \
$(patsubst $(SRC_DIR)/net/third_party/lwip/%.c, $(BUILD_DIR)/lwip/%.o, $(filter $(SRC_DIR)/net/third_party/lwip/%.c, $(C_SOURCES))) \ $(patsubst $(SRC_DIR)/net/third_party/lwip/%.c, $(BUILD_DIR)/lwip/%.o, $(filter $(SRC_DIR)/net/third_party/lwip/%.c, $(C_SOURCES))) \
$(patsubst $(SRC_DIR)/arch/%.asm, $(BUILD_DIR)/%.o, $(ASM_SOURCES)) $(patsubst $(SRC_DIR)/arch/%.asm, $(BUILD_DIR)/%.o, $(ASM_SOURCES))
@ -74,7 +72,7 @@ CFLAGS = -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding \
-I$(SRC_DIR)/sys -I$(SRC_DIR)/mem -I$(SRC_DIR)/dev \ -I$(SRC_DIR)/sys -I$(SRC_DIR)/mem -I$(SRC_DIR)/dev \
-I$(SRC_DIR)/drivers \ -I$(SRC_DIR)/drivers \
-I$(SRC_DIR)/net -I$(SRC_DIR)/net/nic -I$(SRC_DIR)/fs \ -I$(SRC_DIR)/net -I$(SRC_DIR)/net/nic -I$(SRC_DIR)/fs \
-I$(SRC_DIR)/wm -I$(SRC_DIR)/input -I$(SRC_DIR)/usb -I$(SRC_DIR)/wm -I$(SRC_DIR)/input
LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \ LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
-z text -z max-page-size=0x1000 -T linker.ld -z text -z max-page-size=0x1000 -T linker.ld
@ -86,11 +84,7 @@ LIMINE_URL_BASE = https://github.com/limine-bootloader/limine/raw/v$(LIMINE_VERS
HOST_OS := $(shell uname -s 2>/dev/null || echo Windows) HOST_OS := $(shell uname -s 2>/dev/null || echo Windows)
<<<<<<< HEAD
.PHONY: all clean run run-hd limine-setup run-windows run-mac run-linux run-hd-mac run-hd-windows run-hd-linux
=======
.PHONY: all clean run run-hd limine-setup run-windows run-mac run-linux run-hd-mac run-hd-windows run-hd-linux unsafe .PHONY: all clean run run-hd limine-setup run-windows run-mac run-linux run-hd-mac run-hd-windows run-hd-linux unsafe
>>>>>>> 335d1c8 (Add new VGA fix and USB system)
all: all:
$(call PRINT_STEP,STARTING BOREDOS BUILD) $(call PRINT_STEP,STARTING BOREDOS BUILD)
@ -181,16 +175,6 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/wm/%.c | $(BUILD_DIR) limine-setup
mkdir -p $(dir $@) mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/%.o: $(SRC_DIR)/usb/%.c | $(BUILD_DIR) limine-setup
@printf "$(YELLOW)[CC]$(RESET)[usb] $< -> $@"
mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/uhci.o: $(SRC_DIR)/usb/uhci.c | $(BUILD_DIR) limine-setup
@printf "$(YELLOW)[CC]$(RESET)[usb] $< -> $@"
mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/lwip/%.o: $(SRC_DIR)/net/third_party/lwip/%.c | $(BUILD_DIR) limine-setup $(BUILD_DIR)/lwip/%.o: $(SRC_DIR)/net/third_party/lwip/%.c | $(BUILD_DIR) limine-setup
@printf "$(YELLOW)[CC]$(RESET)[lwIP] $< -> $@" @printf "$(YELLOW)[CC]$(RESET)[lwIP] $< -> $@"
mkdir -p $(dir $@) mkdir -p $(dir $@)

View file

@ -36,9 +36,6 @@
#include "input/keymap.h" #include "input/keymap.h"
#include "input/keyboard.h" #include "input/keyboard.h"
#include "../drivers/acpi.h" #include "../drivers/acpi.h"
#include "../usb/usb.h"
#include "../usb/hid.h"
#include "../usb/logitech_b110.h"
extern void sysfs_init_subsystems(void); extern void sysfs_init_subsystems(void);
@ -502,10 +499,6 @@ void kmain(void) {
ps2_init(); ps2_init();
asm("sti"); asm("sti");
usb_init();
usb_enumerate_devices();
usb_hid_init();
keymap_init(); keymap_init();
serial_write("[INIT] Keymap initialized"); serial_write("[INIT] Keymap initialized");

View file

@ -10,7 +10,6 @@
#include <stdbool.h> #include <stdbool.h>
#include "input/keyboard.h" #include "input/keyboard.h"
#include "input/keymap.h" #include "input/keymap.h"
#include "../usb/logitech_b110.h"
extern void serial_print(const char *s); extern void serial_print(const char *s);
extern void serial_print_hex(uint64_t n); extern void serial_print_hex(uint64_t n);
@ -152,7 +151,6 @@ uint64_t mouse_handler(registers_t *regs) {
if (!(status & 0x20)) { if (!(status & 0x20)) {
outb(0x20, 0x20); outb(0x20, 0x20);
outb(0xA0, 0x20); outb(0xA0, 0x20);
logitech_b110_poll();
return (uint64_t)regs; return (uint64_t)regs;
} }
@ -188,7 +186,6 @@ uint64_t mouse_handler(registers_t *regs) {
outb(0x20, 0x20); outb(0x20, 0x20);
outb(0xA0, 0x20); outb(0xA0, 0x20);
logitech_b110_poll();
return (uint64_t)regs; return (uint64_t)regs;
} }

View file

@ -2388,6 +2388,85 @@ static uint64_t sys_cmd_disk_replace_kernel(const syscall_args_t *args) {
return 0; return 0;
} }
static uint64_t sys_cmd_pci_read_config(const syscall_args_t *args) {
uint8_t bus = (uint8_t)args->arg2;
uint8_t device = (uint8_t)args->arg3;
uint8_t function = (uint8_t)args->arg4;
uint8_t offset = (uint8_t)args->arg5;
extern uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset);
return pci_read_config(bus, device, function, offset);
}
static uint64_t sys_cmd_pci_write_config(const syscall_args_t *args) {
uint8_t bus = (uint8_t)args->arg2;
uint8_t device = (uint8_t)args->arg3;
uint8_t function = (uint8_t)args->arg4;
uint8_t offset = (uint8_t)args->arg5;
uint32_t value = 0;
extern void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value);
pci_write_config(bus, device, function, offset, value);
return 0;
}
static uint64_t sys_cmd_io_inb(const syscall_args_t *args) {
uint16_t port = (uint16_t)args->arg2;
return inb(port);
}
static uint64_t sys_cmd_io_outb(const syscall_args_t *args) {
uint16_t port = (uint16_t)args->arg2;
uint8_t value = (uint8_t)args->arg3;
outb(port, value);
return 0;
}
static uint64_t sys_cmd_io_inw(const syscall_args_t *args) {
uint16_t port = (uint16_t)args->arg2;
return inw(port);
}
static uint64_t sys_cmd_io_outw(const syscall_args_t *args) {
uint16_t port = (uint16_t)args->arg2;
uint16_t value = (uint16_t)args->arg3;
outw(port, value);
return 0;
}
static uint64_t sys_cmd_io_inl(const syscall_args_t *args) {
uint16_t port = (uint16_t)args->arg2;
return inl(port);
}
static uint64_t sys_cmd_io_outl(const syscall_args_t *args) {
uint16_t port = (uint16_t)args->arg2;
uint32_t value = (uint32_t)args->arg3;
outl(port, value);
return 0;
}
static uint64_t sys_cmd_mem_map_phys(const syscall_args_t *args) {
uint64_t phys_addr = args->arg2;
uint64_t size = args->arg3;
extern uint64_t p2v(uint64_t phys);
(void)size;
return p2v(phys_addr);
}
static uint64_t sys_cmd_mem_unmap(const syscall_args_t *args) {
(void)args;
return 0;
}
static uint64_t sys_cmd_wm_handle_mouse(const syscall_args_t *args) {
int dx = (int)args->arg2;
int dy = (int)args->arg3;
uint8_t buttons = (uint8_t)args->arg4;
int wheel = (int)args->arg5;
extern void wm_handle_mouse(int dx, int dy, uint8_t buttons, int wheel);
wm_handle_mouse(dx, dy, buttons, wheel);
return 0;
}
#define SYS_CMD_TABLE_SIZE 110 #define SYS_CMD_TABLE_SIZE 110
static const syscall_handler_fn sys_cmd_table[SYS_CMD_TABLE_SIZE] = { static const syscall_handler_fn sys_cmd_table[SYS_CMD_TABLE_SIZE] = {
[SYSTEM_CMD_SET_BG_COLOR] = sys_cmd_set_bg_color, [SYSTEM_CMD_SET_BG_COLOR] = sys_cmd_set_bg_color,
@ -2467,6 +2546,17 @@ static const syscall_handler_fn sys_cmd_table[SYS_CMD_TABLE_SIZE] = {
[SYSTEM_CMD_DISK_RESCAN] = sys_cmd_disk_rescan, [SYSTEM_CMD_DISK_RESCAN] = sys_cmd_disk_rescan,
[SYSTEM_CMD_DISK_REPLACE_KERNEL] = sys_cmd_disk_replace_kernel, [SYSTEM_CMD_DISK_REPLACE_KERNEL] = sys_cmd_disk_replace_kernel,
[SYSTEM_CMD_DISK_SYNC] = sys_cmd_disk_sync, [SYSTEM_CMD_DISK_SYNC] = sys_cmd_disk_sync,
[SYSTEM_CMD_PCI_READ_CONFIG] = sys_cmd_pci_read_config,
[SYSTEM_CMD_PCI_WRITE_CONFIG] = sys_cmd_pci_write_config,
[SYSTEM_CMD_IO_INB] = sys_cmd_io_inb,
[SYSTEM_CMD_IO_OUTB] = sys_cmd_io_outb,
[SYSTEM_CMD_IO_INW] = sys_cmd_io_inw,
[SYSTEM_CMD_IO_OUTW] = sys_cmd_io_outw,
[SYSTEM_CMD_IO_INL] = sys_cmd_io_inl,
[SYSTEM_CMD_IO_OUTL] = sys_cmd_io_outl,
[SYSTEM_CMD_MEM_MAP_PHYS] = sys_cmd_mem_map_phys,
[SYSTEM_CMD_MEM_UNMAP] = sys_cmd_mem_unmap,
[SYSTEM_CMD_WM_HANDLE_MOUSE] = sys_cmd_wm_handle_mouse,
}; };
static uint64_t handle_sys_write(const syscall_args_t *args) { static uint64_t handle_sys_write(const syscall_args_t *args) {

View file

@ -123,6 +123,17 @@ typedef struct {
#define SYSTEM_CMD_SIGPENDING 75 #define SYSTEM_CMD_SIGPENDING 75
#define SYSTEM_CMD_GET_ELF_METADATA 76 #define SYSTEM_CMD_GET_ELF_METADATA 76
#define SYSTEM_CMD_GET_ELF_PRIMARY_IMAGE 77 #define SYSTEM_CMD_GET_ELF_PRIMARY_IMAGE 77
#define SYSTEM_CMD_PCI_READ_CONFIG 78
#define SYSTEM_CMD_PCI_WRITE_CONFIG 79
#define SYSTEM_CMD_IO_INB 80
#define SYSTEM_CMD_IO_OUTB 81
#define SYSTEM_CMD_IO_INW 82
#define SYSTEM_CMD_IO_OUTW 83
#define SYSTEM_CMD_IO_INL 84
#define SYSTEM_CMD_IO_OUTL 85
#define SYSTEM_CMD_MEM_MAP_PHYS 86
#define SYSTEM_CMD_MEM_UNMAP 87
#define SYSTEM_CMD_WM_HANDLE_MOUSE 88
void syscall_init(void); void syscall_init(void);
uint64_t syscall_handler_c(registers_t *regs); uint64_t syscall_handler_c(registers_t *regs);

View file

@ -1,46 +0,0 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#include "logitech_b110.h"
#include "../core/io.h"
extern void serial_write(const char *str);
extern void wm_handle_mouse(int dx, int dy, int buttons, int wheel);
static usb_device_t b110_device;
static bool b110_initialized = false;
bool logitech_b110_probe(usb_device_t *dev) {
if (dev->vendor_id == LOGITECH_VID && dev->product_id == LOGITECH_B110_PID) {
serial_write("[B110] Logitech B110 mouse detected\n");
return true;
}
return false;
}
bool logitech_b110_init(usb_device_t *dev) {
if (!logitech_b110_probe(dev)) return false;
b110_device = *dev;
b110_initialized = hid_init_mouse(dev);
if (b110_initialized) {
serial_write("[LT-B110] Mouse USB driver initialized\n");
}
return b110_initialized;
}
void logitech_b110_poll(void) {
if (!b110_initialized) return;
hid_mouse_report_t report;
if (hid_mouse_get_report(&b110_device, &report) > 0) {
int buttons = 0;
if (report.buttons & 0x01) buttons |= 0x01;
if (report.buttons & 0x02) buttons |= 0x02;
if (report.buttons & 0x04) buttons |= 0x04;
wm_handle_mouse(report.x, report.y, buttons, report.wheel);
}
}

View file

@ -1,117 +0,0 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#include "uhci.h"
#include "../core/io.h"
#include "../core/platform.h"
#include "../mem/memory_manager.h"
#include "../dev/pci.h"
#include <string.h>
extern void serial_write(const char *str);
extern void serial_write_hex(uint64_t n);
static uhci_hc_t uhci_controller;
static uint8_t *frame_list;
static uhci_qh_t *qh_pool;
static uhci_td_t *td_pool;
#define FRAME_LIST_SIZE 1024
#define POOL_SIZE 64
bool uhci_init(usb_hc_t *hc) {
serial_write("[UHCI] Initializing UHCI controller\n");
uint32_t bar = hc->bar0 & 0xFFFFFFF0;
if (bar == 0) {
serial_write("[UHCI] Invalid BAR0\n");
return false;
}
uhci_controller.base = (uint8_t *)p2v(bar);
uhci_controller.regs = (uhci_regs_t *)uhci_controller.base;
uint16_t cmd = inw((uint32_t)&uhci_controller.regs->cmd);
outw((uint32_t)&uhci_controller.regs->cmd, cmd & ~UHCI_CMD_RUN);
for (volatile int i = 0; i < 10000; i++);
outw((uint32_t)&uhci_controller.regs->cmd, cmd | UHCI_CMD_HCRESET);
for (volatile int i = 0; i < 10000; i++);
frame_list = (uint8_t *)kmalloc(FRAME_LIST_SIZE * 4);
if (!frame_list) {
serial_write("[UHCI] Failed to allocate frame list\n");
return false;
}
memset(frame_list, 0, FRAME_LIST_SIZE * 4);
qh_pool = (uhci_qh_t *)kmalloc(sizeof(uhci_qh_t) * POOL_SIZE);
td_pool = (uhci_td_t *)kmalloc(sizeof(uhci_td_t) * POOL_SIZE);
if (!qh_pool || !td_pool) {
serial_write("[UHCI] Failed to allocate pools\n");
return false;
}
memset(qh_pool, 0, sizeof(uhci_qh_t) * POOL_SIZE);
memset(td_pool, 0, sizeof(uhci_td_t) * POOL_SIZE);
uint32_t frame_list_phys = v2p((uint64_t)frame_list);
outl((uint32_t)&uhci_controller.regs->frame_base, frame_list_phys);
outw((uint32_t)&uhci_controller.regs->cmd, UHCI_CMD_RUN | UHCI_CMD_MAXP);
uint16_t port1 = inw((uint32_t)&uhci_controller.regs->port1);
if (port1 & UHCI_PORT_CCS) {
serial_write("[UHCI] Device detected on port 1\n");
outw((uint32_t)&uhci_controller.regs->port1, port1 | UHCI_PORT_PED);
}
uint16_t port2 = inw((uint32_t)&uhci_controller.regs->port2);
if (port2 & UHCI_PORT_CCS) {
serial_write("[UHCI] Device detected on port 2\n");
outw((uint32_t)&uhci_controller.regs->port2, port2 | UHCI_PORT_PED);
}
uhci_controller.initialized = true;
serial_write("[UHCI] Initialization complete\n");
return true;
}
void uhci_reset_port(usb_hc_t *hc, int port) {
(void)hc;
uhci_hc_t *controller = &uhci_controller;
uint16_t port_reg = (port == 1) ? (uint32_t)&controller->regs->port1 : (uint32_t)&controller->regs->port2;
uint16_t status = inw(port_reg);
outw(port_reg, status | UHCI_PORT_PR);
for (volatile int i = 0; i < 10000; i++);
status = inw(port_reg);
outw(port_reg, status & ~UHCI_PORT_PR);
for (volatile int i = 0; i < 10000; i++);
status = inw(port_reg);
outw(port_reg, status | UHCI_PORT_PED);
}
int uhci_control_transfer(usb_hc_t *hc, usb_setup_packet_t *setup, void *data, uint16_t len) {
(void)hc;
(void)setup;
(void)data;
(void)len;
return -1;
}
int uhci_interrupt_in(usb_hc_t *hc, uint8_t endpoint, void *data, uint16_t len) {
(void)hc;
(void)endpoint;
(void)data;
(void)len;
return -1;
}

View file

@ -13,7 +13,7 @@ APP_METADATA_TOOL = ../../tools/gen_userland_note.sh
APP_ICON_SOURCE_DIR = ../images/icons/colloid APP_ICON_SOURCE_DIR = ../images/icons/colloid
APP_METADATA_SOURCE_DOOM = games/doom/doomgeneric_boredos.c APP_METADATA_SOURCE_DOOM = games/doom/doomgeneric_boredos.c
APP_METADATA_SOURCE_LUA = cli/third_party/lua/boredos_onelua.c APP_METADATA_SOURCE_LUA = cli/third_party/lua/boredos_onelua.c
APP_SOURCE_DIRS = . cli gui sys games net cli/third_party APP_SOURCE_DIRS = . cli gui sys games net cli/third_party usb
define app_source_for define app_source_for
$(if $(filter doom,$1),$(APP_METADATA_SOURCE_DOOM),$(if $(filter lua,$1),$(APP_METADATA_SOURCE_LUA),$(if $(filter tcc,$1),cli/third_party/tcc/tcc.c,$(firstword $(foreach d,$(APP_SOURCE_DIRS),$(wildcard $(d)/$1.c)))))) $(if $(filter doom,$1),$(APP_METADATA_SOURCE_DOOM),$(if $(filter lua,$1),$(APP_METADATA_SOURCE_LUA),$(if $(filter tcc,$1),cli/third_party/tcc/tcc.c,$(firstword $(foreach d,$(APP_SOURCE_DIRS),$(wildcard $(d)/$1.c))))))
@ -22,11 +22,11 @@ endef
LIBC_SOURCES = $(wildcard libc/*.c) LIBC_SOURCES = $(wildcard libc/*.c)
LIBC_OBJS = $(patsubst libc/%.c, $(BIN_DIR)/%.o, $(LIBC_SOURCES)) $(BIN_DIR)/crt0.o $(BIN_DIR)/libwidget.o $(BIN_DIR)/stb_image.o LIBC_OBJS = $(patsubst libc/%.c, $(BIN_DIR)/%.o, $(LIBC_SOURCES)) $(BIN_DIR)/crt0.o $(BIN_DIR)/libwidget.o $(BIN_DIR)/stb_image.o
VPATH = cli gui sys games libc net cli/third_party VPATH = cli gui sys games libc net cli/third_party usb
vpath %.c cli gui sys games libc net cli/third_party vpath %.c cli gui sys games libc net cli/third_party usb
APP_SOURCES_FULL = $(wildcard cli/*.c gui/*.c sys/*.c games/*.c *.c net/*.c cli/third_party/*.c) APP_SOURCES_FULL = $(wildcard cli/*.c gui/*.c sys/*.c games/*.c *.c net/*.c cli/third_party/*.c usb/*.c)
APP_SOURCES = $(filter-out stb_image.c, $(APP_SOURCES_FULL)) APP_SOURCES = $(filter-out stb_image.c usb_driver_main.c usb.c uhci.c hid.c logitech_b110.c driver.c syscall.h, $(APP_SOURCES_FULL))
APP_ELFS = $(patsubst %.c, $(BIN_DIR)/%.elf, $(notdir $(APP_SOURCES))) APP_ELFS = $(patsubst %.c, $(BIN_DIR)/%.elf, $(notdir $(APP_SOURCES)))
APP_NAMES = $(sort $(basename $(notdir $(APP_SOURCES))) doom lua) APP_NAMES = $(sort $(basename $(notdir $(APP_SOURCES))) doom lua)
APP_NOTE_CSOURCES = $(patsubst %, $(BIN_DIR)/%.note.c, $(APP_NAMES)) APP_NOTE_CSOURCES = $(patsubst %, $(BIN_DIR)/%.note.c, $(APP_NAMES))
@ -35,10 +35,13 @@ APP_NOTE_OBJS = $(patsubst %, $(BIN_DIR)/%.note.o, $(APP_NAMES))
DOOM_SOURCES = $(wildcard games/doom/*.c) DOOM_SOURCES = $(wildcard games/doom/*.c)
DOOM_OBJS = $(patsubst games/doom/%.c, $(BIN_DIR)/%.o, $(DOOM_SOURCES)) DOOM_OBJS = $(patsubst games/doom/%.c, $(BIN_DIR)/%.o, $(DOOM_SOURCES))
USB_SOURCES = $(wildcard usb/*.c)
USB_OBJS = $(patsubst usb/%.c, $(BIN_DIR)/%.o, $(USB_SOURCES))
LUA_DIR = cli/third_party/lua LUA_DIR = cli/third_party/lua
LUA_CFLAGS = -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-red-zone -isystem $(LUA_DIR)/sysinclude -I. -Ilibc -I$(LUA_DIR) -DLUA_USE_C89 -Wno-conversion -Wno-sign-conversion -Wno-double-promotion -Wno-unused-parameter -Wno-missing-declarations -Wno-shadow -Wno-undef -Wno-redundant-decls -Wno-old-style-definition -Wno-missing-prototypes -Wno-implicit-fallthrough -Wno-type-limits LUA_CFLAGS = -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-red-zone -isystem $(LUA_DIR)/sysinclude -I. -Ilibc -I$(LUA_DIR) -DLUA_USE_C89 -Wno-conversion -Wno-sign-conversion -Wno-double-promotion -Wno-unused-parameter -Wno-missing-declarations -Wno-shadow -Wno-undef -Wno-redundant-decls -Wno-old-style-definition -Wno-missing-prototypes -Wno-implicit-fallthrough -Wno-type-limits
all: $(BIN_DIR) $(APP_ELFS) $(BIN_DIR)/doom.elf $(BIN_DIR)/lua.elf $(BIN_DIR)/tcc.elf $(BIN_DIR)/empty.o all: $(BIN_DIR) $(APP_ELFS) $(BIN_DIR)/doom.elf $(BIN_DIR)/lua.elf $(BIN_DIR)/tcc.elf $(BIN_DIR)/usb_driver_main.elf $(BIN_DIR)/empty.o
$(BIN_DIR): $(BIN_DIR):
mkdir -p $(BIN_DIR) mkdir -p $(BIN_DIR)
@ -92,9 +95,15 @@ $(BIN_DIR)/screenshot.elf: $(LIBC_OBJS) $(BIN_DIR)/screenshot.o $(BIN_DIR)/scree
$(BIN_DIR)/%.o: games/doom/%.c | $(BIN_DIR) $(BIN_DIR)/%.o: games/doom/%.c | $(BIN_DIR)
$(CC) $(CFLAGS) -Wno-error -DBOREDOS -Igames/doom -c $< -o $@ $(CC) $(CFLAGS) -Wno-error -DBOREDOS -Igames/doom -c $< -o $@
$(BIN_DIR)/%.o: usb/%.c | $(BIN_DIR)
$(CC) $(CFLAGS) -Iusb -c $< -o $@
$(BIN_DIR)/doom.elf: $(LIBC_OBJS) $(DOOM_OBJS) $(BIN_DIR)/doom.note.o $(BIN_DIR)/doom.elf: $(LIBC_OBJS) $(DOOM_OBJS) $(BIN_DIR)/doom.note.o
$(LD) $(LDFLAGS) $^ -o $@ $(LD) $(LDFLAGS) $^ -o $@
$(BIN_DIR)/usb_driver_main.elf: $(LIBC_OBJS) $(USB_OBJS)
$(LD) $(LDFLAGS) $^ -o $@
$(BIN_DIR)/%.elf: $(LIBC_OBJS) $(BIN_DIR)/%.o $(BIN_DIR)/%.note.o $(BIN_DIR)/%.elf: $(LIBC_OBJS) $(BIN_DIR)/%.o $(BIN_DIR)/%.note.o
$(LD) $(LDFLAGS) $^ -o $@ $(LD) $(LDFLAGS) $^ -o $@

164
src/userland/usb/driver.c Normal file
View file

@ -0,0 +1,164 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#include "driver.h"
#include <string.h>
#include <stdio.h>
static usb_driver_t *driver_registry[MAX_DRIVERS];
static int driver_count = 0;
static driver_instance_t active_instances[MAX_DRIVERS];
static int instance_count = 0;
void driver_manager_init(void) {
memset(driver_registry, 0, sizeof(driver_registry));
memset(active_instances, 0, sizeof(active_instances));
driver_count = 0;
instance_count = 0;
}
int driver_register(usb_driver_t *driver) {
if (!driver || driver_count >= MAX_DRIVERS) return -1;
for (int i = 0; i < driver_count; i++) {
if (driver_registry[i]->vendor_id == driver->vendor_id &&
driver_registry[i]->product_id == driver->product_id) {
return -1;
}
}
driver_registry[driver_count++] = driver;
driver->loaded = false;
return 0;
}
int driver_unregister(usb_driver_t *driver) {
if (!driver) return -1;
for (int i = 0; i < driver_count; i++) {
if (driver_registry[i] == driver) {
for (int j = i; j < driver_count - 1; j++) {
driver_registry[j] = driver_registry[j + 1];
}
driver_count--;
driver->loaded = false;
return 0;
}
}
return -1;
}
int driver_load_for_device(usb_device_t *dev) {
if (!dev) return -1;
for (int i = 0; i < driver_count; i++) {
usb_driver_t *driver = driver_registry[i];
if (driver->vendor_id == dev->vendor_id &&
driver->product_id == dev->product_id) {
if (instance_count >= MAX_DRIVERS) return -1;
if (driver->probe && !driver->probe(dev)) {
continue;
}
if (driver->init && driver->init(dev) != 0) {
continue;
}
active_instances[instance_count].device = *dev;
active_instances[instance_count].driver = driver;
active_instances[instance_count].active = true;
instance_count++;
driver->loaded = true;
printf("[DRIVER] Loaded %s for VID:PID %04X:%04X\n",
driver->name, dev->vendor_id, dev->product_id);
return 0;
}
}
return -1;
}
void driver_unload_for_device(usb_device_t *dev) {
if (!dev) return;
for (int i = 0; i < instance_count; i++) {
if (active_instances[i].active &&
active_instances[i].device.vendor_id == dev->vendor_id &&
active_instances[i].device.product_id == dev->product_id) {
if (active_instances[i].driver->deinit) {
active_instances[i].driver->deinit(dev);
}
active_instances[i].driver->loaded = false;
active_instances[i].active = false;
for (int j = i; j < instance_count - 1; j++) {
active_instances[j] = active_instances[j + 1];
}
instance_count--;
printf("[DRIVER] Unloaded driver for VID:PID %04X:%04X\n",
dev->vendor_id, dev->product_id);
return;
}
}
}
void driver_hotplug_poll(void) {
extern int usb_get_device_count(void);
extern usb_device_t* usb_get_device(int index);
int current_count = usb_get_device_count();
for (int i = 0; i < current_count; i++) {
usb_device_t *dev = usb_get_device(i);
if (!dev) continue;
bool found = false;
for (int j = 0; j < instance_count; j++) {
if (active_instances[j].active &&
active_instances[j].device.vendor_id == dev->vendor_id &&
active_instances[j].device.product_id == dev->product_id) {
found = true;
break;
}
}
if (!found && !dev->initialized) {
driver_load_for_device(dev);
dev->initialized = true;
}
}
for (int i = 0; i < instance_count; i++) {
bool still_present = false;
for (int j = 0; j < current_count; j++) {
usb_device_t *dev = usb_get_device(j);
if (dev &&
active_instances[i].device.vendor_id == dev->vendor_id &&
active_instances[i].device.product_id == dev->product_id) {
still_present = true;
break;
}
}
if (!still_present) {
driver_unload_for_device(&active_instances[i].device);
i--;
}
}
}
void driver_poll_all(void) {
for (int i = 0; i < instance_count; i++) {
if (active_instances[i].active && active_instances[i].driver->poll) {
active_instances[i].driver->poll(&active_instances[i].device);
}
}
}

37
src/userland/usb/driver.h Normal file
View file

@ -0,0 +1,37 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#ifndef DRIVER_H
#define DRIVER_H
#include "usb.h"
#include <stdbool.h>
#define MAX_DRIVERS 16
typedef struct {
uint16_t vendor_id;
uint16_t product_id;
char name[64];
bool (*probe)(usb_device_t *dev);
int (*init)(usb_device_t *dev);
void (*deinit)(usb_device_t *dev);
int (*poll)(usb_device_t *dev);
bool loaded;
} usb_driver_t;
typedef struct {
usb_device_t device;
usb_driver_t *driver;
bool active;
} driver_instance_t;
void driver_manager_init(void);
int driver_register(usb_driver_t *driver);
int driver_unregister(usb_driver_t *driver);
int driver_load_for_device(usb_device_t *dev);
void driver_unload_for_device(usb_device_t *dev);
void driver_hotplug_poll(void);
void driver_poll_all(void);
#endif

View file

@ -3,10 +3,8 @@
// This header needs to maintain in this file it has in it, as per the GPL license terms. // This header needs to maintain in this file it has in it, as per the GPL license terms.
#include "hid.h" #include "hid.h"
#include "logitech_b110.h" #include "logitech_b110.h"
#include "../core/io.h"
#include <string.h> #include <string.h>
#include <stdio.h>
extern void serial_write(const char *str);
static usb_device_t hid_mouse_devices[8]; static usb_device_t hid_mouse_devices[8];
static int hid_mouse_count = 0; static int hid_mouse_count = 0;
@ -85,7 +83,7 @@ bool hid_init_mouse(usb_device_t *dev) {
hid_mouse_devices[hid_mouse_count++] = *dev; hid_mouse_devices[hid_mouse_count++] = *dev;
dev->initialized = true; dev->initialized = true;
serial_write("[HID] Mouse initialized\n"); printf("[HID] Mouse initialized\n");
return true; return true;
} }
@ -106,7 +104,7 @@ int hid_mouse_get_report(usb_device_t *dev, hid_mouse_report_t *report) {
} }
void usb_hid_init(void) { void usb_hid_init(void) {
serial_write("[HID] Initializing HID subsystem\n"); printf("[HID] Initializing HID subsystem\n");
int device_count = usb_get_device_count(); int device_count = usb_get_device_count();
@ -114,10 +112,10 @@ void usb_hid_init(void) {
usb_device_t *dev = usb_get_device(i); usb_device_t *dev = usb_get_device(i);
if (dev && dev->device_class == USB_CLASS_HID) { if (dev && dev->device_class == USB_CLASS_HID) {
serial_write("[HID] Found HID device\n"); printf("[HID] Found HID device\n");
if (logitech_b110_probe(dev)) { if (logitech_b110_probe(dev)) {
serial_write("[HID] Initializing LT-B110\n"); printf("[HID] Initializing Logitech B110\n");
logitech_b110_init(dev); logitech_b110_init(dev);
} }
} }

View file

@ -0,0 +1,69 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#include "logitech_b110.h"
#include "hid.h"
#include "syscall.h"
#include <string.h>
#include <stdio.h>
static bool b110_initialized = false;
bool logitech_b110_probe(usb_device_t *dev) {
if (!dev) return false;
if (dev->vendor_id == LOGITECH_VID && dev->product_id == LOGITECH_B110_PID) {
return true;
}
return false;
}
int logitech_b110_init(usb_device_t *dev) {
if (!dev) return -1;
b110_initialized = hid_init_mouse(dev);
if (b110_initialized) {
printf("[B110] Mouse USB driver initialized\n");
}
return b110_initialized ? 0 : -1;
}
void logitech_b110_deinit(usb_device_t *dev) {
(void)dev;
b110_initialized = false;
printf("[B110] Mouse USB driver deinitialized\n");
}
int logitech_b110_poll(usb_device_t *dev) {
if (!b110_initialized || !dev) return -1;
uint8_t buffer[8];
int len = usb_interrupt_in(dev, dev->endpoint_in, buffer, sizeof(buffer));
if (len > 0) {
hid_mouse_report_t report;
hid_parse_mouse_report(buffer, len, &report);
wm_handle_mouse(report.x, report.y, report.buttons, report.wheel);
}
return len;
}
static usb_driver_t logitech_b110_driver = {
.vendor_id = LOGITECH_VID,
.product_id = LOGITECH_B110_PID,
.name = "Logitech B110",
.probe = logitech_b110_probe,
.init = logitech_b110_init,
.deinit = logitech_b110_deinit,
.poll = logitech_b110_poll,
.loaded = false
};
usb_driver_t* logitech_b110_get_driver(void) {
return &logitech_b110_driver;
}

View file

@ -4,15 +4,17 @@
#ifndef LOGITECH_B110_H #ifndef LOGITECH_B110_H
#define LOGITECH_B110_H #define LOGITECH_B110_H
#include "hid.h" #include "usb.h"
#include <stdint.h> #include "driver.h"
#include <stdbool.h> #include <stdbool.h>
#define LOGITECH_VID 0x046D #define LOGITECH_VID 0x046D
#define LOGITECH_B110_PID 0xC05A #define LOGITECH_B110_PID 0xC05A
bool logitech_b110_probe(usb_device_t *dev); bool logitech_b110_probe(usb_device_t *dev);
bool logitech_b110_init(usb_device_t *dev); int logitech_b110_init(usb_device_t *dev);
void logitech_b110_poll(void); void logitech_b110_deinit(usb_device_t *dev);
int logitech_b110_poll(usb_device_t *dev);
usb_driver_t* logitech_b110_get_driver(void);
#endif #endif

View file

@ -0,0 +1,74 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#ifndef SYSCALL_H
#define SYSCALL_H
#include <stdint.h>
#define SYSTEM_CMD_PCI_READ_CONFIG 78
#define SYSTEM_CMD_PCI_WRITE_CONFIG 79
#define SYSTEM_CMD_IO_INB 80
#define SYSTEM_CMD_IO_OUTB 81
#define SYSTEM_CMD_IO_INW 82
#define SYSTEM_CMD_IO_OUTW 83
#define SYSTEM_CMD_IO_INL 84
#define SYSTEM_CMD_IO_OUTL 85
#define SYSTEM_CMD_MEM_MAP_PHYS 86
#define SYSTEM_CMD_MEM_UNMAP 87
#define SYSTEM_CMD_WM_HANDLE_MOUSE 88
static inline uint64_t syscall(uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) {
uint64_t ret;
asm volatile ("syscall"
: "=a"(ret)
: "a"(num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg4), "r"(arg5)
: "rcx", "r11", "memory");
return ret;
}
static inline uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) {
return syscall(SYSTEM_CMD_PCI_READ_CONFIG, 0, bus, device, function, offset);
}
static inline void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value) {
syscall(SYSTEM_CMD_PCI_WRITE_CONFIG, 0, bus, device, function, offset);
}
static inline uint8_t inb(uint16_t port) {
return syscall(SYSTEM_CMD_IO_INB, 0, port, 0, 0, 0);
}
static inline void outb(uint16_t port, uint8_t value) {
syscall(SYSTEM_CMD_IO_OUTB, 0, port, value, 0, 0);
}
static inline uint16_t inw(uint16_t port) {
return syscall(SYSTEM_CMD_IO_INW, 0, port, 0, 0, 0);
}
static inline void outw(uint16_t port, uint16_t value) {
syscall(SYSTEM_CMD_IO_OUTW, 0, port, value, 0, 0);
}
static inline uint32_t inl(uint16_t port) {
return syscall(SYSTEM_CMD_IO_INL, 0, port, 0, 0, 0);
}
static inline void outl(uint16_t port, uint32_t value) {
syscall(SYSTEM_CMD_IO_OUTL, 0, port, value, 0, 0);
}
static inline uint64_t p2v(uint64_t phys) {
return syscall(SYSTEM_CMD_MEM_MAP_PHYS, 0, phys, 0, 0, 0);
}
static inline void mem_unmap(uint64_t virt) {
syscall(SYSTEM_CMD_MEM_UNMAP, 0, virt, 0, 0, 0);
}
static inline void wm_handle_mouse(int dx, int dy, uint8_t buttons, int wheel) {
syscall(SYSTEM_CMD_WM_HANDLE_MOUSE, 0, dx, dy, buttons, wheel);
}
#endif

213
src/userland/usb/uhci.c Normal file
View file

@ -0,0 +1,213 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#include "uhci.h"
#include "syscall.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static uhci_hc_t uhci_controller;
static uint8_t *frame_list;
static uhci_qh_t *qh_pool;
static uhci_td_t *td_pool;
static int td_idx = 0;
#define FRAME_LIST_SIZE 1024
#define POOL_SIZE 64
bool uhci_init(usb_hc_t *hc) {
serial_write("[UHCI] Initializing UHCI controller\n");
uint32_t bar = hc->bar0 & 0xFFFFFFF0;
if (bar == 0) {
serial_write("[UHCI] Invalid BAR0\n");
return false;
}
uhci_controller.base = (uint8_t *)p2v(bar);
uhci_controller.regs = (uhci_regs_t *)uhci_controller.base;
uint16_t cmd = inw((uint32_t)&uhci_controller.regs->cmd);
outw((uint32_t)&uhci_controller.regs->cmd, cmd & ~UHCI_CMD_RUN);
for (volatile int i = 0; i < 10000; i++);
outw((uint32_t)&uhci_controller.regs->cmd, cmd | UHCI_CMD_HCRESET);
for (volatile int i = 0; i < 10000; i++);
frame_list = (uint8_t *)malloc(FRAME_LIST_SIZE * 4);
if (!frame_list) {
printf("[UHCI] Failed to allocate frame list\n");
return false;
}
memset(frame_list, 0, FRAME_LIST_SIZE * 4);
qh_pool = (uhci_qh_t *)malloc(sizeof(uhci_qh_t) * POOL_SIZE);
td_pool = (uhci_td_t *)malloc(sizeof(uhci_td_t) * POOL_SIZE);
if (!qh_pool || !td_pool) {
printf("[UHCI] Failed to allocate pools\n");
return false;
}
memset(qh_pool, 0, sizeof(uhci_qh_t) * POOL_SIZE);
memset(td_pool, 0, sizeof(uhci_td_t) * POOL_SIZE);
for (int i = 0; i < FRAME_LIST_SIZE; i++) {
frame_list[i * 4 + 0] = 0x01;
frame_list[i * 4 + 1] = 0x00;
frame_list[i * 4 + 2] = 0x00;
frame_list[i * 4 + 3] = 0x00;
}
uint32_t frame_list_phys = p2v((uint64_t)frame_list);
outl((uint32_t)&uhci_controller.regs->frame_base, frame_list_phys);
outw((uint32_t)&uhci_controller.regs->cmd, UHCI_CMD_RUN | UHCI_CMD_MAXP);
uint16_t port1 = inw((uint32_t)&uhci_controller.regs->port1);
if (port1 & UHCI_PORT_CCS) {
printf("[UHCI] Device detected on port 1\n");
outw((uint32_t)&uhci_controller.regs->port1, port1 | UHCI_PORT_PED);
}
uint16_t port2 = inw((uint32_t)&uhci_controller.regs->port2);
if (port2 & UHCI_PORT_CCS) {
printf("[UHCI] Device detected on port 2\n");
outw((uint32_t)&uhci_controller.regs->port2, port2 | UHCI_PORT_PED);
}
uhci_controller.initialized = true;
printf("[UHCI] Initialization complete\n");
return true;
}
void uhci_reset_port(usb_hc_t *hc, int port) {
(void)hc;
uhci_hc_t *controller = &uhci_controller;
uint16_t port_reg = (port == 1) ? (uint32_t)&controller->regs->port1 : (uint32_t)&controller->regs->port2;
uint16_t status = inw(port_reg);
outw(port_reg, status | UHCI_PORT_PR);
for (volatile int i = 0; i < 10000; i++);
status = inw(port_reg);
outw(port_reg, status & ~UHCI_PORT_PR);
for (volatile int i = 0; i < 10000; i++);
status = inw(port_reg);
outw(port_reg, status | UHCI_PORT_PED);
}
int uhci_control_transfer(usb_hc_t *hc, usb_setup_packet_t *setup, void *data, uint16_t len) {
(void)hc;
if (!uhci_controller.initialized) return -1;
uhci_td_t *td_setup = &td_pool[td_idx++ % POOL_SIZE];
uhci_td_t *td_data = (len > 0) ? &td_pool[td_idx++ % POOL_SIZE] : NULL;
uhci_td_t *td_status = &td_pool[td_idx++ % POOL_SIZE];
uint8_t *setup_buf = (uint8_t *)kmalloc(8);
if (!setup_buf) return -1;
setup_buf[0] = setup->bmRequestType;
setup_buf[1] = setup->bRequest;
setup_buf[2] = setup->wValue & 0xFF;
setup_buf[3] = (setup->wValue >> 8) & 0xFF;
setup_buf[4] = setup->wIndex & 0xFF;
setup_buf[5] = (setup->wIndex >> 8) & 0xFF;
setup_buf[6] = setup->wLength & 0xFF;
setup_buf[7] = (setup->wLength >> 8) & 0xFF;
memset(td_setup, 0, sizeof(uhci_td_t));
td_setup->link = (td_data) ? (p2v((uint64_t)td_data) | 0x4) : (p2v((uint64_t)td_status) | 0x4);
td_setup->status = 0x00800000 | ((7 & 0x7FF) << 21);
td_setup->buffer = p2v((uint64_t)setup_buf);
if (td_data && len > 0) {
memset(td_data, 0, sizeof(uhci_td_t));
td_data->link = p2v((uint64_t)td_status) | 0x4;
td_data->status = 0x00800000 | ((len & 0x7FF) << 21);
td_data->buffer = p2v((uint64_t)data);
}
memset(td_status, 0, sizeof(uhci_td_t));
td_status->link = 0x00000001;
td_status->status = 0x00800000;
uhci_qh_t *qh = &qh_pool[0];
memset(qh, 0, sizeof(uhci_qh_t));
qh->element_link = p2v((uint64_t)td_setup) | 0x4;
qh->link = 0x00000001;
uint32_t qh_phys = p2v((uint64_t)qh);
frame_list[0] = qh_phys & 0xFF;
frame_list[1] = (qh_phys >> 8) & 0xFF;
frame_list[2] = (qh_phys >> 16) & 0xFF;
frame_list[3] = (qh_phys >> 24) & 0xFF;
outw((uint32_t)&uhci_controller.regs->cmd, inw((uint32_t)&uhci_controller.regs->cmd) | UHCI_CMD_MAXP);
for (volatile int i = 0; i < 100000; i++);
uint32_t status = td_status->status;
frame_list[0] = 0x01;
frame_list[1] = 0x00;
frame_list[2] = 0x00;
frame_list[3] = 0x00;
if (status & 0x80000000) {
free(setup_buf);
return len;
}
free(setup_buf);
return -1;
}
int uhci_interrupt_in(usb_hc_t *hc, uint8_t endpoint, void *data, uint16_t len) {
(void)hc;
(void)endpoint;
if (!uhci_controller.initialized) return -1;
uhci_td_t *td = &td_pool[td_idx++ % POOL_SIZE];
memset(td, 0, sizeof(uhci_td_t));
td->link = 0x00000001;
td->status = 0x00800000 | ((len & 0x7FF) << 21) | (0x69 << 16);
td->buffer = p2v((uint64_t)data);
uhci_qh_t *qh = &qh_pool[1];
memset(qh, 0, sizeof(uhci_qh_t));
qh->element_link = p2v((uint64_t)td) | 0x4;
qh->link = 0x00000001;
uint32_t qh_phys = p2v((uint64_t)qh);
frame_list[0] = qh_phys & 0xFF;
frame_list[1] = (qh_phys >> 8) & 0xFF;
frame_list[2] = (qh_phys >> 16) & 0xFF;
frame_list[3] = (qh_phys >> 24) & 0xFF;
outw((uint32_t)&uhci_controller.regs->cmd, inw((uint32_t)&uhci_controller.regs->cmd) | UHCI_CMD_MAXP);
for (volatile int i = 0; i < 50000; i++);
uint32_t status = td->status;
frame_list[0] = 0x01;
frame_list[1] = 0x00;
frame_list[2] = 0x00;
frame_list[3] = 0x00;
if (status & 0x80000000) {
return len;
}
return -1;
}

View file

@ -3,13 +3,10 @@
// This header needs to maintain in any file it has in it, as per the GPL license terms. // This header needs to maintain in any file it has in it, as per the GPL license terms.
#include "usb.h" #include "usb.h"
#include "uhci.h" #include "uhci.h"
#include "../dev/pci.h" #include "syscall.h"
#include "../core/io.h"
#include "../mem/memory_manager.h"
#include <string.h> #include <string.h>
#include <stdio.h>
extern void serial_write(const char *str); #include <stdlib.h>
extern void serial_write_hex(uint64_t n);
static usb_hc_t usb_controllers[8]; static usb_hc_t usb_controllers[8];
static int usb_controller_count = 0; static int usb_controller_count = 0;
@ -17,10 +14,6 @@ static usb_device_t usb_devices[USB_MAX_DEVICES];
static int usb_device_count = 0; static int usb_device_count = 0;
static uint8_t device_address_counter = 1; static uint8_t device_address_counter = 1;
extern uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset);
extern void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value);
extern int pci_find_device_by_class(uint8_t class_code, uint8_t subclass, pci_device_t *dev);
usb_hc_type_t usb_detect_controller(usb_hc_t *hc) { usb_hc_type_t usb_detect_controller(usb_hc_t *hc) {
uint32_t class_code = pci_read_config(hc->bus, hc->device, hc->function, 0x08) >> 24; uint32_t class_code = pci_read_config(hc->bus, hc->device, hc->function, 0x08) >> 24;
uint32_t prog_if = pci_read_config(hc->bus, hc->device, hc->function, 0x09) & 0xFF; uint32_t prog_if = pci_read_config(hc->bus, hc->device, hc->function, 0x09) & 0xFF;
@ -36,7 +29,7 @@ usb_hc_type_t usb_detect_controller(usb_hc_t *hc) {
} }
void usb_init(void) { void usb_init(void) {
serial_write("[USB] Initializing USB stack...\n"); printf("[USB] Initializing USB stack...\n");
int idx = 0; int idx = 0;
@ -65,13 +58,11 @@ void usb_init(void) {
else if (type == USB_HC_EHCI) type_str = "EHCI"; else if (type == USB_HC_EHCI) type_str = "EHCI";
else if (type == USB_HC_XHCI) type_str = "XHCI"; else if (type == USB_HC_XHCI) type_str = "XHCI";
serial_write("[USB] Found controller: "); printf("[USB] Found controller: %s\n", type_str);
serial_write(type_str);
serial_write("\n");
if (type == USB_HC_UHCI) { if (type == USB_HC_UHCI) {
if (uhci_init(&usb_controllers[idx])) { if (uhci_init(&usb_controllers[idx])) {
serial_write("[USB] UHCI initialized\n"); printf("[USB] UHCI initialized\n");
} }
} }
@ -82,9 +73,7 @@ void usb_init(void) {
} }
usb_controller_count = idx; usb_controller_count = idx;
serial_write("[USB] Total controllers found: "); printf("[USB] Total controllers found: %d\n", usb_controller_count);
serial_write_hex(usb_controller_count);
serial_write("\n");
} }
bool usb_enumerate_device(usb_device_t *dev) { bool usb_enumerate_device(usb_device_t *dev) {
@ -151,10 +140,10 @@ int usb_interrupt_in(usb_device_t *dev, uint8_t endpoint, void *data, uint16_t l
} }
void usb_enumerate_devices(void) { void usb_enumerate_devices(void) {
serial_write("[USB] Starting device enumeration\n"); printf("[USB] Starting device enumeration\n");
if (usb_controller_count == 0) { if (usb_controller_count == 0) {
serial_write("[USB] No controllers available\n"); printf("[USB] No controllers available\n");
return; return;
} }
@ -163,11 +152,7 @@ void usb_enumerate_devices(void) {
memset(&dev, 0, sizeof(usb_device_t)); memset(&dev, 0, sizeof(usb_device_t));
if (usb_enumerate_device(&dev)) { if (usb_enumerate_device(&dev)) {
serial_write("[USB] Device enumerated: VID="); printf("[USB] Device enumerated: VID=%04X PID=%04X\n", dev.vendor_id, dev.product_id);
serial_write_hex(dev.vendor_id);
serial_write(" PID=");
serial_write_hex(dev.product_id);
serial_write("\n");
} }
} }
} }

View file

@ -0,0 +1,40 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in this file it has in it, as per the GPL license terms.
#include "usb.h"
#include "driver.h"
#include "logitech_b110.h"
#include <stdio.h>
#include <unistd.h>
extern void wm_handle_mouse(int dx, int dy, uint8_t buttons, int wheel);
int main(int argc, char **argv) {
(void)argc;
(void)argv;
printf("[USB] Starting userspace USB driver\n");
driver_manager_init();
printf("[USB] Initializing USB stack\n");
usb_init();
printf("[USB] Enumerating devices\n");
usb_enumerate_devices();
printf("[USB] Registering drivers\n");
driver_register(logitech_b110_get_driver());
printf("[USB] Loading drivers for detected devices\n");
driver_hotplug_poll();
printf("[USB] Entering main loop\n");
while (1) {
driver_hotplug_poll();
driver_poll_all();
usleep(10000);
}
return 0;
}