summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/i386/include/kernel/keyboard.h33
-rw-r--r--arch/i386/kernel/keyboard.c142
-rw-r--r--arch/i386/make.config1
3 files changed, 176 insertions, 0 deletions
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 <kernel/isr.h>
+#include <stdint.h>
+
+#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 <kernel/keyboard.h>
+#include <kernel/framebuffer.h>
+#include <kernel/pic.h>
+
+#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 \