"8042" PS/2 Controller: Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
(→‎Interrupts: Do any PS/2 controllers not raise IRQs for response bytes?)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(16 intermediate revisions by 14 users not shown)
Line 1:
The PS/2 Controller (often called a "Keyboard“Keyboard controller"controller”) is located on the mainboard. In the early days the controller was a single chip ('''Intel 8042'''). As of today it is part of the [[Advanced Integrated Peripheral]].
== Overview ==
 
The PS/2 Controller (often called a "Keyboard controller") is located on the mainboard. In the early days the controller was a single chip (8042). As of today it is part of the [[Advanced Integrated Peripheral]].
 
The name is misleading because the controller does more than controlling communication with PS/2 devices.
Line 12 ⟶ 10:
== History ==
 
TheA original unimulti-directional, single channel IBM PC and PC-XT keyboard interface was controlled by a multi purpose PPI (Intel 8048, Programmable peripheral interface; also used to control other functions, like sound and parity error) controlled the original uni-directional, single channel IBM PC and PC-XT keyboard interface.
The XT controller is 100% obsolete and won't be discussed further in this page.
 
 
With the PC-AT, IBM introduced new keyboards (with a new bi-directional protocol) and a new keyboard controller (Intel 8042). The old PPI was not part of the mother boardmotherboard any more.
 
{|
Line 22 ⟶ 20:
|}
 
The 8042 was a powerful microcontrollermicro-controller. To reduce costs, some of the general purpose input/output capabilities of the AT controller was used to control various functions unrelated to the keyboard, including :
* System Reset
* The [[A20 Line|A20-Gate]]
 
 
With the introduction of the PS/2 series, the main change to the keyboard controller subsystem was its expansion to control both a keyboard and a mouse. Previously PC and compatible mice were connected to different physical interfaces, including [[Serial Ports]]. The AT keyboard controller and its "clones"“clones” were not capable of interfacing the new PS/2 mouse. Eventually (around the late 80486 and early Pentium time frame) PS/2 style mice became popular, and "PC-compatible"“PC compatible” controllers have supported dual channels from then on (nominally one keyboard and one mouse).
 
For the keyboard functions proper, the PS2 and AT controllers are very similar. The adjunction of a second channel (for the mouse) has forced however to redefine a few status and control bits.
Line 37 ⟶ 35:
Whenever this translation is enabled (and by default, it is) there is no way to reverse it in software. For example, if you receive the byte 0xB5 from the controller, then you can't know if the original data (sent to the controller by the device) was the byte 0xB5; or if it was the two bytes 0xF0, 0x33; or if it was the two bytes 0xF0, 0xB3.
 
For software to actually use "scan code set 2" (or the even newer, rarely used, "scan code set 3"), or to allow different types of devices to be used in the keyboard port, you need to disable this translation to avoid having the data from the device mangled.
 
== USB Legacy Support ==
Line 46 ⟶ 44:
* The [[SMM BIOS]] that's providing the PS/2 USB Legacy Support may not support extended memory techniques or [[Long Mode]] and may cause system crashes.
 
This USB Legacy Support should be disabled by the OS as soon as the OS initialises the USB Controller, and this should be done before the OS attempts to initialise the real PS/2 controller. Otherwise the OS would only be initialisinginitialise the emulated PS/2 controller and there's a large risk of problems caused by deficiencies in the firmware's emulation.
 
== Buffer Naming Perspective ==
 
The PS/2 controller has two (one byte) buffers for data - one buffer for data received from devices that is waiting to be read by your OS, and one for data written by your OS that is waiting to be sent to a PS/2 device. Most datasheetsdata sheets for PS/2 controllers are written from the perspective of the PS/2 device and not from the perspective of software running on the host. Because of this, the names given to these buffers are the opposite of what you expect: the output buffer contains a device's output data (data waiting to be read by software), and the input buffer contains a device's input (data that was sent by software).
 
 
== PS/2 Controller IO Ports ==
 
The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access completely different internal registers.
 
Historical note : The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles.
 
