From a19ae009f9f571d25a90aca5cc5e05d3c76e1aed Mon Sep 17 00:00:00 2001 From: Danny Holman Date: Fri, 16 Feb 2024 13:29:51 -0600 Subject: arch: i386: add basic keyboard driver Add a basic driver for the PS/2 keyboard. This driver just prints whatever it receives back out to the framebuffer. Signed-off-by: Danny Holman --- arch/i386/include/kernel/keyboard.h | 33 +++++++++ arch/i386/kernel/keyboard.c | 142 ++++++++++++++++++++++++++++++++++++ arch/i386/make.config | 1 + 3 files changed, 176 insertions(+) create mode 100644 arch/i386/include/kernel/keyboard.h create mode 100644 arch/i386/kernel/keyboard.c diff --git a/arch/i386/include/kernel/keyboard.h b/arch/i386/include/kernel/keyboard.h new file mode 100644 index 0000000..8f39a70 --- /dev/null +++ b/arch/i386/include/kernel/keyboard.h @@ -0,0 +1,33 @@ +#ifndef I386_KEYBOARD_H +#define I386_KEYBOARD_H + +#include +#include + +#define KB_STAT 0x64 +#define KB_DATA 0x60 + +#define KB_DIB 0x01 +#define KB_SHIFT (1<<0) +#define KB_CTL (1<<1) +#define KB_ALT (1<<2) +#define KB_CPSLK (1<<3) +#define KB_NUMLK (1<<4) +#define KB_SCLLK (1<<5) +#define KB_E0ESC (1<<6) + +#define KB_HOME 0xE0 +#define KB_END 0xE1 +#define KB_UP 0xE2 +#define KB_DOWN 0xE3 +#define KB_LEFT 0xE4 +#define KB_RGHT 0xE5 +#define KB_PGUP 0xE6 +#define KB_PGDN 0xE7 +#define KB_INS 0xE8 +#define KB_DEL 0xE9 + +char keyboard_getchar(void); +void keyboard_handler(struct isr_frame *frame); + +#endif diff --git a/arch/i386/kernel/keyboard.c b/arch/i386/kernel/keyboard.c new file mode 100644 index 0000000..4e4bc9b --- /dev/null +++ b/arch/i386/kernel/keyboard.c @@ -0,0 +1,142 @@ +#include +#include +#include + +#define C(k) (k - '@') + +static uint8_t keymap_modifiers[256] = { + [0x1D] KB_CTL, + [0x2A] KB_SHIFT, + [0x36] KB_SHIFT, + [0x38] KB_ALT, + [0x9D] KB_CTL, + [0xB8] KB_ALT +}; + +static uint8_t keymap_toggles[256] = { + [0x3A] KB_CPSLK, + [0x45] KB_NUMLK, + [0x46] KB_SCLLK +}; + +static uint8_t keymap_normal[256] = { + 0, 0x1B, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', '\b', '\t', + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', '\n', 0, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', 0, '*', + 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', + '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, + [0x9C] '\n', + [0xB5] '/', + [0xC8] KB_UP, + [0xD0] KB_DOWN, + [0xC9] KB_PGUP, + [0xD1] KB_PGDN, + [0xCB] KB_LEFT, + [0xCD] KB_RGHT, + [0x97] KB_HOME, + [0xCF] KB_END, + [0xD2] KB_INS, + [0xD3] KB_DEL +}; + +static uint8_t keymap_shifted[256] = { + 0, 0x33, '!', '@', '#', '$', '%', '^', + '&', '*', '(', ')', '_', '+', '\b', '\t', + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', + 'O', 'P', '{', '}', '\n', 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + '"', '~', 0, '|', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', + 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', + '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, + [0x9C] '\n', + [0xB5] '/', + [0xC8] KB_UP, + [0xD0] KB_DOWN, + [0xC9] KB_PGUP, + [0xD1] KB_PGDN, + [0xCB] KB_LEFT, + [0xCD] KB_RGHT, + [0x97] KB_HOME, + [0xCF] KB_END, + [0xD2] KB_INS, + [0xD3] KB_DEL +}; + +static uint8_t keymap_control[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + C('Q'), C('W'), C('E'), C('R'), C('T'), C('Y'), C('U'), C('I'), + C('O'), C('P'), 0, 0, '\r', 0, C('A'), C('S'), + C('D'), C('F'), C('G'), C('H'), C('J'), C('K'), C('L'), 0, + 0, 0, 0, C('\\'), C('Z'), C('X'), C('C'), C('V'), + C('B'), C('N'), C('M'), 0, 0, C('/'), 0, 0, + [0x9C] '\r', + [0xB5] C('/'), + [0xC8] KB_UP, + [0xD0] KB_DOWN, + [0xC9] KB_PGUP, + [0xD1] KB_PGDN, + [0xCB] KB_LEFT, + [0xCD] KB_RGHT, + [0x97] KB_HOME, + [0xCF] KB_END, + [0xD2] KB_INS, + [0xD3] KB_DEL +}; + +static uint8_t* keymaps[4] = { + keymap_normal, + keymap_shifted, + keymap_control, + keymap_control, +}; + +char keyboard_getchar(void) { + static int shift = 0; + uint8_t st = inb(KB_STAT); + if ((st & KB_DIB) == 0) + return -1; + + uint8_t data = inb(KB_DATA); + + if (data == 0xE0) { + shift |= KB_E0ESC; + return -1; + } else if (data & 0x80) { + if (!(shift & KB_E0ESC)) + data &= 0x7F; + shift &= ~(keymap_modifiers[data] | KB_E0ESC); + return -1; + } else if (shift & KB_E0ESC) { + data |= 0x80; + shift &= ~KB_E0ESC; + } + + shift |= keymap_modifiers[data]; + shift ^= keymap_toggles[data]; + char c = keymaps[shift & (KB_CTL | KB_SHIFT)][data]; + if (shift & KB_CPSLK) { + if ('a' <= c && c <= 'z') + c += 'A' - 'a'; + else if ('A' <= c && c <= 'Z') + c += 'a' - 'A'; + } + return c; +} + +void keyboard_handler(struct isr_frame *frame) { + char c = keyboard_getchar(); + // TODO: actually put this in a buffer + if (c != -1) + fb_putchar(c); + return; +} diff --git a/arch/i386/make.config b/arch/i386/make.config index 2c87912..9d74c33 100644 --- a/arch/i386/make.config +++ b/arch/i386/make.config @@ -9,6 +9,7 @@ KERNEL_ARCH_OBJS=$(ARCHDIR)/boot/boot.o \ $(ARCHDIR)/boot/gdt.o \ $(ARCHDIR)/kernel/framebuffer.o \ $(ARCHDIR)/kernel/multiboot.o \ + $(ARCHDIR)/kernel/keyboard.o \ $(ARCHDIR)/kernel/serial.o \ $(ARCHDIR)/kernel/pic.o \ $(ARCHDIR)/kernel/timer.o \ -- cgit v1.2.3