#include #include "window.h" #include "drive.h" #include "panic.h" #include "pmap.h" #include "util.h" #include "kbd.h" #define SCANTAB_DIR "sys/scantabs" #define LAYOUT_HARDCODE_TMP "qwerty" 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 }; static uint32_t n_scantabs; static struct scantab_info { uint8_t *scantab; uint8_t prefix_length; uint8_t prefix[256]; } *scantabs; enum { ST_ILLEGAL, ST_SUBTABLE, ST_FLIP, ST_SKIP }; 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); //TODO: get layout from some config file file_id_t stf = drives->get_file(drives, SCANTAB_DIR "/" LAYOUT_HARDCODE_TMP ".sct"); fmcpy(&n_scantabs, drives, stf, 0, 4); scantabs = allocate_kernel_pages((sizeof(struct scantab_info) * n_scantabs - 1) / 4096 + 1); uint32_t fi = 0x10; void *st_data = allocate_kernel_pages((n_scantabs - 1) / 8 + 1); for (uint32_t n = 0; n < n_scantabs; ++n) { uint32_t data_sector; fmcpy(&data_sector, drives, stf, fi, 4); drives->load_sector(drives, stf, data_sector, st_data + 512 * n); scantabs[n].scantab = st_data + 512 * n; uint8_t pl; fmcpy(&pl, drives, stf, fi + 4, 1); scantabs[n].prefix_length = pl; fmcpy(scantabs[n].prefix, drives, stf, fi + 5, pl); fi += 5 + pl; if (fi & 0xf) fi = (fi & ~0xf) + 0x10; } drives->free_file(drives, stf); } static inline uint8_t get_next_code_byte() { for (uint32_t spin = 0; spin < 10000000; ++spin) ; return inb(PS2_DATA); } static enum key_modifiers_t keymods = 0; void on_kbd_isr() { //logf(LOG_INFO, "on_kbd_isr()"); while (inb(PS2_CMD) & PS2S_CODE_READY) { uint8_t code[256]; uint8_t code_i = 0; sub_table: code[code_i] = get_next_code_byte(); const uint8_t *table; for (uint32_t i = 0; i < n_scantabs; ++i) { if (scantabs[i].prefix_length != code_i) continue; for (uint8_t j = 0; j < code_i; ++j) if (scantabs[i].prefix[j] != code[j]) goto next_table; table = scantabs[i].scantab; goto got_table; next_table:; } PANIC("Couldn't find scantable"); got_table:; bool is_up = false; flipped_table:; uint8_t entry = table[code[code_i]]; switch (entry) { case ST_ILLEGAL: PANIC("Illegal scancode encountered"); case ST_SUBTABLE: ++code_i; goto sub_table; case ST_FLIP: if (is_up) PANIC("Recursive flip in scantable"); table += 0x100; is_up = true; goto flipped_table; case ST_SKIP: continue; } switch ((enum key_id_t)entry) { case KEY_LEFT_SHIFT: if (is_up) keymods &= ~LSHIFT; else keymods |= LSHIFT; break; case KEY_RIGHT_SHIFT: if (is_up) keymods &= ~RSHIFT; else keymods |= RSHIFT; break; case KEY_LEFT_CONTROL: if (is_up) keymods &= ~LCTRL; else keymods |= LCTRL; break; case KEY_RIGHT_CONTROL: if (is_up) keymods &= ~RCTRL; else keymods |= RCTRL; break; case KEY_LEFT_ALT: if (is_up) keymods &= ~LALT; else keymods |= LALT; break; case KEY_RIGHT_ALT: if (is_up) keymods &= ~RALT; else keymods |= RALT; break; case KEY_LEFT_WIN: if (is_up) keymods &= ~LWIN; else keymods |= LWIN; break; case KEY_RIGHT_WIN: if (is_up) keymods &= ~RWIN; else keymods |= RWIN; break; case KEY_CAPS_LOCK: if (!is_up) keymods ^= CAPS; break; case KEY_NUM_LOCK: if (!is_up) keymods ^= NUM; break; case KEY_SCROLL_LOCK: if (!is_up) keymods ^= SCROLL; break; case KEY_INSERT: if (!is_up) keymods ^= INSERT; break; default: break; } on_action((struct window_action){ .action_type = is_up ? KEY_UP : KEY_DOWN, .as_key = (struct key_packet){ .key_id = entry, .modifiers = keymods } }); } }