Anonymous user
"8042" PS/2 Controller: Difference between revisions
Did some grammar overhaul
[unchecked revision] | [unchecked revision] |
m (Did some minor rewriting) |
(Did some grammar overhaul) |
||
Line 12:
== 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:
|}
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 “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
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:
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:
* 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 — 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
== 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:
=== 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:
== PS/2 Controller Commands ==
The PS/2 Controller accepts
To send a command to the controller,
Line 323:
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 331:
==== 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 340:
==== 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 360:
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 372:
'''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
== 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)
A partial list of responses includes:
Line 418:
== 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 431:
== 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 445:
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 461:
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 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
<source lang="asm">
;Wait for a empty Input Buffer
|