Plan 9 from Bell Labs’s /sys/src/pub/doc/misc/kbd.txt

Copyright © 2021 Plan 9 Foundation
Distributed under the MIT License.
Download the Plan 9 distribution.


                      The Keyboard Interface Tutorial
Preface:

The Keyboard on the IBM PC and compatible is connected to the PPI -
Programmable Peripheral Interface, which generally takes care of Keyboard
functions, equipment information and timer functions. The PPI is addressable
via port reads and writes, to addresses 060h thru 063h.

There are several type of keyboards available. The main difference between the
various types is the key count. Existing sizez are:

83  Key (Original PC)
84  Key (XT and clones)
101 Key (Usually on AT's and up, called Enhanced Keyboard)

In addition to those standard types, there are numerous non-standard types,
which varry from manufacturer to manufacturer. There are 102 Key keyboards,
keyboards with two F-Key sets (upper and left), keyboards with weird
hardly-used keys like 'Macro' and 'Turbo' (which DO have a scan code, though)
etcetera.

The IBM AT and up provides a better way of negotiating the keyboard, by
allowing the user to directly access and command the keyboard, as it will be
demonstrated later.

Using assembly language, there are two major ways to handle the keyboard and
keystrokes:

1. Using DOS functions:

   DOS provides a useful set of functions to use in context with the keyboard.
   This includes one-key-input and string input.

2. Using BIOS interrupts:

   The IBM PC BIOS (Basic Input Output System) provides an interrupt to handle
   the keyboard - Interrupt 016h (022d). These functions, titles KEYBOARD I/O,
   are an efficient medium level way of using the keyboard

   In addition to the Interrupt 016h interface, there is the Keyboard
   Interrupt, Interrupt 009h. As opposed to the other interrupt, Interrupt
   009h is an IRQ - Interrupt Request, which means that it is never called by
   software. Only hardware, when certain conditions are met, calls IRQ
   interrupts. Naturally, the user is able to invoke them himself, but that is
   not commonly done.

3. Direct port access:

   It is possible to access the keyboard using direct port reads and writes.
   As mentioned before, this is usually done by addressing the PPI. On AT's
   and up, however, it is possible to directly access the keyboard itself.


The BIOS also supplies a certain amount of information about the keyboard
within it's BDA - BIOS Data Area, aka BDS - BIOS Data Segment - which is the
segment that lies at paragraph 040h (0040h:XXXXh or 0000h:04XXh):

Address Size Contents
------- ---- --------
0:0412    1  Errors in PCjr InfraRed keyboard link

0:0417    2  Keyboard status bits. See Keyboard Flags
0:0419    1  Current (accumulating) value of Alt+numpad pseudo-key input.
             Normally 0.  When [Alt] is released, value is stored in kbd buf.
0:041A    2  Address of keyboard buffer head (keystroke at that addr is next)
0:041C    2  Address of keyboard buffer tail
0:041E   32  Keyboard buffer.  BIOS stores keystrokes here (head and tail
             point to addresses from 041Eh to 043Dh inclusive).

0:0480    2  AT PS/2 Keyboard buffer offset start address (usually 01Eh)
0:0482    2                                        end address (usually 03Eh)

0:0496    1  AT Keyboard flag bit 4=1 (10h) if 101-key keyboard is attached
0:0497    1  AT Keyboard flag for LED 'key lock' display
                  bits 0-2 are ScrollLock, NumLock, CapsLock respectively

******************************************************************************

Using DOS functions:
--------------------

DOS provides a set of 7 functions to handle the keyboard:

01h Keyboard Input
06h Console I/O
07h No Echo Unfiltered Input
08h No Echo Filtered Input
0Ah Buffered Input
0Bh Input Status
0Ch Clear Keyboard Buffer & Input

In addition to these functions, it is also possible to read a selected amount
of characters from the keyboard, using DOS's File Handle functions, as the
Keyboard, aka Standard Input, has a pre-set handle of 0000h:

                    DOS Fn 3Fh: Read from keyboard via Handle
------------------------------------------------------------------------------
/-----------------------------------------------------------------\
| Expects | AH    | 3Fh                                           |
\---------| BX    | 0000h - Handle for Standard Input (Keyboard)  |
          | DS:DX | Address of buffer to receive data             |
          | CX    | Number of bytes to read                       |
/---------|-------|-----------------------------------------------|
| Returns | AX    | Error code if CF is set to CY                 |
\---------| AX    | Number of bytes actually read                 |
          \-------------------------------------------------------/

Description: CX bytes of data are read from the keyboard. The data is placed
             into the caller's buffer pointed to by DS:DX.

Notes:       It is handy to use this function for reading default handles
             such as the Standard I/O handles, instead of the buffered input
             or character-by-character input functions.

             When you read from a device, AX returns the length of the line
             up to and including the termination CR (ASCII 13h).

******************************************************************************

Using BIOS Interrupts:
----------------------

As mentioned before, there are two ways to use interrupts to access the
keyboard.

The first is Interrupt 016h - Keyboard I/O.

                          INT 16h: Keyboard Services
------------------------------------------------------------------------------
 This is the application-level interface to the keyboard.  Keystrokes are
 actually processed asynchronously in the background.  As each keystroke is
 received from the keyboard, it is processed by INT 09h and placed into a
 circular queue.


The second is Interrupt 009h - Keyboard Interrupt, IRQ 1

                         INT 09h: Keyboard Interrupt
------------------------------------------------------------------------------
 This hardware-generated interrupt (IRQ 1) is executed upon each press and
 release of a key.  The ROM-BIOS code interprets the keystroke, storing values
 into the keyboard buffer at 40:1Eh.  It also handles the special cases of the
 PrtSc and SysReq keys, and tracks the status of the shift and case-lock keys.

See:  INT 16h .......... BIOS service to access the keys stored in the buffer
                         and obtain status of the certain shift keys.
      Scan Codes ....... a list of the values of each possible keystroke as
                         it is received by INT 09h.
      Extended ASCII ... for a summary of the values that BIOS stores into the
                         the keyboard buffer after it translates a scan code.
      Keyboard Flags ... for a summary of how to obtain, test for, and modify
                         the bit-settings of shift and case-lock flags.

 TSRs (RAM-resident programs) that have a hot-key to trigger a popup usually
 intercept INT 09h and test for a certain key with a sequence such as this:

         push    ax
         in      al,60h             ; Read the key
         cmp     al,POP_KEY         ; Is this the hot key?
         je      do_pop             ; Yes, trigger the popup
                                    ;  No, drop through to original driver
         pop     ax
         jmp     cs:[int9_vect]     ; Just hop out to original int handler

do_pop:  ;------ the following housekeeping is needed to satisfy the hdwr int

         in      al,61h             ; Get value of keyboard control lines
         mov     ah,al              ;  Save it
         or      al,80h             ; Set the "enable kbd" bit
         out     61h,al             ;  And write it out the control port
         xchg    ah,al              ; Fetch the original control port value
         out     61h,al             ;  And write it back

         mov     al,20h             ; Send End-Of-Interrupt signal
         out     20h,al             ;  to the 8259 Interrupt Controller

         ;------ other code handles other tests and finally the popup code

******************************************************************************

Direct port access:
-------------------

The keyboard is addressable in two manners.

The first, available on all IBM PCs of all types, is by addressing the PPI -
Programmable Peripheral Interface.

Port  Description
----  -----------
060h  PC/XT  PPI port A.  Read keyboard scan code:

      IN   al,60h  ; Fetche most recent scan code.  See INT 09h and Scan Code

      AT keyboard data register.                     See AT Keyboard

061h  PC/XT PPI (Programmable Peripheral Interface) port B.

       7 6 5 4 3 2 1 0
       | | | | | | | |  
       | | | | | | | \-> 0: Timer 2 gate (speaker) --/--> OR 03h=speaker ON
       | | | | | | \---> 1: Timer 2 data  ---------/    AND 0FCh=speaker OFF
       | | | | | \-----> 2: Always 0
       | | | | \-------> 3: 1=Read high switches; 0=read low switches(see 62h)
       | | | \---------> 4: 0=Enable RAM parity checking; 1=disable
       | | \-----------> 5: 0=Enable I/O channel check
       | \-------------> 6: 0=Hold keyboard clock low
       \---------------> 7: 0=Enable keyboard; 1=disable keyboard

------------------------------------------------------------------------------

The second, available only on IBM PC/ATs and up, is by directly commanding the
keyboard itself. -= This is for the AT keyboard only. =-

Port  Description
----  -----------
064h  AT keyboard command register.  This port communicates with the 8042
      which runs an on-chip control program for the keyboard.  It accepts
      command codes and data bytes.

 The keyboard of the AT (and its Intel 8042 microcomputer interface) is
 programmable and a lot more interesting than the old-style PC keyboards.
 Using the information below, you can set the key repeat speed and play
 games with the "lock" key LED display.

 Note: This is not a comprehensive coverage of the details of keyboard and
       8042 operation, but it should provide some food for thought.

 Port 60h is for writing data and is maintained for compatibility with
 earlier models.  If the examples using port 64h don't work, try using 60h.

 Port 64h is for writing commands and data and for reading keyboard status.
 Before sending a command to the keyboard, the BIOS tests its status
 (IN al,64h) and makes sure a key isn't being pressed or the internal buffer
 isn't full, etc.  There's a small risk if you just go ahead and send the
 command:

       mov   al,cmd_code
       out   64h,al

 For a two-part command such as setting the typeamatic rate, it's wise to
 delay a little while between OUTs:

       mov   al,cmd_code
       out   64h,al
       mov   cx,2000h  ;arbitrary �ms+
delay: loop  delay
       mov   al,data_value
       out   64h,al

Cmd  Description
---  -----------
0FFh Reset the keyboard and start internal diagnostics
0FEh Resend the last transmission
0FDh-0F7h (NOP)
0F6h Set keyboard to defaults and continue scanning
0F5h Set keyboard to defaults and disable keyboard scanning
0F4h Enable the keyboard. Kybd sends 'ACK', clears buffer, and starts scanning

0F3h Set typeamatic rate and delay.  First send 0F3h, then send data byte:

		 -7-6-5-4-3-2-1-0-
		 |0|dly|rept rate|
		 -----------------
                  | | | \---------> bits 0-4 set the repeat rate (see below)
                  | \-------------> bits 5-6 set initial delay before first repeat:
                  |                          00=250ms; 01=500ms; 10=750ms; 11=1000ms
                  \---------------> bit 7 is always 0
                                                    Value Rate    Value Rate
     This chart is a partial guide for the repeat    0  = 30.0    0Ah = 10.0
     rate (bits 0-4).  You can interpolate for       1  = 26.7    0Dh =  9.2
     values not shown, but let's face it, you're     2  = 24.0    10h =  7.5
     only interested in the fastest rates.           4  = 20.0    14h =  5.0
                                                     8  = 15.0    1Fh =  2.0

     The keyboard is initially set to begin repeating after 1/2-second and
     repeat at a rate of 10 repeats per second.  This is much too slow.  A
     data byte of 01h sets the delay to 1/4-second with 26 repeats per second.

0F2h-0EFh (NOP)
0EEh Echo.  Diagnostics aid.  Simply sends 0EEh right back.

0EDh Turn LED 'lock key' lights on or off. First send 0EDh, then send byte:

		 -7-6-5-4-3-2-1-0-
		 | not used|c|n|s|
		 -----------|-|-|-
                            | | \-> ScrollLock light 01h=turn on
                            | \---> NumLock light    02h=turn on
                            \-----> CapsLock light   04h=turn on

     The bit positions 0-3 correspond to bits 4-6 of the keyboard flags
     variable in the BIOS Data area.  You should make an effort to keep the
     flags in sync with the lights.  For instance, if you do a big favor for
     the user and set his ten-key pad into NumLock mode (by setting bit 5 of
     0:0417h) then be sure to turn on the corresponding LED (eg, bit 1).

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@plan9.bell-labs.com.