hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/boot/keyboard.zig
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-12 10:59:26 +0200
committerhachem <im@hachem.wtf>2026-09-12 10:59:26 +0200
commitd6d908e3386e107b41241e9eda7dc546581524df (patch)
tree8219d02a7494152722ac7f32140d63c8a3b3daa7 /boot/keyboard.zig
parent4f540af34d7a88547d60bed7bd28850e6d0e18ab (diff)
feat: basic keyboard driver + tester shell
Diffstat (limited to 'boot/keyboard.zig')
-rw-r--r--boot/keyboard.zig42
1 files changed, 42 insertions, 0 deletions
diff --git a/boot/keyboard.zig b/boot/keyboard.zig
new file mode 100644
index 0000000..8e3a58f
--- /dev/null
+++ b/boot/keyboard.zig
@@ -0,0 +1,42 @@
+// top half of the PS/2 keyboard driver.
+// the IRQ1 handler calls onIrq and reads the raw scancode out
+// of the controller and drops it in a ring buffer. thats ALLLLLL it does
+// no decoding, no allocation, nothing that could (should) fault or reenter
+// the only reason this exists is because the interrupt handler is not a safe
+// spot to execute revo code and shit can break easily and i am NOT going to debug
+// it so its just better to do it like this.
+//
+// since there is just one producer (ISR) and one consumer (the event loop)
+// i dont need to make a lock, the ISR just moves the tail and the loop just
+// moves the head
+
+const port = @import("port.zig");
+
+const DATA_PORT: u16 = 0x60;
+const SIZE: usize = 256; // u8 indices wrap mod 256 for free
+
+var buf: [SIZE]u8 = undefined;
+var head: u8 = 0; // next slot the loop will read
+var tail: u8 = 0; // next slot the ISR will write
+
+// called from the IRQ1 handler. read the scancode (which also ACKs the
+// controller so it'll send the next one) and enqueue it, dropping it on the
+// floor if the buffer is somehow full.
+pub fn onIrq() void {
+ const code = port.inb(DATA_PORT);
+ const t: *volatile u8 = &tail;
+ const h: *volatile u8 = &head;
+ if (t.* +% 1 == h.*) return; // full, drop
+ buf[t.*] = code;
+ t.* +%= 1;
+}
+
+// called from the event loop. next queued scancode, or null if empty.
+pub fn pop() ?u8 {
+ const t: *volatile u8 = &tail;
+ const h: *volatile u8 = &head;
+ if (h.* == t.*) return null;
+ const code = buf[h.*];
+ h.* +%= 1;
+ return code;
+}