1 ; MMURTL Operating System Source Code
\r
2 ; Copyright 1991,1992,1993,1994,1995 Richard A. Burgess
\r
3 ; ALL RIGHTS RESERVED
\r
6 .DATA ;Begin Keyboard Data
\r
14 ;The keyboard service is designed to return the complete status
\r
15 ;of the keyboard shift, control, alt, and lock keys as well as
\r
16 ;the key in the buffer that the state applies to.
\r
18 ;This is done by using two buffers. The first is a "RAW" key buffer
\r
19 ;that holds keys from the interrupt service routine which contains
\r
20 ;all raw keystrokes including shift keys going up and down.
\r
21 ;This information is needed to build coherent keystroke information
\r
22 ; for an application. This buffer is 32 bytes long.
\r
24 ;The second buffer is 256 bytes and contains the translated information
\r
25 ;in the form of DWords (a 4 byte quantity times 64). This DWord contains the
\r
26 ;following information:
\r
28 ;Low byte (bits 0-7) Partially translated application keystroke
\r
29 ;Next byte (bits 8-15) Shift State (Ctrl, Shift, Alt)
\r
30 ;Next byte (bits 16-23) Lock State (CAPS, Num, Scroll)
\r
31 ;Hi Byte (bits 24-31) Key Source (Bit 1 Set = Key From Numeric Pad)
\r
33 KBDSvcName DB 'KEYBOARD'
\r
35 KbdMainExch DD 0 ;Used by the Kbd Process
\r
36 KbdHoldExch DD 0 ;Used for requestors that don't own the keyboard
\r
37 KbdGlobExch DD 0 ;Used to hold Global CTRL-ALT requests
\r
38 KbdWaitExch DD 0 ;Used for Kbd Wait-For-Key requests
\r
39 KbdTempExch DD 0 ;Used to rifle thru requests
\r
41 dGlobalKey DD 0 ;Global Key Found, else 0
\r
44 KbdMsgBuf1L DD 0 ;Message buffers for Kbd Service
\r
50 KbdOwner DD 1 ;Current owner of Kbd (Mon is default)
\r
51 KbdAbortJob DD 0 ;Job that is aborting
\r
52 KbdCancelJob DD 0 ;Job that is cancelling global request
\r
54 rgbKbdBuf DB 20h DUP (0) ;32 byte RAW buffer
\r
56 pKbdIn DD OFFSET rgbKbdBuf ;ptr to next char going in
\r
57 pKbdOut DD OFFSET rgbKbdBuf ;ptr to next char going out
\r
59 bKbdMode DB 0 ;ZERO for Cooked, 1 for RAW (testing)
\r
60 fKBDInitDone DB 0 ;Set true when KBD Service is up and running
\r
62 KbdState DB 0 ;(See State Masks below)
\r
63 KbdLock DB 0 ;(See Lock Masks below)
\r
65 rgdKBBuf DD 40h DUP (0) ;64 Dwords for translated key buffer
\r
67 pKBIn DD OFFSET rgdKBBuf ;ptr to codes comming in
\r
68 pKBOut DD OFFSET rgdKBBuf ;ptr to codes going out
\r
70 ; These "masks" are for keyboard states that change with special keys:
\r
71 ; They are BIT OFFSETS and NOT MASKS for logical operations!!!!!
\r
80 ; Mask to tell if one of the 3 states exist (Ctrl, Shift, Alt)
\r
81 CtrlDownMask EQU 00000011b
\r
82 ShftDownMask EQU 00001100b
\r
83 AltDownMask EQU 00110000b
\r
90 CpLockMask DB 00000100b
\r
91 NmLockMask DB 00000010b
\r
92 ScLockMask DB 00000001b
\r
95 ; The following special keys are processed by the Keyboard Task and handled
\r
97 ; NUMLOCK - Lights NumLock LED and processes keys accordingly
\r
98 ; SHIFT - Sets shift flag and processes keys accordingly
\r
99 ; CTRL - Sets Ctrl flag
\r
100 ; CAPSLOCK - Lights CapsLock LED and processes keys accordingly
\r
101 ; ALT - Sets Alt flag.
\r
102 ; SCRLLOCK - Lights ScrollLock LED and flag
\r
104 ; This table is used to translate all active editing keys from
\r
105 ; the raw value provided by the hardware.
\r
111 DB 031h ; 1 02 21h !
\r
112 DB 032h ; 2 03 40h @
\r
113 DB 033h ; 3 04 23h #
\r
114 DB 034h ; 4 05 24h $
\r
115 DB 035h ; 5 06 25h %
\r
116 DB 036h ; 6 07 5Eh ^
\r
117 DB 037h ; 7 08 26h &
\r
118 DB 038h ; 8 09 2Ah *
\r
119 DB 039h ; 9 0A 28h (
\r
120 DB 030h ; 0 0B 29h )
\r
121 DB 02Dh ; - 0C 5Fh _
\r
122 DB 03Dh ; = 0D 2Bh +
\r
138 DB 0h ; LCtrl 1D Special handling
\r
147 DB 06Ch ; l (L) 26 4Ch
\r
151 DB 0h ; LfShf 2A Special handling
\r
163 DB 0h ; RtShf 36 Special handling
\r
164 DB 02Ah ; Num * 37 Num pad
\r
165 DB 0h ; LAlt 38 Special handling
\r
167 DB 0h ; CpsLk 3A Special handling
\r
178 DB 0h ; NumLk 45 Special handling
\r
179 DB 0h ; ScrLk 46 Special handling
\r
180 DB 086h ; Num 7 47 37h Num Home
\r
181 DB 081h ; Num 8 48 38h Num Up
\r
182 DB 085h ; Num 9 49 39h Num Pg Up
\r
183 DB 0ADh ; Num - 4A Num Pad
\r
184 DB 083h ; Num 4 4B 34h Num Left
\r
185 DB 09Fh ; Num 5 4C 35h Num (Extra code)
\r
186 DB 084h ; Num 6 4D 36h Num Right
\r
187 DB 0ABh ; Num + 4E Num Pad
\r
188 DB 08Bh ; Num 1 4F 31h Num End
\r
189 DB 082h ; Num 2 50 32h Num Down
\r
190 DB 08Ch ; Num 3 51 33h Num Pg Dn
\r
191 DB 08Eh ; Num 0 52 30h Num Insert
\r
192 DB 0FFh ; Num . 53 2Eh Num Del
\r
193 DB 01Ch ; Pr Scr 54 SYS REQUEST
\r
204 DB 000h ; 5F ;The following chars are subs from table2
\r
205 DB 00Eh ; Ins 60 Cursor pad
\r
206 DB 00Bh ; End 61 Cursor pad
\r
207 DB 002h ; Down 62 Cursor pad
\r
208 DB 00Ch ; PgDn 63 Cursor pad
\r
209 DB 003h ; Left 64 Cursor pad
\r
211 DB 004h ; Right 66 Cursor pad
\r
212 DB 006h ; Home 67 Cursor pad
\r
213 DB 001h ; Up 68 Cursor pad
\r
214 DB 005h ; PgUp 69 Cursor pad
\r
215 DB 07Fh ; Delete 6A Cursor pad
\r
216 DB 0AFh ; / 6B Num Pad
\r
217 DB 08Dh ; ENTER 6C Num Pad
\r
238 ;This table does an initial character translation from the characters
\r
239 ;provided by the keyboard. The Kbd translates incoming keystrokes
\r
240 ;from the original scan set 2 for the IBM PC. All PCs are are set to this
\r
241 ;by default. Keys on the 101 keyboard that were common to the numeric
\r
242 ;keypad use a two character escape sequence begining with E0 hex.
\r
243 ;If we see an E0 hex we scan this table and provide the translation
\r
244 ;to another unique character which is looked up in the primary
\r
245 ;table above. This gives us unique single characters for every key.
\r
249 KbdTable2 DB 052h, 060h ;Insert
\r
251 DB 050h, 062h ;Down
\r
252 DB 051h, 063h ;Pg Down
\r
253 DB 04Bh, 064h ;Left
\r
254 DB 04Dh, 066h ;Rite
\r
255 DB 047h, 067h ;Home
\r
257 DB 049h, 069h ;Pg Up
\r
258 DB 053h, 06Ah ;Delete
\r
260 DB 037h, 06Bh ;Num /
\r
261 DB 01Ch, 06Ch ;Num ENTER
\r
263 DB 038h, 070h ;Right ALT DOWN These are special cause we
\r
264 DB 01Dh, 071h ;Right Ctrl DOWN track UP & DOWN!!!
\r
265 DB 0B8h, 0F0h ;Right ALT UP
\r
266 DB 09Dh, 0F1h ;Right Ctrl UP
\r
269 ;This table provides shift level values for codes from the primary KbdTable.
\r
270 ;In Shift-ON state, keycodes 21 - 7E hex are translated through this table.
\r
271 ;In CAPS LOCK state, codes 61h to 7Ah are translated through this table
\r
272 ;In NUM LOCK state, codes with High Bit set are translated
\r
276 DB 38h ; 01 Up 8 Numeric pad
\r
277 DB 32h ; 02 Dn 2 Numeric pad
\r
278 DB 34h ; 03 Left 4 Numeric pad
\r
279 DB 36h ; 04 Rite 6 Numeric pad
\r
280 DB 39h ; 05 PgUp 9 Numeric pad
\r
281 DB 37h ; 06 Home 7 Numeric pad
\r
286 DB 31h ; 0B End 1 Numeric Pad
\r
287 DB 33h ; 0C PgDn 3 Numeric pad
\r
289 DB 30h ; 0E Ins 0 Numeric pad
\r
306 DB 35h ; 1F Blnk 5 Numeric pad
\r
402 DB 2Eh ; 7F Del . Numeric Pad
\r
405 KbdSvcStack DD 255 DUP(0) ;1024 byte stack for KbsSvc
\r
406 KbdSvcStackTop DD 0
\r
408 ;=============================================================================
\r
409 ;The following equates are for the hardware handling code.
\r
410 ;8042 Status Byte, Port Hex 0064 Read
\r
411 ;=============================================================================
\r
414 COMMANDPORT EQU 64h
\r
417 PARITYERROR EQU 10000000b
\r
418 GENERALTIMEOUT EQU 01000000b
\r
419 AUXOUTBUFFFULL EQU 00100000b
\r
420 INHIBITSWITCH EQU 00010000b
\r
421 COMMANDDATA EQU 00001000b
\r
422 SYSTEMFLAG EQU 00000100b
\r
423 INPUTBUFFFULL EQU 00000010b
\r
424 OUTPUTBUFFFULL EQU 00000001b
\r
427 ;==================Begin Keyboard Code ===================
\r
432 ;ISR for the keyboard. This is vectored to by the processor whenever
\r
433 ;INT 21 fires off. This puts the single byte from the 8042
\r
434 ;KBD processor into the buffer. Short and sweet the way all ISRs
\r
435 ;should be... (most are not this easy though). This also sends
\r
436 ;a message to the KBD Task (using ISend) when the buffer is almost
\r
437 ;full so it will be forced to process some of the raw keys even
\r
438 ;if no keyboard requests are waiting.
\r
440 PUBLIC IntKeyBrd: ;Key Board (KB) INT 21
\r
441 PUSHAD ;Save all registers
\r
442 MOV ESI, pKbdIn ;Set up pointer
\r
444 IN AL, 60h ;Read byte
\r
445 MOV EBX, dKbdCnt ;See if buffer full
\r
446 CMP EBX, 20h ;Buffer size
\r
447 JE KbdEnd ;Buffer is full - Don't save it
\r
448 MOV BYTE PTR [ESI], AL ;Move into buf
\r
449 INC dKbdCnt ;One more in the buf
\r
450 INC ESI ;Next byte in
\r
451 CMP ESI, OFFSET rgbKbdBuf+20h ;past end yet?
\r
453 MOV ESI, OFFSET rgbKbdBuf ;Back to beginning of buffer
\r
455 MOV pKbdIn, ESI ;Set up pointer for next time
\r
457 CMP BYTE PTR fKBDInitDone, 0 ;Service isn't ready for messages yet
\r
460 ;ISend a msg to Keyboard task
\r
461 MOV EBX, KbdMainExch ;Yes - ISend Message to KbdTask
\r
462 PUSH EBX ;exchange to send to
\r
463 PUSH 0FFFFFFFFh ;bogus msg
\r
464 PUSH 0FFFFFFFFh ;bogus msg
\r
465 CALL FWORD PTR _ISendMsg ;tell him to come and get it...
\r
468 CALL FWORD PTR _EndOfIRQ
\r
472 ;===============================================
\r
473 ;This gets one byte from the Kbd Buffer and returns it in AL
\r
474 ;Zero is returned if no key exists.
\r
478 MOV ESI, pKbdOut ;Get ptr to next char to come out
\r
479 MOV EAX, dKbdCnt ;See if there are any bytes
\r
481 JE RdKBDone ;No - Leave 0 in EAX
\r
482 DEC dKbdCnt ;Yes - make cnt right
\r
484 MOV AL, BYTE PTR [ESI] ;Put byte in AL
\r
486 CMP ESI, OFFSET rgbKbdBuf+20h ;past end yet?
\r
488 MOV ESI, OFFSET rgbKbdBuf ;Back to beginning of buffer
\r
490 MOV pKbdOut, ESI ;Save ptr to next char to come out
\r
494 ;========================================================
\r
496 ; Reads and processes all bytes from the RAW keyboard buffer
\r
497 ; and places them and their proper state bytes and into the next DWord
\r
498 ; in the translated buffer if it is an edit key.
\r
505 MOV BL, bKbdMode ;See if we are RAW... (for testing ONLY)
\r
507 JNE KB001 ;NO - keep going
\r
508 JMP KB029A ;Yes, leave the key in AL for buffer
\r
510 ;Now we check to see if the byte is 0Eh which tells us
\r
511 ;this is a two key code that needs to be translated from
\r
512 ;our special table before processing. This turns the
\r
513 ;two key code into a single code and sets a state
\r
514 ;bit to indicate this.
\r
519 CMP AL, 0E0h ;Key PREFIX???
\r
521 MOV dfPrefix, 1 ;Yes, We got an E0
\r
525 MOV dfPrefix, 0 ;No prefix
\r
526 MOV ESI, OFFSET KbdTable2
\r
527 MOV ECX, nKbdTable2
\r
529 CMP BYTE PTR [ESI], AL
\r
531 INC ESI ;Two byte further into table 2
\r
534 JNZ KB004 ;Go to next table entry
\r
535 JMP XLateDone ;No translation - ignore it
\r
538 INC ESI ;One byte further over to get Xlate byte
\r
540 MOV AL, [ESI] ;Fall thru to check on char...
\r
542 ;This next section checks for special keys (shift, alt, etc.)
\r
543 ;BL has SHIFT state, CL has LOCK State, AL has byte from buffer.
\r
546 MOV dfPrefix, 0 ;No prefix
\r
549 MOV BL, KbdState ;BL has Shift, Alt, Ctrl states
\r
550 MOV CL, KbdLock ;BH has Num, Caps, & Scroll Lock
\r
552 CMP AL, 45h ;Key = NumLock ?
\r
554 BTC ECX, NmLockBit ;Compliment bit
\r
557 CMP AL, 3Ah ;Caps Lock?
\r
559 BTC ECX, CpLockBit ;Compliment bit in BH
\r
562 CMP AL, 46h ;Scroll Lock?
\r
564 BTC ECX, ScLockBit ;Compliment bit in BH
\r
567 CMP AL, 2Ah ;Char Left Shift On?
\r
569 BTS EBX, ShftLeftBit
\r
572 CMP AL, 36h ;Right Shift On?
\r
574 BTS EBX, ShftRiteBit
\r
577 CMP AL, 0AAh ;Left Shift Off?
\r
579 BTR EBX, ShftLeftBit
\r
583 CMP AL, 0B6h ;Right Shift Off?
\r
585 BTR EBX, ShftRiteBit
\r
589 CMP AL, 1Dh ;Left Ctrl On?
\r
591 BTS EBX, CtrlLeftBit
\r
595 CMP AL, 71h ;Right Ctrl On?
\r
597 BTS EBX, CtrlRiteBit
\r
601 CMP AL, 09Dh ;Left Ctrl Off?
\r
603 BTR EBX, CtrlLeftBit
\r
607 CMP AL, 0F1h ;Right Ctrl Off?
\r
609 BTR EBX, CtrlRiteBit
\r
612 CMP AL, 38h ;Left Alt On?
\r
614 BTS EBX, AltLeftBit
\r
617 CMP AL, 70h ;Right Alt On?
\r
619 BTS EBX, AltRiteBit
\r
622 CMP AL, 0B8h ;Left Alt Off?
\r
624 BTR EBX, AltLeftBit
\r
627 CMP AL, 0F0h ;Right Alt Off?
\r
629 BTR EBX, AltRiteBit
\r
631 MOV KbdState, BL ;Put Kbd Shift State back
\r
634 MOV KbdLock, CL ;Put Kbd Lock State back
\r
635 CALL SetKbdLEDS ;Set LEDs on keyboard
\r
638 ;We jumped here if it wasn't a key that is specially handled
\r
641 TEST AL, 80h ;Check for high bit (key-up code)
\r
642 JNZ XLateDone ;Go back, else fall through
\r
644 OR AL,AL ;Zero not a valid code
\r
645 JZ XLateDone ;Go back, else fall through
\r
647 ;If we got here, IT'S AN EDIT KEY DOWN!
\r
648 ;Now we lookup the code and do a single translation.
\r
650 AND EAX, 07Fh ;Chop off any upper bit junk
\r
651 MOV ESI, OFFSET KbdTable ;Set up to index table
\r
652 MOV DL, BYTE PTR [ESI+EAX] ;Save in DL
\r
653 OR AL,AL ;Zero not a valid code
\r
654 JZ XLateDone ;Go back, else fall through
\r
656 MOV CL, KbdState ;Get Shift state
\r
657 MOV CH, KbdLock ;Get lock state
\r
659 ;TO let the user know if the key came from the Numeric
\r
660 ;keypad we set the high bits in the first translation
\r
661 ;table for these keys. This next piece of code tests for it
\r
662 ;and sets the low bit in DH if it its. DH is later moved
\r
663 ;into the high byte of the returned key code.
\r
666 TEST DL, 80h ;High bit set?
\r
668 MOV DH, 1 ;Indicates key came numeric pad
\r
670 ;See if shift key is down and shift all keys it is is
\r
672 TEST CL, ShftDownMask ;Either shift key down?
\r
673 JZ KB025 ;No, go look for locks
\r
674 CMP DL, 21h ;Is key < ' '
\r
675 JB KB025 ;Yes, look for locks
\r
676 CMP DL, 7Eh ;Is key > '~'
\r
677 JA KB025 ;Yes, look for locks
\r
678 JMP SHORT KB027 ;In-range, go do the translation
\r
680 KB025: ;See if key is from Numerc Keypad (high bit will be set)
\r
682 TEST DL, 80h ;High bit set?
\r
684 AND CH, NmLockMask ;Yes, is NumLock ON
\r
686 CMP DL, 0ADh ;Yes, but don't shift DASH (-) Special Case
\r
688 JMP SHORT KB027 ;Do the shift Xlation
\r
690 KB026: ;See if Caps Lock is on and if key is between 61h and 7Ah
\r
691 ;do the translation
\r
693 TEST CH, CpLockMask ;Is CpLock ON
\r
695 CMP DL, 61h ;Is key >= 'a'
\r
697 CMP DL, 7Ah ;Is key <= 'z'
\r
699 ;Fall through to do the translation
\r
701 KB027: ;Do the shift translation and leave in DL
\r
702 MOV AL, DL ;Put in AL
\r
703 AND EAX, 07Fh ;Chop all above 7 bits
\r
704 MOV ESI, OFFSET KbdTableS ;Set up to index table
\r
705 MOV DL, BYTE PTR [ESI+EAX] ;Save in DL
\r
706 ;Fall though to put key in final buffer
\r
708 ;Place DL in the LOW byte of the DWord to go into the
\r
709 ;final buffer (the data the user will get)
\r
710 ;If the high bit is set coming from the primary
\r
711 ;translation table, this means the key was from the
\r
712 ;numeric keypad so we set the numpad bit in status
\r
713 ;which should already be in DH
\r
716 SHL EAX, 8 ;Num Pad indicator
\r
717 MOV AL, KbdState ;Get Shift state
\r
718 MOV AH, KbdLock ;Get lock state
\r
720 AND DL, 7Fh ;Lop of high bit (if there)
\r
723 ;EAX now has the buffered info for the user (Key, Shifts & Locks)
\r
724 ;Now we put it in the DWord buffer if it is NOT a GLOBAL.
\r
725 ;If global, we put it in dGlobalKey.
\r
727 TEST AH, CtrlDownMask ;Either Ctrl Down?
\r
729 TEST AH, AltDownMask ;Either Alt Down?
\r
732 ;It IS a global key request!
\r
733 MOV dGlobalKey, EAX ;Save it
\r
734 JMP XLateRawKBD ;Back for more (if there is any)
\r
737 MOV EBX, dKBCnt ;See if buffer full
\r
738 CMP EBX, 64 ;number of DWords in final buffer
\r
739 JE XLateDone ;Buffer is FULL..
\r
740 MOV ESI, pKBIn ;Get ptr to next IN to final buffer
\r
741 MOV [ESI], EAX ;Move into buf
\r
742 INC dKBCnt ;One more DWord in the buf
\r
744 CMP ESI, OFFSET rgdKBBuf+100h ;40h * 4
\r
746 MOV ESI, OFFSET rgdKBBuf ;Reset to buf beginning
\r
748 MOV pKBIn, ESI ;Save ptr to next in
\r
754 ;========================================================
\r
756 ; Returns a keyboard code from FINAL keyboard buffer.
\r
757 ; Returns zero in EAX if buffer is empty.
\r
760 ; OUT: EAX has Key or 0 if none
\r
762 ; MODIFIES: dKBCnt, pKBOut
\r
767 JE KBFDone ;Nothing final buffer
\r
768 DEC dKBCnt ;One more DWord in the buf
\r
769 MOV ESI, pKBOut ;ptr to next code out
\r
770 MOV EAX, [ESI] ;Put it in EAX
\r
771 ADD ESI, 4 ;Next code please...
\r
772 CMP ESI, OFFSET rgdKBBuf+100h ;Past end of buff?
\r
774 MOV ESI, OFFSET rgdKBBuf ;Yes, Reset to beginning
\r
776 MOV pKBOut, ESI ;Update pKBOut
\r
780 ;========================================================
\r
782 ; This is the keyboard Service task. It is an infinite loop
\r
783 ; that services requests from users of the keyboard. It
\r
784 ; calls XLateRawKBD to process raw keyboard buffer data,
\r
785 ; and waits at the KeyBoard Service Main Exchange for users.
\r
786 ; When it gets a request it checks the service code and handles
\r
790 CALL XLateRawKBD ;Processes RAW buffer if not empty
\r
792 CMP DWORD PTR dGlobalKey, 0
\r
793 JE KST01 ;No global key came in
\r
796 PUSH OFFSET KbdMsgBuf1L ;Where to return pRqBlk
\r
797 CALL FWORD PTR _CheckMsg ;Check to see if RqWaiting
\r
798 OR EAX, EAX ;Yes if ZERO
\r
799 JZ KBDGlobal2 ;Rq waiting for global
\r
800 MOV DWORD PTR dGlobalKey, 0 ;Wipe out global key (no one wants it)
\r
801 JMP KBDServiceTask ;Start over again
\r
804 MOV EBX, KbdMsgBuf1L ;pRqBlk into EBX
\r
805 MOV ESI, [EBX+pData1] ;Ptr where to return key
\r
806 OR ESI, ESI ;Is it null?? (Bad news if so)
\r
807 JNZ KBDGlobal3 ;No, probably good ptr
\r
808 PUSH EBX ;Yes, BAD PTR. Push pRqBlk
\r
809 PUSH ErcNullPtr ;Push error
\r
810 CALL FWORD PTR _Respond
\r
811 JMP KBDServiceTask ;Go back to the top
\r
813 MOV EDX, dGlobalKey
\r
814 MOV [ESI], EDX ;Give em the key!
\r
815 PUSH EBX ;Push pRqBlk
\r
816 PUSH 0 ;Push NO ERROR
\r
817 CALL FWORD PTR _Respond
\r
818 JMP KBDGlobal1 ;Go back to see if others want it
\r
821 CMP DWORD PTR ddVidOwner, 2 ;Debugger has video
\r
822 JNE KST01ND ;NOT in Debugger
\r
824 CALL FWORD PTR _Sleep ;
\r
825 CALL XLateRawKBD ;Processes RAW buffer
\r
826 JMP KBDServiceTask ;Go back to the top
\r
829 PUSH KbdMainExch ;See if someones "Requesting"
\r
830 PUSH OFFSET KbdMsgBuf1L ;
\r
831 CALL FWORD PTR _WaitMsg ;Wait for the message
\r
833 ;If we got here, we have a Request or a Msg the from ISR
\r
835 CMP DWORD PTR KbdMsgBuf1L, 0FFFFFFFFh ;Is it a msg from the KBD ISR?
\r
836 JNE KST02 ;No, jump to handle Request
\r
838 ;If we got here, ISR sent msg to us (something in the buffer)
\r
840 CALL XLateRawKBD ;Processes RAW buffer
\r
842 CMP DWORD PTR dGlobalKey, 0
\r
843 JNE KBDGlobal1 ;A global key came in
\r
845 PUSH KbdWaitExch ;See if owner is waiting for a key
\r
846 PUSH OFFSET KbdMsgBuf1L ;Where to return Request or msg
\r
847 CALL FWORD PTR _CheckMsg ;
\r
849 JNZ KBDServiceTask ;No Rq/Msg waiting, Go back to the top,
\r
850 ;or fall thru to check the request
\r
853 ;If we got here we've got a Request from Main or Wait Exch
\r
854 MOV EBX, KbdMsgBuf1L ;pRqBlk into EBX
\r
855 MOV CX, [EBX+ServiceCode] ;Save in CX
\r
857 CMP CX, 0 ;Job Abort Notify
\r
861 CMP CX, 2 ;ReadKbdGlobal
\r
863 CMP CX, 3 ;CancelGlobal
\r
864 JE KSTCancelGlobal ;
\r
865 CMP CX, 4 ;AssignKBD
\r
867 PUSH EBX ;HOMEY DON'T SERVICE THAT!
\r
868 PUSH ErcBadSvcCode ;Bad service code
\r
869 CALL FWORD PTR _Respond
\r
870 JMP KBDServiceTask ;Go back to the top
\r
872 ;-------------------------------------------------------
\r
874 MOV EAX, [EBX+RqOwnerJob] ;Whose Request is it?
\r
876 JE KSTRead00 ;This guy owns it!
\r
877 PUSH EBX ;Not the owner, so send to Hold Exch
\r
879 CALL FWORD PTR _MoveRequest
\r
880 JMP KBDServiceTask ;Go back to the top
\r
882 CALL ReadKBFinal ;Get Code from Buf (Uses EAX, ESI)
\r
883 CMP EAX, 0 ;No Key in Final Buffer
\r
884 JE KSTRead02 ;Go see if they asked to wait
\r
885 MOV ESI, [EBX+pData1] ;Ptr where to return key
\r
886 CMP ESI, 0 ;Is it null?? (Bad news if so)
\r
887 JNE KSTRead01 ;No, probably good ptr
\r
888 PUSH EBX ;Yes, BAD PTR. Push pRqBlk
\r
889 PUSH ErcNullPtr ;Push error
\r
890 CALL FWORD PTR _Respond
\r
891 JMP KBDServiceTask ;Go back to the top
\r
893 MOV [ESI], EAX ;Give them the key code
\r
896 CALL FWORD PTR _Respond
\r
897 JMP KBDServiceTask ;Go back to the top
\r
900 CMP DWORD PTR [EBX+dData0], 0 ;Wait for key? 0 in dData0 = Don't wait
\r
903 PUSH ErcNoKeyAvail ;Error Code (No key to give you)
\r
904 CALL FWORD PTR _Respond
\r
905 JMP KBDServiceTask ;Go back to the top
\r
908 PUSH EBX ;They opted to wait for a key
\r
909 PUSH KbdWaitExch ;Send em to the wait exch
\r
910 CALL FWORD PTR _MoveRequest
\r
911 JMP KBDServiceTask ;Go back to the top
\r
912 ;--------------------------------------------------------
\r
915 ;Respond to all requests we are holding for Job in dData0
\r
916 ;with Erc with ErcOwnerAbort. Then respond to Abort
\r
917 ;request last. Requests can be at the HoldExch, the WaitExch,
\r
918 ;or the GlobalKeyExch. We must chack all 3!
\r
919 ;Save abort job for comparison
\r
921 MOV EAX, [EBX+dData0] ;Get aborting job number
\r
922 MOV KbdAbortJob, EAX ;this is aborting job
\r
924 KSTAbort10: ;Check the WaitExch
\r
925 PUSH KbdWaitExch ;See if he was "waiting" for a key
\r
926 PUSH OFFSET KbdMsgBuf2L ;Where to return Request
\r
927 CALL FWORD PTR _CheckMsg ;
\r
928 OR EAX, EAX ;Yes (someone's waiting) if ZERO
\r
929 JNZ KSTAbort20 ;No more waiters
\r
930 MOV EDX, KbdMsgBuf2L ;pRq of holding job into EDX
\r
931 MOV EBX, [EDX+RqOwnerJob]
\r
932 CMP EBX, KbdAbortJob
\r
933 JE KSTAbort11 ;Go to respond with Erc
\r
934 PUSH EDX ;Else move Request to MainKbd Exch
\r
935 PUSH KbdMainExch ; to be reevaluated
\r
936 CALL FWORD PTR _MoveRequest
\r
937 JMP KSTAbort10 ;Go back to look for more waiters
\r
939 PUSH EDX ;Respond to this request
\r
940 PUSH ErcOwnerAbort ;cause he's dead
\r
941 CALL FWORD PTR _Respond
\r
942 JMP SHORT KSTAbort10
\r
944 KSTAbort20: ;Check HoldExch for dead job
\r
945 PUSH KbdHoldExch ;See if anyone is on hold
\r
946 PUSH OFFSET KbdMsgBuf2L ;Where to return Request
\r
947 CALL FWORD PTR _CheckMsg ;
\r
948 OR EAX, EAX ;Yes (someones holding) if ZERO
\r
949 JNZ KSTAbort30 ;No more holders
\r
950 MOV EDX, KbdMsgBuf2L ;pRq of holding job into EDX
\r
951 MOV EBX, [EDX+RqOwnerJob]
\r
952 CMP EBX, KbdAbortJob
\r
953 JE KSTAbort21 ;Go to respond with Erc
\r
954 PUSH EDX ;Else move Request to MainKbd Exch
\r
955 PUSH KbdMainExch ; to be reevaluated. It's not him.
\r
956 CALL FWORD PTR _MoveRequest
\r
957 JMP KSTAbort20 ;Go back to look for more holders
\r
959 PUSH EDX ;Respond to this request
\r
960 PUSH ErcOwnerAbort ;cause he's dead
\r
961 CALL FWORD PTR _Respond
\r
962 JMP SHORT KSTAbort20 ;Go back to look for more holders
\r
964 KSTAbort30: ;Check GlobalExch for dead job
\r
965 PUSH KbdGlobExch ;See if anyone is at global
\r
966 PUSH OFFSET KbdMsgBuf2L ;Where to return Request
\r
967 CALL FWORD PTR _CheckMsg ;
\r
968 OR EAX, EAX ;Yes (someones holding) if ZERO
\r
969 JNZ KSTAbort40 ;No more holders
\r
970 MOV EDX, KbdMsgBuf2L ;pRq of holding job into EDX
\r
971 MOV EBX, [EDX+RqOwnerJob]
\r
972 CMP EBX, KbdAbortJob
\r
973 JE KSTAbort31 ;Go to respond with Erc
\r
974 PUSH EDX ;Else move Request to MainKbd Exch
\r
975 PUSH KbdMainExch ; to be reevaluated
\r
976 CALL FWORD PTR _MoveRequest
\r
977 JMP KSTAbort30 ;Go back to look for more globals
\r
979 PUSH EDX ;Respond to this request
\r
980 PUSH ErcOwnerAbort ;cause he's dead
\r
981 CALL FWORD PTR _Respond
\r
982 JMP SHORT KSTAbort30
\r
984 KSTAbort40: ;Respond to original abort Req
\r
985 MOV EBX, KbdMsgBuf1L ;pRqBlk of original Abort Request
\r
987 PUSH 0 ;Error Code (OK)
\r
988 CALL FWORD PTR _Respond
\r
989 JMP KBDServiceTask ;Go back to the top
\r
990 ;----------------------------------------------------------
\r
993 PUSH EBX ;They want a global key
\r
994 PUSH KbdGlobExch ;Send em to the Global exch
\r
995 CALL FWORD PTR _MoveRequest
\r
996 JMP KBDServiceTask ;Go back to the top
\r
997 ;-----------------------------------------------------------
\r
998 ;Assign a new owner for the keyboard. We must check to see
\r
999 ;if the new owner had any keyboard requests on hold.
\r
1000 ;We do this by sending all the requests that were on hold
\r
1001 ;back to the main exchange to be reevaluated.
\r
1002 ;Then we respond to the original request.
\r
1005 ;Change owner of Kbd
\r
1006 MOV EAX, [EBX+dData0] ;Get new owner
\r
1008 JNE KSTAssign01 ;New Owner!
\r
1010 PUSH EBX ;Same owner
\r
1011 PUSH 0 ;Error Code (OK)
\r
1012 CALL FWORD PTR _Respond
\r
1013 JMP KBDServiceTask ;Go back to the top
\r
1015 MOV KbdOwner, EAX ;Set new owner
\r
1017 KSTAssign02: ;Move all waiters to main exch
\r
1018 PUSH KbdWaitExch ;See if anyone is "waiting" for a key
\r
1019 PUSH OFFSET KbdMsgBuf2L ;Where to return Request
\r
1020 CALL FWORD PTR _CheckMsg ;
\r
1021 OR EAX, EAX ;Yes (someones waiting) if ZERO
\r
1022 JNZ KSTAssign03 ;No more waiters
\r
1023 MOV EDX, KbdMsgBuf2L ;pRq into EDX
\r
1024 PUSH EDX ;Move Request to MainKbd Exch
\r
1025 PUSH KbdMainExch ; to be reevaluated
\r
1026 CALL FWORD PTR _MoveRequest
\r
1027 JMP KSTAssign02 ;Go back to look for more waiters
\r
1028 KSTAssign03: ;Waiter have been moved, Respond to Req
\r
1029 PUSH KbdHoldExch ;See if anyone is on hold
\r
1030 PUSH OFFSET KbdMsgBuf2L ;Where to return Request
\r
1031 CALL FWORD PTR _CheckMsg ;
\r
1032 OR EAX, EAX ;Yes if ZERO
\r
1033 JNZ KSTAssign04 ;No more holders
\r
1034 MOV EDX, KbdMsgBuf2L ;pRq into EDX
\r
1035 PUSH EDX ;Move Request to MainKbd Exch
\r
1036 PUSH KbdMainExch ; to be reevaluated
\r
1037 CALL FWORD PTR _MoveRequest
\r
1038 JMP KSTAssign03 ;Go back to look for more holders
\r
1039 KSTAssign04: ;Holders have been moved, Respond to Req
\r
1040 MOV EBX, KbdMsgBuf1L ;pRqBlk of original Assign Request
\r
1042 PUSH 0 ;Error Code (OK)
\r
1043 CALL FWORD PTR _Respond
\r
1044 JMP KBDServiceTask ;Go back to the top
\r
1045 ;-------------------------------------------------------
\r
1048 ;Rifle thru Global Exch and respond with ErcNoKeyAvail
\r
1049 ;to those with the same JobNum as dData0
\r
1050 MOV EAX, [EBX+dData0] ;Save Job that is cancelling global request
\r
1051 MOV KbdCancelJob, EAX ;
\r
1053 KSTCancel10: ;Check GlobalExch for canceled job
\r
1054 PUSH KbdGlobExch ;See if anyone is at global
\r
1055 PUSH OFFSET KbdMsgBuf2L ;Where to return Request
\r
1056 CALL FWORD PTR _CheckMsg ;
\r
1057 OR EAX, EAX ;Yes (someones holding) if ZERO
\r
1058 JNZ KSTCancel20 ;No more globals
\r
1059 MOV EDX, KbdMsgBuf2L ;pRq of holding job into EDX
\r
1060 MOV EBX, [EDX+RqOwnerJob]
\r
1061 CMP EBX, KbdCancelJob
\r
1062 JE KSTCancel11 ;Go to respond with Erc
\r
1063 PUSH EDX ;Else move Request to MainKbd Exch
\r
1064 PUSH KbdMainExch ; to be reevaluated
\r
1065 CALL FWORD PTR _MoveRequest
\r
1066 JMP KSTCancel10 ;Go back to look for more globals
\r
1068 PUSH EDX ;Respond to this request
\r
1069 PUSH ErcNoKeyAvail ;cause he cancelled it!
\r
1070 CALL FWORD PTR _Respond
\r
1071 JMP SHORT KSTCancel10 ;Back to check for more
\r
1073 KSTCancel20: ;Respond to original cancel Req
\r
1074 MOV EBX, KbdMsgBuf1L ;pRqBlk of original Request
\r
1076 PUSH 0 ;Error Code (OK)
\r
1077 CALL FWORD PTR _Respond
\r
1078 JMP KBDServiceTask ;Go back to the top
\r
1080 ;=============================================================
\r
1081 ;PUBLIC blocking call to read the keyboard. This uses the
\r
1082 ;Default TSS exchange and the stack to make the request to
\r
1083 ;the keyboard service for the caller. The request is a standard
\r
1084 ;service code one (Wait On Key) request.
\r
1085 ;If fWait is NON-ZERO, this will not return without a key unless
\r
1086 ;a kernel/fatal error occurs.
\r
1088 ;The call is fully reentrant (it has to be...).
\r
1090 ; Procedural interface:
\r
1092 ; ReadKbd(pKeyCodeRet, fWait): dError
\r
1094 ; pKeyCodeRet is a pointer to a DWORD where the keycode is returned.
\r
1096 ; fWait is NON-ZERO to wait for a key.
\r
1099 ; Stack Variables:
\r
1103 PUSH EBP ; Save the Previous FramePtr
\r
1104 MOV EBP,ESP ; Set up New FramePtr
\r
1105 SUB ESP, 4 ; One DWORD local var
\r
1107 MOV EAX, OFFSET KBDSvcName ;'KEYBOARD '
\r
1110 PUSH 1 ;Service Code (Read Keyboard)
\r
1112 MOV ECX,pRunTSS ;Get TSS_Exch for our use
\r
1113 MOV EBX,[ECX+TSS_Exch] ;Exchange (TSS Exch)
\r
1116 LEA EAX, [EBP-4] ;Rq Handle (Local Var)
\r
1120 MOV EAX, [EBP+16] ;Key Code return (Their Ptr)
\r
1122 PUSH 4 ;Size of key code
\r
1127 CMP DWORD PTR [EBP+12], 0 ;Don't wait for Key?
\r
1128 JE ReadKbd1 ;No wait
\r
1129 MOV EAX, 1 ;Set up to wait!
\r
1131 PUSH EAX ;Wait value (dData0)
\r
1136 CALL FWORD PTR _Request ;make the Request
\r
1138 ;The request is made. Now we call Wait!
\r
1140 MOV ECX,pRunTSS ;Get TSS_Exch for our use
\r
1141 MOV EBX,[ECX+TSS_Exch] ;
\r
1142 PUSH EBX ;Pass exchange (for WaitMsg)
\r
1143 ADD ECX,TSS_Msg ;Offset of TSS msg area
\r
1145 CALL FWORD PTR _WaitMsg ;Wait on it
\r
1147 ;When we get here the caller should have the key code
\r
1148 ;HOWEVER, we want to pass any errors back via EAX
\r
1150 OR EAX, EAX ;Was there a kernel error?
\r
1151 JNZ ReadKbdEnd ;YES.... bummer
\r
1152 MOV ECX,pRunTSS ;Get TSS_Msg area so we can get error
\r
1153 ADD ECX,TSS_Msg ;Offset of TSS msg area
\r
1154 MOV EBX, [ECX] ;pRqBlk
\r
1155 MOV EAX, [ECX+4] ;Service error in second DWord
\r
1159 RETF 8 ; Rtn to Caller & Remove Params from stack
\r
1161 ;=============================================================
\r
1162 ;Special Call for Debugger so it doesn't have to pass thru
\r
1163 ;the kernel Request mechanism for a keystroke.
\r
1164 ;It acts like ReadKbd with fWait set to true.
\r
1165 ;It sucks keys directly from the Final Keyboard buffer.
\r
1167 ; Procedural interface:
\r
1169 ; ReadDbgKbd(pKeyCodeRet)
\r
1171 ; pKeyCodeRet is a pointer to a DWORD where the keycode is returned.
\r
1174 PUBLIC ReadDbgKBD:
\r
1175 PUSH EBP ; Save the Previous FramePtr
\r
1176 MOV EBP,ESP ; Set up New FramePtr
\r
1178 CALL ReadKBFinal ;Get Code from Buf (Uses EAX, ESI)
\r
1179 OR EAX, EAX ;Got a key?? (non zero)
\r
1180 JNZ RDKB1 ;No. Loop back again
\r
1181 PUSH 2 ;Sleep for 20 ms
\r
1182 CALL FWORD PTR _Sleep
\r
1183 JMP RDKB0 ;Check again
\r
1185 MOV ESI, [EBP+8] ;Ptr where to return key
\r
1190 RETN 4 ; Rtn to Caller & Remove Params from stack
\r
1192 ;=================================================
\r
1193 ;This sets the Keyboard Scan Set to #2 with 8042 interpretation ON
\r
1198 CALL FWORD PTR _MaskIRQ
\r
1200 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1201 MOV AL,0FAh ;Set ALL keys typematic/make/break
\r
1202 OUT DataPort,AL ;Send Command to KBD (not 8042)
\r
1204 CALL OutBuffFull ;Eat response
\r
1207 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1208 MOV AL,0F0h ;Set Scan code set
\r
1209 OUT DataPort,AL ;Send Command to KBD (not 8042)
\r
1211 CALL OutBuffFull ;Eat response
\r
1215 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1216 MOV AL,02h ;Scan set 2
\r
1217 OUT DataPort,AL ;Send Command
\r
1219 CALL OutBuffFull ;Eat response
\r
1222 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1223 MOV AL,060h ;Set up to write 8042 command byte
\r
1224 OUT COMMANDPORT,AL ;Send Command
\r
1225 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1226 MOV AL,45h ;Enable IBM Xlate
\r
1227 OUT DataPort,AL ;Send Command
\r
1230 CALL FWORD PTR _UnMaskIRQ
\r
1236 ;=============================================================================
\r
1237 ;This creates the Keyboard Task and Service.
\r
1239 PUBLIC _InitKBDService:
\r
1241 ;All initial requests and messages from the ISR come to
\r
1244 MOV EAX, OFFSET KbdMainExch ;Alloc Main Kbd exch for service
\r
1246 CALL FWORD PTR _AllocExch
\r
1247 OR EAX, EAX ;Check for error on AllocExch
\r
1248 JNZ InitKBDSvcEnd ;YUP, we got bad problems
\r
1250 ;TempExch for testing
\r
1252 MOV EAX, OFFSET KbdTempExch ;Alloc Hold Kbd exch for Kbd service
\r
1254 CALL FWORD PTR _AllocExch
\r
1255 OR EAX, EAX ;Check for error on AllocExch
\r
1256 JNZ InitKBDSvcEnd ;YUP, we got bad problems
\r
1258 ;Requests for ReadkeyBoard (ScvCode #1) that are from job
\r
1259 ;that currently owns the keyboard waits here if it wants
\r
1260 ;to wait for a key.
\r
1262 MOV EAX, OFFSET KbdWaitExch ;Alloc Hold Kbd exch for Kbd service
\r
1264 CALL FWORD PTR _AllocExch
\r
1265 OR EAX, EAX ;Check for error on AllocExch
\r
1266 JNZ InitKBDSvcEnd ;YUP, we got bad problems
\r
1268 ;Requests for ReadkeyBoard (ScvCode #1) that are from jobs
\r
1269 ;that do NOT currently own the keyboard get sent here using
\r
1272 MOV EAX, OFFSET KbdHoldExch ;Alloc Hold Kbd exch for Kbd service
\r
1274 CALL FWORD PTR _AllocExch
\r
1275 OR EAX, EAX ;Check for error on AllocExch
\r
1276 JNZ InitKBDSvcEnd ;YUP, we got bad problems
\r
1278 ;Requests for ReadkeyGlobal (SvcCode #3) wait here until we
\r
1279 ;get a global key from the keyboard.
\r
1281 MOV EAX, OFFSET KbdGlobExch ;Alloc Global Wait exch for Kbd service
\r
1283 CALL FWORD PTR _AllocExch
\r
1284 OR EAX, EAX ;Check for error on AllocExch
\r
1285 JNZ InitKBDSvcEnd ;YUP, we got bad problems
\r
1287 ;Spawn the Keyboard Service task
\r
1289 MOV EAX, OFFSET KBDServiceTask
\r
1293 MOV EAX, OFFSET KbdSvcStackTop
\r
1295 PUSH 1 ;OS Job task
\r
1296 CALL FWORD PTR _SpawnTask
\r
1297 OR EAX, EAX ;Check for error on AllocExch
\r
1298 JNZ InitKBDSvcEnd ;YUP, we got bad problems
\r
1300 MOV EAX, OFFSET KBDSvcName
\r
1303 CALL FWORD PTR _RegisterSvc
\r
1305 MOV BYTE PTR fKBDInitDone, 1 ;We're UP!
\r
1308 ;=============================================================================
\r
1309 ;This tells the 8042 Controller to Disable the Keyboard device.
\r
1310 ;=============================================================================
\r
1314 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1315 MOV AL,0ADh ;Set Command to "Write the 8042 Command Byte"
\r
1316 OUT COMMANDPORT,AL ;Send Command
\r
1317 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1321 ;=============================================================================
\r
1322 ; This tells the 8042 Controller to Enable the Keyboard Device.
\r
1323 ;=============================================================================
\r
1326 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1327 MOV AL,0AEh ;Set Command to "Write the 8042 Command Byte"
\r
1328 OUT COMMANDPORT,AL ;Send Command
\r
1329 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1332 ;=============================================================================
\r
1333 ; Waits until the 8042 Input Buffer is EMPTY
\r
1334 ;=============================================================================
\r
1339 MOV ECX,2FFFFh ;check 128k times
\r
1345 IN AL,STATUSPORT ;Read Status Byte into AL
\r
1346 TEST AL,INPUTBUFFFULL ;Test The Input Buffer Full Bit
\r
1352 ;=============================================================================
\r
1353 ; Waits until the 8042 Output Buffer is FULL so we can read it
\r
1354 ;=============================================================================
\r
1356 ; Before calling this makes sure that the Keyboard interrupts have been
\r
1357 ; masked so the keyboard interrupt doesn't eat the byte you're
\r
1369 IN AL,STATUSPORT ;Read Status Byte into AL
\r
1370 TEST AL,OUTPUTBUFFFULL ;Test The Output Buffer Full Bit
\r
1376 ;=============================================================================
\r
1377 ; This sets the indicators on the keyboard based on data in KbdState
\r
1378 ;=============================================================================
\r
1384 CALL FWORD PTR _MaskIRQ
\r
1386 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1387 MOV AL,0EDh ;Set/Reset Status Indicators
\r
1388 OUT DATAPORT,AL ;Send KBD Command
\r
1390 CALL OutBuffFull ;Eat response
\r
1393 CALL InBuffEmpty ;Wait for Input Buffer to Empty
\r
1394 MOV AL,KbdLock ;Get Current Lock Status Byte
\r
1395 AND AL,00000111b ;Mask all but low order 3 bits
\r
1396 OUT DATAPORT,AL ;Send KBD Command
\r
1398 CALL OutBuffFull ;Eat response
\r
1402 CALL FWORD PTR _UnMaskIRQ
\r
1406 ;================= END OF MODULE ==================
\r