]> pd.if.org Git - mmurtl/commitdiff
autocommit for file dated 1995-02-07 17:27:52
authorRichard Burgess <>
Tue, 7 Feb 1995 17:27:52 +0000 (17:27 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Mon, 17 Oct 2016 14:03:48 +0000 (14:03 +0000)
ossource/keyboard.asm [new file with mode: 0644]

diff --git a/ossource/keyboard.asm b/ossource/keyboard.asm
new file mode 100644 (file)
index 0000000..b02c0a6
--- /dev/null
@@ -0,0 +1,1406 @@
+;   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