5755146 [rkeene@sledge /home/rkeene/devel/old/kblockd/Docs]$ cat keybd_controler.txt
**********************************************
**            keyboard controller           **
**                   8042                   **
**      Keyboard Controller  (AT,PS/2)      **
**********************************************

%	8042 Status Register (port 64h read)

	¦7¦6¦5¦4¦3¦2¦1¦0¦  8042 Status Register
	 ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---- output register (60h) has data for system
	 ¦ ¦ ¦ ¦ ¦ ¦ +----- input register (60h/64h) has data for 8042
	 ¦ ¦ ¦ ¦ ¦ +------ system flag (set to 0 after power on reset)
	 ¦ ¦ ¦ ¦ +------- data in input register is command (1) or data (0)
	 ¦ ¦ ¦ +-------- 1=keyboard enabled, 0=keyboard disabled (via switch)
	 ¦ ¦ +--------- 1=transmit timeout (data transmit not complete)
	 ¦ +---------- 1=receive timeout (data transmit not complete)
	 +----------- 1=even parity rec'd, 0=odd parity rec'd (should be odd)

%	Port Mode		  Description

	64h  read   8042 status register. Can be read at any time.  See
		    table above for more information.
	64h  write  8042 command register.  Writing this port sets Bit 3
		    of the status register to 1 and the byte is treated
		    as a controller command.  Devices attached to the
		    8042 should be disabled before issuing commands that
		    return data since data in the output register will
		    be overwritten.
	60h  read   8042 output register (should only be read if Bit 0 of
		    status port is set to 1)
	60h  write  8042 data register.  Data should only be written if
		    Bit 1 of the status register is zero (register is empty).
		    When this port is written Bit 3 of the status register
		    is set to zero and the byte is treated as a data.  The
		    8042 uses this byte if it's expecting data for a previous
		    command, otherwise the data is written directly to the
		    keyboard.	See ~KEYBOARD COMMANDS~ for information on
		    programming the actual keyboard hardware.


^8042 Commands Related to PC Systems  (Port 64h)

