/** * keyboard.c * * Main keyboard handling routines. * * Exports: * keyboard_irq(); * init_keyboard(); * * Imports: * video.c console_t _vc[]; * video.c select_vc(); * video.c putch(); * main.c printf(); * main.c printk(); */ //#include <conio.h> /* key scancode definitions */ #include <keyboard.h> #include <x86.h> /* outportb, inportb(), etc */ #include <string.h> #include <esh/esh.h> /* shell commands */ #include "_krnl.h" /* MAX_VC */ #include "bootlog.h" /* klog() */ #define KBD_BUF_SIZE 64 /** * Imports */ extern console_t _vc[]; void select_vc(unsigned which_vc); void putch(unsigned c); void printf(const char *fmt, ...); void printk(int type, const char *fmt, ...); void dumpheapk(void); void testheap(void); unsigned get_current_vc(); static int rawkey, keys[128]; static int numkeysbuffer; static char szInBuf[KBD_BUF_SIZE]; /** * 0 if not set * 1 if make code * 2 if break code */ static int makebreak; /** * reboot() * */ static void reboot(void) { unsigned temp; disable(); /** * flush the keyboard controller */ do { temp = inportb(0x64); if((temp & 0x01) != 0) { (void)inportb(0x60); continue; } } while((temp & 0x02) != 0); /** * now pulse the cpu reset line */ outportb(0x64, 0xFE); /** * if that didn't work, just halt */ while(1); } /** * XXX * * I'm not even sure if we need the following functions yet, * however they are here just in case. Leave them alone. */ /** * _write_kb() * */ static void _write_kb(unsigned adr, unsigned d) { unsigned long t; unsigned s; for(t = 5000000L; t != 0; t--) { s = inportb(0x64); /** * loop until 8042 input buffer is empty */ if((s & 0x02) == 0) break; } if(t != 0) outportb(adr, d); } /** * _kb_wait() * */ static inline void _kb_wait(void) { int i; for(i = 0; i < 0x1000000; i++) if((inportb(0x64) & 0x02) == 0) return; printk(0, "Keyboard timeout\n"); } /** * _kb_send() * */ static inline void _kb_send(unsigned char c) { _kb_wait(); outportb(c, 0x64); } /** * _translate_sc() * * Translates a scancode from the keyboard */ unsigned _translate_sc(unsigned k) { unsigned c; static unsigned altk; unsigned donefirst = 0; if(k == KEY_BKSPACE) { if(numkeysbuffer - 1 < 0) { numkeysbuffer = 0; return 0; } } switch(k) { case 0xE0: altk = 1; c = 0; donefirst = 1; break; case KEY_TILDA: /* ` or ~ */ c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 126 : 126; break; case KEY_END: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 49; break; case KEY_1: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 33 : 49; break; case KEY_DOWN: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 50; break; case KEY_2: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 64 : 50; break; case KEY_PGDOWN: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 51; break; case KEY_3: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 35 : 51; break; case KEY_LEFT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 52; break; case KEY_4: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 36 : 52; break; case KEYP_5: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 53; break; case KEY_5: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 35 : 53; break; case KEY_RIGHT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 54; break; case KEY_6: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 94 : 54; break; case KEY_HOME: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 55; break; case KEY_7: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 38 : 55; break; case KEY_UP: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 56; break; case KEYP_ASTERISK: c = 42; break; case KEY_8: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 42 : 56; break; case KEY_PGUP: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 57; break; case KEY_9: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 40 : 57; break; case KEY_INSERT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 48; break; case KEY_0: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 41 : 48; break; case KEYP_MINUS: c = 45; break; case KEY_MINUS: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 95 : 45; break; case KEYP_PLUS: c = 43; break; case KEY_PLUS: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 61 : 43; break; case KEY_BKSLASH: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 124 : 92; break; case KEY_Q: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 81 : 113; break; case KEY_W: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 87 : 119; break; case KEY_E: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 69 : 101; break; case KEY_R: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 82 : 114; break; case KEY_T: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 84 : 116; break; case KEY_Y: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 89 : 121; break; case KEY_U: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 85 : 117; break; case KEY_I: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 73 : 105; break; case KEY_O: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 79 : 111; break; case KEY_P: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 80 : 112; break; case KEY_LBRACKET: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 123 : 91; break; case KEY_RBRACKET: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 125 : 93; break; case KEY_ENTER: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 10 : 10; break; case KEY_A: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 65 : 97; break; case KEY_S: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 83 : 115; break; case KEY_D: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 68 : 100; break; case KEY_F: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 70 : 102; break; case KEY_G: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 71 : 103; break; case KEY_H: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 72 : 104; break; case KEY_J: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 74 : 106; break; case KEY_K: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 75 : 107; break; case KEY_L: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 76 : 108; break; case KEY_SEMICOLON: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 58 : 59; break; case KEY_QUOTE: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 34 : 39; break; case KEY_Z: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 90 : 122; break; case KEY_X: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 88 : 120; break; case KEY_C: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 67 : 99; break; case KEY_V: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 86 : 118; break; case KEY_B: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 66 : 98; break; case KEY_N: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 78 : 110; break; case KEY_M: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 77 : 109; break; case KEY_COMMA: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 60 : 44; break; case KEY_DEL: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 46; break; case KEY_PERIOD: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 62 : 46; break; case KEY_SLASH: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 63 : 47; break; case KEY_SPACE: c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 32 : 32; break; case KEY_BKSPACE: c = '\b'; break; /* just for now */ default: c = 0; } if(donefirst == 0) altk = 0; if(keys[KEY_CAPS]) { if(keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) { if(c >= 'A' && c <= 'Z') c += 32; } else { if(c >= 'a' && c <= 'z') c -= 32; } } /** * Simple shell for now */ if(c != 0 && c != '\n' && c != '\b') { if((numkeysbuffer - 1) == KBD_BUF_SIZE) { numkeysbuffer = 0; szInBuf[0] = '\0'; szInBuf[numkeysbuffer] = c; numkeysbuffer++; } else { szInBuf[numkeysbuffer] = c; numkeysbuffer++; } } else if(c == '\n') { printf("\n"); /** * Make it a real string */ szInBuf[numkeysbuffer] = '\0'; /** * Process command */ processCommand(&szInBuf[0], numkeysbuffer - 1); /** * Clear buffer */ numkeysbuffer = 0; szInBuf[0] = '\0'; /** * Print "line" */ printf("$ "); c = 0; } else if(c == '\b') { szInBuf[numkeysbuffer] = '\0'; numkeysbuffer--; printf("\b \b"); c = 0; } return c; } /** * handle_meta_key() * * I'll pretty this up later */ void handle_meta_key(unsigned k) { int i; k = k; /* to shut gcc up */ /** * Check for the infamous three finger salute */ if((keys[KEY_RCTRL] || keys[KEY_LCTRL]) && (keys[KEY_RALT] || keys[KEY_LALT]) && keys[KEY_DEL]) { /** * FIXME * * This should call _send_signal() */ reboot(); } /** * Check for Alt + F1-F12 for virtual terminals */ for(i = 0; i < 10; i++) { if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[i + KEY_F1]) { select_vc(i); return; } } if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[KEY_F11]) { select_vc(10); return; } if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[KEY_F12]) { select_vc(11); return; } } /** * keyboard_irq() * * Called when a keyboard interrupt is generated. */ void keyboard_irq(void) { register char a; unsigned c; unsigned short kbdstat; rawkey = inportb(0x60); outportb(0x61, (a=inportb(0x61)|0x82)); outportb(0x61, a & 0x7F); /** * If it's less than 0x80 then it's definatelly * a make code or a repeat code */ if(rawkey < 0x80) { /** * We don't want to gunk up the numlock key * because we will define it's state in the * break code a bit later */ if((rawkey != KEYP_NUMLCK) && (rawkey != KEY_SCRLCK) && (rawkey != KEY_CAPS)) keys[rawkey] = 1; keyDown(rawkey); } else /* rawkey >= 0x80 */ { if(rawkey == 0xE0) { /** * It's either a make code, break code, or repeat code */ rawkey = inportb(0x60); outportb(0x61, (a=inportb(0x61)|0x82)); outportb(0x61, a & 0x7F); if(rawkey < 0x80) { /** * Ok, it's a make code or repeat code for the numeric * keypad (gray keys) */ keys[rawkey] = 1; keyDown(rawkey); } else /* rawkey >= 0x80 */ { /** * It's either a make code for the numeric keypad or * a break code for the numeric keypad. */ if(rawkey == 0x2A) { /** * Ok, we have a make code for the numeric keypad * and NUMLOCK is on. The second byte is what we * want since what we have so far is this: * * 0xE0 0x2A */ rawkey = inportb(0x60); outportb(0x61, (a=inportb(0x61)|0x82)); outportb(0x61, a & 0x7F); rawkey = inportb(0x60); outportb(0x61, (a=inportb(0x61)|0x82)); outportb(0x61, a & 0x7F); keys[rawkey] = 1; keyDown(rawkey); } else { /** * It's a break code from the numeric keypad. */ keys[rawkey] = 0; keyUp(rawkey); } } } else /* rawkey != 0xE0 */ { /** * It's a break code * * Make sure we toggle the numlock, scroll lock, and caps lock key. */ if(((rawkey - 0x80) == KEYP_NUMLCK) || ((rawkey - 0x80) == KEY_SCRLCK) || ((rawkey - 0x80) == KEY_CAPS)) { keys[rawkey - 0x80] = !keys[rawkey - 0x80]; kbdstat = 0; if(keys[KEY_SCRLCK]) kbdstat |= 1; if(keys[KEYP_NUMLCK]) kbdstat |= 2; if(keys[KEY_CAPS]) kbdstat |= 4; _write_kb(0x60, 0xED); _write_kb(0x60, kbdstat); outportb(0x20, 0x20); keyUp(rawkey); return; } keys[rawkey - 0x80] = 0; keyUp(rawkey); } } c = _translate_sc(rawkey); if(c != 0) printf("%c", c); else { /** * We need to check for meta-key-crap here */ handle_meta_key(rawkey); } //enable(); outportb(0x20, 0x20); } /** * init_keyboard() * */ void init_keyboard(void) { static unsigned char buffers[KBD_BUF_SIZE * MAX_VC]; int i; //klog("init", "keyboard %2u buf, %2ub each", K_KLOG_PENDING, &_vc[0]); for(i = 0; i < MAX_VC; i++) { _vc[i].keystrokes.data = buffers + KBD_BUF_SIZE * i; _vc[i].keystrokes.size = KBD_BUF_SIZE; } for(i = 0; i < 128; i++) keys[i] = 0; makebreak = 0; //klog(NULL, K_KLOG_SUCCESS, &_vc[0], NULL); //kprintf("init_kbd: %u buffers, %u bytes each\n", // MAX_VC, KBD_BUF_SIZE); //kprintf("[ Entering Runlevel 0 ].......................................................Ok"); _vc[0].attrib = 8; printf("[ "); _vc[0].attrib = 15; printf("init: keyboard %2u buf, %2ub each ", MAX_VC, KBD_BUF_SIZE); _vc[0].attrib = 8; printf("]..........................................."); _vc[0].attrib = 2; printf("Ok"); _vc[0].attrib = 7; }