The original IBM PC (1981), and its immediate successor, the IBM PC/XT (1983), had keyboards limited to unidirectional communication:  data flowed one-way from the keyboard to the motherboard.

With the launch of the IBM PC/AT (1984), IBM added a keyboard controller, the venerable Intel 8042.  The Intel 8042 implemented a bidirectional keyboard controller interface based on I/O ports 0x60 and 0x64, which remains with us today, 40 years later:

Arrow Lake-S PCH datasheet, 2024

The keyboard controller communicates with the system through a status register, a command register, an output buffer, and an input buffer; and communicates with the keyboard via an input port and output port.

credit: The Indispensable PC Hardware Book

The keyboard controller sends and receives serial data to and from the keyboard, checks the parity of the data, translates scan codes, and presents the data to the system as a byte of data in its output buffer. The controller will interrupt the system (IRQ1) when data is placed in its output buffer. The status register contains bits that indicate if an error was detected while receiving the data. Data may be sent to the keyboard by writing commands to the keyboard controller's input buffer.

From the IBM PC/AT Technical Reference:

PC/AT Tech Ref, 1984

It's important to distinguish between sending commands or data to the keyboard controller vs. the keyboard.  Both are possible.  The following tables illustrate which commands are available for each target, and should make this distinction more clear.

Keyboard Commands

Commands and data for the keyboard are sent to the keyboard controller on port 0x60, then passed on to the keyboard.  Note that several of these commands are for a PS/2 mouse.  When addressing the mouse, the programmer first sends the keyboard controller the command 0xD4 over port 0x64; then, the next byte to port 0x60 will be directed to the mouse, rather than the keyboard.

credit:  The Undocumented PC

Keyboard Controller Commands

Commands and data meant for the keyboard controller are sent to port 0x64.

credit:  The Undocumented PC

Let's try some examples.  Let's read the status register the old-fashioned way, in assembly from DOS:

  1. Before any instruction, AX is 0
  2. Execute the instruction IN AL,64, which reads into AL one byte from I/O port 0x64
  3. Note that now AX contains the value 0x1C

For a more modern rendition, let's do the same thing from the UEFI Shell:

The mm command reads/writes memory, MMIO, PCI/PCIe, and I/O space.  This short command is saying the same thing we did in DOS:  read a byte from I/O port 0x64, and it comes up with the same answer, 0x1C.

So, what does 0x1C mean?  Here is the status register definition and bit pattern breakdown:

credit: The Indispensable PC Hardware Book

Moving from least-significant to most-significant:

bit 0:  OUTB, output buffer state, 0 = buffer empty
bit 1:  INPB, input buffer state, 0 = buffer empty
bit 2:  SYSF, 1 = self-test successful
bit 3:  C/D, command/data?, 1 = command to port 0x64
bit 4:  KEYL, keyboard lock status, 1 = keyboard free
bit 5:  AUXB, output buffer for PS/2 devices, 0 = keyboard data
bit 6:  TIM, time-out, 0 = no time-out error
bit 7:  PARE, parity error, 0 = last byte without parity error

Here's another example:  let's send the keyboard controller the Disable Keyboard command:

  1. We put 0xAD in AL, the keyboard controller command to Disable Keyboard
  2. Send 0xAD to port 0x64

Warning!  This really will disable the keyboard, including Ctrl+Alt+Del! 😀

Input and Output Ports

Finally, don't confuse the input and output ports with the input and output buffers—see the diagram (above) where they are both represented.  For example, you can read the input port by passing the keyboard controller the command read input port via port 0x64. The keyboard controller then transfers the contents of the input port to the output buffer, from which you may read the byte with an IN instruction referring to port 0x60.

Input port, The Indispensable PC Hardware Book

Output port, The Indispensable PC Hardware Book

Note that while the register definitions I've provided here are correct historically, if you're going to use this interface on a modern system you'll need to check your embedded controller's datasheet.  While much of this information is unchanged, other values may be interpreted differently, or ignored, on modern implementations.

Sharp-eyed readers will notice references in these command/register definitions to Enable A20 Address Line, or gate for A20.  Historically, the keyboard controller played a role in managing the A20 gate.  I'm not going to describe that here, (maybe a topic for a future article!) since the A20 gate functionality was removed from hardware 10+ years ago.

Conclusion

I hope you enjoyed this overview of the keyboard controller interface.  While it's a decent-enough overview, there are definitely nuances and use cases I didn't take the time to explain here.  If you need a comprehensive technical deep dive, I recommend a book like The Indispensable PC Hardware Book.

Post a Comment

Be sure to select an account profile (e.g. Google, OpenID, etc.) before typing your comment!