keyboard.c (5090B)
1 /* 2 * core/keyboard.c 3 * 4 * Copyright (C) 2009 stateless 5 */ 6 7 #include <keyboard.h> 8 #include <x86.h> 9 #include <idt.h> 10 #include <common.h> 11 #include <kdb.h> 12 #include <tty.h> 13 14 enum { KBD_BUF_SIZE = 4096 }; 15 enum { CMD_PORT = 0x64, DATA_PORT = 0x60 /* to/from the kbd */, STATUS_PORT = 0x64 }; 16 17 /* special keys */ 18 enum { 19 LALT, RALT, 20 LCTRL, RCTRL, 21 LSHIFT, RSHIFT, 22 F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, 23 CAPSLK, NUMLK, SCRLK, SYSRQ, 24 ESC = 27, 25 INSERT, DEL, HOME, END, PGUP, PGDN, LEFT, RIGHT, UP, DOWN, 26 NUM_DOT, NUM_ENTER, NUM_PLUS, NUM_MINUS, NUM_MUL, NUM_DIV, 27 NUM_0, NUM_1, NUM_2, NUM_3, NUM_4, NUM_5, NUM_6, NUM_7, NUM_8, NUM_9, 28 BACKSP = 127 29 }; 30 31 int f_kdb = 0; 32 33 static uint8_t kbd_buffer[KBD_BUF_SIZE]; /* plain ascii 0 - 127 */ 34 static uint32_t head = 0, tail = 0; 35 static bool shift_st = 0; 36 37 static int keycodes_lower[] = { 38 0, ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', BACKSP, /* 0 - e */ 39 '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\r', /* f - 1c */ 40 LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', /* 1d - 29 */ 41 LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', RSHIFT, /* 2a - 36 */ 42 NUM_MUL, LALT, ' ', CAPSLK, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, /* 37 - 44 */ 43 NUMLK, SCRLK, NUM_7, NUM_8, NUM_9, NUM_MINUS, NUM_4, NUM_5, NUM_6, NUM_PLUS, /* 45 - 4e */ 44 NUM_1, NUM_2, NUM_3, NUM_0, NUM_DOT, SYSRQ, 0, 0, F11, F12, /* 4d - 58 */ 45 0, 0, 0, 0, 0, 0, 0, /* 59 - 5f */ 46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */ 47 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 70 - 7f */ 48 }; 49 50 static int keycodes_upper[] = { 51 0, ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', BACKSP, /* 0 - e */ 52 '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\r', /* f - 1c */ 53 LCTRL, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', /* 1d - 29 */ 54 LSHIFT, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', RSHIFT, /* 2a - 36 */ 55 NUM_MUL, LALT, ' ', CAPSLK, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, /* 37 - 44 */ 56 NUMLK, SCRLK, NUM_7, NUM_8, NUM_9, NUM_MINUS, NUM_4, NUM_5, NUM_6, NUM_PLUS, /* 45 - 4e */ 57 NUM_1, NUM_2, NUM_3, NUM_0, NUM_DOT, SYSRQ, 0, 0, F11, F12, /* 4d - 58 */ 58 0, 0, 0, 0, 0, 0, 0, /* 59 - 5f */ 59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */ 60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 70 - 7f */ 61 }; 62 63 static inline void 64 wait_cmd_buffer(void) 65 { 66 while (inb(STATUS_PORT) & 0x2) 67 ; 68 } 69 70 static inline void 71 wait_result_buffer(void) 72 { 73 while (!(inb(STATUS_PORT) & 0x1)) 74 ; 75 } 76 77 static inline void 78 send_kbd_cmd(uint8_t byte) 79 { 80 wait_cmd_buffer(); 81 outb(CMD_PORT, byte); 82 wait_cmd_buffer(); 83 } 84 85 static inline uint8_t 86 recv_kbd_res(void) 87 { 88 uint8_t byte; 89 wait_result_buffer(); 90 byte = inb(DATA_PORT); 91 return byte; 92 } 93 94 void 95 keyboard_callback(__attribute__ ((unused)) struct trapframe_t *regs) 96 { 97 wait_result_buffer(); 98 uint8_t scancode = inb(DATA_PORT); 99 100 if (!(scancode & 0x80)) { 101 if (tail != KBD_BUF_SIZE) { 102 if (scancode == 0x2a) 103 shift_st = 1; 104 if (scancode == 0x58) { 105 if (!f_kdb) { 106 f_kdb = 1; 107 set_trapframe(regs); 108 assert(!IS_ERR(create_kthread("kdb", kdb_enter))); 109 freeze_tasks(); 110 } 111 return; 112 } 113 if (!is_tty_attached()) return; 114 kbd_buffer[tail++] = (shift_st) ? keycodes_upper[scancode] 115 : keycodes_lower[scancode]; 116 if (scancode == 0x1c) kbd_buffer[tail - 1] = '\n'; 117 resume_task(tty_get_sleep_chan()); 118 } 119 } else if (scancode == 0xaa) 120 shift_st = 0; 121 } 122 123 int 124 kbd_getchar(void) 125 { 126 int ch; 127 uint32_t state; 128 129 save_flags(&state); 130 cli(); 131 if (head == tail) { 132 if (tail == KBD_BUF_SIZE) 133 head = tail = 0; 134 load_flags(state); 135 return -1; 136 } 137 ch = kbd_buffer[head]; 138 ++head; 139 load_flags(state); 140 return ch; 141 } 142 143 void 144 initialize_keyboard(void) 145 { 146 uint8_t byte; 147 148 /* disable keyboard */ 149 send_kbd_cmd(0xad); 150 151 /* perform a self-test */ 152 send_kbd_cmd(0xaa); 153 if (recv_kbd_res() != 0x55) 154 panic("keyboard self-test failed!"); 155 156 /* read the CCB */ 157 send_kbd_cmd(0x20); 158 byte = recv_kbd_res(); 159 160 /* if keyboard translation is not enabled, try to enable it */ 161 if (!(byte & (1 << 6))) { 162 info("translation is not enabled, attempting to enable it ...\n"); 163 byte |= (1 << 6); 164 send_kbd_cmd(0x60); 165 outb(DATA_PORT, byte); 166 wait_cmd_buffer(); 167 send_kbd_cmd(0x20); 168 if (!(recv_kbd_res() & (1 << 6))) { 169 printf("failed!\n"); 170 hlt(); 171 } 172 printf("OK!\n"); 173 } 174 175 /* check if we are in polling mode and if so enable interrupts on IRQ1 */ 176 if (!(byte & 0x1)) { 177 byte |= 0x1; 178 send_kbd_cmd(0x60); 179 outb(DATA_PORT, byte); 180 wait_cmd_buffer(); 181 } 182 183 /* enable keyboard */ 184 send_kbd_cmd(0xae); 185 register_isr_handler(33, keyboard_callback); 186 } 187