// keyboard.c // Author: Josh Holtrop // Created: 04/17/03 // Modified: 03/02/04 #include "hos_defines.h" #include "keyboard.h" #include "sys/io.h" #include "sys/pic.h" #include "functions.h" #include "kio.h" #define KBD_BUFFER_LENGTH 64 byte kbdFlags = 0; //holds current keyboard flags - caps/num/scroll/shift/ctrl/alt byte kbdAscii = 0; //holds ASCII value of a key pressed byte kbdScan = 0; //holds the keyboard scan code of a key pressed dword kbdBuffer[KBD_BUFFER_LENGTH]; //a buffer for all keypresses int kbdBufferStart = 0; //position of next key in buffer int kbdBufferLen = 0; //number of keys left in the buffer byte kbdExt = 0; //# of extended key codes left to input byte kbdExt2 = 0; //# of 2nd-set-extended key codes left to input byte ackReason = 0; //used to record the reason why we would get an acknowledge byte (0xFA) //these arrays convert a keyboard scan code to an ASCII character value //nul esc bksp tab lctl lsft rsft lalt caps F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 numScrlNumPad------- unknown---- F11 F12 unknown.... const byte SCAN2ASCII[128] = "\000\0331234567890-=\010\011qwertyuiop[]\n\001asdfghjkl;'`\001\\zxcvbnm,./\001*\001 \001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001-\001\001\001+\001\001\001\001\001\002\002\002\001\001\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002"; const byte SCAN2ASCIISHIFT[128] = "\000\033!@#$%^&*()_+\010\011QWERTYUIOP{}\n\001ASDFGHJKL:\"~\001|ZXCVBNM<>?\001*\001 \001\001\001\001\001\001\001\001\001\001\001\001\001789-456+1230.\002\002\002\001\001\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002"; //====FUNCTIONS: // The Keyboard Interrupt Service Routine void isr_keyboard() { kbdScan = inportb(0x60); //printf("\nKEYBOARD INTERRUPT: 0x%x", kbdScan); byte inState = inportb(0x61); outportb(0x61, inState|0x80); outportb(0x61, inState); //printf("IRQ 1: %x\n", kbdScan); if (kbdScan == 0xFA) //250 //ACKnowledge { //printf("KBD_ACK 0x%x!\n", ackReason); if (ackReason == 0xED) //reset LEDs { outportb(0x60, (kbdFlags & 0x07)); } ackReason = 0; } if (kbdScan == 224) //extended key { kbdExt = 1; pic_eoi(); return; } if (kbdScan == 225) //2nd-set-extended key { kbdExt2 = 2; pic_eoi(); return; } //====handle control keys:: kbdAscii = 2; switch (kbdScan) //control keys { case KBD_SCAN_LSHIFT: kbdFlags |= KBD_SHIFT; kbdAscii = 1; break; case KBD_SCAN_RSHIFT: kbdFlags |= KBD_SHIFT; kbdAscii = 1; break; case KBD_SCAN_LCTRL: kbdFlags |= KBD_CTRL; kbdAscii = 1; break; case KBD_SCAN_LALT: kbdFlags |= KBD_ALT; kbdAscii = 1; break; case KBD_SCAN_LSHIFT + KBD_SCAN_RELEASED: kbdFlags &= (KBD_SHIFT ^ 0xFF); kbdAscii = 1; break; case KBD_SCAN_RSHIFT + KBD_SCAN_RELEASED: kbdFlags &= (KBD_SHIFT ^ 0xFF); kbdAscii = 1; break; case KBD_SCAN_LCTRL + KBD_SCAN_RELEASED: kbdFlags &= (KBD_CTRL ^ 0xFF); kbdAscii = 1; break; case KBD_SCAN_LALT + KBD_SCAN_RELEASED: kbdFlags &= (KBD_ALT ^ 0xFF); kbdAscii = 1; break; case KBD_SCAN_CAPS+KBD_SCAN_RELEASED: kbdFlags ^= KBD_CAPS; kbdAscii = 1; kbd_resetLEDs(); //update LEDs break; case KBD_SCAN_SCROLL+KBD_SCAN_RELEASED: kbdFlags ^= KBD_SCROLL; kbdAscii = 1; kbd_resetLEDs(); //update LEDs break; case KBD_SCAN_NUM+KBD_SCAN_RELEASED: kbdFlags ^= KBD_NUM; kbdAscii = 1; kbd_resetLEDs(); //update LEDs break; } if (kbdAscii == 1) { if (kbdExt > 0) kbdExt--; pic_eoi(); return; } //====determine ASCII value of key:: if (kbdExt > 0) //extended key, kbdScan holds extended key { kbdExt--; kbdAscii = 1; switch (kbdScan) { case KBD_SCANE_ENTER: kbdAscii = '\n'; break; case 53: // '/' character (divide on numpad) kbdAscii = '/'; break; } } else if (kbdExt2 > 0) //extended key 2 { kbdExt2--; // if (kbdScan == 69) // (pause|break) // kbdAscii = 2; //flag ascii value of 1 means control character (pausebreak) // else kbdAscii = 2; //flag ascii value of 2 means ignore key (or unknown value) } else //not an extended key { // if letter key if (((kbdScan >= 16) && (kbdScan <= 25)) || ((kbdScan >= 30) && (kbdScan <= 38)) || ((kbdScan >= 44) && (kbdScan <= 50))) { // if caps and shift are different (either one pressed, not both) if (((kbdFlags & KBD_SHIFT) != 0) & ((kbdFlags & KBD_CAPS) != 0)) kbdAscii = SCAN2ASCII[kbdScan & 0x7F]; else if (((kbdFlags & KBD_SHIFT) == 0) & ((kbdFlags & KBD_CAPS) == 0)) kbdAscii = SCAN2ASCII[kbdScan & 0x7F]; else kbdAscii = SCAN2ASCIISHIFT[kbdScan & 0x7F]; } // if numpad key else if ((kbdScan >= 71) && (kbdScan <= 83)) { // if numlock on if (kbdFlags & KBD_NUM) kbdAscii = SCAN2ASCIISHIFT[kbdScan & 0x7F]; else kbdAscii = SCAN2ASCII[kbdScan & 0x7F]; } // other key else { if ((kbdFlags & KBD_SHIFT) != 0) kbdAscii = SCAN2ASCIISHIFT[kbdScan & 0x7F]; else kbdAscii = SCAN2ASCII[kbdScan & 0x7F]; } } //====do something with key:: // printf("kbdScan == %d\nkbdAscii == %d\nkbdFlags == %d\n", kbdScan, kbdAscii, kbdFlags); if ((kbdScan == 83) && (kbdFlags & KBD_CTRL) && (kbdFlags & KBD_ALT)) { printf("Initiating reboot."); restart(); } if (kbdAscii == 2) //unknown key / ignore key { pic_eoi(); return; } if (kbdScan < KBD_SCAN_RELEASED) //a key was pressed, save it { if (kbdBufferLen >= KBD_BUFFER_LENGTH) //no key slots available { pic_eoi(); return; } else { kbdBuffer[(kbdBufferStart+kbdBufferLen++)%KBD_BUFFER_LENGTH] = (dword) ((kbdFlags << 16) | (kbdScan << 8) | kbdAscii); // printf("S:%d\tL:%d\tR:%x\n", kbdBufferStart, kbdBufferLen, kbdBuffer[kbdBufferStart]); } } pic_eoi(); } //Gets a key from the buffer, returns 0 if no keys available, returns immediately dword kbdGetKey() { if (kbdBufferLen == 0) //buffer empty return 0; dword retVal = kbdBuffer[kbdBufferStart]; kbdBufferStart++; kbdBufferLen--; if (kbdBufferStart >= KBD_BUFFER_LENGTH) kbdBufferStart = 0; return retVal; } //Gets a key from the buffer, if no keys available, waits for one to be entered dword kbdWaitKey() { for (;;) { if (kbdBufferLen != 0) //buffer empty break; } dword retVal = kbdBuffer[kbdBufferStart]; kbdBufferStart++; kbdBufferLen--; if (kbdBufferStart >= KBD_BUFFER_LENGTH) kbdBufferStart = 0; return retVal; } //Resets the keyboard LEDs to reflect the current state of the num lock, caps lock, and scroll lock bits void kbd_resetLEDs() { outportb(0x60, 0xED); ackReason = 0xED; }