%	Command 		   Description

	 20   Read 8042 Command Byte: current 8042 command byte is placed
	      in port 60h.  
	 60   Write 8042 Command Byte: next data byte written to port 60h is
	      placed in 8042 command register.	Format:

	     ¦7¦6¦5¦4¦3¦2¦1¦0¦	8042 Command Byte
	      ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---- 1=enable output register full interrupt
	      ¦ ¦ ¦ ¦ ¦ ¦ +----- should be 0
	      ¦ ¦ ¦ ¦ ¦ +------ 1=set status register system, 0=clear
	      ¦ ¦ ¦ ¦ +------- 1=override keyboard inhibit, 0=allow inhibit
	      ¦ ¦ ¦ +-------- disable keyboard I/O by driving clock line low
	      ¦ ¦ +--------- disable auxiliary device, drives clock line low
	      ¦ +---------- IBM scancode translation 0=AT, 1=PC/XT
	      +----------- reserved, should be 0

	 A4   Password Installed Test: returned data can be read
	      from port 60h;  FA=password installed, F1=no password
	 A5   Load Security: bytes written to port 60h will be read
	      until a null (0) is found.
	 A6   Enable Security: works only if a password is already loaded
	 A7   Disable Auxiliary Interface: sets Bit 5 of command register
	      stopping auxiliary I/O by driving the clock line low
	 A8   Enable Auxiliary Interface: clears Bit 5 of command register
	 A9   Auxiliary Interface Test: clock and data lines are tested;
	      results placed at port 60h are listed below:

		00  no error
		01  keyboard clock line is stuck low
		02  keyboard clock line is stuck high
		03  keyboard data line is stuck low
		04  keyboard data line is stuck high

	 AA   Self Test: diagnostic result placed at port 60h, 55h=OK
	 AB   Keyboard Interface Test:	clock and data lines are tested;
	      results placed at port 60h are listed above with command A9
	 AC   Diagnostic Dump: sends 16 bytes of 8042's RAM, current input
	      port state, current output port state and 8042 program status
	      word to port 60h in scan-code format.
	 AD   Disable Keyboard Interface: sets Bit 4 of command register
	      stopping keyboard I/O by driving the clock line low
	 AE   Enable Keyboard Interface: clears Bit 4 of command register
	      enabling keyboard interface.
	 C0   Read Input Port: data is read from its input port (which is
	      inaccessible to the data bus) and written to output register
	      at port 60h;  output register should be empty before call.

	       ¦7¦6¦5¦4¦3-0¦  8042 Input Port
		¦ ¦ ¦ ¦ +---- undefined
		¦ ¦ ¦ +----- 1=enable 2nd 256K of motherboard RAM, 0=disable
		¦ ¦ +------ 1=manufacturing jumper not installed, 0=installed
		¦ +------- 1=primary display is MDA, 0=primary display is CGA
		+-------- 1=keyboard not inhibited, 0=keyboard inhibited

	 C1   Poll Input Port Low Bits: Bits 0-3 of port 1 placed in
	      status Bits 4-7
	 C2   Poll Input Port High Bits: Bits 4-7 of port 1 placed in
	      status Bits 4-7
	 D0   Read Output Port: data is read from 8042 output port (which is
	      inaccessible to the data bus) and placed in output register;
	      the output register should be empty.  (see command D1 below)
	 D1   Write Output Port: next byte written to port 60h is placed in
	      the 8042 output port (which is inaccessible to the data bus)

		¦7¦6¦5¦4¦3¦2¦1¦0¦  8042 Output Port
		 ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---- system reset line
		 ¦ ¦ ¦ ¦ ¦ ¦ +----- gate A20
		 ¦ ¦ ¦ ¦ +-------- undefined
		 ¦ ¦ ¦ +--------- output buffer full
		 ¦ ¦ +---------- input buffer empty
		 ¦ +----------- keyboard clock (output)
		 +------------ keyboard data (output)

	 D2   Write Keyboard Output Register: on PS/2 systems the next data
	      byte written to port 60h input register is written to port 60h
	      output register as if initiated by a device; invokes interrupt
	      if enabled
	 D3   Write Auxiliary Output Register: on PS/2 systems the next data
	      byte written to port 60h input register is written to port 60h
	      output register as if initiated by a device; invokes interrupt
	      if enabled
	 D4   Write Auxiliary Device: on PS/2 systems the next data byte
	      written to input register a port at 60h is sent to the
	      auxiliary device
	 E0   Read Test Inputs: 8042 reads its T0 and T1 inputs; data is
	      placed in output register;  Bit 0 is T0, Bit 1 is T1:

		¦1¦0¦  Test Input Port Bits
		 ¦ +---- keyboard clock
		 +----- keyboard data

	 Fx   Pulse Output Port: Bits 0-3 of the 8042 output port can be
	      pulsed low for 6 µs;  Bits 0-3 of command indicate which
	      Bits should be pulsed; 0=pulse, 1=don't pulse; pulsing
	      Bit 0 results in CPU reset since it is connected to system
	      reset line.

	- PC systems previous to the AT use the 8255 PPI as a keyboard
	  controller and use the keyboard's internal 8048.
	- the keyboard's internal controller buffers up to 16 bytes of
	  make/break code information.	This is common among all PC systems
	  and shouldn't be confused with the (32 byte) keyboard buffer
	  maintained by the BIOS.
	- see  ~KEYBOARD COMMANDS~ for information on programming the
	  keyboards internal microprocessor



^Keyboard Commands & Responses

