feat: partially implement PS/2 input subsystem with keyboard and mouse support

This implementation is incomplete, and doesn't work, but it will soon, to be determined, hopefully, uh, yknow.

Signed-off-by kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
kaguya
2026-04-17 17:34:46 -04:00
parent 016ee32987
commit 551eb00708
13 changed files with 686 additions and 8 deletions
+2 -2
View File
@@ -130,7 +130,7 @@ bool ata_read_sectors(uint64_t lba, uint8_t sector_count, void* buffer)
return true;
}
bool ata_write_sectors(uint64_t lba, uint8_t sector_count, const void* buffer) {
bool ata_write_sectors(uint64_t lba, uint8_t sector_count, void* buffer) {
if (sector_count == 0) return true;
@@ -143,7 +143,7 @@ bool ata_write_sectors(uint64_t lba, uint8_t sector_count, const void* buffer) {
x86_64_outb(ATA_PRIMARY_LBAHIGH, (uint8_t)(lba >> 16));
x86_64_outb(ATA_PRIMARY_COMMAND, 0x30); // write sectors
const uint16_t* buf = buffer;
uint16_t* buf = buffer;
for (uint8_t i = 0; i < sector_count; i++) {
if (!ata_poll()) {
+1 -1
View File
@@ -10,4 +10,4 @@ void ata_identify(void);
// Buffer must be large enough (sector_count * 512).
bool ata_read_sectors(uint64_t lba, uint8_t sector_count, void* buffer);
bool ata_write_sectors(uint64_t lba, uint8_t sector_count, const void* buffer);
bool ata_write_sectors(uint64_t lba, uint8_t sector_count, void* buffer);
+5
View File
@@ -63,4 +63,9 @@ void x86_64_IRQ_Initialize(void)
void x86_64_IRQ_RegisterHandler(int irq, IRQHandler handler)
{
g_IRQHandlers[irq] = handler;
}
void x86_64_IRQ_Unmask(int irq)
{
if (g_Driver) g_Driver->Unmask(irq);
}
+2 -1
View File
@@ -5,4 +5,5 @@
typedef void (*IRQHandler)(Registers* regs);
void x86_64_IRQ_Initialize();
void x86_64_IRQ_RegisterHandler(int irq, IRQHandler handler);
void x86_64_IRQ_RegisterHandler(int irq, IRQHandler handler);
void x86_64_IRQ_Unmask(int irq);
+332
View File
@@ -0,0 +1,332 @@
#include "ps2.h"
#include "io.h"
#include "irq.h"
#include "stdio.h"
#include "mp/spinlock.h"
#include <stddef.h>
#include "input/input.h"
#define PS2_DATA 0x60
#define PS2_COMMAND 0x64
/* ====================== CONTROLLER HELPERS ====================== */
static inline bool ps2_wait_write(void) {
uint32_t timeout = 1000000;
while (x86_64_inb(PS2_COMMAND) & 2) {
if (--timeout == 0) {
printf("PS/2: write timeout!\n");
return false;
}
asm volatile("pause");
}
return true;
}
static inline bool ps2_wait_read(void) {
uint32_t timeout = 1000000;
while (!(x86_64_inb(PS2_COMMAND) & 1)) {
if (--timeout == 0) {
printf("PS/2: read timeout!\n");
return false;
}
asm volatile("pause");
}
return true;
}
static inline uint8_t ps2_read(void) {
if (!ps2_wait_read()) return 0xFF; // error value
return x86_64_inb(PS2_DATA);
}
static inline void ps2_write(uint8_t val) {
if (!ps2_wait_write()) return;
x86_64_outb(PS2_DATA, val);
}
static inline void ps2_command(uint8_t cmd) {
if (!ps2_wait_write()) return;
x86_64_outb(PS2_COMMAND, cmd);
}
/* Send command to AUX (mouse) port */
static void ps2_write_mouse(uint8_t val) {
ps2_command(0xD4); // tell controller next byte goes to mouse
ps2_write(val);
}
/* ====================== KEYBOARD RING BUFFER ====================== */
#define KB_BUFFER_SIZE 256
static uint8_t kb_buffer[KB_BUFFER_SIZE];
static size_t kb_read_idx = 0;
static size_t kb_write_idx = 0;
static spinlock_t kb_lock = SPINLOCK_INIT;
/* US QWERTY scancode set 2 -> ASCII (unshifted) */
static const char kb_map[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, 0,
/*48*/ 0, 0, '-', 0, 0, 0, '+', 0,
/*50*/ 0, 0, 0, 0, 0, 0, 0, 0,
/*58*/ 0, 0, 0, 0, 0, 0, 0, 0,
/*60*/ 0, 0, 0, 0, 0, 0, 0, 0,
/*68*/ 0, 0, 0, 0, 0, 0, 0, 0,
/*70*/ 0, 0, 0, 0, 0, 0, 0, 0,
/*78*/ 0, 0, 0, 0, 0, 0, 0, 0,
};
/* Shifted version */
static const char kb_map_shift[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,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
};
static bool shift = false;
static bool caps = false;
static void kb_enqueue(uint8_t sc) {
spinlock_acquire_or_wait(&kb_lock);
size_t next = (kb_write_idx + 1) % KB_BUFFER_SIZE;
if (next != kb_read_idx) {
kb_buffer[kb_write_idx] = sc;
kb_write_idx = next;
}
spinlock_drop(&kb_lock);
}
bool ps2_keyboard_has_data(void) {
spinlock_acquire_or_wait(&kb_lock);
bool has = (kb_read_idx != kb_write_idx);
spinlock_drop(&kb_lock);
return has;
}
/* ====================== MOUSE RING BUFFER ====================== */
#define MOUSE_BUFFER_SIZE 32
static mouse_packet_t mouse_buffer[MOUSE_BUFFER_SIZE];
static size_t mouse_read_idx = 0;
static size_t mouse_write_idx = 0;
static spinlock_t mouse_lock = SPINLOCK_INIT;
static uint8_t mouse_packet[4];
static int mouse_idx = 0;
static int mouse_packet_size = 3; // 3 or 4 for wheel
static void mouse_enqueue(const mouse_packet_t* pkt) {
spinlock_acquire_or_wait(&mouse_lock);
size_t next = (mouse_write_idx + 1) % MOUSE_BUFFER_SIZE;
if (next != mouse_read_idx) {
mouse_buffer[mouse_write_idx] = *pkt;
mouse_write_idx = next;
}
spinlock_drop(&mouse_lock);
}
bool ps2_mouse_get_packet(mouse_packet_t* out) {
spinlock_acquire_or_wait(&mouse_lock);
if (mouse_read_idx == mouse_write_idx) {
spinlock_drop(&mouse_lock);
return false;
}
*out = mouse_buffer[mouse_read_idx];
mouse_read_idx = (mouse_read_idx + 1) % MOUSE_BUFFER_SIZE;
spinlock_drop(&mouse_lock);
return true;
}
bool ps2_mouse_has_packet(void) {
spinlock_acquire_or_wait(&mouse_lock);
bool has = (mouse_read_idx != mouse_write_idx);
spinlock_drop(&mouse_lock);
return has;
}
/* ====================== IRQ HANDLERS ====================== */
void keyboard_irq_handler(Registers* regs) {
(void)regs;
uint8_t sc = x86_64_inb(PS2_DATA);
// Optional: keep the old buffer if you still use the polling API somewhere
kb_enqueue(sc);
// === NEW: process and push to the input subsystem ===
bool released = (sc & 0x80) != 0;
sc &= 0x7F;
if (sc == 0x2A || sc == 0x36) { // L/R Shift
shift = !released;
return;
}
if (sc == 0x3A && !released) { // Caps Lock
caps = !caps;
return;
}
bool is_alpha = (sc >= 0x10 && sc <= 0x19) ||
(sc >= 0x1E && sc <= 0x26) ||
(sc >= 0x2C && sc <= 0x32);
bool use_upper = shift ^ (caps && is_alpha);
char ascii = use_upper ? kb_map_shift[sc] : kb_map[sc];
input_push_key(sc, released ? 0 : ascii, !released);
}
void mouse_irq_handler(Registers* regs)
{
(void)regs;
uint8_t data = x86_64_inb(PS2_DATA);
if (mouse_idx == 0 && !(data & 0x08)) return;
mouse_packet[mouse_idx++] = data;
if (mouse_idx == mouse_packet_size) {
mouse_packet_t pkt = {0};
uint8_t status = mouse_packet[0];
pkt.overflow_x = !!(status & (1 << 6));
pkt.overflow_y = !!(status & (1 << 7));
if (pkt.overflow_x || pkt.overflow_y) {
mouse_idx = 0;
return;
}
pkt.buttons = status & 0x07;
pkt.x_delta = (int8_t)mouse_packet[1];
pkt.y_delta = -(int8_t)mouse_packet[2];
pkt.z_delta = (mouse_packet_size == 4) ? (int8_t)mouse_packet[3] : 0;
mouse_enqueue(&pkt);
if (pkt.x_delta || pkt.y_delta)
input_push_mouse_rel(pkt.x_delta, pkt.y_delta);
if (pkt.z_delta)
input_push_mouse_wheel(pkt.z_delta);
static uint8_t prev_buttons = 0;
uint8_t changed = pkt.buttons ^ prev_buttons;
for (int i = 0; i < 3; i++) {
if (changed & (1 << i))
input_push_mouse_btn(i, !!(pkt.buttons & (1 << i)));
}
prev_buttons = pkt.buttons;
mouse_idx = 0;
}
}
/* ====================== DEVICE INITIALIZATION ====================== */
static bool ps2_controller_init(void) {
ps2_command(0xAD);
ps2_command(0xA7);
while (x86_64_inb(PS2_COMMAND) & 1)
x86_64_inb(PS2_DATA);
ps2_command(0xAA);
if (ps2_read() != 0x55) {
printf("PS/2: Controller self-test failed!\n");
return false;
}
ps2_command(0xAB);
if (ps2_read() != 0x00) {
printf("PS/2: Keyboard interface test failed!\n");
return false;
}
ps2_command(0xA9);
if (ps2_read() != 0x00) {
printf("PS/2: Mouse interface test failed (no mouse?)\n");
}
ps2_command(0x20);
uint8_t cfg = ps2_read();
cfg |= (1 << 0) | (1 << 1) | (1 << 6);
cfg &= ~((1 << 4) | (1 << 5));
ps2_command(0x60);
ps2_write(cfg);
ps2_command(0xAE);
ps2_command(0xA8);
printf("PS/2: Controller ready (IRQs enabled, translation on)\n");
return true;
}
static void ps2_keyboard_init(void) {
ps2_write(0xFF);
ps2_read(); // ACK
ps2_read(); ps2_read(); // AA 00
ps2_write(0xF4);
if (ps2_read() != 0xFA)
printf("PS/2: Keyboard enable failed\n");
printf("PS/2: Keyboard initialized (scancode set 2)\n");
}
static void ps2_mouse_init(void) {
ps2_write_mouse(0xFF);
ps2_read(); ps2_read(); ps2_read(); // ACK, AA, 00
ps2_write_mouse(0xF3); ps2_write_mouse(200);
ps2_write_mouse(0xF3); ps2_write_mouse(100);
ps2_write_mouse(0xF3); ps2_write_mouse(80);
ps2_write_mouse(0xF2);
uint8_t id = ps2_read();
if (id == 0x03) {
mouse_packet_size = 4;
printf("PS/2: IntelliMouse (wheel) detected\n");
} else {
mouse_packet_size = 3;
printf("PS/2: Standard mouse detected\n");
}
ps2_write_mouse(0xF6);
ps2_write_mouse(0xF4);
printf("PS/2: Mouse initialized (packet size %d)\n", mouse_packet_size);
}
/* ====================== MAIN INIT ====================== */
void ps2_init(void) {
if (!ps2_controller_init()) {
printf("PS/2: Controller initialization failed - input disabled\n");
return;
}
input_init();
ps2_keyboard_init();
ps2_mouse_init();
x86_64_IRQ_RegisterHandler(1, keyboard_irq_handler);
x86_64_IRQ_RegisterHandler(12, mouse_irq_handler);
x86_64_IRQ_Unmask(1);
x86_64_IRQ_Unmask(12);
printf("PS/2 subsystem initialized successfully!\n");
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "mp/spinlock.h"
/* ====================== PUBLIC API ====================== */
/* Keyboard */
uint8_t ps2_keyboard_get_scancode(void); // non-blocking, returns 0 if empty
bool ps2_keyboard_has_data(void);
char ps2_keyboard_get_char(void); // processed ASCII (handles shift/caps)
/* Mouse */
typedef struct {
int8_t x_delta;
int8_t y_delta;
int8_t z_delta; // wheel (0 if not supported)
uint8_t buttons; // bit 0 = left, bit 1 = right, bit 2 = middle
bool overflow_x;
bool overflow_y;
} mouse_packet_t;
bool ps2_mouse_get_packet(mouse_packet_t* out_packet); // non-blocking, returns false if empty
bool ps2_mouse_has_packet(void);
/* Subsystem */
void ps2_init(void);
+59
View File
@@ -2,12 +2,55 @@
#include <video/render.h>
#include <arch/x86_64/e9.h>
#include "mp/spinlock.h"
#include "stdio.h"
#include "string.h"
static spinlock_t s_vfs_lock = SPINLOCK_INIT;
static vfs_file_t vfs_fd_table[VFS_MAX_FDS];
typedef struct {
const char* path;
int (*read)(void* buf, size_t len);
int (*write)(const void* buf, size_t len);
} vfs_chardev_t;
#define VFS_MAX_CHARDEVS 8
static vfs_chardev_t s_chardevs[VFS_MAX_CHARDEVS];
static int s_num_chardevs = 0;
int VFS_RegisterCharDev(const char* path,
int (*read)(void* buf, size_t len),
int (*write)(const void* buf, size_t len))
{
if (s_num_chardevs >= VFS_MAX_CHARDEVS) {
printf("VFS: too many char devices!\n");
return -1;
}
s_chardevs[s_num_chardevs].path = path;
s_chardevs[s_num_chardevs].read = read;
s_chardevs[s_num_chardevs].write = write;
printf("VFS: registered chardev %s\n", path);
s_num_chardevs++;
return 0;
}
fd_t VFS_Open_internal(const char* path)
{
for (int i = 0; i < s_num_chardevs; i++) {
if (strcmp(s_chardevs[i].path, path) == 0) {
for (int fd = 4; fd < VFS_MAX_FDS; fd++) {
if (!vfs_fd_table[fd].used) {
vfs_fd_table[fd].used = true;
vfs_fd_table[fd].type = VFS_NODE_CHARDEV;
vfs_fd_table[fd].offset = 0;
vfs_fd_table[fd].chardev.dev_idx = i;
return fd;
}
}
return -1;
}
}
uint32_t ino = ext2_resolve_path(path);
if (ino == 0)
return -1;
@@ -92,6 +135,14 @@ int VFS_Read(fd_t fd, uint8_t* buf, size_t size)
return size;
}
case VFS_NODE_CHARDEV:
{
int idx = file->chardev.dev_idx;
if (idx < 0 || idx >= s_num_chardevs || !s_chardevs[idx].read)
return -1;
return s_chardevs[idx].read(buf, size);
}
default:
return -1;
}
@@ -143,5 +194,13 @@ int VFS_Write(fd_t file, uint8_t* data, size_t size)
return size;
}
if (f->type == VFS_NODE_CHARDEV)
{
int idx = f->chardev.dev_idx;
if (idx >= 0 && idx < s_num_chardevs && s_chardevs[idx].write)
return s_chardevs[idx].write(data, size);
return -1;
}
return -1;
}
+10 -2
View File
@@ -16,7 +16,7 @@ typedef int fd_t;
typedef enum {
VFS_NODE_NONE,
VFS_NODE_EXT2,
VFS_NODE_DEVICE
VFS_NODE_CHARDEV
} vfs_node_type_t;
typedef struct {
@@ -27,6 +27,10 @@ typedef struct {
uint32_t inode_num;
ext2_inode_t inode;
} ext2;
struct {
int dev_idx;
} chardev;
};
size_t offset;
@@ -37,4 +41,8 @@ typedef struct {
fd_t VFS_Open(const char* path);
int VFS_Read(fd_t fd, uint8_t* buf, size_t size);
int VFS_Write(fd_t fd, uint8_t* data, size_t size);
int VFS_Close(fd_t fd);
int VFS_Close(fd_t fd);
int VFS_RegisterCharDev(const char* path,
int (*read)(void* buf, size_t len),
int (*write)(const void* buf, size_t len));
+117
View File
@@ -0,0 +1,117 @@
#include "input/input.h"
#include "mp/spinlock.h"
#include "stdio.h"
#include "fs/vfs.h"
#include <stddef.h>
#include "mm/memory.h"
#include "string.h"
/* ------------------------------------------------------------------ *
* Event ring-buffer
* ------------------------------------------------------------------ */
#define INPUT_BUF_SIZE 512
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;
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);
}
/* ------------------------------------------------------------------ *
* /dev/input/event0 VFS device node
*
* Adjust VFS_RegisterDevice() to match whatever your VFS layer exposes
* for character-device registration.
* ------------------------------------------------------------------ */
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();
printf("input: subsystem initialized\n");
}
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#include <stdint.h>
#include <stdbool.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);
/* 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 */
+65
View File
@@ -27,6 +27,8 @@
#include "arch/x86_64/pci.h"
#include "sound/hda.h"
#include "sound/pcm.h"
#include "arch/x86_64/ps2.h"
#include "input/input.h"
uintptr_t g_hhdm_offset;
@@ -201,6 +203,7 @@ void kmain(void) {
x86_64_ISR_Initialize();
x86_64_IRQ_Initialize();
x86_64_PIT_Initialize(1000);
ps2_init();
asm volatile("sti");
calibrate_tsc();
@@ -446,6 +449,68 @@ void kmain(void) {
//start_userspace();
printf("tst");
printf("\n=== Input Subsystem Test ===\n");
printf("Opening /dev/input/event0...\n");
fd_t input_fd = VFS_Open("/dev/input/event0");
if (input_fd < 0) {
printf("Failed to open /dev/input/event0!\n");
} else {
printf("Successfully opened /dev/input/event0 (fd=%d)\n", input_fd);
printf("Press keys or move mouse... (press ESC to exit test)\n\n");
input_event_t ev;
bool running = true;
while (running) {
// Non-blocking read from the input device
int bytes = VFS_Read(input_fd, (uint8_t*)&ev, sizeof(input_event_t));
if (bytes == sizeof(input_event_t)) {
switch (ev.type) {
case INPUT_EV_KEY:
printf("KEY: scancode=0x%02X ascii='%c' (%d) pressed=%s\n",
ev.key.scancode,
ev.key.ascii ? ev.key.ascii : '?',
ev.key.ascii,
ev.key.pressed ? "YES" : "NO");
// Exit test on ESC key release
if (ev.key.scancode == 0x01 && !ev.key.pressed) {
printf("ESC pressed - exiting input test.\n");
running = false;
}
break;
case INPUT_EV_MOUSE_REL:
if (ev.rel.dx || ev.rel.dy) {
printf("MOUSE MOVE: dx=%d dy=%d\n", ev.rel.dx, ev.rel.dy);
}
break;
case INPUT_EV_MOUSE_BTN:
printf("MOUSE BTN: button=%d pressed=%s\n",
ev.btn.button,
ev.btn.pressed ? "YES" : "NO");
break;
case INPUT_EV_MOUSE_WHEEL:
printf("MOUSE WHEEL: delta=%d\n", ev.wheel.delta);
break;
default:
printf("Unknown event type %d\n", ev.type);
break;
}
}
// Small yield so we don't spin the CPU too hard
// (you can replace with a proper sleep later)
asm volatile("pause");
}
VFS_Close(input_fd);
printf("Input test finished.\n");
}
// We're done, just hang...
hcf();
+1 -1
View File
@@ -19,7 +19,7 @@ uint64_t rdtsc(void)
void calibrate_tsc(void)
{
// Use a stable PIT rate for calibration
const uint32_t pit_freq = 1000; // 100 Hz = 10ms per tick
const uint32_t pit_freq = 1000; // 1000 Hz = 1ms per tick
const uint32_t calibration_ticks = 1000; // 1 second total