{| {{wikitable}}
Line 81 ⟶ 79:
=== Data Port ===
 
The Data Port (IO Port 0x60) is used for reading data that was received from a PS/2 device or from the PS/2 controller itself, and writing data to a PS/2 device or to the PS/2 controller itself.
 
 
=== Status Register ===
 
The Status Register contains various flags that indicateshow the state of the PS/2 controller. The meanings for each bit are:
 
{| {{wikitable}}
Line 131 ⟶ 129:
== PS/2 Controller Commands ==
 
The PS/2 Controller accepts some commands and performs them. These commands should not be confused with bytes sent to a PS/2 device (e.g. keyboard, mouse).
 
To send a command to the controller, simply write the command byte to IO port 0x64. If there is a "next byte" (the command is 2 bytes) then the next byte needs to be written to IO Port 0x60 after making sure that the controller is ready for it (by making sure bit 1 of the Status Register is clear). If there is a response byte, then the response byte needs to be read from IO Port 0x60 after making sure that it has arrived (by making sure bit 0 of the Status Register is set).
 
 
Line 188 ⟶ 186:
|-
|0xAC
|Diagnostic dump (realread all bytes of internal RAM)
|Unknown
|-
Line 318 ⟶ 316:
 
Note: Bits that are marked in the table above as "only if 2 PS/2 ports supported" should be treated as either "chipset specific" or "unknown" if the controller only supports one PS/2 port.
 
 
== Initialising the PS/2 Controller ==
Line 324 ⟶ 321:
Some people assume the PS/2 controller exists and was configured correctly by firmware. This approach can work, but isn't very robust and doesn't correctly support "less simple" scenarios. Examples of why this approach may not work well include:
* Something (e.g. a Boot Manager) left the PS/2 Controller in a dodgy state
* The PS/2 Controller has hardware faults and your OS didn'tdid do anyno testing
* There's a USB keyboard and a PS/2 mouse, and the BIOS didn't bother initialising the PS/2 controller because it was using USB Legacy Support and not using the mouse
* You want to reliably send data to the second PS/2 device on older hardware and have to know the second PS/2 port exists (see the warning for "Sending Bytes To The Second PS/2 Port" below).
Line 332 ⟶ 329:
==== Step 1: Initialise USB Controllers ====
 
This doesn'thas have anythingnothing to do with the PS/2 Controller or PS/2 Devices, however if the system is using (typically limited/dodgy) USB Legacy Support it will interfere with PS/2 Controller initialisation. Therefore you need to initialise USB controllers and disable USB Legacy Support beforehand.
 
==== Step 2: Determine if the PS/2 Controller Exists ====
Before you touch the PS/2 controller at all, you should determine if it actually exists. On some systems (e.g. 80x86 Apple machines) it doesn't exist and any attempt to touch it can result incause a system crash. The correct way to do this is is with [[ACPI]]. More specifically, checkCheck bit 1 (value = 2, the "8042" flag) in the "IA PC Boot Architecture Flags" field at offset 109 in the Fixed ACPI Description Table (FADT). If this bit is clear, then there is no PS/2 Controller to configure. Otherwise, if the bit is set, or the system doesn't support ACPI (no ACPI tables and no FADT) then there is a PS/2 Controller.
 
==== Step 3: Disable Devices ====
Line 341 ⟶ 338:
 
==== Step 4: Flush The Output Buffer ====
Sometimes (e.g. due to interrupt controllercontrolled initialisation causing a lost IRQ) data can beget stuck in the PS/2 controller's output buffer. To guard against this, now that the devices are disabled (and can't send more data to the output buffer) it can be a good idea to flush the controller's output buffer. There's 2 ways to do this - poll bit 0 of the Status Register (while reading from IO Port 0x60 if/when bit 0 becomes set), or read from IO Port 0x60 without testing bit 0. Either way should work (as you're discarding the data and don't care what it was).
 
==== Step 5: Set the Controller Configuration Byte ====
 
Because some bits of the Controller Configuration Byte are "unknown", this means reading the old value (command 0x20), changing some bits, then writing the modifiedchanged value back (command 0x60). You want to disable all IRQs and disable translation (clear bits 0, 1 and 6).
 
While you've got the Configuration Byte, test if bit 5 was set. If it was clear, then you know it can't be a "dual channel" PS/2 controller (because the second PS/2 port should be disabled).
 
==== Step 6: Perform Controller Self Test ====
 
To test the PS/2 controller, send command 0xAA to it. Then wait for its response and check that it replied with 0x55. Note: this can reset the PS/2 controller on some hardware (tested on a 2016 laptop). At the very least, the Controller Configuration Byte should be restored for compatibility with such hardware. You can either determine the correct value yourself based on the above table or restore the value read before issuing 0xAA.
 
==== Step 7: Determine If There Are 2 Channels ====
Line 361 ⟶ 358:
This step tests the PS/2 ports. Use command 0xAB to test the first PS/2 port, then check the result. Then (if it's a "dual channel" controller) use command 0xA9 to test the second PS/2 port, then check the result.
 
At this stage, check to see how many PS/2 ports are left. If there aren't any that work you can just give up (display some errors and terminate the PS/2 Controller driver). ''Note: If one of the PS/2 ports on a dual PS/2 controller fails, then you can still keep going and useusing/supportsupporting the other PS/2 port.''
 
==== Step 9: Enable Devices ====
Line 373 ⟶ 370:
'''TODO''': Potential wiki error, the 0xFF reset device command seems to respond 0xAA and then 0xFA on self-test success, and [[PS/2_Keyboard]] agrees. --[[User:Sortie|Sortie]] 14:15, 27 April 2015 (CDT)
 
'''TODO''': Sortie: I don't think so, I send byte 0xFF to keyboard (or mouse), then received 0xFA (command acknowledged) after that reveivedreceived 0xAA (self test successful) the last one was 0x00 - mouse device ID. --[[User:Akasei|Akasei]] 00:35, 19 February 2017 (UTC+1)
 
== Detecting PS/2 Device Types ==
 
All PS/2 devices should support the "identify" command and the "disable scanning" command (which are commands for the device, and not commands for the PS/2 Controller). The device should respond to the "identify" command by sending a sequence of none, one or two identification bytes. However, if you just send the "identify" command you can't prevent the response from the "identify" command from being mixed up with keyboard/mouse data. To fix this problem, you need to send the "disable scanning" command first. Disabling scanning means that the device ignores the user (e.g. keyboards ignore keypresseskey presses, mice ignore mouse movement and button presses, etc) and won't send data to mess your device identification code up.
 
The full sequence is:
* Send the "disable scanning" command 0xF5 to the device
* Wait for the device to send "ACK" back (0xFA)
* Send the "identify" command 0xF2 to the device
* Wait for the device to send "ACK" back (0xFA)
* Wait for the device to send up to 2 bytes of reply, with a time-out to determine when it's finished (e.g. in case it only sends 1 byte)
* Send the "enable scanning" command 0xF4 to the device
 
A partial list of responses includes:
Line 390 ⟶ 388:
{| {{wikitable}}
|-
! Bytes (Normal)
! Byte/s
! Bytes (Translated*)
! Device Type
|-
| None
| None
| Ancient AT keyboard with translation enabled in the PS/Controller (not possible for the second PS/2 port)
| MF2Ancient AT keyboard
|-
| 0x00
| n/a
| Standard PS/2 mouse
|-
| 0x03
| n/a
| Mouse with scroll wheel
|-
| 0x04
| n/a
| 5-button mouse
|-
| 0xAB, 0x41 or 0xAB, 0xC1
| MF2 keyboard with translation enabled in the PS/Controller (not possible for the second PS/2 port)
|-
| 0xAB, 0x83
| 0xAB, 0x41 or 0xAB, 0xC1
| MF2 keyboard
| rowspan="2" | MF2 keybaord
|-
| 0xAB, 0xC1
| 0xAB, 0xC1
|-
| 0xAB, 0x84
| 0xAB, 0x54
| IBM ThinkPads, Spacesaver keyboards, many other "short" keyboards
|-
| rowspan="2" | 0xAB, 0x85
| rowspan="2" | 0xAB, 0x85
| NCD N-97 keyboard
|-
| 122-Key Host Connect(ed) Keyboard
|-
| 0xAB, 0x86
| 0xAB, 0x86
| 122-key keyboards
|-
| 0xAB, 0x90
| 0xAB, 0x90
| Japanese "G" keyboards
|-
| 0xAB, 0x91
| 0xAB, 0x91
| Japanese "P" keyboards
|-
| 0xAB, 0x92
| 0xAB, 0x92
| Japanese "A" keyboards
|-
| 0xAC, 0xA1
| 0xAC, 0xA1
| NCD Sun layout keyboard
|}
 
<nowiki>*</nowiki> Translation is not possible for the second PS/2 port
Note: If anyone sees any other responses please add to the list above!
 
Notes:
Once your PS/2 Controller driver knows what types of PS/2 devices are present, it can start suitable device drivers for those devices. Don't forget that we've left devices in a "scanning disabled" state.
Note:* If anyone sees any other responses please add to the list above!
* Translated IDs are provided in the table above for completeness, but it's arguably better to disable translation in the controller prior to pulling a device ID to avoid potential confusion.
 
Once your PS/2 Controller driver knows what types of PS/2 devices are present, it can start suitable device drivers for those devices. Don't forget that we've left devices in a "scanning disabled" state.
 
== Hot Plug PS/2 Devices ==
 
'''WARNING:''' PS/2 was never intentionally designed to support hot-plug. Usually it is fine as most PS/2 controllers have reasonably robust IO lines, however some PS/2 controllers (mostly those in old chipsets) maymight potentially beget damaged.
 
Despite the warning, most OSs (Windows, Linux, etc) do support hot-plug PS/2. It is also relied on by old "mechanical switch" KVMs (which allow multiple computers to share the same PS/2 devices to be shared by multiple computers by effectively disconnecting the device from one computer and connecting it to the next).
 
When a PS/2 device is removed the PS/2 controller won't know. To work around this, when no data has been received from the device for some length of time (e.g. 2 seconds), an OS can periodically test for the presence of the device by sending an "echo" command to the device and checking for a reply. If the device doesn't respond, then assume the device has been unplugged.
Line 432 ⟶ 469:
== Sending Bytes To Device/s ==
 
Unfortunately, the PS/2 Controller does not support interrupt driven transmission (e.g. you can't have a queue of bytes waiting to be sent and then send each byte from inside a "transmitter empty" IRQ handler). Fortunately very, little data needs to be sent to typical PS/2 devices and polling suffices.
 
=== First PS/2 Port ===
 
To send data to the first PS/2 Port:
* Set up some sort of timer or counter to use as a time-out
* Poll bit 1 of the Status Register ("Input buffer empty/full") until it becomes clear, or until your time-out expires
* If the time-out expired, return an error
Line 446 ⟶ 483:
Sending data to the second PS/2 port is a little more complicated, as you need to send a command to the PS/2 controller to tell it that you want to talk to the second PS/2 port instead of the first PS/2 port. To send data to the second PS/2 Port:
* Write the command 0xD4 to IO Port 0x64
* Set up some sort of timer or counter to use as a time-out
* Poll bit 1 of the Status Register ("Input buffer empty/full") until it becomes clear, or until your time-out expires
* If the time-out expired, return an error
* Otherwise, write the data to the Data Port (IO port 0x60)
 
'''WARNING:''' If the PS/2 controller is an (older) "single PS/2 device only" controller, if you attempt to send a byte to the second PS/2 port the controller will ignore the command 0xD4 you send to IO Port 0x64, and therefore the byte you send will actually be sent to the first PS/2 device. This means that (if you support older hardware) to reliably send data to the second device you have to know that the PS/2 Controller actually does havehas a second PS/2 port.
 
 
== RecievingReceiving Bytes From Device/s ==
 
There are 2 ways to receive bytes from device/s: polling, and using IRQ.
 
=== Polling ===
Line 462 ⟶ 499:
To poll, wait until bit 0 of the Status Register becomes set, then read the received byte of data from IO Port 0x60.
 
There are 2 major problems with polling. The first problem is that (like all polling) it wastes a lot of CPU time for nothing. The second problem is that if the PS/2 controller supports two PS/2 devices, there's no way to reliably determine which device sent the byte that you've received, unless one of them is disabled and unable to send data.
 
Note: if the PS/2 controller uses bit 5 of the Status Register as a "second PS/2 port output buffer full" flag, you'd still have problems trying to determine which device sent a byte of data you've received without race conditions. For example, there may be data from the second PS/2 device waiting for you when you check the flag, but before you read from IO Port 0x60 data from the first PS/2 device might arrive and you might read data from the first PS/2 device when you think you're reading data from the second PS/2 device. Of course thereThere's also no easy way to know if the PS/2 controller does useuses bit 5 of the Status Register as a "second PS/2 port output buffer full" flag.
 
=== Interrupts ===
 
Using interrupts is actually easy. When IRQ1 occurs you just read from IO Port 0x60 (there is no need to check bit 0 in the Status Register first), send the EOI to the interrupt controller and return from the interrupt handler. You know that the data came from the first PS/2 device because you received an IRQ1.
 
When IRQ12 occurs you just read from IO Port 0x60 (there is no need to check bit 0 in the Status Register first), send the EOI to the interrupt controller/s and return from the interrupt handler. You know that the data came from the second PS/2 device because you received an IRQ12.
 
Unfortunately, there is one problem to worry about. If you send a command to the PS/2 controller that involves a response, the PS/2 controller may generate IRQ1, IRQ12, or no IRQ (depending on the firmware) when it puts the "response byte" into the buffer. In all three cases, you can't tell if the byte came from a PS/2 device or the PS/2 controller. In the no IRQ case, you additionally will need to poll for the byte. Fortunately, you should never need to send a command to the PS/2 controller itself after initialisation (and you can disable IRQs and both PS/2 devices where necessary during initialisation).
 
== CPU Reset ==
To trigger a CPU Reset, regardless of what state the CPU is currently in, write the value 0xFE to the Output port.
<sourcesyntaxhighlight lang="asm">
;Wait for a empty Input Buffer
wait1:
Line 486 ⟶ 523:
mov al, 0xFE
out 0x64, al
</syntaxhighlight>
</source>
 
==See Also==
Line 496 ⟶ 533:
*[[Post:69151|PS/2 controller initialisation]]
===External Links===
* [http://web.archive.org/web/20210417040153/http://www.diakom.ru/el/elfirms/datashts/Smsc/42w11.pdf SMS "8042" Datasheet]
 
[[Category:X86]]