^Commands System Issues to Keyboard (via 8042 port 60h)

	ED  Set/Reset Mode Indicators, keyboard responds with ACK then
	    waits for a following option byte.	When the option byte is
	    received the keyboard again ACK's and then sets the LED's
	    accordingly.  Scanning is resumed if scanning was enabled.
	    If another command is received instead of the option byte
	    (high bit set on) this command is terminated.  Hardware
	    defaults to these indicators turned off.

	    ¦7-3¦2¦1¦0¦ Keyboard Status Indicator Option Byte
	      ¦  ¦ ¦ +--- Scroll-Lock indicator  (0=off, 1=on)
	      ¦  ¦ +---- Num-Lock indicator  (0=off, 1=on)
	      ¦  +----- Caps-Lock indicator  (0=off, 1=on)
	      +------- reserved (must be zero)

	EE  Diagnostic Echo, keyboard echoes the EE byte back to the system
	    without an acknowledgement.
	F0  PS/2 Select/Read Alternate Scan Code Sets, instructs keyboard
	    to use one of the three make/break scan code sets.	 Keyboard
	    responds by clearing the output buffer/typematic key and then
	    transmits an ACK.  The system must follow up by sending an
	    option byte which will again be ACK'ed by the keyboard:

	      00  return byte indicating scan code set in use
	      01  select scan code set 1  (used on PC & XT)
	      02  select scan code set 2
	      03  select scan code set 3

	F2  PS/2 Read Keyboard ID, keyboard responds with an ACK and a two
	    byte keyboard ID of 83AB.
	F3  Set Typematic Rate/Delay, keyboard responds with ACK and waits
	    for rate/delay byte.   Upon receipt of the rate/delay byte the
	    keyboard responds with an ACK, then sets the new typematic
	    values and scanning continues if scanning was enabled.
	    
	    ¦7¦6¦5¦4¦3¦2¦1¦0¦  Typematic Rate/Delay Option Byte
	     ¦ ¦ ¦ +-+-+-+-+---- typematic rate indicator (see ~INT 16,3~)
	     ¦ ¦ ¦ ¦ ¦ +------- A in period formula (see below)
	     ¦ ¦ ¦ +---------- B is period formula (see below)
	     ¦ +------------- typematic delay
	     +-------------- always zero

	    delay = (rate+1) * 250   (in milliseconds)
	    rate = (8+A) * (2**B) * 4.17  (in seconds, ± 20%)

	    Defaults to 10.9 characters per second and a 500ms delay.  If a
	    command byte (byte with high bit set) is received instead of an
	    option byte this command is cancelled.
	F4  Enable Keyboard, cause the keyboard to clear its output buffer
	    and last typematic key and then respond with an ACK.  The
	    keyboard then begins scanning.
	F5  Default w/Disable, resets keyboard to power-on condition by
	    clearing the output buffer, resetting typematic rate/delay,
	    resetting last typematic key and setting default key types.
	    The keyboard responds with an ACK and waits for the next
	    instruction.
	F6  Set Default, resets to power-on condition by clearing the output
	    buffer, resetting typematic rate/delay and last typematic key
	    and sets default key types.  The keyboard responds with an ACK
	    and continues scanning.
	F7  PS/2 Set All Keys to Typematic, keyboard responds by sending an
	    ACK, clearing its output buffer and setting the key type to
	    Typematic.	 Scanning continues if scanning was enabled.  This
	    command may be sent while using any Scan Code Set but only has
	    effect when Scan Code Set 3 is in use.
	F8  PS/2 Set All Keys to Make/Break, keyboard responds by sending an
	    ACK, clearing its output buffer and setting the key type to
	    Make/Break.  Scanning continues if scanning was enabled.  This
	    command may be sent while using any Scan Code Set but only has
	    effect when Scan Code Set 3 is in use.
	F9  PS/2 Set All Keys to Make, keyboard responds by sending an ACK,
	    clearing its output buffer and setting the key type to Make.
	    Scanning continues if scanning was enabled.  This command may
	    be sent while using any Scan Code Set but only has effect when
	    Scan Code Set 3 is in use.
	FA  PS/2 Set All Keys to Typematic Make/Break, keyboard responds by
	    sending an ACK, clearing its output buffer and setting the key
	    type to Typematic Make/Break.  Scanning continues if scanning
	    was enabled.  This command may be sent while using any Scan Code
	    Set but only has effect when Scan Code Set 3 is in use.
	FB  PS/2 Set Key Type to Typematic, keyboard responds by sending an
	    ACK, clearing its output buffer and then waiting for the key ID
	    (make code from Scan Code Set 3).  The specified key type is then
	    set to typematic.	This command may be sent while using any
	    Scan Code Set but only has effect when Scan Code Set 3 is in use.
	FC  PS/2 Set Key Type to Make/Break, keyboard responds by sending an
	    ACK, clearing its output buffer and then waiting for the key ID
	    (make code from Scan Code Set 3).  The specified key type is then
	    set to Make/Break.	 This command may be sent while using any Scan
	    Code Set but only has effect when Scan Code Set 3 is in use.
	FD  PS/2 Set Key Type to Make, keyboard responds by sending an ACK,
	    clearing its output buffer and then waiting for the key ID (make
	    code from Scan Code Set 3).  The specified key type is then set
	    to Make.  This command may be sent while using any Scan Code Set
	    but only has effect when Scan Code Set 3 is in use.
	FE  Resend, should be sent when a transmission error is detected
	    from the keyboard
	FF  Reset, Keyboard sends ACK and waits for system to receive it
	    then begins a program reset and Basic Assurance Test (BAT).
	    Keyboard returns a one byte completion code then sets default
	    Scan Code Set 2.


