"8042" PS/2 Controller: Difference between revisions
[unchecked revision] | [unchecked revision] |
Content deleted Content added
multiple small typo fixes |
m Bot: Replace deprecated source tag with syntaxhighlight |
||
(22 intermediate revisions by 17 users not shown) | |||
Line 1:
The PS/2 Controller (often called a
▲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 ==
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
{|
Line 22 ⟶ 20:
|}
The 8042 was a powerful
* 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
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
== 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
== Buffer Naming Perspective ==
The PS/2 controller has two (one byte) buffers for data
== 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
Historical note
{| {{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
=== Status Register ===
The Status Register contains various flags that
{| {{wikitable}}
Line 131 ⟶ 129:
== PS/2 Controller Commands ==
The PS/2 Controller accepts
To send a command to the controller,
Line 188 ⟶ 186:
|-
|0xAC
|Diagnostic dump (
|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
* 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
==== Step 2: Determine if the PS/2 Controller Exists ====
Before you touch the PS/2 controller at all, you should determine if it
==== Step 3: Disable Devices ====
Line 341 ⟶ 338:
==== Step 4: Flush The Output Buffer ====
Sometimes (e.g. due to interrupt
==== 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
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
==== 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
==== Step 9: Enable Devices ====
Line 371 ⟶ 368:
All PS/2 devices should support the "reset" command (which is a command for the device, and not a command for the PS/2 Controller). To send the reset, just send the byte 0xFF to each (usable) device. The device/s will respond with 0xFA (success) or 0xFC (failure), or won't respond at all (no device present). If your code supports "hot-plug PS/2 devices" (see later), then you can assume each device is "not present" and let the hot-plug code figure out that the device is present if/when 0xFA or 0xFC is received on a PS/2 port.
'''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 received 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
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 387 ⟶ 388:
{| {{wikitable}}
|-
! Bytes (Normal)
! Bytes (Translated*)
! Device Type
|-
| None
| None
|-
| 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▼
|-
| 0xAB, 0x83
▲| 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.▼
* 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
== 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)
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
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 429 ⟶ 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
=== First PS/2 Port ===
To send data to the first PS/2 Port:
* Set up some
* 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 443 ⟶ 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
* 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
==
There are 2 ways to receive bytes from device/s: polling
=== Polling ===
Line 459 ⟶ 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
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.
=== Interrupts ===
Using interrupts is
When IRQ12 occurs you
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 will put a "response byte" into the buffer and won't generate any IRQ (because the byte didn't come from any PS/2 device). In this case you have to poll, and if you have to poll you can't determine where the byte came from unless all PS/2 devices are disabled. Fortunately you should never need to send a command to the PS/2 controller itself after initialisation (and you can disable both PS/2 devices where necessary during initialisation).▼
▲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
== CPU Reset ==
To trigger a CPU Reset,
<
;Wait for a empty Input Buffer
wait1:
Line 484 ⟶ 523:
mov al, 0xFE
out 0x64, al
</syntaxhighlight>
==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
[[Category:X86]]
[[Category:Common Devices]]
[[de:Keyboard_Controller]]
|