IBM AT keyboard controller trivia
These more-or-less random facts relate to the 8042 keyboard controller in the IBM AT.
XT keyboard support
The AT keyboard controller supports the XT keyboard protocol as well as its native one. This has been documented in a number of places, but always in fairly obscure terms. The Interrupt List, for example, refers to the feature as "use 8086 codes" or "IBM PC mode"; so does the Keyboard Scancodes page. It is, however, clearly documented in 8042 INTERN.
XT keyboard support must be switched on manually, by setting bit 5 of the controller command byte. On PS/2 and later computers, this bit is used to disable the mouse, so this feature is pretty certain not to work on any system with a PS/2 mouse.
On a real IBM 5170 AT, on the other hand, it works fine. The BIOS did not detect the XT keyboard and (for unrelated reasons) will not boot without a keyboard present, so I had to boot with an AT keyboard connected, switch XT support on, and hotplug the XT keyboard. This is obviously not an ideal solution, since IBM keyboards are not supposed to be hotplugged.
If you want to try this, KBXT.EXE will set/clear the appropriate bit of the command byte:
KBXT -- displays status. KBXT XT -- switches the keyboard controller into XT mode. KBXT AT -- switches the keyboard controller into AT mode.
Keylock
The keylock only blocks scancodes that correspond to set 3 keys. That is, scancodes 00h-7Fh, plus 83h and 84h. Other scancodes, such as the 0E0h prefix from an enhanced keyboard, or the Windows keys on a keyboard using set 3, are still passed through to the BIOS.
Scancode translation table
At the time the AT keyboard controller was created, Scancode Set 2 did not exist — only Sets 1 and 3. The controller contains a 128-byte table, mapping from Set 3 scancodes to Set 1. This supports all 127 Set 3 keys, even though the AT keyboard can only return 89 of them.
Some notes on scancode sets:
- Set 3, at least on genuine IBM keyboards, is a position-based system. Various references, for example, say that the Set 3 scancode for F1 is 07h. The truth is a bit more complicated; 07h is the Set 3 scancode for the leftmost function key in the row of function keys immediately above the numbers. If the function keys are on the left, as on the AT keyboard, then F1 is in a different place and so returns a different Set 3 scancode (05h).
- It's commonly said that the AT keyboard uses Set 2. It doesn't; it uses a subset of Set 3. All the actual keys on the board have the same scancodes in Set 2 and Set 3, but the extra positions under double-size keys (for example, under the right-hand Shift key) return Set 3 scancodes.
The table below describes the position of each key using the 6110344 keyboard. To avoid ambiguity, the ten function keys on the left are referred to as L1-L10, and the 24 function keys at the top are referred to as PF1-PF24. For some keys, I have also said what key would be in that position on a standard 102-key keyboard.
Keys where the translated scancode is higher than 0x54 (SysRQ) are generally not present on the AT keyboard, though eight of them correspond to unused positions under double-size keys. The translated scancodes in this case are 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x7C and 0x57.
Except for two clear ranges (0x58-0x6E correspond to PF1-PF23, and 0x70-0x75 are unused positions in the main alphanumeric area) there seems to be no attempt to group related keys. I also can't explain why PF24 should be mapped to 0x76 rather than 0x6F, the next key in sequence after PF23.
Key | Set 3 code | Set 1 code | Notes |
---|---|---|---|
Error code | 0x00 | 0xFF | Error code |
L9 | 0x01 | 0x43 | |
L7 | 0x02 | 0x41 | Never seen on the wire; the keyboard sends 0x83 instead. The controller internally changes 0x83 back to 0x02 before translating it. |
L5 | 0x03 | 0x3f | |
L3 | 0x04 | 0x3d | |
L1 | 0x05 | 0x3b | |
L2 | 0x06 | 0x3c | |
PF1 | 0x07 | 0x58 | |
PF13 | 0x08 | 0x64 | |
L10 | 0x09 | 0x44 | |
L8 | 0x0a | 0x42 | |
L6 | 0x0b | 0x40 | |
L4 | 0x0c | 0x3e | |
Tab | 0x0d | 0x0f | |
~ ` | 0x0e | 0x29 | |
PF2 | 0x0f | 0x59 | |
PF14 | 0x10 | 0x65 | |
Left Ctrl | 0x11 | 0x38 | |
Left Shift | 0x12 | 0x2a | |
\ (between left shift and Z) | 0x13 | 0x70 | |
Caps Lock | 0x14 | 0x1d | |
Q | 0x15 | 0x10 | |
1 | 0x16 | 0x02 | |
PF3 | 0x17 | 0x5a | |
PF15 | 0x18 | 0x66 | |
Left Alt | 0x19 | 0x71 | |
Z | 0x1a | 0x2c | |
S | 0x1b | 0x1f | |
A | 0x1c | 0x1e | |
W | 0x1d | 0x11 | |
2 | 0x1e | 0x03 | |
PF4 | 0x1f | 0x5b | |
PF16 | 0x20 | 0x67 | |
C | 0x21 | 0x2e | |
X | 0x22 | 0x2d | |
D | 0x23 | 0x20 | |
E | 0x24 | 0x12 | |
4 | 0x25 | 0x05 | |
3 | 0x26 | 0x04 | |
PF5 | 0x27 | 0x5c | |
PF17 | 0x28 | 0x68 | |
Space | 0x29 | 0x39 | |
V | 0x2a | 0x2f | |
F | 0x2b | 0x21 | |
T | 0x2c | 0x14 | |
R | 0x2d | 0x13 | |
5 | 0x2e | 0x06 | |
PF6 | 0x2f | 0x5d | |
PF18 | 0x30 | 0x69 | |
N | 0x31 | 0x31 | |
B | 0x32 | 0x30 | |
H | 0x33 | 0x23 | |
G | 0x34 | 0x22 | |
Y | 0x35 | 0x15 | |
6 | 0x36 | 0x07 | |
PF7 | 0x37 | 0x5e | |
PF19 | 0x38 | 0x6a | |
Right Alt | 0x39 | 0x72 | |
M | 0x3a | 0x32 | |
J | 0x3b | 0x24 | |
U | 0x3c | 0x16 | |
7 | 0x3d | 0x08 | |
8 | 0x3e | 0x09 | |
PF8 | 0x3f | 0x5f | |
PF20 | 0x40 | 0x6b | |
< , | 0x41 | 0x33 | |
K | 0x42 | 0x25 | |
I | 0x43 | 0x17 | |
O | 0x44 | 0x18 | |
0 | 0x45 | 0x0b | |
9 | 0x46 | 0x0a | |
PF9 | 0x47 | 0x60 | |
PF21 | 0x48 | 0x6c | |
> . | 0x49 | 0x34 | |
? / | 0x4a | 0x35 | |
L | 0x4b | 0x26 | |
: ; | 0x4c | 0x27 | |
P | 0x4d | 0x19 | |
_ | 0x4e | 0x0c | |
PF10 | 0x4f | 0x61 | |
PF22 | 0x50 | 0x6d | |
Between / and Right Shift | 0x51 | 0x73 | |
@ ' | 0x52 | 0x28 | |
Key left of Return (ISO) | 0x53 | 0x74 | |
{ [ | 0x54 | 0x1a | |
+ = | 0x55 | 0x0d | |
PF11 | 0x56 | 0x62 | |
PF23 | 0x57 | 0x6e | |
Right Ctrl | 0x58 | 0x3a | |
Right Shift | 0x59 | 0x36 | |
Return | 0x5a | 0x1c | |
} ] | 0x5b | 0x1b | |
Key above Return (ANSI) | 0x5c | 0x75 | |
Between + and Backspace | 0x5d | 0x2b | |
PF12 | 0x5e | 0x63 | |
PF24 | 0x5f | 0x76 | |
Cursor down | 0x60 | 0x55 | |
Cursor left | 0x61 | 0x56 | |
Cursor home | 0x62 | 0x77 | |
Cursor up | 0x63 | 0x78 | |
Backtab [Del on 102-key] | 0x64 | 0x79 | |
Insert [End on 102-key] | 0x65 | 0x7a | |
Backspace | 0x66 | 0x0e | |
PA1 [Ins on 102-key] | 0x67 | 0x7b | |
Under keypad 0 | 0x68 | 0x7c | |
Keypad 1 | 0x69 | 0x4f | |
Cursor right | 0x6a | 0x7d | |
Keypad 4 | 0x6b | 0x4b | |
Keypad 7 | 0x6c | 0x47 | |
Del [PgDn on 102-key] | 0x6d | 0x7e | |
PA2 [Home on 102-key] | 0x6e | 0x7f | |
PA3 [PgUp on 102-key] | 0x6f | 0x6f | |
Keypad 0 | 0x70 | 0x52 | |
Keypad . | 0x71 | 0x53 | |
Keypad 2 | 0x72 | 0x50 | |
Keypad 5 | 0x73 | 0x4c | |
Keypad 6 | 0x74 | 0x4d | |
Keypad 8 | 0x75 | 0x48 | |
Keypad Esc [Numlock on 102-key] | 0x76 | 0x01 | |
Keypad NumLk [Keypad / on 102-key] | 0x77 | 0x45 | |
Under keypad Enter | 0x78 | 0x57 | |
Keypad Enter | 0x79 | 0x4e | |
Keypad 3 | 0x7a | 0x51 | |
Keypad - [under keypad + on 102-key] | 0x7b | 0x4a | |
Keypad + | 0x7c | 0x37 | |
Keypad 9 | 0x7d | 0x49 | |
Keypad ScrLk [Keypad * on 102-key] | 0x7e | 0x46 | |
Keypad Space [Keypad - on 102-key] | 0x7f | 0x54 | Never seen on the wire. The keyboard sends 0x84 instead. The controller internally changes 0x84 back to 0x7F before translating it. |
L7 | 0x83 | 0x41 | |
Keypad Space [Keypad - on 102-key] | 0x84 | 0x54 |
John Elliott 3 April 2011.