// keyboard.c // Author: Josh Holtrop // Created: 04/17/03 // Modified: 08/16/04 #include "hos_defines.h" #include "char/keyboard.h" #include "sys/io.h" #include "sys/pic.h" #include "functions.h" #include "kout.h" #define KBD_BUFFER_LENGTH 64 u8_t kbdFlags = 0; // holds current keyboard flags - caps/num/scroll/shift/ctrl/alt char lastWasE0 = 0; // was the last byte 0x0E ? u32_t 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 u8_t rawIgnore = 0; // how many signals to blatantly ignore u8_t 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 const u8_t SCAN2ASCII[129] = "\000\0331234567890-=\010\011" // null,esc,1234567890-=,bksp,tab "qwertyuiop[]\n\000as" // qwertyuiop[],enter,lctrl,as "dfghjkl;'`\000\\zxcv" // dfghjkl;'`,lshift,\zxcv "bnm,./\000*\000 \000\000\000\000\000\000" // bnm,./,rshift,*,alt,space,caps,f1,f2,f3,f4,f5 "\000\000\000\000\000\000\000\000\000\000-\000\000\000+\000" // f6,f7,f8,f9,f10,num,scrl,home,up,pgup,dash,left,center,right,plus,end "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // down,pgdn,ins,del,?,?,?,f11,f12,?,?,winL,winR,menu,?,? "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // ? "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; // ? const u8_t SCAN2ASCII2[129] = "\000\033!@#$%^&*()_+\010\011" "QWERTYUIOP{}\n\000AS" "DFGHJKL:\"~\000|ZXCV" "BNM<>?\000*\000 \000\000\000\000\000\000" "\000\000\000\000\000\000\000789-456+1" "230.\000\000\000\000\000\000\000\000\000\000\000\000" "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; //====FUNCTIONS: // The Keyboard Interrupt Service Routine void isr_keyboard() { kbdScan = inportb(0x60); kprintf("KEYBOARD INTERRUPT: 0x%x\n", kbdScan); u8_t inState = inportb(0x61); outportb(0x61, inState|0x80); outportb(0x61, inState); return; //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) // 0xE0 == extended key { kbdExt = 1; pic_eoi(); return; } if (kbdScan == 225) // 0xE1 == 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)) { kprintf("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] = (u32_t) ((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 u32_t kbdGetKey() { if (kbdBufferLen == 0) //buffer empty return 0; u32_t 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 u32_t kbdWaitKey() { for (;;) { if (kbdBufferLen != 0) //buffer empty break; } u32_t 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; }