Introduction: This article tries to cover every aspect of AT and PS/2 keyboards. It includes information on the low-level signals and protocol, scan codes, the command set, initialization, compatibility issues, and other miscellaneous information. Since it's closely related, I've also included information on the PC keyboard controller. All code samples involving the keyboard interface are written in assembly for Microchip's PIC microcontrollers. All code samples related to the keyboard controller are written in x86 assembly. I should mention that all of the information in this article comes from my own experiences and other sources that may or may not be accurate. I did not consult any official documentation of since none has been available to me. Therefore, I provide the following disclaimer: ALL INFORMATION WITHIN THIS ARTICLE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. I DO NOT GUARANTEE ANY INFORMATION IN THIS ARTICLE IS ACCURATE, AND IT SHOULD BE USED FOR ABSTRACT EDUCATIONAL PURPOSES ONLY. You may click here to goto my main page. There, you will find other articles, code, projects, and links related to the computer keyboard. Please send me an email if you find any errors on these pages. A History Lesson: The most popular keyboards in use today include:
IBM PC/XT Keyboard (1981):
Today, "AT keyboard" and "PS/2 keyboard" refers only to their connector size. Which settings/commands any given keyboard does or does not support is anyone's guess. For example, the keyboard I'm using right now has a PS/2-style connector but only fully supports seven commands, partially supports two, and merely "acknowledges" the rest. In contrast, my "Test" keyboard has an AT-style connector but supports every feature/command of the original PS/2 device (plus a few extra.) It's important you treat modern keyboards as compatible, not standard. If your project relies on non-general features, it may work on some systems, but not on others... Modern AT-PS/2 compatible keyboards
Footnote 1) XT keyboards use a completely different protocol than that used by AT and PS/2 systems, making it incompatible with the newer PCs. However, there was a transition period where some keyboard controllers supported both XT and AT-PS/2 keyboards (through a switch, jumper, or auto-sense.) Also, some keyboards were made to work on both types of systems (again, through the use of a switch or auto-sensing.) If you've owned such a PC or keyboard, don't let it fool you--XT keyboards are NOT compatible with modern computers. General Description: Keyboards consist of a large matrix of keys, all of which are monitored
by an on-board processor (called the "keyboard encoder".) The specific
processor(1) varies
from keyboard-to-keyboard but they all basically do the same thing:
Monitor which key(s) are being pressed/released and send the appropriate
data to the host. This processor takes care of all the debouncing
and buffers any data in its 16-byte buffer, if needed. Your motherboard
contains a "keyboard controller"(2) that is in charge of decoding
all of the data received from the keyboard and informing your software of
what's going on. All communication between the host and the keyboard
uses an IBM protocol. Electrical Interface / Protocol: The AT and PS/2 keyboards use the same protocol as the PS/2 mouse. Click here for detailed information about that protocol. Scan Codes: Your keyboard's processor spends most of its time "scanning", or monitoring, the matrix of keys. If it finds that any key is being pressed, released, or held down, the keyboard will send a packet of information known as a "scan code" to your computer. There are two different types of scan codes: "make codes" and "break codes". A make code is sent when a key is pressed or held down. A break code is sent when a key is released. Every key is assigned its own unique make code and break code so the host can determine exactly what happened to which key by looking at a single scan code. The set of make and break codes for every key comprises a "scan code set". There are three standard scan code sets, named one, two, and three. All modern keyboards default to set two.(1) So how do you figure out what the scan codes are for each key? Unfortunately, there's no simple formula for calculating this. If you want to know what the make code or break code is for a specific key, you'll have to look it up in a table. I've composed tables for all make codes and break codes in all three scan code sets:
Footnote 1) Originally, the AT keyboard only supported set two, and the PS/2 keyboard would default to set two but supported all three. Most modern keyboards behave like the PS/2 device, but I have come across a few that didn't support set one, set three, or both. Also, if you've ever done any low-level PC programming, you've probably notice the keyboard controller supplies set ONE scan codes by default. This is because the keyboard controller converts all incomming scan codes to set one (this stems from retaining compatibility with software written for XT systems.) However, it's still set two scan codes being sent down the keyboard's serial line. Make Codes, Break Codes, and Typematic Repeat: Whenever a key is pressed, that key's make code is sent to the computer. Keep in mind that a make code only represents a key on a keyboard--it does not represent the character printed on that key. This means that there is no defined relationship between a make code and an ASCII code. It's up to the host to translate scan codes to characters or commands. Although most set two make codes are only one-byte wide, there are a handfull of "extended keys" whose make codes are two or four bytes wide. These make codes can be identified by the fact that their first byte is E0h. Just as a make code is sent to the computer whenever a key is pressed, a break code is sent whenever a key is released. In addition to every key having its own unique make code, they all have their own unique break code(1). Fortunately, however, you won't always have to use lookup tables to figure out a key's break code--certain relationships do exist between make codes and break codes. Most set two break codes are two bytes long where the first byte is F0h and the second byte is the make code for that key. Break codes for extended keys are usually three bytes long where the first two bytes are E0h, F0h, and the last byte is the last byte of that key's make code. As an example, I have listed below a the set two make codes and break codes for a few keys: If you press a key, its make code is sent to the computer. When you press and hold down a key, that key becomes typematic, which means the keyboard will keep sending that key's make code until the key is released or another key is pressed. To verify this, open a text editor and hold down the "A" key. When you first press the key, the character "a" immediately appears on your screen. After a short delay, another "a" will appear followed by a whole stream of "a"s until you release the "A" key. There are two important parameters here: the typematic delay, which is the short delay between the first and second "a", and the typematic rate, which is how many characters per second will appear on your screen after the typematic delay. The typematic delay can range from 0.25 seconds to 1.00 second and the typematic rate can range from 2.0 cps (characters per second) to 30.0 cps. You may change the typematic rate and delay using the "Set Typematic Rate/Delay" (0xF3) command.Example: What sequence of make codes and break codes should be sent to your computer for the character "G" to appear in a word processor? Since this is an upper-case letter, the sequence of events that need to take place are: press the "Shift" key, press the "G" key, release the "G" key, release the "Shift" key. The scan codes associated with these events are the following: make code for the "Shift" key (12h), make code for the "G" key (34h), break code for the "G" key(F0h,34h), break code for the "Shift" key (F0h,12h). Therefore, the data sent to your computer would be: 12h, 34h, F0h, 34h, F0h, 12h. Typematic data is not buffered within the keyboard. In the case where more than one key is held down, only the last key pressed becomes typematic. Typematic repeat then stops when that key is released, even though other keys may be held down. Reset: At power-on or software reset (see the "Reset" command) the keyboard performs a diagnostic self-test referred to as BAT (Basic Assurance Test) and loads the following default values:
When entering BAT, the keyboard enables its three LED indicators, and turns them off when BAT has completed. At this time, a BAT completion code of either 0xAA (BAT successful) or 0xFC (Error) is sent to the host. This BAT completion code must be sent 500~750 milliseconds after power-on. Many of the keyboards I've tested ignore their CLOCK and DATA lines until after the BAT completion code has been sent. Therefore, an "Inhibit" condition (CLOCK line low) may not prevent the keyboard from sending its BAT completion code. Command Set: A few notes regarding commands the host can issue to the keyboard:
The next six commands can be issued when the keyboard is in any mode, but it only effects the behavior of the keyboard when in "mode 3" (ie, set to scan code set 3.)
.
Delay
*Originally available in PS/2 keyboards only. Emulation:
Up to this point in the article, all information has been presented from a hardware point-of-view. However, if you're writing low-level keyboard-related software for the host PC, you won't be communicating directly with the keyboard. Instead, a keyboard controller provides an interface between the keyboard and the peripheral bus. This controller takes care of all the signal-level and protocol details, as well as providing some conversion, interpretation, and handling of scan codes and commands. An Intel 8042/compatible microcontroller is used as the PC's keyboard controller. In modern computers, this microcontroller is hidden within the motherboard's chipset, which integrates many controllers in a single package. Nonetheless, this device is still there, and the keyboard controller is still commonly referred to as "the 8042". Depending on the motherboard, the keyboard controller may operate in one of two modes: "AT-compatible" mode, or "PS/2-compatible" mode. The latter is used if a PS/2 mouse is supported by the motherboard. If this is the case, the 8042 acts as the keyboard controller and the mouse controller. The keyboard controller auto-detects which mode it is to use according to how it's wired to the keyboard port. The 8042 contains the following registers:
Writing to port 0x64 doesn't write to any specific register, but sends a command for the 8042 to interpret. If the command accepts a parameter, this parameter is sent to port 0x60. Likewise, any results returned by the command may be read from port 0x60. When describing the 8042, I may occasionally refer to its physical I/O pins. These pins are defined below: AT-compatible mode
PS/2-compatible mode
(Note: Reading keyboard controller datasheets can be confusing--it will refer to the "input buffer" as the "output buffer" and vice versa. This makes sense from the point-of-view of someone writing firmware for the controller, but for somebody used to interfacing the controller, this can cause problems. Throughout this document, I only refer to the "input buffer" as the one containing input from the keyboard, and the "output buffer" as the one that contains output to be sent to the keyboard.) Status Register: The 8042's status flags are read from port 0x64. They contain
error information, status information, and indicate whether or not data
is present in the input and output buffers. The flags are defined as
follows:
0: Output buffer empty - Okay to write to port 0x60 1: Output buffer full - Don't write to port 0x60 0: Input buffer empty - No unread input at port 0x60 1: Input buffer full - New input can be read from port 0x60 0: Power-up value - System is in power-on reset. 1: BAT code received - System has already beed initialized. 0: A2 = 0 - Port 0x60 was last written to 1: A2 = 1 - Port 0x64 was last written to 0: Keyboard Clock = 0 - Keyboard is inhibited 1: Keyboard Clock = 1 - Keyboard is not inhibited 0: No Error - Keyboard accepted the last byte written to it. 1: Timeout error - Keyboard didn't generate clock signals within 15 ms of "request-to-send". 0: No Error - Keyboard responded to last byte. 1: Timeout error - Keyboard didn't generate clock signals within 20 ms of command reception. 0: No Error - Odd parity received and proper command response recieved. 1: Parity Error - Even parity received or 0xFE received as command response. 0: Output buffer empty - Okay to write to auxillary device's output buffer 1: Output buffer full - Don't write to port auxillary device's output buffer 0: No Error - Keyboard received and responded to last command. 1: Timeout Error - See TxTO and RxTO for more information. Reading keyboard input: When the 8042 recieves a valid scan code from the keyboard, it is converted to its set 1 equivalent. The converted scan code is then placed in the input buffer, the IBF (Input Buffer Full) flag is set, and IRQ 1 is asserted. Furthermore, when any byte is received from the keyboard, the 8042 inhibits further reception (by pulling the "Clock" line low), so no other scan codes will be received until the input buffer is emptied. If enabled, IRQ 1 will activate the keyboard driver, pointed to by interrupt vector 0x09. The driver reads the scan code from port 0x60, which causes the 8042 to de-assert IRQ 1 and reset the IBF flag. The scan code is then processed by the driver, which responds to special key combinations and updates an area of the system RAM reserved for keyboard input. If you don't want to patch into interrupt 0x09, you may poll the keyboard controller for input. This is accomplished by disabling the 8042's IBF Interrupt and polling the IBF flag. This flag is set (1) when data is available in the input buffer, and is cleared (0) when data is read from the input buffer. Reading the input buffer is accomplished by reading from port 0x60, and the IBF flag is at port 0x64, bit 1. The following assembly code illustrates this: kbRead: Writing to keyboard: When you write to the 8042's output buffer (via port 0x60), the controller sets the OBF ("Output Buffer Full") flag and processes the data. The 8042 will send this data to the keyboard and wait for a response. If the keyboard does not accept or generate a response within a given amount of time, the appropriate timeout flag will be set (see Status register definition for more info.) If an incorrect parity bit is read, the 8042 will send the "Resend" (0xFE) command to the keyboard. If the keyboard continues to send erroneous bytes, the "Parity Error" flag is set in the Status register. If no errors occur, the response byte is placed in the input buffer, the IBF ("Input Buffer Full") flag is set, and IRQ 1 is activated, signaling the keyboard driver. The following assembly code shows how to write to the output buffer. (Remember, after you write to the output buffer, you should use int 9h or poll port 64h to get the keyboard's response.) kbWrite: Keyboard Controller Commands: Commands are sent to the keyboard controller by writing to port 0x64. Command parameters are written to port 0x60 after teh command is sent. Results are returned on port 0x60. Always test the OBF ("Output Buffer Full") flag before writing commands or parameters to the 8042.
0: IBF Interrupt Disabled - You must poll STATUS<IBF> to read input. 1: IBF Interrupt Enabled - Keyboard driver at software int 0x09 handles input. 0: Power-on value - Tells POST to perform power-on tests/initialization. 1: BAT code received - Tells POST to perform "warm boot" tests/initiailization. 0: Inhibit switch enabled - Keyboard inhibited if pin P17 is high. 1: Inhibit switch disabled - Keyboard not inhibited even if P17 = high. 0: Enable - Keyboard interface enabled. 1: Disable - All keyboard communication is disabled. 0: Disable - ??? 1: Enable - ??? 0: Translation disabled - Data appears at input buffer exactly as read from keyboard 1: Translation enabled - Scan codes translated to set 1 before put in input buffer 0: Auxillary IBF Interrupt Disabled - 1: Auxillary IBF Interrupt Enabled - 0: Enable - Auxillary PS/2 device interface enabled 1: Disable - Auxillary PS/2 device interface disabled
So far, I've only discussed the 8042 keyboard controller. Although modern keyboard controllers remain compatible with the original device, compatibility is their only requirement (and their goal.) My motherboard's keyboard controller is a great example of this. I connected a microcontroller+LCD in parallel to my keyboard to see what data is sent by the keyboard controller. At power-up, the keyboard controller sent the "Set LED state" command to turn off all LEDs, then reads the keyboard's ID. When I tried writing data to the output buffer, I found the keyboard controller only forwards the "Set LED state" command and "Set Typematic Rate/Delay" command. It does not allow any other commands to be sent to the keyboard. However, it does emulate the keyboard's response by placing "acknowledge" (0xFA) in the input buffer when appropriate (or 0xEE in response to the "Echo" command.) Furthermore, if the keyboard sends it an erroneous byte, the keyboard controller takes care of error handling (sends the "Retry" command; if byte still erroneous; sends error code to keyboard and places error code in input buffer.) Once again, keep in mind chipset designers are more interested in compatibility than standardization. Initialization: The following is the communication between my computer and keyboard when it boots-up. I beleive the first three commands were initiated by the keyboad controller, the next command (which enables Num lock LED) was sent by the BIOS, then the rest of the commands were sent my the OS (Win98SE). Remember, these results are specific to my computer, but it should give you a general idea as to what happens at startup. Keyboard: AA Self-test passed ;Keyboard controller init
|