+; MMURTL Operating System Source Code\r
+; Copyright 1991,1992,1993,1994,1995 Richard A. Burgess\r
+; ALL RIGHTS RESERVED\r
+; Version 1.0\r
+;\r
+.DATA ;Begin Keyboard Data\r
+.INCLUDE MOSEDF.INC\r
+.INCLUDE RQB.INC\r
+.INCLUDE TSS.INC\r
+.ALIGN DWORD\r
+\r
+EXTRN ddVidOwner DD\r
+\r
+;The keyboard service is designed to return the complete status\r
+;of the keyboard shift, control, alt, and lock keys as well as\r
+;the key in the buffer that the state applies to.\r
+;\r
+;This is done by using two buffers. The first is a "RAW" key buffer\r
+;that holds keys from the interrupt service routine which contains\r
+;all raw keystrokes including shift keys going up and down.\r
+;This information is needed to build coherent keystroke information\r
+; for an application. This buffer is 32 bytes long.\r
+;\r
+;The second buffer is 256 bytes and contains the translated information\r
+;in the form of DWords (a 4 byte quantity times 64). This DWord contains the\r
+;following information:\r
+;\r
+;Low byte (bits 0-7) Partially translated application keystroke\r
+;Next byte (bits 8-15) Shift State (Ctrl, Shift, Alt)\r
+;Next byte (bits 16-23) Lock State (CAPS, Num, Scroll)\r
+;Hi Byte (bits 24-31) Key Source (Bit 1 Set = Key From Numeric Pad)\r
+;\r
+KBDSvcName DB 'KEYBOARD'\r
+\r
+KbdMainExch DD 0 ;Used by the Kbd Process\r
+KbdHoldExch DD 0 ;Used for requestors that don't own the keyboard\r
+KbdGlobExch DD 0 ;Used to hold Global CTRL-ALT requests\r
+KbdWaitExch DD 0 ;Used for Kbd Wait-For-Key requests\r
+KbdTempExch DD 0 ;Used to rifle thru requests\r
+\r
+dGlobalKey DD 0 ;Global Key Found, else 0\r
+dfPrefix DD 0\r
+\r
+KbdMsgBuf1L DD 0 ;Message buffers for Kbd Service\r
+KbdMsgBuf1H DD 0\r
+\r
+KbdMsgBuf2L DD 0\r
+KbdMsgBuf2H DD 0\r
+\r
+KbdOwner DD 1 ;Current owner of Kbd (Mon is default)\r
+KbdAbortJob DD 0 ;Job that is aborting\r
+KbdCancelJob DD 0 ;Job that is cancelling global request\r
+\r
+rgbKbdBuf DB 20h DUP (0) ;32 byte RAW buffer\r
+dKbdCnt DD 0\r
+pKbdIn DD OFFSET rgbKbdBuf ;ptr to next char going in\r
+pKbdOut DD OFFSET rgbKbdBuf ;ptr to next char going out\r
+;\r
+bKbdMode DB 0 ;ZERO for Cooked, 1 for RAW (testing)\r
+fKBDInitDone DB 0 ;Set true when KBD Service is up and running\r
+;\r
+KbdState DB 0 ;(See State Masks below)\r
+KbdLock DB 0 ;(See Lock Masks below)\r
+;\r
+rgdKBBuf DD 40h DUP (0) ;64 Dwords for translated key buffer\r
+dKBCnt DD 0\r
+pKBIn DD OFFSET rgdKBBuf ;ptr to codes comming in\r
+pKBOut DD OFFSET rgdKBBuf ;ptr to codes going out\r
+;\r
+; These "masks" are for keyboard states that change with special keys:\r
+; They are BIT OFFSETS and NOT MASKS for logical operations!!!!!\r
+\r
+CtrlLeftBit EQU 0\r
+CtrlRiteBit EQU 1\r
+ShftLeftBit EQU 2\r
+ShftRiteBit EQU 3\r
+AltLeftBit EQU 4\r
+AltRiteBit EQU 5\r
+;\r
+; Mask to tell if one of the 3 states exist (Ctrl, Shift, Alt)\r
+CtrlDownMask EQU 00000011b\r
+ShftDownMask EQU 00001100b\r
+AltDownMask EQU 00110000b\r
+;\r
+; BIT OFFSETS\r
+CpLockBit EQU 2\r
+NmLockBit EQU 1\r
+ScLockBit EQU 0\r
+; MASKS\r
+CpLockMask DB 00000100b\r
+NmLockMask DB 00000010b\r
+ScLockMask DB 00000001b\r
+\r
+;\r
+; The following special keys are processed by the Keyboard Task and handled\r
+; as follows:\r
+; NUMLOCK - Lights NumLock LED and processes keys accordingly\r
+; SHIFT - Sets shift flag and processes keys accordingly\r
+; CTRL - Sets Ctrl flag\r
+; CAPSLOCK - Lights CapsLock LED and processes keys accordingly\r
+; ALT - Sets Alt flag.\r
+; SCRLLOCK - Lights ScrollLock LED and flag\r
+;\r
+; This table is used to translate all active editing keys from\r
+; the raw value provided by the hardware.\r
+;\r
+; SHIFT\r
+; Value\r
+KbdTable DB 0; 00\r
+DB 01Bh ; Esc 01\r
+DB 031h ; 1 02 21h !\r
+DB 032h ; 2 03 40h @\r
+DB 033h ; 3 04 23h #\r
+DB 034h ; 4 05 24h $\r
+DB 035h ; 5 06 25h %\r
+DB 036h ; 6 07 5Eh ^\r
+DB 037h ; 7 08 26h &\r
+DB 038h ; 8 09 2Ah *\r
+DB 039h ; 9 0A 28h (\r
+DB 030h ; 0 0B 29h )\r
+DB 02Dh ; - 0C 5Fh _\r
+DB 03Dh ; = 0D 2Bh +\r
+DB 008h ; BkSpc 0E\r
+DB 009h ; TAB 0F\r
+DB 071h ; q 10 51h\r
+DB 077h ; w 11 57h\r
+DB 065h ; e 12 45h\r
+DB 072h ; r 13 52h\r
+DB 074h ; t 14 54h\r
+DB 079h ; y 15 59h\r
+DB 075h ; u 16 55h\r
+DB 069h ; i 17 49h\r
+DB 06Fh ; o 18 4Fh\r
+DB 070h ; p 19 50h\r
+DB 05Bh ; [ 1A 7Bh\r
+DB 05Dh ; ] 1B 7Dh\r
+DB 00Dh ; CR 1C\r
+DB 0h ; LCtrl 1D Special handling\r
+DB 061h ; a 1E 41h\r
+DB 073h ; s 1F 53h\r
+DB 064h ; d 20 44h\r
+DB 066h ; f 21 46h\r
+DB 067h ; g 22 47h\r
+DB 068h ; h 23 48h\r
+DB 06Ah ; j 24 4Ah\r
+DB 06Bh ; k 25 4Bh\r
+DB 06Ch ; l (L) 26 4Ch\r
+DB 03Bh ; ; 27 3Ah\r
+DB 027h ; ' 28 22h\r
+DB 060h ; ` 29 7Eh\r
+DB 0h ; LfShf 2A Special handling\r
+DB 05Ch ; \ 2B 7Ch\r
+DB 07Ah ; z 2C 5Ah\r
+DB 078h ; x 2D 58h\r
+DB 063h ; c 2E 43h\r
+DB 076h ; v 2F 56h\r
+DB 062h ; b 30 42h\r
+DB 06Eh ; n 31 4Eh\r
+DB 06Dh ; m 32 4Dh\r
+DB 02Ch ; , 33 3Ch\r
+DB 02Eh ; . 34 3Eh\r
+DB 02Fh ; / 35 3Fh\r
+DB 0h ; RtShf 36 Special handling\r
+DB 02Ah ; Num * 37 Num pad\r
+DB 0h ; LAlt 38 Special handling\r
+DB 020h ; Space 39\r
+DB 0h ; CpsLk 3A Special handling\r
+DB 00Fh ; F1 3B\r
+DB 010h ; F2 3C\r
+DB 011h ; F3 3D\r
+DB 012h ; F4 3E\r
+DB 013h ; F5 3F\r
+DB 014h ; F6 40\r
+DB 015h ; F7 41\r
+DB 016h ; F8 42\r
+DB 017h ; F9 43\r
+DB 018h ; F10 44\r
+DB 0h ; NumLk 45 Special handling\r
+DB 0h ; ScrLk 46 Special handling\r
+DB 086h ; Num 7 47 37h Num Home\r
+DB 081h ; Num 8 48 38h Num Up\r
+DB 085h ; Num 9 49 39h Num Pg Up\r
+DB 0ADh ; Num - 4A Num Pad\r
+DB 083h ; Num 4 4B 34h Num Left\r
+DB 09Fh ; Num 5 4C 35h Num (Extra code)\r
+DB 084h ; Num 6 4D 36h Num Right\r
+DB 0ABh ; Num + 4E Num Pad\r
+DB 08Bh ; Num 1 4F 31h Num End\r
+DB 082h ; Num 2 50 32h Num Down\r
+DB 08Ch ; Num 3 51 33h Num Pg Dn\r
+DB 08Eh ; Num 0 52 30h Num Insert\r
+DB 0FFh ; Num . 53 2Eh Num Del\r
+DB 01Ch ; Pr Scr 54 SYS REQUEST\r
+DB 000h ; 55\r
+DB 000h ; 56\r
+DB 019h ; F11 57\r
+DB 01Ah ; F12 58\r
+DB 000h ; 59\r
+DB 000h ; 5A\r
+DB 000h ; 5B\r
+DB 000h ; 5C\r
+DB 000h ; 5D\r
+DB 000h ; 5E\r
+DB 000h ; 5F ;The following chars are subs from table2\r
+DB 00Eh ; Ins 60 Cursor pad\r
+DB 00Bh ; End 61 Cursor pad\r
+DB 002h ; Down 62 Cursor pad\r
+DB 00Ch ; PgDn 63 Cursor pad\r
+DB 003h ; Left 64 Cursor pad\r
+DB 000h ; 65\r
+DB 004h ; Right 66 Cursor pad\r
+DB 006h ; Home 67 Cursor pad\r
+DB 001h ; Up 68 Cursor pad\r
+DB 005h ; PgUp 69 Cursor pad\r
+DB 07Fh ; Delete 6A Cursor pad\r
+DB 0AFh ; / 6B Num Pad\r
+DB 08Dh ; ENTER 6C Num Pad\r
+DB 0h ; 6D\r
+DB 0h ; 6E\r
+DB 0h ; 6F\r
+DB 0h ; 70\r
+DB 0h ; 71\r
+DB 0h ; 72\r
+DB 0h ; 73\r
+DB 0h ; 74\r
+DB 0h ; 75\r
+DB 0h ; 76\r
+DB 0h ; 77\r
+DB 0h ; 78\r
+DB 0h ; 79\r
+DB 0h ; 7A\r
+DB 0h ; 7B\r
+DB 0h ; 7C\r
+DB 0h ; 7D\r
+DB 0h ; 7E\r
+DB 0h ; 7F\r
+;\r
+;This table does an initial character translation from the characters\r
+;provided by the keyboard. The Kbd translates incoming keystrokes\r
+;from the original scan set 2 for the IBM PC. All PCs are are set to this\r
+;by default. Keys on the 101 keyboard that were common to the numeric\r
+;keypad use a two character escape sequence begining with E0 hex.\r
+;If we see an E0 hex we scan this table and provide the translation\r
+;to another unique character which is looked up in the primary\r
+;table above. This gives us unique single characters for every key.\r
+;\r
+nKbdTable2 EQU 16\r
+;\r
+KbdTable2 DB 052h, 060h ;Insert\r
+ DB 04Fh, 061h ;End\r
+ DB 050h, 062h ;Down\r
+ DB 051h, 063h ;Pg Down\r
+ DB 04Bh, 064h ;Left\r
+ DB 04Dh, 066h ;Rite\r
+ DB 047h, 067h ;Home\r
+ DB 048h, 068h ;Up\r
+ DB 049h, 069h ;Pg Up\r
+ DB 053h, 06Ah ;Delete\r
+\r
+ DB 037h, 06Bh ;Num /\r
+ DB 01Ch, 06Ch ;Num ENTER\r
+\r
+ DB 038h, 070h ;Right ALT DOWN These are special cause we\r
+ DB 01Dh, 071h ;Right Ctrl DOWN track UP & DOWN!!!\r
+ DB 0B8h, 0F0h ;Right ALT UP\r
+ DB 09Dh, 0F1h ;Right Ctrl UP\r
+\r
+\r
+;This table provides shift level values for codes from the primary KbdTable.\r
+;In Shift-ON state, keycodes 21 - 7E hex are translated through this table.\r
+;In CAPS LOCK state, codes 61h to 7Ah are translated through this table\r
+;In NUM LOCK state, codes with High Bit set are translated\r
+;\r
+\r
+KbdTableS DB 0; 00\r
+DB 38h ; 01 Up 8 Numeric pad\r
+DB 32h ; 02 Dn 2 Numeric pad\r
+DB 34h ; 03 Left 4 Numeric pad\r
+DB 36h ; 04 Rite 6 Numeric pad\r
+DB 39h ; 05 PgUp 9 Numeric pad\r
+DB 37h ; 06 Home 7 Numeric pad\r
+DB 07h ; 07\r
+DB 08h ; 08\r
+DB 09h ; 09\r
+DB 0Ah ; 0A\r
+DB 31h ; 0B End 1 Numeric Pad\r
+DB 33h ; 0C PgDn 3 Numeric pad\r
+DB 0Dh ; 0D\r
+DB 30h ; 0E Ins 0 Numeric pad\r
+DB 0Fh ; 0F\r
+DB 10h ; 10\r
+DB 11h ; 11\r
+DB 12h ; 12\r
+DB 13h ; 13\r
+DB 14h ; 14\r
+DB 15h ; 15\r
+DB 16h ; 16\r
+DB 17h ; 17\r
+DB 18h ; 18\r
+DB 18h ; 19\r
+DB 1Ah ; 1A\r
+DB 1Bh ; 1B\r
+DB 1Ch ; 1C\r
+DB 1Dh ; 1D\r
+DB 1Eh ; 1E\r
+DB 35h ; 1F Blnk 5 Numeric pad\r
+DB 20h ; 20\r
+DB 21h ; 21\r
+DB 22h ; 22\r
+DB 23h ; 23\r
+DB 24h ; 24\r
+DB 25h ; 25\r
+DB 26h ; 26\r
+DB 22h ; 27 ' "\r
+DB 28h ; 28\r
+DB 29h ; 29\r
+DB 2Ah ; 2A\r
+DB 2Bh ; 2B\r
+DB 3Ch ; 2C , <\r
+DB 5Fh ; 2D - _\r
+DB 3Eh ; 2E . >\r
+DB 3Fh ; 2F / ?\r
+DB 29h ; 30 0 )\r
+DB 21h ; 31 1 !\r
+DB 40h ; 32 2 @\r
+DB 23h ; 33 3 #\r
+DB 24h ; 34 4 $\r
+DB 25h ; 35 5 %\r
+DB 5Eh ; 36 6 ^\r
+DB 26h ; 37 7 &\r
+DB 2Ah ; 38 8 *\r
+DB 28h ; 39 9 (\r
+DB 3Ah ; 3A\r
+DB 3Ah ; 3B ; :\r
+DB 3Ch ; 3C\r
+DB 2Bh ; 3D = +\r
+DB 3Eh ; 3E\r
+DB 3Fh ; 3F\r
+DB 40h ; 40\r
+DB 41h ; 41\r
+DB 42h ; 42\r
+DB 43h ; 43\r
+DB 44h ; 44\r
+DB 45h ; 45\r
+DB 46h ; 46\r
+DB 47h ; 47\r
+DB 48h ; 48\r
+DB 49h ; 49\r
+DB 4Ah ; 4A\r
+DB 4Bh ; 4B\r
+DB 4Ch ; 4C\r
+DB 4Dh ; 4D\r
+DB 4Eh ; 4E\r
+DB 4Fh ; 4F\r
+DB 50h ; 50\r
+DB 51h ; 51\r
+DB 52h ; 52\r
+DB 53h ; 53\r
+DB 54h ; 54\r
+DB 55h ; 55\r
+DB 56h ; 56\r
+DB 57h ; 57\r
+DB 58h ; 58\r
+DB 59h ; 59\r
+DB 5Ah ; 5A\r
+DB 7Bh ; 5B [ {\r
+DB 7Ch ; 5C \ |\r
+DB 7Dh ; 5D ] }\r
+DB 5Eh ; 5E\r
+DB 5Fh ; 5F\r
+DB 7Eh ; 60 ` ~\r
+DB 41h ; 61 a A\r
+DB 42h ; 62 b B\r
+DB 43h ; 63 c C\r
+DB 44h ; 64 d D\r
+DB 45h ; 65 e E\r
+DB 46h ; 66 f F\r
+DB 47h ; 67 g G\r
+DB 48h ; 68 h H\r
+DB 49h ; 69 i I\r
+DB 4Ah ; 6A j J\r
+DB 4Bh ; 6B k K\r
+DB 4Ch ; 6C l L\r
+DB 4Dh ; 6D m M\r
+DB 4Eh ; 6E n N\r
+DB 4Fh ; 6F o O\r
+DB 50h ; 70 p P\r
+DB 51h ; 71 q Q\r
+DB 52h ; 72 r R\r
+DB 53h ; 73 s S\r
+DB 54h ; 74 t T\r
+DB 55h ; 75 u U\r
+DB 56h ; 76 v V\r
+DB 57h ; 77 w W\r
+DB 58h ; 78 x X\r
+DB 59h ; 79 y Y\r
+DB 5Ah ; 7A z Z\r
+DB 7Bh ; 7B\r
+DB 7Ch ; 7C\r
+DB 7Dh ; 7D\r
+DB 7Eh ; 7E\r
+DB 2Eh ; 7F Del . Numeric Pad\r
+\r
+\r
+KbdSvcStack DD 255 DUP(0) ;1024 byte stack for KbsSvc\r
+KbdSvcStackTop DD 0\r
+\r
+;=============================================================================\r
+;The following equates are for the hardware handling code.\r
+;8042 Status Byte, Port Hex 0064 Read\r
+;=============================================================================\r
+\r
+STATUSPORT EQU 64h\r
+COMMANDPORT EQU 64h\r
+DATAPORT EQU 60h\r
+\r
+PARITYERROR EQU 10000000b\r
+GENERALTIMEOUT EQU 01000000b\r
+AUXOUTBUFFFULL EQU 00100000b\r
+INHIBITSWITCH EQU 00010000b\r
+COMMANDDATA EQU 00001000b\r
+SYSTEMFLAG EQU 00000100b\r
+INPUTBUFFFULL EQU 00000010b\r
+OUTPUTBUFFFULL EQU 00000001b\r
+\r
+\r
+;==================Begin Keyboard Code ===================\r
+\r
+.CODE\r
+;\r
+;\r
+;ISR for the keyboard. This is vectored to by the processor whenever\r
+;INT 21 fires off. This puts the single byte from the 8042\r
+;KBD processor into the buffer. Short and sweet the way all ISRs\r
+;should be... (most are not this easy though). This also sends\r
+;a message to the KBD Task (using ISend) when the buffer is almost\r
+;full so it will be forced to process some of the raw keys even\r
+;if no keyboard requests are waiting.\r
+\r
+PUBLIC IntKeyBrd: ;Key Board (KB) INT 21\r
+ PUSHAD ;Save all registers\r
+ MOV ESI, pKbdIn ;Set up pointer\r
+ XOR EAX,EAX\r
+ IN AL, 60h ;Read byte\r
+ MOV EBX, dKbdCnt ;See if buffer full\r
+ CMP EBX, 20h ;Buffer size\r
+ JE KbdEnd ;Buffer is full - Don't save it\r
+ MOV BYTE PTR [ESI], AL ;Move into buf\r
+ INC dKbdCnt ;One more in the buf\r
+ INC ESI ;Next byte in\r
+ CMP ESI, OFFSET rgbKbdBuf+20h ;past end yet?\r
+ JB KbdEnd\r
+ MOV ESI, OFFSET rgbKbdBuf ;Back to beginning of buffer\r
+KbdEnd:\r
+ MOV pKbdIn, ESI ;Set up pointer for next time\r
+\r
+ CMP BYTE PTR fKBDInitDone, 0 ;Service isn't ready for messages yet\r
+ JE KbdExit\r
+\r
+ ;ISend a msg to Keyboard task\r
+ MOV EBX, KbdMainExch ;Yes - ISend Message to KbdTask\r
+ PUSH EBX ;exchange to send to\r
+ PUSH 0FFFFFFFFh ;bogus msg\r
+ PUSH 0FFFFFFFFh ;bogus msg\r
+ CALL FWORD PTR _ISendMsg ;tell him to come and get it...\r
+KbdExit:\r
+ PUSH 1\r
+ CALL FWORD PTR _EndOfIRQ\r
+ POPAD\r
+ IRETD\r
+\r
+;===============================================\r
+;This gets one byte from the Kbd Buffer and returns it in AL\r
+;Zero is returned if no key exists.\r
+;\r
+ReadKBDBuf:\r
+ CLI\r
+ MOV ESI, pKbdOut ;Get ptr to next char to come out\r
+ MOV EAX, dKbdCnt ;See if there are any bytes\r
+ CMP EAX, 0\r
+ JE RdKBDone ;No - Leave 0 in EAX\r
+ DEC dKbdCnt ;Yes - make cnt right\r
+ XOR EAX,EAX\r
+ MOV AL, BYTE PTR [ESI] ;Put byte in AL\r
+ INC ESI\r
+ CMP ESI, OFFSET rgbKbdBuf+20h ;past end yet?\r
+ JB RdKBDone\r
+ MOV ESI, OFFSET rgbKbdBuf ;Back to beginning of buffer\r
+RdKBDone:\r
+ MOV pKbdOut, ESI ;Save ptr to next char to come out\r
+ STI\r
+ RETN\r
+;\r
+;========================================================\r
+;\r
+; Reads and processes all bytes from the RAW keyboard buffer\r
+; and places them and their proper state bytes and into the next DWord\r
+; in the translated buffer if it is an edit key.\r
+\r
+XLateRawKBD:\r
+ CALL ReadKbdBuf\r
+ CMP EAX, 0\r
+ JE XLateDone ;No\r
+\r
+ MOV BL, bKbdMode ;See if we are RAW... (for testing ONLY)\r
+ CMP BL, 1\r
+ JNE KB001 ;NO - keep going\r
+ JMP KB029A ;Yes, leave the key in AL for buffer\r
+\r
+ ;Now we check to see if the byte is 0Eh which tells us\r
+ ;this is a two key code that needs to be translated from\r
+ ;our special table before processing. This turns the\r
+ ;two key code into a single code and sets a state\r
+ ;bit to indicate this.\r
+\r
+KB001:\r
+ CMP dfPrefix, 1\r
+ JE KB003\r
+ CMP AL, 0E0h ;Key PREFIX???\r
+ JNE KB006 ;No\r
+ MOV dfPrefix, 1 ;Yes, We got an E0\r
+ JMP XLateDone ;\r
+\r
+KB003:\r
+ MOV dfPrefix, 0 ;No prefix\r
+ MOV ESI, OFFSET KbdTable2\r
+ MOV ECX, nKbdTable2\r
+KB004:\r
+ CMP BYTE PTR [ESI], AL\r
+ JE KB005\r
+ INC ESI ;Two byte further into table 2\r
+ INC ESI\r
+ DEC ECX\r
+ JNZ KB004 ;Go to next table entry\r
+ JMP XLateDone ;No translation - ignore it\r
+\r
+KB005:\r
+ INC ESI ;One byte further over to get Xlate byte\r
+ XOR EAX,EAX\r
+ MOV AL, [ESI] ;Fall thru to check on char...\r
+\r
+ ;This next section checks for special keys (shift, alt, etc.)\r
+ ;BL has SHIFT state, CL has LOCK State, AL has byte from buffer.\r
+\r
+KB006:\r
+ MOV dfPrefix, 0 ;No prefix\r
+ XOR EBX, EBX\r
+ XOR ECX, ECX\r
+ MOV BL, KbdState ;BL has Shift, Alt, Ctrl states\r
+ MOV CL, KbdLock ;BH has Num, Caps, & Scroll Lock\r
+\r
+ CMP AL, 45h ;Key = NumLock ?\r
+ JNE KB007 ;NO...\r
+ BTC ECX, NmLockBit ;Compliment bit\r
+ JMP KB022\r
+KB007:\r
+ CMP AL, 3Ah ;Caps Lock?\r
+ JNE KB008\r
+ BTC ECX, CpLockBit ;Compliment bit in BH\r
+ JMP KB022\r
+KB008:\r
+ CMP AL, 46h ;Scroll Lock?\r
+ JNE KB009\r
+ BTC ECX, ScLockBit ;Compliment bit in BH\r
+ JMP KB022\r
+KB009:\r
+ CMP AL, 2Ah ;Char Left Shift On?\r
+ JNE KB010\r
+ BTS EBX, ShftLeftBit\r
+ JMP KB021\r
+KB010:\r
+ CMP AL, 36h ;Right Shift On?\r
+ JNE KB011\r
+ BTS EBX, ShftRiteBit\r
+ JMP KB021\r
+KB011:\r
+ CMP AL, 0AAh ;Left Shift Off?\r
+ JNE KB012\r
+ BTR EBX, ShftLeftBit\r
+ JMP KB021\r
+\r
+KB012:\r
+ CMP AL, 0B6h ;Right Shift Off?\r
+ JNE KB013\r
+ BTR EBX, ShftRiteBit\r
+ JMP KB021\r
+\r
+KB013:\r
+ CMP AL, 1Dh ;Left Ctrl On?\r
+ JNE KB014\r
+ BTS EBX, CtrlLeftBit\r
+ JMP KB021\r
+\r
+KB014:\r
+ CMP AL, 71h ;Right Ctrl On?\r
+ JNE KB015\r
+ BTS EBX, CtrlRiteBit\r
+ JMP KB021\r
+\r
+KB015:\r
+ CMP AL, 09Dh ;Left Ctrl Off?\r
+ JNE KB016\r
+ BTR EBX, CtrlLeftBit\r
+ JMP KB021\r
+\r
+KB016:\r
+ CMP AL, 0F1h ;Right Ctrl Off?\r
+ JNE KB017\r
+ BTR EBX, CtrlRiteBit\r
+ JMP KB021\r
+KB017:\r
+ CMP AL, 38h ;Left Alt On?\r
+ JNE KB018\r
+ BTS EBX, AltLeftBit\r
+ JMP KB021\r
+KB018:\r
+ CMP AL, 70h ;Right Alt On?\r
+ JNE KB019\r
+ BTS EBX, AltRiteBit\r
+ JMP KB021\r
+KB019:\r
+ CMP AL, 0B8h ;Left Alt Off?\r
+ JNE KB020\r
+ BTR EBX, AltLeftBit\r
+ JMP KB021\r
+KB020:\r
+ CMP AL, 0F0h ;Right Alt Off?\r
+ JNE KB023\r
+ BTR EBX, AltRiteBit\r
+KB021:\r
+ MOV KbdState, BL ;Put Kbd Shift State back\r
+ JMP XLateDone ;\r
+KB022:\r
+ MOV KbdLock, CL ;Put Kbd Lock State back\r
+ CALL SetKbdLEDS ;Set LEDs on keyboard\r
+ JMP XLateRawKBD ;\r
+\r
+ ;We jumped here if it wasn't a key that is specially handled\r
+\r
+KB023:\r
+ TEST AL, 80h ;Check for high bit (key-up code)\r
+ JNZ XLateDone ;Go back, else fall through\r
+\r
+ OR AL,AL ;Zero not a valid code\r
+ JZ XLateDone ;Go back, else fall through\r
+\r
+ ;If we got here, IT'S AN EDIT KEY DOWN!\r
+ ;Now we lookup the code and do a single translation.\r
+\r
+ AND EAX, 07Fh ;Chop off any upper bit junk\r
+ MOV ESI, OFFSET KbdTable ;Set up to index table\r
+ MOV DL, BYTE PTR [ESI+EAX] ;Save in DL\r
+ OR AL,AL ;Zero not a valid code\r
+ JZ XLateDone ;Go back, else fall through\r
+\r
+ MOV CL, KbdState ;Get Shift state\r
+ MOV CH, KbdLock ;Get lock state\r
+\r
+ ;TO let the user know if the key came from the Numeric\r
+ ;keypad we set the high bits in the first translation\r
+ ;table for these keys. This next piece of code tests for it\r
+ ;and sets the low bit in DH if it its. DH is later moved\r
+ ;into the high byte of the returned key code.\r
+\r
+ MOV DH, 0\r
+ TEST DL, 80h ;High bit set?\r
+ JZ SHORT KB024\r
+ MOV DH, 1 ;Indicates key came numeric pad\r
+\r
+ ;See if shift key is down and shift all keys it is is\r
+KB024:\r
+ TEST CL, ShftDownMask ;Either shift key down?\r
+ JZ KB025 ;No, go look for locks\r
+ CMP DL, 21h ;Is key < ' '\r
+ JB KB025 ;Yes, look for locks\r
+ CMP DL, 7Eh ;Is key > '~'\r
+ JA KB025 ;Yes, look for locks\r
+ JMP SHORT KB027 ;In-range, go do the translation\r
+\r
+KB025: ;See if key is from Numerc Keypad (high bit will be set)\r
+\r
+ TEST DL, 80h ;High bit set?\r
+ JZ KB026 ;No\r
+ AND CH, NmLockMask ;Yes, is NumLock ON\r
+ JZ KB026 ;No\r
+ CMP DL, 0ADh ;Yes, but don't shift DASH (-) Special Case\r
+ JE KB026\r
+ JMP SHORT KB027 ;Do the shift Xlation\r
+\r
+KB026: ;See if Caps Lock is on and if key is between 61h and 7Ah\r
+ ;do the translation\r
+\r
+ TEST CH, CpLockMask ;Is CpLock ON\r
+ JZ KB029 ;No\r
+ CMP DL, 61h ;Is key >= 'a'\r
+ JB KB029 ;No\r
+ CMP DL, 7Ah ;Is key <= 'z'\r
+ JA KB029 ;No\r
+ ;Fall through to do the translation\r
+\r
+KB027: ;Do the shift translation and leave in DL\r
+ MOV AL, DL ;Put in AL\r
+ AND EAX, 07Fh ;Chop all above 7 bits\r
+ MOV ESI, OFFSET KbdTableS ;Set up to index table\r
+ MOV DL, BYTE PTR [ESI+EAX] ;Save in DL\r
+ ;Fall though to put key in final buffer\r
+\r
+ ;Place DL in the LOW byte of the DWord to go into the\r
+ ;final buffer (the data the user will get)\r
+ ;If the high bit is set coming from the primary\r
+ ;translation table, this means the key was from the\r
+ ;numeric keypad so we set the numpad bit in status\r
+ ;which should already be in DH\r
+KB029:\r
+ MOV AH, DH\r
+ SHL EAX, 8 ;Num Pad indicator\r
+ MOV AL, KbdState ;Get Shift state\r
+ MOV AH, KbdLock ;Get lock state\r
+ SHL EAX, 8\r
+ AND DL, 7Fh ;Lop of high bit (if there)\r
+ MOV AL, DL\r
+\r
+ ;EAX now has the buffered info for the user (Key, Shifts & Locks)\r
+ ;Now we put it in the DWord buffer if it is NOT a GLOBAL.\r
+ ;If global, we put it in dGlobalKey.\r
+\r
+ TEST AH, CtrlDownMask ;Either Ctrl Down?\r
+ JZ KB029A ;No\r
+ TEST AH, AltDownMask ;Either Alt Down?\r
+ JZ KB029A ;No\r
+\r
+ ;It IS a global key request!\r
+ MOV dGlobalKey, EAX ;Save it\r
+ JMP XLateRawKBD ;Back for more (if there is any)\r
+\r
+KB029A:\r
+ MOV EBX, dKBCnt ;See if buffer full\r
+ CMP EBX, 64 ;number of DWords in final buffer\r
+ JE XLateDone ;Buffer is FULL..\r
+ MOV ESI, pKBIn ;Get ptr to next IN to final buffer\r
+ MOV [ESI], EAX ;Move into buf\r
+ INC dKBCnt ;One more DWord in the buf\r
+ ADD ESI, 4\r
+ CMP ESI, OFFSET rgdKBBuf+100h ;40h * 4\r
+ JB KB030\r
+ MOV ESI, OFFSET rgdKBBuf ;Reset to buf beginning\r
+KB030:\r
+ MOV pKBIn, ESI ;Save ptr to next in\r
+ JMP XLateRawKBD\r
+XlateDone:\r
+ XOR EAX, EAX\r
+ RETN\r
+\r
+;========================================================\r
+;\r
+; Returns a keyboard code from FINAL keyboard buffer.\r
+; Returns zero in EAX if buffer is empty.\r
+;\r
+; IN : Nothing\r
+; OUT: EAX has Key or 0 if none\r
+; USED: EAX, ESI\r
+; MODIFIES: dKBCnt, pKBOut\r
+;\r
+ReadKBFinal:\r
+ MOV EAX, dKBCnt\r
+ CMP EAX, 0\r
+ JE KBFDone ;Nothing final buffer\r
+ DEC dKBCnt ;One more DWord in the buf\r
+ MOV ESI, pKBOut ;ptr to next code out\r
+ MOV EAX, [ESI] ;Put it in EAX\r
+ ADD ESI, 4 ;Next code please...\r
+ CMP ESI, OFFSET rgdKBBuf+100h ;Past end of buff?\r
+ JB KBF02 ;No\r
+ MOV ESI, OFFSET rgdKBBuf ;Yes, Reset to beginning\r
+KBF02:\r
+ MOV pKBOut, ESI ;Update pKBOut\r
+KBFDone:\r
+ RETN\r
+\r
+;========================================================\r
+;\r
+; This is the keyboard Service task. It is an infinite loop\r
+; that services requests from users of the keyboard. It\r
+; calls XLateRawKBD to process raw keyboard buffer data,\r
+; and waits at the KeyBoard Service Main Exchange for users.\r
+; When it gets a request it checks the service code and handles\r
+; it accordingly.\r
+\r
+KBDServiceTask:\r
+ CALL XLateRawKBD ;Processes RAW buffer if not empty\r
+\r
+ CMP DWORD PTR dGlobalKey, 0\r
+ JE KST01 ;No global key came in\r
+KBDGlobal1:\r
+ PUSH KbdGlobExch\r
+ PUSH OFFSET KbdMsgBuf1L ;Where to return pRqBlk\r
+ CALL FWORD PTR _CheckMsg ;Check to see if RqWaiting\r
+ OR EAX, EAX ;Yes if ZERO\r
+ JZ KBDGlobal2 ;Rq waiting for global\r
+ MOV DWORD PTR dGlobalKey, 0 ;Wipe out global key (no one wants it)\r
+ JMP KBDServiceTask ;Start over again\r
+\r
+KBDGlobal2:\r
+ MOV EBX, KbdMsgBuf1L ;pRqBlk into EBX\r
+ MOV ESI, [EBX+pData1] ;Ptr where to return key\r
+ OR ESI, ESI ;Is it null?? (Bad news if so)\r
+ JNZ KBDGlobal3 ;No, probably good ptr\r
+ PUSH EBX ;Yes, BAD PTR. Push pRqBlk\r
+ PUSH ErcNullPtr ;Push error\r
+ CALL FWORD PTR _Respond\r
+ JMP KBDServiceTask ;Go back to the top\r
+KBDGlobal3:\r
+ MOV EDX, dGlobalKey\r
+ MOV [ESI], EDX ;Give em the key!\r
+ PUSH EBX ;Push pRqBlk\r
+ PUSH 0 ;Push NO ERROR\r
+ CALL FWORD PTR _Respond\r
+ JMP KBDGlobal1 ;Go back to see if others want it\r
+\r
+KST01:\r
+ CMP DWORD PTR ddVidOwner, 2 ;Debugger has video\r
+ JNE KST01ND ;NOT in Debugger\r
+ PUSH 20\r
+ CALL FWORD PTR _Sleep ;\r
+ CALL XLateRawKBD ;Processes RAW buffer\r
+ JMP KBDServiceTask ;Go back to the top\r
+\r
+KST01ND:\r
+ PUSH KbdMainExch ;See if someones "Requesting"\r
+ PUSH OFFSET KbdMsgBuf1L ;\r
+ CALL FWORD PTR _WaitMsg ;Wait for the message\r
+\r
+ ;If we got here, we have a Request or a Msg the from ISR\r
+\r
+ CMP DWORD PTR KbdMsgBuf1L, 0FFFFFFFFh ;Is it a msg from the KBD ISR?\r
+ JNE KST02 ;No, jump to handle Request\r
+\r
+ ;If we got here, ISR sent msg to us (something in the buffer)\r
+\r
+ CALL XLateRawKBD ;Processes RAW buffer\r
+\r
+ CMP DWORD PTR dGlobalKey, 0\r
+ JNE KBDGlobal1 ;A global key came in\r
+\r
+ PUSH KbdWaitExch ;See if owner is waiting for a key\r
+ PUSH OFFSET KbdMsgBuf1L ;Where to return Request or msg\r
+ CALL FWORD PTR _CheckMsg ;\r
+ OR EAX, EAX\r
+ JNZ KBDServiceTask ;No Rq/Msg waiting, Go back to the top,\r
+ ;or fall thru to check the request\r
+\r
+KST02:\r
+ ;If we got here we've got a Request from Main or Wait Exch\r
+ MOV EBX, KbdMsgBuf1L ;pRqBlk into EBX\r
+ MOV CX, [EBX+ServiceCode] ;Save in CX\r
+\r
+ CMP CX, 0 ;Job Abort Notify\r
+ JE KSTAbort ;\r
+ CMP CX, 1 ;ReadKbd\r
+ JE KSTRead ;\r
+ CMP CX, 2 ;ReadKbdGlobal\r
+ JE KSTReadGlobal ;\r
+ CMP CX, 3 ;CancelGlobal\r
+ JE KSTCancelGlobal ;\r
+ CMP CX, 4 ;AssignKBD\r
+ JE KSTAssignKbd ;\r
+ PUSH EBX ;HOMEY DON'T SERVICE THAT!\r
+ PUSH ErcBadSvcCode ;Bad service code\r
+ CALL FWORD PTR _Respond\r
+ JMP KBDServiceTask ;Go back to the top\r
+\r
+;-------------------------------------------------------\r
+KSTRead:\r
+ MOV EAX, [EBX+RqOwnerJob] ;Whose Request is it?\r
+ CMP EAX, KbdOwner\r
+ JE KSTRead00 ;This guy owns it!\r
+ PUSH EBX ;Not the owner, so send to Hold Exch\r
+ PUSH KbdHoldExch ;\r
+ CALL FWORD PTR _MoveRequest\r
+ JMP KBDServiceTask ;Go back to the top\r
+KSTRead00:\r
+ CALL ReadKBFinal ;Get Code from Buf (Uses EAX, ESI)\r
+ CMP EAX, 0 ;No Key in Final Buffer\r
+ JE KSTRead02 ;Go see if they asked to wait\r
+ MOV ESI, [EBX+pData1] ;Ptr where to return key\r
+ CMP ESI, 0 ;Is it null?? (Bad news if so)\r
+ JNE KSTRead01 ;No, probably good ptr\r
+ PUSH EBX ;Yes, BAD PTR. Push pRqBlk\r
+ PUSH ErcNullPtr ;Push error\r
+ CALL FWORD PTR _Respond\r
+ JMP KBDServiceTask ;Go back to the top\r
+KSTRead01:\r
+ MOV [ESI], EAX ;Give them the key code\r
+ PUSH EBX ;RqHandle\r
+ PUSH 0 ;NO Error\r
+ CALL FWORD PTR _Respond\r
+ JMP KBDServiceTask ;Go back to the top\r
+\r
+KSTRead02:\r
+ CMP DWORD PTR [EBX+dData0], 0 ;Wait for key? 0 in dData0 = Don't wait\r
+ JNE KSTRead04 ;Yes\r
+ PUSH EBX\r
+ PUSH ErcNoKeyAvail ;Error Code (No key to give you)\r
+ CALL FWORD PTR _Respond\r
+ JMP KBDServiceTask ;Go back to the top\r
+\r
+KSTRead04:\r
+ PUSH EBX ;They opted to wait for a key\r
+ PUSH KbdWaitExch ;Send em to the wait exch\r
+ CALL FWORD PTR _MoveRequest\r
+ JMP KBDServiceTask ;Go back to the top\r
+;--------------------------------------------------------\r
+\r
+KSTAbort:\r
+ ;Respond to all requests we are holding for Job in dData0\r
+ ;with Erc with ErcOwnerAbort. Then respond to Abort\r
+ ;request last. Requests can be at the HoldExch, the WaitExch,\r
+ ;or the GlobalKeyExch. We must chack all 3!\r
+ ;Save abort job for comparison\r
+\r
+ MOV EAX, [EBX+dData0] ;Get aborting job number\r
+ MOV KbdAbortJob, EAX ;this is aborting job\r
+\r
+KSTAbort10: ;Check the WaitExch\r
+ PUSH KbdWaitExch ;See if he was "waiting" for a key\r
+ PUSH OFFSET KbdMsgBuf2L ;Where to return Request\r
+ CALL FWORD PTR _CheckMsg ;\r
+ OR EAX, EAX ;Yes (someone's waiting) if ZERO\r
+ JNZ KSTAbort20 ;No more waiters\r
+ MOV EDX, KbdMsgBuf2L ;pRq of holding job into EDX\r
+ MOV EBX, [EDX+RqOwnerJob]\r
+ CMP EBX, KbdAbortJob\r
+ JE KSTAbort11 ;Go to respond with Erc\r
+ PUSH EDX ;Else move Request to MainKbd Exch\r
+ PUSH KbdMainExch ; to be reevaluated\r
+ CALL FWORD PTR _MoveRequest\r
+ JMP KSTAbort10 ;Go back to look for more waiters\r
+KSTAbort11: ;\r
+ PUSH EDX ;Respond to this request\r
+ PUSH ErcOwnerAbort ;cause he's dead\r
+ CALL FWORD PTR _Respond\r
+ JMP SHORT KSTAbort10\r
+\r
+KSTAbort20: ;Check HoldExch for dead job\r
+ PUSH KbdHoldExch ;See if anyone is on hold\r
+ PUSH OFFSET KbdMsgBuf2L ;Where to return Request\r
+ CALL FWORD PTR _CheckMsg ;\r
+ OR EAX, EAX ;Yes (someones holding) if ZERO\r
+ JNZ KSTAbort30 ;No more holders\r
+ MOV EDX, KbdMsgBuf2L ;pRq of holding job into EDX\r
+ MOV EBX, [EDX+RqOwnerJob]\r
+ CMP EBX, KbdAbortJob\r
+ JE KSTAbort21 ;Go to respond with Erc\r
+ PUSH EDX ;Else move Request to MainKbd Exch\r
+ PUSH KbdMainExch ; to be reevaluated. It's not him.\r
+ CALL FWORD PTR _MoveRequest\r
+ JMP KSTAbort20 ;Go back to look for more holders\r
+KSTAbort21: ;\r
+ PUSH EDX ;Respond to this request\r
+ PUSH ErcOwnerAbort ;cause he's dead\r
+ CALL FWORD PTR _Respond\r
+ JMP SHORT KSTAbort20 ;Go back to look for more holders\r
+\r
+KSTAbort30: ;Check GlobalExch for dead job\r
+ PUSH KbdGlobExch ;See if anyone is at global\r
+ PUSH OFFSET KbdMsgBuf2L ;Where to return Request\r
+ CALL FWORD PTR _CheckMsg ;\r
+ OR EAX, EAX ;Yes (someones holding) if ZERO\r
+ JNZ KSTAbort40 ;No more holders\r
+ MOV EDX, KbdMsgBuf2L ;pRq of holding job into EDX\r
+ MOV EBX, [EDX+RqOwnerJob]\r
+ CMP EBX, KbdAbortJob\r
+ JE KSTAbort31 ;Go to respond with Erc\r
+ PUSH EDX ;Else move Request to MainKbd Exch\r
+ PUSH KbdMainExch ; to be reevaluated\r
+ CALL FWORD PTR _MoveRequest\r
+ JMP KSTAbort30 ;Go back to look for more globals\r
+KSTAbort31: ;\r
+ PUSH EDX ;Respond to this request\r
+ PUSH ErcOwnerAbort ;cause he's dead\r
+ CALL FWORD PTR _Respond\r
+ JMP SHORT KSTAbort30\r
+\r
+KSTAbort40: ;Respond to original abort Req\r
+ MOV EBX, KbdMsgBuf1L ;pRqBlk of original Abort Request\r
+ PUSH EBX ;\r
+ PUSH 0 ;Error Code (OK)\r
+ CALL FWORD PTR _Respond\r
+ JMP KBDServiceTask ;Go back to the top\r
+;----------------------------------------------------------\r
+\r
+KSTReadGlobal:\r
+ PUSH EBX ;They want a global key\r
+ PUSH KbdGlobExch ;Send em to the Global exch\r
+ CALL FWORD PTR _MoveRequest\r
+ JMP KBDServiceTask ;Go back to the top\r
+;-----------------------------------------------------------\r
+;Assign a new owner for the keyboard. We must check to see\r
+;if the new owner had any keyboard requests on hold.\r
+;We do this by sending all the requests that were on hold\r
+;back to the main exchange to be reevaluated.\r
+;Then we respond to the original request.\r
+\r
+KSTAssignKBD:\r
+ ;Change owner of Kbd\r
+ MOV EAX, [EBX+dData0] ;Get new owner\r
+ CMP EAX, KbdOwner\r
+ JNE KSTAssign01 ;New Owner!\r
+\r
+ PUSH EBX ;Same owner\r
+ PUSH 0 ;Error Code (OK)\r
+ CALL FWORD PTR _Respond\r
+ JMP KBDServiceTask ;Go back to the top\r
+KSTAssign01:\r
+ MOV KbdOwner, EAX ;Set new owner\r
+\r
+KSTAssign02: ;Move all waiters to main exch\r
+ PUSH KbdWaitExch ;See if anyone is "waiting" for a key\r
+ PUSH OFFSET KbdMsgBuf2L ;Where to return Request\r
+ CALL FWORD PTR _CheckMsg ;\r
+ OR EAX, EAX ;Yes (someones waiting) if ZERO\r
+ JNZ KSTAssign03 ;No more waiters\r
+ MOV EDX, KbdMsgBuf2L ;pRq into EDX\r
+ PUSH EDX ;Move Request to MainKbd Exch\r
+ PUSH KbdMainExch ; to be reevaluated\r
+ CALL FWORD PTR _MoveRequest\r
+ JMP KSTAssign02 ;Go back to look for more waiters\r
+KSTAssign03: ;Waiter have been moved, Respond to Req\r
+ PUSH KbdHoldExch ;See if anyone is on hold\r
+ PUSH OFFSET KbdMsgBuf2L ;Where to return Request\r
+ CALL FWORD PTR _CheckMsg ;\r
+ OR EAX, EAX ;Yes if ZERO\r
+ JNZ KSTAssign04 ;No more holders\r
+ MOV EDX, KbdMsgBuf2L ;pRq into EDX\r
+ PUSH EDX ;Move Request to MainKbd Exch\r
+ PUSH KbdMainExch ; to be reevaluated\r
+ CALL FWORD PTR _MoveRequest\r
+ JMP KSTAssign03 ;Go back to look for more holders\r
+KSTAssign04: ;Holders have been moved, Respond to Req\r
+ MOV EBX, KbdMsgBuf1L ;pRqBlk of original Assign Request\r
+ PUSH EBX ;\r
+ PUSH 0 ;Error Code (OK)\r
+ CALL FWORD PTR _Respond\r
+ JMP KBDServiceTask ;Go back to the top\r
+;-------------------------------------------------------\r
+\r
+KSTCancelGlobal:\r
+ ;Rifle thru Global Exch and respond with ErcNoKeyAvail\r
+ ;to those with the same JobNum as dData0\r
+ MOV EAX, [EBX+dData0] ;Save Job that is cancelling global request\r
+ MOV KbdCancelJob, EAX ;\r
+\r
+KSTCancel10: ;Check GlobalExch for canceled job\r
+ PUSH KbdGlobExch ;See if anyone is at global\r
+ PUSH OFFSET KbdMsgBuf2L ;Where to return Request\r
+ CALL FWORD PTR _CheckMsg ;\r
+ OR EAX, EAX ;Yes (someones holding) if ZERO\r
+ JNZ KSTCancel20 ;No more globals\r
+ MOV EDX, KbdMsgBuf2L ;pRq of holding job into EDX\r
+ MOV EBX, [EDX+RqOwnerJob]\r
+ CMP EBX, KbdCancelJob\r
+ JE KSTCancel11 ;Go to respond with Erc\r
+ PUSH EDX ;Else move Request to MainKbd Exch\r
+ PUSH KbdMainExch ; to be reevaluated\r
+ CALL FWORD PTR _MoveRequest\r
+ JMP KSTCancel10 ;Go back to look for more globals\r
+KSTCancel11: ;\r
+ PUSH EDX ;Respond to this request\r
+ PUSH ErcNoKeyAvail ;cause he cancelled it!\r
+ CALL FWORD PTR _Respond\r
+ JMP SHORT KSTCancel10 ;Back to check for more\r
+\r
+KSTCancel20: ;Respond to original cancel Req\r
+ MOV EBX, KbdMsgBuf1L ;pRqBlk of original Request\r
+ PUSH EBX ;\r
+ PUSH 0 ;Error Code (OK)\r
+ CALL FWORD PTR _Respond\r
+ JMP KBDServiceTask ;Go back to the top\r
+\r
+;=============================================================\r
+;PUBLIC blocking call to read the keyboard. This uses the\r
+;Default TSS exchange and the stack to make the request to\r
+;the keyboard service for the caller. The request is a standard\r
+;service code one (Wait On Key) request.\r
+;If fWait is NON-ZERO, this will not return without a key unless\r
+;a kernel/fatal error occurs.\r
+;\r
+;The call is fully reentrant (it has to be...).\r
+;\r
+; Procedural interface:\r
+;\r
+; ReadKbd(pKeyCodeRet, fWait): dError\r
+;\r
+; pKeyCodeRet is a pointer to a DWORD where the keycode is returned.\r
+; [EBP+16]\r
+; fWait is NON-ZERO to wait for a key.\r
+; [EBP+12]\r
+;\r
+; Stack Variables:\r
+; Hndl [EBP-4]\r
+;\r
+PUBLIC __ReadKBD:\r
+ PUSH EBP ; Save the Previous FramePtr\r
+ MOV EBP,ESP ; Set up New FramePtr\r
+ SUB ESP, 4 ; One DWORD local var\r
+\r
+ MOV EAX, OFFSET KBDSvcName ;'KEYBOARD '\r
+ PUSH EAX\r
+\r
+ PUSH 1 ;Service Code (Read Keyboard)\r
+\r
+ MOV ECX,pRunTSS ;Get TSS_Exch for our use\r
+ MOV EBX,[ECX+TSS_Exch] ;Exchange (TSS Exch)\r
+ PUSH EBX ;\r
+\r
+ LEA EAX, [EBP-4] ;Rq Handle (Local Var)\r
+ PUSH EAX\r
+\r
+ PUSH 0 ;npSend\r
+ MOV EAX, [EBP+16] ;Key Code return (Their Ptr)\r
+ PUSH EAX ;pData1\r
+ PUSH 4 ;Size of key code\r
+ PUSH 0 ;pData2\r
+ PUSH 0 ;cbData2\r
+\r
+ XOR EAX, EAX\r
+ CMP DWORD PTR [EBP+12], 0 ;Don't wait for Key?\r
+ JE ReadKbd1 ;No wait\r
+ MOV EAX, 1 ;Set up to wait!\r
+ReadKbd1:\r
+ PUSH EAX ;Wait value (dData0)\r
+\r
+ PUSH 0\r
+ PUSH 0\r
+\r
+ CALL FWORD PTR _Request ;make the Request\r
+\r
+ ;The request is made. Now we call Wait!\r
+\r
+ MOV ECX,pRunTSS ;Get TSS_Exch for our use\r
+ MOV EBX,[ECX+TSS_Exch] ;\r
+ PUSH EBX ;Pass exchange (for WaitMsg)\r
+ ADD ECX,TSS_Msg ;Offset of TSS msg area\r
+ PUSH ECX\r
+ CALL FWORD PTR _WaitMsg ;Wait on it\r
+\r
+ ;When we get here the caller should have the key code\r
+ ;HOWEVER, we want to pass any errors back via EAX\r
+\r
+ OR EAX, EAX ;Was there a kernel error?\r
+ JNZ ReadKbdEnd ;YES.... bummer\r
+ MOV ECX,pRunTSS ;Get TSS_Msg area so we can get error\r
+ ADD ECX,TSS_Msg ;Offset of TSS msg area\r
+ MOV EBX, [ECX] ;pRqBlk\r
+ MOV EAX, [ECX+4] ;Service error in second DWord\r
+ReadKbdEnd:\r
+ MOV ESP,EBP ;\r
+ POP EBP ;\r
+ RETF 8 ; Rtn to Caller & Remove Params from stack\r
+\r
+;=============================================================\r
+;Special Call for Debugger so it doesn't have to pass thru\r
+;the kernel Request mechanism for a keystroke.\r
+;It acts like ReadKbd with fWait set to true.\r
+;It sucks keys directly from the Final Keyboard buffer.\r
+;\r
+; Procedural interface:\r
+;\r
+; ReadDbgKbd(pKeyCodeRet)\r
+;\r
+; pKeyCodeRet is a pointer to a DWORD where the keycode is returned.\r
+; [EBP+8]\r
+;\r
+PUBLIC ReadDbgKBD:\r
+ PUSH EBP ; Save the Previous FramePtr\r
+ MOV EBP,ESP ; Set up New FramePtr\r
+RDKB0:\r
+ CALL ReadKBFinal ;Get Code from Buf (Uses EAX, ESI)\r
+ OR EAX, EAX ;Got a key?? (non zero)\r
+ JNZ RDKB1 ;No. Loop back again\r
+ PUSH 2 ;Sleep for 20 ms\r
+ CALL FWORD PTR _Sleep\r
+ JMP RDKB0 ;Check again\r
+RDKB1:\r
+ MOV ESI, [EBP+8] ;Ptr where to return key\r
+ MOV [ESI], EAX\r
+ XOR EAX, EAX\r
+ MOV ESP,EBP ;\r
+ POP EBP ;\r
+ RETN 4 ; Rtn to Caller & Remove Params from stack\r
+\r
+;=================================================\r
+;This sets the Keyboard Scan Set to #2 with 8042 interpretation ON\r
+;\r
+PUBLIC InitKBD:\r
+\r
+ PUSH 1 ;KBD IRQ\r
+ CALL FWORD PTR _MaskIRQ\r
+\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ MOV AL,0FAh ;Set ALL keys typematic/make/break\r
+ OUT DataPort,AL ;Send Command to KBD (not 8042)\r
+\r
+ CALL OutBuffFull ;Eat response\r
+ IN AL, DATAPORT\r
+\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ MOV AL,0F0h ;Set Scan code set\r
+ OUT DataPort,AL ;Send Command to KBD (not 8042)\r
+\r
+ CALL OutBuffFull ;Eat response\r
+ IN AL, DATAPORT\r
+\r
+\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ MOV AL,02h ;Scan set 2\r
+ OUT DataPort,AL ;Send Command\r
+\r
+ CALL OutBuffFull ;Eat response\r
+ IN AL, DATAPORT\r
+\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ MOV AL,060h ;Set up to write 8042 command byte\r
+ OUT COMMANDPORT,AL ;Send Command\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ MOV AL,45h ;Enable IBM Xlate\r
+ OUT DataPort,AL ;Send Command\r
+\r
+ PUSH 1 ;KBD IRQ\r
+ CALL FWORD PTR _UnMaskIRQ\r
+\r
+ CALL SetKbdLEDs\r
+\r
+ RETN\r
+\r
+;=============================================================================\r
+;This creates the Keyboard Task and Service.\r
+;\r
+PUBLIC _InitKBDService:\r
+\r
+ ;All initial requests and messages from the ISR come to\r
+ ;this exchange\r
+\r
+ MOV EAX, OFFSET KbdMainExch ;Alloc Main Kbd exch for service\r
+ PUSH EAX\r
+ CALL FWORD PTR _AllocExch\r
+ OR EAX, EAX ;Check for error on AllocExch\r
+ JNZ InitKBDSvcEnd ;YUP, we got bad problems\r
+\r
+ ;TempExch for testing\r
+\r
+ MOV EAX, OFFSET KbdTempExch ;Alloc Hold Kbd exch for Kbd service\r
+ PUSH EAX\r
+ CALL FWORD PTR _AllocExch\r
+ OR EAX, EAX ;Check for error on AllocExch\r
+ JNZ InitKBDSvcEnd ;YUP, we got bad problems\r
+\r
+ ;Requests for ReadkeyBoard (ScvCode #1) that are from job\r
+ ;that currently owns the keyboard waits here if it wants\r
+ ;to wait for a key.\r
+\r
+ MOV EAX, OFFSET KbdWaitExch ;Alloc Hold Kbd exch for Kbd service\r
+ PUSH EAX\r
+ CALL FWORD PTR _AllocExch\r
+ OR EAX, EAX ;Check for error on AllocExch\r
+ JNZ InitKBDSvcEnd ;YUP, we got bad problems\r
+\r
+ ;Requests for ReadkeyBoard (ScvCode #1) that are from jobs\r
+ ;that do NOT currently own the keyboard get sent here using\r
+ ;MoveRequest.\r
+\r
+ MOV EAX, OFFSET KbdHoldExch ;Alloc Hold Kbd exch for Kbd service\r
+ PUSH EAX\r
+ CALL FWORD PTR _AllocExch\r
+ OR EAX, EAX ;Check for error on AllocExch\r
+ JNZ InitKBDSvcEnd ;YUP, we got bad problems\r
+\r
+ ;Requests for ReadkeyGlobal (SvcCode #3) wait here until we\r
+ ;get a global key from the keyboard.\r
+ ;\r
+ MOV EAX, OFFSET KbdGlobExch ;Alloc Global Wait exch for Kbd service\r
+ PUSH EAX\r
+ CALL FWORD PTR _AllocExch\r
+ OR EAX, EAX ;Check for error on AllocExch\r
+ JNZ InitKBDSvcEnd ;YUP, we got bad problems\r
+\r
+ ;Spawn the Keyboard Service task\r
+\r
+ MOV EAX, OFFSET KBDServiceTask\r
+ PUSH EAX\r
+ PUSH 7 ;Priority\r
+ PUSH 0 ;fDebug\r
+ MOV EAX, OFFSET KbdSvcStackTop\r
+ PUSH EAX\r
+ PUSH 1 ;OS Job task\r
+ CALL FWORD PTR _SpawnTask\r
+ OR EAX, EAX ;Check for error on AllocExch\r
+ JNZ InitKBDSvcEnd ;YUP, we got bad problems\r
+\r
+ MOV EAX, OFFSET KBDSvcName\r
+ PUSH EAX\r
+ PUSH KbdMainExch\r
+ CALL FWORD PTR _RegisterSvc\r
+InitKBDSvcEnd:\r
+ MOV BYTE PTR fKBDInitDone, 1 ;We're UP!\r
+ RETN\r
+;\r
+;=============================================================================\r
+;This tells the 8042 Controller to Disable the Keyboard device.\r
+;=============================================================================\r
+\r
+KbdDisable:\r
+ PUSH EAX\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ MOV AL,0ADh ;Set Command to "Write the 8042 Command Byte"\r
+ OUT COMMANDPORT,AL ;Send Command\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ POP EAX\r
+ RETN\r
+\r
+;=============================================================================\r
+; This tells the 8042 Controller to Enable the Keyboard Device.\r
+;=============================================================================\r
+\r
+KbdEnable:\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ MOV AL,0AEh ;Set Command to "Write the 8042 Command Byte"\r
+ OUT COMMANDPORT,AL ;Send Command\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ RETN\r
+;\r
+;=============================================================================\r
+; Waits until the 8042 Input Buffer is EMPTY\r
+;=============================================================================\r
+\r
+InBuffEmpty:\r
+ PUSH EAX\r
+ PUSH ECX\r
+ MOV ECX,2FFFFh ;check 128k times\r
+IBE:\r
+ JMP IBE1\r
+IBE1:\r
+ JMP IBE2\r
+IBE2:\r
+ IN AL,STATUSPORT ;Read Status Byte into AL\r
+ TEST AL,INPUTBUFFFULL ;Test The Input Buffer Full Bit\r
+ LOOPNZ IBE\r
+ POP ECX\r
+ POP EAX\r
+ RETN\r
+\r
+;=============================================================================\r
+; Waits until the 8042 Output Buffer is FULL so we can read it\r
+;=============================================================================\r
+;\r
+; Before calling this makes sure that the Keyboard interrupts have been\r
+; masked so the keyboard interrupt doesn't eat the byte you're\r
+; looking for!!\r
+;\r
+OutBuffFull:\r
+ PUSH EAX\r
+ PUSH ECX\r
+ MOV ECX,2FFFFh\r
+OBF:\r
+ JMP OBF1:\r
+OBF1:\r
+ JMP OBF2:\r
+OBF2:\r
+ IN AL,STATUSPORT ;Read Status Byte into AL\r
+ TEST AL,OUTPUTBUFFFULL ;Test The Output Buffer Full Bit\r
+ LOOPZ OBF\r
+ POP ECX\r
+ POP EAX\r
+ RETN\r
+\r
+;=============================================================================\r
+; This sets the indicators on the keyboard based on data in KbdState\r
+;=============================================================================\r
+\r
+SetKbdLEDs:\r
+ PUSH EAX\r
+\r
+ PUSH 1 ;KBD IRQ\r
+ CALL FWORD PTR _MaskIRQ\r
+\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ MOV AL,0EDh ;Set/Reset Status Indicators\r
+ OUT DATAPORT,AL ;Send KBD Command\r
+\r
+ CALL OutBuffFull ;Eat response\r
+ IN AL, DATAPORT\r
+\r
+ CALL InBuffEmpty ;Wait for Input Buffer to Empty\r
+ MOV AL,KbdLock ;Get Current Lock Status Byte\r
+ AND AL,00000111b ;Mask all but low order 3 bits\r
+ OUT DATAPORT,AL ;Send KBD Command\r
+\r
+ CALL OutBuffFull ;Eat response\r
+ IN AL, DATAPORT\r
+\r
+ PUSH 1 ;KBD IRQ\r
+ CALL FWORD PTR _UnMaskIRQ\r
+ POP EAX\r
+ RETN\r
+\r
+;================= END OF MODULE ==================\r