diff options
Diffstat (limited to 'src/kernel/kbd.c')
-rw-r--r-- | src/kernel/kbd.c | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/src/kernel/kbd.c b/src/kernel/kbd.c new file mode 100644 index 0000000..73a5ec6 --- /dev/null +++ b/src/kernel/kbd.c @@ -0,0 +1,285 @@ +#include <stdint.h> +#include <stdbool.h> +#include "panic.h" +#include "log.h" +#include "util.h" + +static uint32_t *kbd_in_pointer; +static uint32_t *kbd_out_pointer; + +#define KBD_BUFFER_LENGTH 1024 +static uint32_t kbd_buffer[KBD_BUFFER_LENGTH]; + +static uint32_t mod_mask; + +enum { + PS2_CMD = 0x64, + PS2_DATA = 0x60 +}; + +enum { + PS2C_READ_CONFIG = 0x20, + PS2C_WRITE_CONFIG = 0x60, + PS2C_DISABLE = 0xad, + PS2C_ENABLE = 0xae +}; + +enum { + PS2S_CODE_READY = 0x01 +}; + +enum { + PS2G_XT_COMPAT = 0x40 +}; + +void init_kbd() { + outb(PS2_CMD, PS2C_READ_CONFIG); + uint8_t config = inb(PS2_DATA); + outb(PS2_CMD, PS2C_WRITE_CONFIG); + outb(PS2_DATA, config | PS2G_XT_COMPAT); + + kbd_in_pointer = kbd_buffer; + kbd_out_pointer = kbd_buffer; + mod_mask = 0; +} + +uint32_t get_key_code() { + if (kbd_in_pointer == kbd_out_pointer) + return 0; + uint32_t code = *kbd_out_pointer; + if (++kbd_out_pointer == kbd_buffer + KBD_BUFFER_LENGTH) + kbd_out_pointer = kbd_buffer; + return code; +} + +enum { + MOD_LSHIFT = 0x00100, + MOD_RSHIFT = 0x00200, + MOD_CAPS = 0x00400, + MOD_INSERT = 0x00800, + MOD_NUMPAD = 0x01000, + MOD_SCROLL = 0x02000, + MOD_LALT = 0x04000, + MOD_RALT = 0x08000, + MOD_LCTRL = 0x10000, + MOD_RCTRL = 0x20000, + MOD_LMETA = 0x40000, + MOD_RMETA = 0x80000 +}; + +enum { + CODE_CAPS = 0x80, + CODE_INSERT, + CODE_NUMPAD, + CODE_SCROLL, + CODE_LSHIFT, + CODE_RSHIFT, + CODE_LALT, + CODE_RALT, + CODE_LCTRL, + CODE_RCTRL, + CODE_LMETA, + CODE_RMETA, + /* 0x8c - 0x97 reserved */ + /* 0x98 - 0x9f unassigned */ + CODE_F1 = 0xa0, + CODE_F2, + CODE_F3, + CODE_F4, + CODE_F5, + CODE_F6, + CODE_F7, + CODE_F8, + CODE_F9, + CODE_F10, + CODE_F11, + CODE_F12, + /* 0xac - 0xaf unassigned */ + CODE_NUM0 = 0xb0, + CODE_NUM1, + CODE_NUM2, + CODE_NUM3, + CODE_NUM4, + CODE_NUM5, + CODE_NUM6, + CODE_NUM7, + CODE_NUM8, + CODE_NUM9, + CODE_NTIMES, + CODE_NPLUS, + CODE_NENTER, + CODE_NMINUS, + CODE_NDOT, + CODE_NSLASH, + /* 0xc0 unassigned */ + CODE_DELETE, + CODE_HOME, + CODE_END, + CODE_PUP, + CODE_PDOWN, + CODE_UP, + CODE_DOWN, + CODE_LEFT, + CODE_RIGHT, + CODE_ESC, + CODE_MENU, + CODE_PAUSE, + CODE_PRSCR, + /* 0xce - 0xef unassigned */ + CODE_END_LSHIFT = 0xf0, + CODE_END_RSHIFT, + CODE_END_LALT, + CODE_END_RALT, + CODE_END_LCTRL, + CODE_END_RCTRL, + CODE_END_LMETA, + CODE_END_RMETA +}; + +static const uint32_t mod_bits[] = { + MOD_CAPS, + MOD_INSERT, + MOD_NUMPAD, + MOD_SCROLL, + MOD_LSHIFT, + MOD_RSHIFT, + MOD_LALT, + MOD_RALT, + MOD_LCTRL, + MOD_RCTRL, + MOD_LMETA, + MOD_RMETA +}; + +static const uint32_t *const unmod_bits = mod_bits + 4; + +//in these tables, 0x00 represents an unknown key, +// and 0xff represents a key release. + +static const uint8_t codes[] = { + 0, CODE_ESC, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', '\b', '\t', + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', '\n', CODE_LCTRL, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', CODE_LSHIFT, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', CODE_RSHIFT, CODE_NTIMES, + CODE_LALT, ' ', CODE_CAPS, CODE_F1, CODE_F2, CODE_F3, CODE_F4, CODE_F5, + CODE_F6, CODE_F7, CODE_F8, CODE_F9, CODE_F10, CODE_NUMPAD, CODE_SCROLL, CODE_NUM7, + CODE_NUM8, CODE_NUM9, CODE_NMINUS, CODE_NUM4, CODE_NUM5, CODE_NUM6, CODE_NPLUS, CODE_NUM1, + CODE_NUM2, CODE_NUM3, CODE_NUM0, CODE_NDOT, 0, 0, 0, CODE_F11, + CODE_F12, 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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, CODE_END_LCTRL, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, CODE_END_LSHIFT, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, CODE_END_RSHIFT, 0xff, + CODE_END_LALT, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, + 0xff, 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 const uint8_t codes_e0[] = { + 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, CODE_NENTER, CODE_RCTRL, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, CODE_NSLASH, 0, 0, + CODE_RALT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, CODE_HOME, + CODE_UP, CODE_PUP, 0, CODE_LEFT, 0, CODE_RIGHT, 0, CODE_END, + CODE_DOWN, CODE_PDOWN, CODE_INSERT, CODE_DELETE, 0, 0, 0, 0, + 0, 0, 0, CODE_LMETA, CODE_RMETA, CODE_MENU, 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, 0xff, CODE_END_RCTRL, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0xff, 0, 0, + CODE_END_RALT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0xff, + 0xff, 0xff, 0, 0xff, 0, 0xff, 0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, + 0, 0, 0, CODE_END_LMETA, CODE_END_RMETA, 0xff, 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 +}; + +void on_kbd_isr() { + while (inb(PS2_CMD) & PS2S_CODE_READY) { + uint8_t code = inb(PS2_DATA); + if (code == 0xe1) { + code = inb(PS2_DATA); + if (code == 0x1d) { + if (inb(PS2_DATA) != 0x45) + code = 0; + else + code = CODE_PAUSE; + } + else if (code == 0x9d) { + if (inb(PS2_DATA) != 0xc5) + code = 0; + else + code = 0xff; + } + else + code = 0; + } + else if (code == 0xe0) { + code = inb(PS2_DATA); + if (code == 0x2a) { + if ((inb(PS2_DATA) != 0xe0) || + (inb(PS2_DATA) != 0x37)) + code = 0; + else + code = CODE_PRSCR; + } + else if (code == 0xb7) { + if ((inb(PS2_DATA) != 0xe0) || + (inb(PS2_DATA) != 0xaa)) + code = 0; + else + code = 0xff; + } + else + code = codes_e0[code]; + } + else + code = codes[code]; + + if (!code) + PANIC("Unknown scancode."); + + if (code < 0xf0) + *kbd_in_pointer++ = mod_mask | code; + if ((code >= 0x80) && (code <= 0x83)) + mod_mask ^= mod_bits[code & 0x03]; + else if ((code >= 0x84) && (code <= 0x8b)) + mod_mask |= mod_bits[code & 0x0f]; + else if (code >= 0xf0) + mod_mask &= ~unmod_bits[code & 0x0f]; + } +}
\ No newline at end of file |