^Keyboard Responses to System (via 8042 port 60h)

	00  Key Detection Error or Overrun Error for Scan Code Set 1,
	    replaces last key in the keyboard buffer if the buffer is full. 
	AA  BAT Completion Code, keyboard sends this to indicate the keyboard
	    test was successful.
	EE  Echo Response, response to the Echo command.
	F0  Break Code Prefix in Scan Code Sets 2 and 3.
	FA  Acknowledge, keyboard sends this whenever a valid command or
	    data byte is received (except on Echo and Resend commands).
	FC  BAT Failure Code, keyboard sends this to indicate the keyboard
	    test failed and stops scanning until a response or reset is sent.
	FE  Resend, keyboard request resend of data when data sent to it is
	    invalid or arrives with invalid parity.
	FF  Key Detection Error or Overrun Error for Scan Code Set 2 or 3,
	    replaces last key in the keyboard buffer if the buffer is full.
	id  Keyboard ID Response, keyboard sends a two byte ID after ACK'ing
	    the Read ID command.  The byte stream contains 83AB in LSB, MSB
	    order.  The keyboard then resumes scanning.


	- command F7 through FD are NOP's on the AT and are ACK'ed but not
	  acted upon


Programming the Keyboard 


=============================================================================
 Overview 
==========

The operation of the keyboard is really quite simple. Every time a key
is pressed or released an interrupt 9 is generated, and reading the value
from port 60h tells you what happened.

=============================================================================
 Decoding the Keyboard Byte 
============================

So let's say you've installed an interrupt handler to handle all keyboard
events and when an interrupt is generated your handler reads the byte from
port 60h. What now?

