📄 at keyboard interfacing.htm
字号:
is inhibited. <BR>0: Keyboard Clock = 0 - Keyboard is inhibited <BR>1:
Keyboard Clock = 1 - Keyboard is not inhibited
<LI>TxTO (Transmit Timeout) - Indicates keyboard isn't accepting input
(kbd may not be plugged in). <BR>0: No Error - Keyboard accepted the
last byte written to it. <BR>1: Timeout error - Keyboard didn't generate
clock signals within 15 ms of "request-to-send".
<LI>RxTO (Receive Timeout) - Indicates keyboard didn't respond to a
command (kbd probably broke) <BR>0: No Error - Keyboard responded to
last byte. <BR>1: Timeout error - Keyboard didn't generate clock signals
within 20 ms of command reception.
<LI>PERR (Parity Error) - Indicates communication error with keyboard
(possibly noisy/loose connection) <BR>0: No Error - Odd parity received
and proper command response recieved. <BR>1: Parity Error - Even parity
received or 0xFE received as command response.
<LI>MOBF (Mouse Output Buffer Full) - Similar to OBF, except for PS/2
mouse. <BR>0: Output buffer empty - Okay to write to auxillary device's
output buffer <BR>1: Output buffer full - Don't write to port auxillary
device's output buffer
<LI>TO (General Timout) - Indicates timeout during command write or
response. (Same as TxTO + RxTO.) <BR>0: No Error - Keyboard received and
responded to last command. <BR>1: Timeout Error - See TxTO and RxTO for
more information. </LI></UL>[EG: On my PC, the normal value of the 8042's
"Status" register is 14h = 00010100b. This indicates keyboard
communication is not inhibited, and the 8042 has already completed its
self-test ("BAT"). The "Status" register is accessed by reading from
port 64h ("IN AL, 64h")]
<P><I>Reading keyboard input:</I> </P>
<P>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. </P>
<P>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. </P>
<P>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: </P>
<P><TT>kbRead:</TT> <BR><TT>WaitLoop:
in al, 64h ; Read Status
byte</TT>
<BR><TT>
and al, 10b ; Test IBF flag
(Status<1>)</TT>
<BR><TT>
jz WaitLoop ; Wait for IBF =
1</TT>
<BR><TT>
in al, 60h ; Read input
buffer</TT> </P>
<P><I>Writing to keyboard:</I> </P>
<P>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. </P>
<P>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.) </P>
<P><TT>kbWrite:</TT> <BR><TT>WaitLoop:
in al, 64h ; Read Status
byte</TT>
<BR><TT>
and al, 01b ; Test OBF flag
(Status<0>)</TT>
<BR><TT>
jnz WaitLoop ; Wait for OBF = 0</TT>
<BR><TT>
out 60h, cl ; Write data to
output buffer</TT> </P>
<P><I>Keyboard Controller Commands:</I> </P>
<P>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. </P>
<UL>
<LI>0x20 (Read Command Byte) - Returns command byte. (See "Write
Command Byte" below).
<LI>0x60 (Write Command Byte) - Stores parameter as command byte.
Command byte defined as follows: </LI></UL>
<CENTER>
<TABLE border=0 cellPadding=0 cellSpacing=0>
<TBODY>
<TR>
<TD><BR></TD>
<TD>
<CENTER>
<TABLE border=0 cellPadding=3 cellSpacing=0 cols=8 width=400>
<TBODY>
<TR>
<TD>MSb</TD>
<TD><BR></TD>
<TD><BR></TD>
<TD><BR></TD>
<TD><BR></TD>
<TD><BR></TD>
<TD><BR></TD>
<TD>
<DIV align=right>LSb</DIV></TD></TR></TBODY></TABLE></CENTER></TD></TR>
<TR>
<TD>AT-compatible mode:</TD>
<TD>
<CENTER>
<TABLE border=1 cellPadding=2 cellSpacing=0 cols=8 width=400>
<TBODY>
<TR>
<TD>
<CENTER>--</CENTER></TD>
<TD>
<CENTER>XLAT</CENTER></TD>
<TD>
<CENTER>PC</CENTER></TD>
<TD>
<CENTER>_EN</CENTER></TD>
<TD>
<CENTER>OVR</CENTER></TD>
<TD>
<CENTER>SYS</CENTER></TD>
<TD>
<CENTER>--</CENTER></TD>
<TD>
<CENTER>INT</CENTER></TD></TR></TBODY></TABLE></CENTER></TD></TR>
<TR>
<TD>PS/2-compatible mode: </TD>
<TD>
<CENTER>
<TABLE border=1 cellPadding=2 cellSpacing=0 cols=8 width=400>
<TBODY>
<TR>
<TD>
<CENTER>--</CENTER></TD>
<TD>
<CENTER>XLAT</CENTER></TD>
<TD>
<CENTER>_EN2</CENTER></TD>
<TD>
<CENTER>_EN</CENTER></TD>
<TD>
<CENTER>--</CENTER></TD>
<TD>
<CENTER>SYS</CENTER></TD>
<TD>
<CENTER>INT2</CENTER></TD>
<TD>
<CENTER>INT</CENTER></TD></TR></TBODY></TABLE></CENTER></TD></TR></TBODY></TABLE></CENTER>
<UL>
<UL>
<LI>INT (Input Buffer Full Interrupt) - When set, IRQ 1 is generated
when data is available in the input buffer. <BR>0: IBF Interrupt
Disabled - You must poll STATUS<IBF> to read input. <BR>1: IBF
Interrupt Enabled - Keyboard driver at software int 0x09 handles
input.
<LI>SYS (System Flag) - Used to manually set/clear SYS flag in Status
register. <BR>0: Power-on value - Tells POST to perform power-on
tests/initialization. <BR>1: BAT code received - Tells POST to perform
"warm boot" tests/initiailization.
<LI>OVR (Inhibit Override) - Overrides keyboard's "inhibit" switch on
older motherboards. <BR>0: Inhibit switch enabled - Keyboard inhibited
if pin P17 is high. <BR>1: Inhibit switch disabled - Keyboard not
inhibited even if P17 = high.
<LI>_EN (Disable keyboard) - Disables/enables keyboard interface.
<BR>0: Enable - Keyboard interface enabled. <BR>1: Disable - All
keyboard communication is disabled.
<LI>PC ("PC Mode") - ???Enables keyboard interface somehow??? <BR>0:
Disable - ??? <BR>1: Enable - ???
<LI>XLAT (Translate Scan Codes) - Enables/disables translation to set
1 scan codes. <BR>0: Translation disabled - Data appears at input
buffer exactly as read from keyboard <BR>1: Translation enabled - Scan
codes translated to set 1 before put in input buffer
<LI>INT2 (Mouse Input Buffer Full Interrupt) - When set, IRQ 12 is
generated when mouse data is available. <BR>0: Auxillary IBF Interrupt
Disabled - <BR>1: Auxillary IBF Interrupt Enabled -
<LI>_EN2 (Disable Mouse) - Disables/enables mouse interface. <BR>0:
Enable - Auxillary PS/2 device interface enabled <BR>1: Disable -
Auxillary PS/2 device interface disabled </LI></UL></UL>
<UL>
<LI>?0x90-0x9F (Write to output port) - Writes command's lower nibble to
lower nibble of output port (see Output Port definition.)
<LI>?0xA1 (Get version number) - Returns firmware version number.
<LI>?0xA4 (Get password) - Returns 0xFA if password exists; otherwise,
0xF1.
<LI>?0xA5 (Set password) - Set the new password by sending a
null-terminated string of scan codes as this command's parameter.
<LI>?0xA6 (Check password) - Compares keyboard input with current
password.
<LI>0xA7 (Disable mouse interface) - PS/2 mode only. Similar to
"Disable keyboard interface" (0xAD) command.
<LI>0xA8 (Enable mouse interface) - PS/2 mode only. Similar to
"Enable keyboard interface" (0xAE) command.
<LI>0xA9 (Mouse interface test) - Returns 0x00 if okay, 0x01 if Clock
line stuck low, 0x02 if clock line stuck high, 0x03 if data line stuck
low, and 0x04 if data line stuck high.
<LI>0xAA (Controller self-test) - Returns 0x55 if okay.
<LI>0xAB (Keyboard interface test) - Returns 0x00 if okay, 0x01 if Clock
line stuck low, 0x02 if clock line stuck high, 0x03 if data line stuck
low, and 0x04 if data line stuck high.
<LI>0xAD (Disable keyboard interface) - Sets bit 4 of command byte and
disables all communication with keyboard.
<LI>0xAE (Enable keyboard interface) - Clears bit 4 of command byte and
re-enables communication with keyboard.
<LI>0xAF (Get version)
<LI>0xC0 (Read input port) - Returns values on input port (see Input
Port definition.)
<LI>0xC1 (Copy input port LSn) - PS/2 mode only. Copy input port's low
nibble to Status register (see Input Port definition)
<LI>0xC2 (Copy input port MSn) - PS/2 mode only. Copy input port's high
nibble to Status register (see Input Port definition.)
<LI>0xD0 (Read output port) - Returns values on output port (see Output
Port definition.)
<LI>0xD1 (Write output port) - Write parameter to output port (see
Output Port definition.)
<LI>0xD2 (Write keyboard buffer) - Parameter written to input buffer as
if received from keyboard.
<LI>0xD3 (Write mouse buffer) - Parameter written to input buffer as if
received from mouse.
<LI>0xD4 (Write mouse Device) - Sends parameter to the auxillary PS/2
device.
<LI>0xE0 (Read test port) - Returns values on test port (see Test Port
definition.)
<LI>0xF0-0xFF (Pulse output port) - Pulses command's lower nibble onto
lower nibble of output port (see Output Port definition.) </LI></UL>
<P><BR><I>Modern Keyboard Controllers:</I> </P>
<P>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.) </P>
<P>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.) </P>
<P>Once again, keep in mind chipset designers are more interested in
compatibility than standardization. </P>
<P><B>Initialization:</B> </P>
<P>The following is the communication between my computer and keyboard
when it boots-up. I beleive the first three commands were initiated
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -