/* Keyboard.c, Copyright (c) by Lukas Ruf, lr@lpr.ch, Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. TOPSY -- A Teachable Operating System. Implementation of a tiny and simple micro kernel for teaching purposes. For further information, please visit http://www.tik.ee.ethz.ch/~topsy This software is provided under the terms of the GNU General Public Licence. A full copy of the GNU GPL is provided in the file COPYING found in the development root of Topsy. */ /* File: $Source: /usr/drwho/vault/cvs/topsy/Topsy/IO/Drivers/ia32/Keyboard.c,v $ Author(s): Lukas Ruf, lr@lpr.ch Affiliation: ETH Zuerich, TIK Version: $Revision: 1.2 $ Creation Date: Last Date of Change: $Date: 1999/12/13 21:48:27 $ by: $Author: ruf $ $Log: Keyboard.c,v $ Revision 1.2 1999/12/13 21:48:27 ruf GNU General Public Licence Update Revision 1.1 1999/06/06 20:58:20 jeker putting everything together for Topsy 2.0 Revision 1.1 1999/05/13 17:05:29 jeker Initial revision */ #include "keyboard.h" #include "SupportAsm.h" #include "Video.h" #include "Topsy.h" #include "TMHalAsm.h" #include "video.h" #define KEYECHO TRUE #define KEYDEBUG FALSE #define KEYGETDEBUG FALSE /* Translate Break-Key PrtScr to unqiue "Hardware Make/Break Code" according coding scheme of my keyboard handling. See MakeKey.TBL, resp. Documentation to Keyboard-Handling These codes are not used in the standard MF-II 102-Keyboard */ /* selfmade MAKE CODEs */ #define kBREAK_MAKE_CODE 90 #define kPRTSCR_MAKE_CODE 91 #define kENTER_MAKE_CODE 92 #define kHOME_MAKE_CODE 94 #define kUP_MAKE_CODE 95 #define kPGUP_MAKE_CODE 98 #define kLEFT_MAKE_CODE 99 #define kRIGHT_MAKE_CODE 100 #define kEND_MAKE_CODE 101 #define kDOWN_MAKE_CODE 102 #define kPGDN_MAKE_CODE 103 #define kINSERT_MAKE_CODE 104 #define kDELETE_MAKE_CODE 105 /* MAKE CODES specially handled */ #define KEYCTRL 29 #define KEYLEFTSHIFT 42 #define KEYRIGHTSHIFT 54 #define KEYALT 56 #define KEYCAPSLOCK 58 #define KEYNUMLOCK 69 #define KEYSCROLLLOCK 70 #define KEYALTSYSRQ 84 #define KEYEXT2SIGN 0xE1 #define KEYEXTSIGN 0xE0 #define KBBSIZE 0x80 /* module global variables */ static unsigned char kLEDSetting = 0x00; static unsigned char KBB[KBBSIZE]; static unsigned int KBBHead; static unsigned int KBBTail; /* This variable performs the mutex :-) */ static unsigned int KeyBoardLock; #define HEADLOCK 0 /* set bit 0 */ #define TAILLOCK 1 /* set bit 1 */ #define K_SCLLOCK 1 /* SCROLL LOCK - LED */ #define K_NUMLOCK 2 /* NUM LOCK - LED */ #define K_CPSLOCK 4 /* CAPS LOCK - LED */ static unsigned char *K_LHWMap; /* Scan Code to Logical HW Key Code Map (7b -> 7b) */ static unsigned char *K_LKCMap; /* Logical HW Key Code to ASCII Map (10b -> 8b) */ static unsigned short *K_LMSMap; /* Key Message Map (10b -> 16b) */ /* Keyboard-Variables: */ static char KeyExt2Cnt; /* Counter for two extended bytes */ static Boolean KeyExt2Set; /* 0xE1 */ static Boolean KeyExtSet; /* 0xE0 */ static Boolean KeyAltDown; static Boolean KeyCtrlDown; static Boolean KeyShiftDown; static Boolean KeyCapsSet; static Boolean KeyNumLockSet; static Boolean KeyScrollSet; Boolean _IsKeypressed() { return KBBHead > KBBTail; } Boolean _GetChar(char *pCharToGet) { Boolean xret = FALSE; *pCharToGet = 0; if (_IsKeypressed()) { __mutex(&KeyBoardLock,TAILLOCK); *pCharToGet = (char)KBB[KBBTail % KBBSIZE]; KBBTail++; __demutex(&KeyBoardLock,TAILLOCK); if (KEYGETDEBUG) kprintc(*pCharToGet); xret = TRUE; } return xret; } static void SetKeyLED(Boolean pSet, unsigned char pPos) { if (pSet) kLEDSetting |= pPos; else kLEDSetting &= !pPos; kLEDSetting &= 7; /* make sure only lower 3 bits are set */ __outb(0xED,0x60); while (__inb(0x64) & 0x02) ; /* wait until CPU->Keyboard Buffer empty */ __outb(kLEDSetting,0x60); return; } /*********************/ /* KEYBOARD HANDLERS */ /*********************/ static void KeyInit() { /* Initialize Keyboard Variables */ KeyExt2Set = FALSE; /* ATTENTION Byte Marker (PrtScr) */ KeyExtSet = FALSE; KeyAltDown = FALSE; /* ALT Key is not pressed */ KeyCtrlDown = FALSE; /* CTRL */ KeyShiftDown = FALSE; /* SHIFT */ KeyCapsSet = FALSE; /* CAPS LOCK is not set */ KeyNumLockSet = FALSE; /* NUM LOCK */ KeyScrollSet = FALSE; /* SCROLL LOCK */ K_LHWMap = __addrHWKeyTrl(); /* Assign Address via function, as direct */ K_LKCMap = __addrKeyAscTrl(); /* assignment has not worked properly ??? */ K_LMSMap = __addrKeyMsgTrl(); KBBHead = 0; KBBTail = 0; KeyBoardLock = 0; return; } void KeyboardInit() { KeyInit(); __enable_IRQ(0x21); __endOf_IRQ(0x21); return; } unsigned long KeyModifier(unsigned char pRawKey) { Boolean xbreak, xerr; unsigned long xret = 1; if (KEYDEBUG) Debug("KeyModifier called: 0x%x (%i) -- ",pRawKey,(int)pRawKey); if (KeyAltDown && KeyCtrlDown && (pRawKey == 0x53)) /* Alt-Ctrl-Delete */ __reboot(); if (pRawKey == 0xFA) { /* if (KEYDEBUG) Debug("(=ACK)\n"); */ return 0x00; } if (KeyExt2Set) { /* 1st byte after 0xE1 */ /* Break was pressed -> 0xE1 0x1D 0x45 */ /* or released -> 0xE1 0x9D 0xC5 */ xerr = FALSE; switch (pRawKey & 0x7F) { case 0x1D : KeyExt2Cnt = 1; break; case 0x45 : KeyExt2Cnt = 2; break; default : xerr = TRUE; } if (KEYDEBUG) Debug(" \"Break\" "); KeyExt2Set = (KeyExt2Cnt < 2); if (KeyExt2Set) xret = 0; /* disable key output until all bytes passed */ else pRawKey = kBREAK_MAKE_CODE | (pRawKey & 0x80); if (xerr) { printf(" Warning !!! Unknown Raw Key Code 0x%x\n",(int)pRawKey); xret = 0; } } else if (KeyExtSet) { /* byte after 0xE0 */ /* PrtScr Press: -> 0xE0 0x2A 0xE0 0x37 --> Repeated only "0xE0 0x37" */ /* Release: -> 0xE0 0xB7 0xE0 0xAA */ /* Ctrl-PrtScr : -> 0xE0 0x37 */ /* Release: -> 0xE0 0xB7 */ if ((pRawKey & 0x7F) == 0x2A) /* discard envelopping 0xE0 0x2A resp. 0xAA */ xret = 0; else /* translate extended keycodes to unique Topsy HW KeyCode !! */ switch (pRawKey & 0x7F) { case 0x28 : /* NumPad Enter */ pRawKey = kENTER_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"NumPad Enter\" "); break; case 0x37 : /* PrtScr */ pRawKey = kPRTSCR_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"PrtScr\" "); break; case 0x46 : /* Break (resp. Ctrl-Break) */ pRawKey = kBREAK_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"Break\" "); break; case 0x47 : /* Middle Home */ pRawKey = kHOME_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"Home\" "); break; case 0x48 : /* Middle Up */ pRawKey = kUP_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"Up\" "); break; case 0x49 : /* Middle PgUp */ pRawKey = kPGUP_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"PgUp\" "); break; case 0x4B : /* Middle Left */ pRawKey = kLEFT_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"Left\" "); break; case 0x4D : /* Middle Right */ pRawKey = kRIGHT_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"Right\" "); break; case 0x4F : /* Middle End */ pRawKey = kEND_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"End\" "); break; case 0x50 : /* Middle Down */ pRawKey = kDOWN_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"Down\" "); break; case 0x51 : /* Middle PgDn */ pRawKey = kPGDN_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"PgDn\" "); break; case 0x52 : /* Middle Insert */ pRawKey = kINSERT_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"Insert\" "); break; case 0x53 : /* Middle Delete */ pRawKey = kDELETE_MAKE_CODE | (pRawKey & 0x80); if (KEYDEBUG) Debug(" \"Delete\" "); break; } KeyExtSet = FALSE; } if (xret && !KeyExt2Set) { KeyExtSet = (pRawKey == 0xE0); KeyExt2Set= (pRawKey == 0xE1); xbreak = ((pRawKey & 0x80) == 0x80); /* is it break code */ xret = 0; if (!KeyExtSet && !KeyExt2Set) if (xbreak) switch (pRawKey & 0x7F) { case KEYALT : /* left or right ALT Key */ KeyAltDown = FALSE; /* Toggle Flag */ if (KEYDEBUG) Debug(" KeyALT released "); break; case KEYCTRL: /* left or right CTRL Key */ KeyCtrlDown = FALSE; /* Toggle Flag */ if (KEYDEBUG) Debug(" KeyCTRL released "); break; case KEYRIGHTSHIFT : /* right SHIFT Key */ KeyShiftDown = FALSE; /* Toggle Flag */ if (KEYDEBUG) Debug(" KeyRIGHTSHIFT released "); break; case KEYLEFTSHIFT : /* left SHIFT Key */ KeyShiftDown = FALSE; /* Toggle Flag */ if (KEYDEBUG) Debug(" KeyLEFTSHIFT released "); break; } else switch (pRawKey) { case KEYALT : /* left or right ALT Key */ KeyAltDown = TRUE; /* Toggle Flag */ if (KEYDEBUG) Debug(" KeyALT pressed "); break; case KEYCTRL: /* left or right CTRL Key */ KeyCtrlDown = TRUE; /* Toggle Flag */ if (KEYDEBUG) Debug(" KeyCTRL pressed "); break; case KEYRIGHTSHIFT : /* right SHIFT Key */ KeyShiftDown = TRUE; /* Toggle Flag */ if (KEYDEBUG) Debug(" KeyRIGHTSHIFT pressed "); break; case KEYLEFTSHIFT : /* left SHIFT Key */ KeyShiftDown = TRUE; /* Toggle Flag */ if (KEYDEBUG) Debug(" KeyLEFTSHIFT pressed "); break; case KEYCAPSLOCK : KeyCapsSet = (KeyCapsSet) ? FALSE : TRUE; SetKeyLED(KeyCapsSet,K_CPSLOCK); if (KEYDEBUG) Debug(" CapsLock Toggled "); break; case KEYNUMLOCK : /* NumLock */ KeyNumLockSet = (KeyNumLockSet) ? FALSE : TRUE; SetKeyLED(KeyNumLockSet,K_NUMLOCK); if (KEYDEBUG) Debug(" NumLock Toggled "); break; case KEYSCROLLLOCK : /* Scroll Lock Key */ KeyScrollSet = (KeyScrollSet) ? FALSE : TRUE; SetKeyLED(KeyScrollSet,K_SCLLOCK); if (KEYDEBUG) Debug(" Scroll Lock toggled "); break; case KEYALTSYSRQ : /* Alt-PrtScr == Alt-SysRq */ xret = kPRTSCR_MAKE_CODE; if (KEYDEBUG) Debug(" \"Alt-PrtScr\" "); break; case kBREAK_MAKE_CODE : case kPRTSCR_MAKE_CODE : case kENTER_MAKE_CODE : case kHOME_MAKE_CODE : case kUP_MAKE_CODE : case kPGUP_MAKE_CODE : case kLEFT_MAKE_CODE : case kRIGHT_MAKE_CODE : case kEND_MAKE_CODE : case kDOWN_MAKE_CODE : case kPGDN_MAKE_CODE : case kINSERT_MAKE_CODE : case kDELETE_MAKE_CODE : xret = (pRawKey & 0x7F); if (KEYDEBUG) Debug(" \"Selfmade\" MAKE CODE processed "); break; default : xret = 1; } else KeyExt2Cnt = 0; } if (KEYDEBUG) Debug(" --> xret = 0x%x\n",(int)xret); __printchar((24*80+79-6)*2,0x1E,KeyAltDown ? 'A' : ' '); /* ALT */ __printchar((24*80+79-5)*2,0x1E,KeyCtrlDown ? 'C' : ' '); /* CTRL */ __printchar((24*80+79-4)*2,0x1E,KeyShiftDown ? 'S' : ' '); /* SHIFT */ __printchar((24*80+79-3)*2,0x1E,KeyCapsSet ? 'L' : ' '); /* Caps Lock */ __printchar((24*80+79-2)*2,0x1E,KeyScrollSet ? 'R' : ' '); /* Scroll Lock */ __printchar((24*80+79-1)*2,0x1E,KeyNumLockSet ? 'N' : ' '); /* Num Lock */ return xret; } static void KeyIntoBuffer(unsigned char pASCII) { if (KEYDEBUG) Debug("KeyIntoBuffer: %c\n",(char)pASCII); __mutex(&KeyBoardLock,HEADLOCK); if (KEYECHO) { if (pASCII==13) kprintc(10); else kprintc(pASCII); } KBB[KBBHead % KBBSIZE] = pASCII; KBBHead++; __demutex(&KeyBoardLock,HEADLOCK); return; } /* return from SCANCODE an "eineindeutig", continously ranged 7b-Keycode */ /* -> so called Logical HW Key (=7b) */ static unsigned char KeyMappedCode(unsigned long pSCANCODE) { unsigned char xc; if (KEYDEBUG) Debug("-> KeyMappedCode: %i -- ",pSCANCODE); xc = K_LHWMap[pSCANCODE & 0x7F]; if (KEYDEBUG) Debug("<- KeyMappedCode: %i \n",(int)xc); return xc; } /* Translate Logical HW Key into KEYCODE depending on Modifier state */ /* -> so called Key Code (=10b) */ static unsigned short KeyGetCode(unsigned char pLHWKey) { unsigned short xret = 0; Boolean oldState = KeyShiftDown; if (KeyCapsSet && (pLHWKey >= 61) && (pLHWKey <= 86)) KeyShiftDown = TRUE; xret = pLHWKey + (unsigned short)KeyAltDown*0x200 + (unsigned short)KeyCtrlDown*0x100 + (unsigned short)KeyShiftDown*0x80; KeyShiftDown = oldState; return xret; } static unsigned char KeyASCIICode(unsigned short pKeyCode) { unsigned char xc; if (KEYDEBUG) Debug("-> KeyASCIICode: %i -- ",(int)pKeyCode); xc = K_LKCMap[pKeyCode & 0x3FF]; if (KEYDEBUG) Debug("<- KeyASCIICode: %i \n",(int)xc); return xc; } static void KeyMsgSender(unsigned short pKeyMsg) { /* Send Message K_LMSMap[pKeyMsg & 0x3FF];*/ return; } void _KeyboardISR() { unsigned long lksl, lkmr; unsigned short lkoc; unsigned char lksb; lksb = __inb(0x60); /* read Keyboard; */ lksl = lksb; /* convert to long */ lkmr = KeyModifier(lksb); /* handle key struck */ if (lkmr != 0) { /* if "normal" key was pressed */ if (lkmr != 1) lksl = lkmr; /* if "selfmade" SCAN CODE */ lksb = KeyMappedCode(lksl); /* get code mapped to continous ranges (1st translation) ( -> unequivocal code (7b)) */ if (lksb < 0x80) { lkoc = KeyGetCode(lksb); /* get one of 1024 Topsy Key Codes (2nd translation, considers modifiers) (7b -> 10b) */ lksb = KeyASCIICode(lkoc); /* translate Topsy Key Code to ASCII (10b -> 8b) */ if ((lksb > 0x00) && (lksb < 0xFF)) /* 0x00 = abort, 0xFF = send associated message */ KeyIntoBuffer(lksb); /* insert ascii code into keyboard buffer */ else KeyMsgSender(lkoc); /* or send an associated message to running process */ } } return ; } /**********************************************************/ /* END OF KEYBOARD HANDLING */ /**********************************************************/