Well..each key on the keyboard has an associated scan code which is contained
in the lower 7 bits of the byte. The most significant bit (ie bit 7) tells
you what was actually done, 0 = key was just pressed, 1 = key was just
released. If someone had just pressed the ESC key for instance, the port will
show a value of 1 (1 is the ESC key's scan code). If they hold their finger
on the button the keyboard will keep generating interrupt 9's and each
time the port will still show a value of 1. When the person releases the key
a final interrupt will be generated and the port will return 129 (1 + 128,
since the high bit will be set indicating the person has released the key).

Well...it's almost this simple. Some keys are "extended" keys. When an
extended key is pressed an interrupt is generated and the keyboard port
will return a value of 224 (E0h). This means that an extended key was pressed
and it's *extended* scan code will be available during the *next* interrupt.
Note that the left control key has a scan code of 29, while the *right*
control key has an *extended* scan code of 29. The same applies to the alt
keys and the arrow keys (keypad arrows vs the other ones).

It would be nice if all keys were created equal and we could just throw away
the 224 extended bytes and handle all the other bytes normally. Unfortunately
there are two buttons which on my machine at least (and others I have tested)
do some really weird stuff:

PrtScn
======

Pressing this button will send *2* extended characters to the handler, 42
and 55, so the actual byte sequence will be 224, 42, 224, 55. (Also note
that the left shift key has a regular scan code of 42, so there goes our
idea of just throwing 224's away). Only the extended 55's are sent during
auto-repeat. When the key is released, the two are sent again with the high
bits set (224, 170, 224, and 183). If any of the shift or control keys are
being held down when the PrtScn button is pressed then only the (224, 55) is
sent when the key is pressed and only the (224, 183) is sent when it's
released. If the alt key is being held down (System Request) then the key
behaves like an ordinary key with scan code 84. The practical upshot of all
this is that the handlers you write to handle normal keys and extended keys
will work fine with all the different PrtScn combinations (although a program
would have to check normal key 84 *AND* extended key 55 in order to determine
if the key is currently being pressed).

Pause/Break
===========

Welcome to hell. If you press this key while either of the the control keys
are being held down, it will behave like extended key 70, at all other times
it will send the following bytes: (225, 29, 69, 225, 157, 197). Holding the
key down does not result in autorepeat. Taking your finger off the key does
not send any extra bytes, they appear to be sent after the "key down" bytes
when you first press the key. Notice that 225 isn't 224, so our normal
extended character handler will not take care of this. My personal theory is
that while a scan code of 224 (E0h) means there is 1 more character
following, a scan code of 225 (E1h) means there are *2* more following. I've
seen a number of keyboard handler libraries and they all seem to overlook
this key. So why not be the first kid on your block to have a keyboard
handler which properly supports the Pause/Break key? CHECK IT OUT!!

=============================================================================
 Writing a Handler 
===================

Writing a keyboard handler is fairly straightforward. This section will
show how to do it in Pascal (you C and asm programmers would probably already
know this stuff anyway).

First we'll declare a few things we'll need:

const KEYBOARDINTR = 9;
      KEYBOARDPORT = $60;

var BIOSKeyboardHandler : procedure;
    CallBIOSHandler : boolean;

The CallBIOSHandler variable will be initialised by the calling program. If
we also want the BIOS handler to process all keystrokes then this variable
must be set to true.

Next we need to store the value of the current handler and set up own our
own one. We'll use a procedure called KeyboardHandler to handle the actual
interrupt.

CallBIOSHandler := false; { ...or set it to true if you want. }
GetIntVec(KEYBOARDINTR, @BIOSKeyboardHandler);
SetIntVec(KEYBOARDINTR, Addr(KeyboardHandler));

Ok, so everything is now set up and our handler will now be able to process
all keyboard events. The actual interrupt handler could look like this:

{$F+}
procedure KeyboardHandler(Flags, CS, IP, AX, BX, CX, DX,
                          SI, DI, DS, ES, BP: Word);
interrupt;
var key : byte;
begin

  key := Port[KEYBOARDPORT];

  { PROCESS THE KEYSTROKE HERE }

  if CallBIOSHandler then

  { Call the BIOS keyboard handler if the calling program wants us to }
    begin
      asm pushf end;
      BIOSKeyboardHandler;
    end

  { Otherwise just acknowledge the interrupt }
  else Port[$20] := $20;
end;
{$F-}


When the program is finished we can set the old keyboard handler again:

SetIntVec(KEYBOARDINTR, @BIOSKeyboardHandler);

=============================================================================
 A Word of Warning 
===================

When I was writing a simple handler to test the info in this file I did
something REALLY stoopid which I would like to share with the world. I
thought that my program was stuffing the keyboard up because when I exited
the program my editor (Borland Pascal 7.0) would act as though the control
button was being held down (I'm sure some of you have already started
laughing by now). I had to press it after each time I ran the program
just to sort it out. After spending a few hours looking all over the place
for info on what could possibly be wrong I realised what I was doing. I was
pressing CTRL-F9 to compile the program which would also immediately make it
run and I was releasing the control key when my program was running, ie the
regular BIOS handler was not getting the control key's "key up" command and
still thought it was being held down when my program returned control to
it. Moron.....

=============================================================================
 Scan Codes 
============

The following is a list of all the regular key scan codes in numerical
order:

Scan                                   Scan
Code Key                               Code Key
==========================             ==============================
 1   ESC                               44   Z
 2   1                                 45   X
 3   2                                 46   C
 4   3                                 47   V
 5   4                                 48   B
 6   5                                 49   N
 7   6                                 50   M
 8   7                                 51   , <
 9   8                                 52   . >
10   9                                 53   / ?
11   0                                 54   RIGHT SHIFT
12   - _                               55   *            (KEYPAD)
13   = +                               56   LEFT ALT
14   BACKSPACE                         57   SPACEBAR
15   TAB                               58   CAPSLOCK
16   Q                                 59   F1
17   W                                 60   F2
18   E                                 61   F3
19   R                                 62   F4
20   T                                 63   F5
21   Y                                 64   F6
22   U                                 65   F7
23   I                                 66   F8
24   O                                 67   F9
25   P                                 68   F10
26   [ {                               69   NUMLOCK      (KEYPAD)
27   ] }                               70   SCROLL LOCK
28   ENTER (RETURN)                    71   7 HOME       (KEYPAD)
29   LEFT CONTROL                      72   8 UP         (KEYPAD)
30   A                                 73   9 PGUP       (KEYPAD)
31   S                                 74   -            (KEYPAD)
32   D                                 75   4 LEFT       (KEYPAD)
33   F                                 76   5            (KEYPAD)
34   G                                 77   6 RIGHT      (KEYPAD)
35   H                                 78   +            (KEYPAD)
36   J                                 79   1 END        (KEYPAD)
37   K                                 80   2 DOWN       (KEYPAD)
38   L                                 81   3 PGDN       (KEYPAD)
39   ; :                               82   0 INSERT     (KEYPAD)
40   ' "                               83   . DEL        (KEYPAD)
41   ` ~                               87   F11
42   LEFT SHIFT                        88   F12


The following is a list of all the extended key scan codes in numerical
order:

Scan                                   Scan
Code Key                               Code Key
==========================             ===============================
28   ENTER        (KEYPAD)              75   LEFT         (NOT KEYPAD)
29   RIGHT CONTROL                      77   RIGHT        (NOT KEYPAD)
42   PRINT SCREEN (SEE TEXT)            79   END          (NOT KEYPAD)
53   /            (KEYPAD)              80   DOWN         (NOT KEYPAD)
55   PRINT SCREEN (SEE TEXT)            81   PAGE DOWN    (NOT KEYPAD)
56   RIGHT ALT                          82   INSERT       (NOT KEYPAD)
71   HOME         (NOT KEYPAD)          83   DELETE       (NOT KEYPAD)
72   UP           (NOT KEYPAD)         111   MACRO
73   PAGE UP      (NOT KEYPAD)

5755147 [rkeene@sledge /home/rkeene/devel/old/kblockd/Docs]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 1999-07-17 21:29:00