major refactorings

Signed-off-by: kaguya3311 <kaguya3311@national.shitposting.agency>
This commit is contained in:
kaguya
2026-05-18 04:02:59 -04:00
parent f7aa6f913a
commit b28a6bcf29
211 changed files with 17699 additions and 8107 deletions
+150
View File
@@ -0,0 +1,150 @@
#include "drivers/input/input.h"
#include "mp/spinlock.h"
#include "libk/stdio.h"
#include "fs/vfs.h"
#include <stddef.h>
#include "mm/memory.h"
#include "libk/string.h"
#include <stddef.h>
#include "libk/debug.h"
/* ------------------------------------------------------------------ *
* Event ring-buffer
* ------------------------------------------------------------------ */
#define INPUT_BUF_SIZE 512
#define CONSOLE_BUF_SIZE 256
static char s_console_buf[CONSOLE_BUF_SIZE];
static size_t s_console_rpos = 0;
static size_t s_console_wpos = 0;
static input_event_t s_buf[INPUT_BUF_SIZE];
static size_t s_rpos = 0;
static size_t s_wpos = 0;
static spinlock_t s_lock = SPINLOCK_INIT;
/* Called from IRQ context */
void input_push_char(char c)
{
uint64_t flags;
spinlock_acquire_irqsave(&s_lock, &flags);
size_t next = (s_console_wpos + 1) % CONSOLE_BUF_SIZE;
if (next != s_console_rpos) { /* drop if full */
s_console_buf[s_console_wpos] = c;
s_console_wpos = next;
}
spinlock_release_irqrestore(&s_lock, flags);
}
int input_read_console(void *buf, size_t len)
{
uint8_t *p = buf;
size_t count = 0;
uint64_t flags;
spinlock_acquire_irqsave(&s_lock, &flags);
while (count < len && s_console_rpos != s_console_wpos) {
p[count++] = s_console_buf[s_console_rpos];
s_console_rpos = (s_console_rpos + 1) % CONSOLE_BUF_SIZE;
}
spinlock_release_irqrestore(&s_lock, flags);
return (int)count;
}
static void push_event(const input_event_t *ev)
{
spinlock_acquire_or_wait(&s_lock);
size_t next = (s_wpos + 1) % INPUT_BUF_SIZE;
if (next != s_rpos) { /* drop if full */
s_buf[s_wpos] = *ev;
s_wpos = next;
}
spinlock_drop(&s_lock);
}
bool input_poll(input_event_t *out)
{
spinlock_acquire_or_wait(&s_lock);
if (s_rpos == s_wpos) {
spinlock_drop(&s_lock);
return false;
}
*out = s_buf[s_rpos];
s_rpos = (s_rpos + 1) % INPUT_BUF_SIZE;
spinlock_drop(&s_lock);
return true;
}
bool input_has_event(void)
{
spinlock_acquire_or_wait(&s_lock);
bool has = (s_rpos != s_wpos);
spinlock_drop(&s_lock);
return has;
}
/* ------------------------------------------------------------------ *
* Driver-facing helpers
* ------------------------------------------------------------------ */
void input_push_key(uint8_t scancode, char ascii, bool pressed)
{
input_event_t ev = {
.type = INPUT_EV_KEY,
.key = { .scancode = scancode, .ascii = ascii, .pressed = pressed },
};
push_event(&ev);
}
void input_push_mouse_rel(int16_t dx, int16_t dy)
{
input_event_t ev = { .type = INPUT_EV_MOUSE_REL, .rel = { dx, dy } };
push_event(&ev);
}
void input_push_mouse_btn(uint8_t button, bool pressed)
{
input_event_t ev = {
.type = INPUT_EV_MOUSE_BTN,
.btn = { .button = button, .pressed = pressed },
};
push_event(&ev);
}
void input_push_mouse_wheel(int8_t delta)
{
input_event_t ev = { .type = INPUT_EV_MOUSE_WHEEL, .wheel = { delta } };
push_event(&ev);
}
static int dev_input_read(void *buf, size_t len)
{
size_t count = 0;
while (count + sizeof(input_event_t) <= len) {
input_event_t ev;
if (!input_poll(&ev)) break;
memcpy((uint8_t*)buf + count, &ev, sizeof(ev));
count += sizeof(ev);
}
return (int)count;
}
static int dev_input_write(const void *buf, size_t len)
{
(void)buf; (void)len;
return -1; /* read-only */
}
void input_register_devnodes(void)
{
VFS_RegisterCharDev("/dev/input/event0", dev_input_read, dev_input_write);
}
void input_init(void)
{
input_register_devnodes();
kprintf("input: subsystem initialized\n");
}
+65
View File
@@ -0,0 +1,65 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
/* ------------------------------------------------------------------ *
* Generic input event types
* ------------------------------------------------------------------ */
typedef enum {
INPUT_EV_NONE = 0,
INPUT_EV_KEY, /* key press / release */
INPUT_EV_MOUSE_REL, /* relative mouse movement */
INPUT_EV_MOUSE_BTN, /* mouse button press/release */
INPUT_EV_MOUSE_WHEEL,
} input_ev_type_t;
typedef struct {
input_ev_type_t type;
union {
/* INPUT_EV_KEY */
struct {
uint8_t scancode; /* raw set-1 scancode (break bit cleared) */
char ascii; /* 0 if non-printable */
bool pressed;
} key;
/* INPUT_EV_MOUSE_REL */
struct {
int16_t dx, dy;
} rel;
/* INPUT_EV_MOUSE_BTN */
struct {
uint8_t button; /* 0=left 1=right 2=middle */
bool pressed;
} btn;
/* INPUT_EV_MOUSE_WHEEL */
struct {
int8_t delta;
} wheel;
};
} input_event_t;
/* ------------------------------------------------------------------ *
* Public API
* ------------------------------------------------------------------ */
void input_init(void);
/* Called by drivers (PS/2, USB HID, …) to publish events */
void input_push_key(uint8_t scancode, char ascii, bool pressed);
void input_push_mouse_rel(int16_t dx, int16_t dy);
void input_push_mouse_btn(uint8_t button, bool pressed);
void input_push_mouse_wheel(int8_t delta);
void input_push_char(char c);
int input_read_console(void *buf, size_t len);
/* Consumer API */
bool input_poll(input_event_t *out); /* non-blocking; false if empty */
bool input_has_event(void);
/* VFS helpers — call after VFS is ready */
void input_register_devnodes(void); /* creates /dev/input/event0 */
+195
View File
@@ -0,0 +1,195 @@
#include "ps2.h"
#include "drivers/input/input.h"
#include "arch/x86_64/sys/irq.h"
#include "arch/x86_64/boot/isr.h"
#include "arch/x86_64/cpu/io.h"
#include "arch/x86_64/sys/ioapic.h"
#include "arch/x86_64/sys/apic.h"
#include "libk/stdio.h"
#include "libk/debug.h"
#include "drivers/video/render.h"
/* ── PS/2 I/O ports ───────────────────────────────────────────────────────── */
#define PS2_DATA_PORT 0x60 /* Read: scancode / Write: command data */
#define PS2_STATUS_PORT 0x64 /* Read: controller status */
#define PS2_CMD_PORT 0x64 /* Write: controller command */
/* Status register bits */
#define PS2_STATUS_OBF (1 << 0) /* Output buffer full (data ready to read) */
#define PS2_STATUS_IBF (1 << 1) /* Input buffer full (don't write yet) */
/* ── IRQ number for the keyboard ─────────────────────────────────────────── */
#define KBD_IRQ 1
#define KBD_IDT_VECTOR (0x20 + KBD_IRQ) /* 0x21 with PIC_REMAP_OFFSET=0x20 */
/* ── Modifier state ───────────────────────────────────────────────────────── */
static bool s_shift = false;
static bool s_ctrl = false;
static bool s_alt = false;
static bool s_caps_lock = false;
static bool s_extended = false; /* true after receiving 0xE0 prefix */
/* ══════════════════════════════════════════════════════════════════════════
* Set-1 keycode → ASCII translation tables
*
* Index = Set-1 make code (0x000x58 covers the full AT-101 layout).
* 0x00 = unmapped / non-printable.
* ══════════════════════════════════════════════════════════════════════════ */
static const char s_normal[128] = {
/*00*/ 0, 0, '1', '2', '3', '4', '5', '6',
/*08*/ '7', '8', '9', '0', '-', '=', '\b', '\t',
/*10*/ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
/*18*/ 'o', 'p', '[', ']', '\n', 0, 'a', 's',
/*20*/ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
/*28*/ '\'','`', 0, '\\','z', 'x', 'c', 'v',
/*30*/ 'b', 'n', 'm', ',', '.', '/', 0, '*',
/*38*/ 0, ' ', 0, 0, 0, 0, 0, 0,
/*40*/ 0, 0, 0, 0, 0, 0, 0, '7',
/*48*/ '8', '9', '-', '4', '5', '6', '+', '1',
/*50*/ '2', '3', '0', '.', 0, 0, 0, 0,
/*58*/ 0
};
static const char s_shifted[128] = {
/*00*/ 0, 0, '!', '@', '#', '$', '%', '^',
/*08*/ '&', '*', '(', ')', '_', '+', '\b', '\t',
/*10*/ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
/*18*/ 'O', 'P', '{', '}', '\n', 0, 'A', 'S',
/*20*/ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
/*28*/ '"', '~', 0, '|', 'Z', 'X', 'C', 'V',
/*30*/ 'B', 'N', 'M', '<', '>', '?', 0, '*',
/*38*/ 0, ' ', 0, 0, 0, 0, 0, 0,
/*40*/ 0, 0, 0, 0, 0, 0, 0, '7',
/*48*/ '8', '9', '-', '4', '5', '6', '+', '1',
/*50*/ '2', '3', '0', '.', 0, 0, 0, 0,
/*58*/ 0
};
/* ══════════════════════════════════════════════════════════════════════════
* Extended (0xE0-prefixed) make codes we care about
* ══════════════════════════════════════════════════════════════════════════ */
typedef enum {
/* Regular Set-1 make codes (non-extended) */
SC_LSHIFT = 0x2A,
SC_RSHIFT = 0x36,
SC_LCTRL = 0x1D,
SC_LALT = 0x38,
SC_CAPSLOCK = 0x3A,
SC_BACKSPACE= 0x0E,
SC_ENTER = 0x1C,
SC_TAB = 0x0F,
SC_ESC = 0x01,
/* Function keys */
SC_F1 = 0x3B, SC_F2 = 0x3C, SC_F3 = 0x3D, SC_F4 = 0x3E,
SC_F5 = 0x3F, SC_F6 = 0x40, SC_F7 = 0x41, SC_F8 = 0x42,
SC_F9 = 0x43, SC_F10 = 0x44, SC_F11 = 0x57, SC_F12 = 0x58,
} scancode_t;
/* ══════════════════════════════════════════════════════════════════════════
* IRQ1 handler
* ══════════════════════════════════════════════════════════════════════════ */
void ps2_kbd_handler(Registers *regs)
{
(void)regs;
/*
* Always drain the output buffer even if we don't handle the byte,
* otherwise the PS/2 controller stalls and stops sending interrupts.
*/
uint8_t status = x86_64_inb(PS2_STATUS_PORT);
if (!(status & PS2_STATUS_OBF)) {
/* Spurious interrupt with no data — just return */
return;
}
uint8_t byte = x86_64_inb(PS2_DATA_PORT);
/* ── Handle 0xE0 extended-key prefix ─────────────────────────────── */
if (byte == 0xE0) {
s_extended = true;
return;
}
/* ── Decode make / break ─────────────────────────────────────────── */
bool pressed = !(byte & 0x80); /* bit 7 = 0 → make, 1 → break */
uint8_t scancode = byte & 0x7F; /* strip the break bit */
bool extended = s_extended;
s_extended = false;
/* ── Update modifier keys ────────────────────────────────────────── */
if (!extended) {
switch (scancode) {
case SC_LSHIFT: case SC_RSHIFT:
s_shift = pressed;
return; /* don't push a key event for bare modifiers */
case SC_LCTRL:
s_ctrl = pressed;
return;
case SC_LALT:
s_alt = pressed;
return;
case SC_CAPSLOCK:
if (pressed) s_caps_lock = !s_caps_lock;
return;
}
}
/* ── Translate to ASCII ──────────────────────────────────────────── */
char ascii = 0;
if (!extended && scancode < 128) {
bool use_upper = s_shift ^ s_caps_lock; /* XOR: caps inverts shift */
ascii = use_upper ? s_shifted[scancode] : s_normal[scancode];
}
/* Extended keys (arrows, home, end, etc.) leave ascii=0 */
/* ── Push event ──────────────────────────────────────────────────── */
input_push_key(scancode, ascii, pressed);
if (pressed && ascii) {
input_push_char(ascii);
}
}
/* ══════════════════════════════════════════════════════════════════════════
* Public helpers
* ══════════════════════════════════════════════════════════════════════════ */
uint8_t ps2_kbd_read_scancode(void)
{
/* Spin until data is available (for early/polled use only) */
while (!(x86_64_inb(PS2_STATUS_PORT) & PS2_STATUS_OBF))
asm volatile("pause");
return x86_64_inb(PS2_DATA_PORT);
}
/* ══════════════════════════════════════════════════════════════════════════
* Initialisation
* ══════════════════════════════════════════════════════════════════════════ */
void ps2_kbd_init(void)
{
/*
* ── Step 1: Flush the PS/2 output buffer ─────────────────────────
*
* Any leftover bytes from before boot will cause the controller to
* withhold interrupts. Drain them now.
*/
int attempts = 16;
while (attempts-- && (x86_64_inb(PS2_STATUS_PORT) & PS2_STATUS_OBF))
(void)x86_64_inb(PS2_DATA_PORT);
x86_64_APIC_IRQ_RedirectAndRegister(1, 0x21, ps2_kbd_handler);
kprintf("[PS2] Keyboard driver initialised (IRQ%d vector 0x%02x)\n",
KBD_IRQ, KBD_IDT_VECTOR);
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
void ps2_kbd_init(void);
uint8_t ps2_kbd_read_scancode(void);