297 lines
13 KiB
Plaintext
297 lines
13 KiB
Plaintext
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 <20> 10ms+
|
||
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).
|