PS/2 Mouse: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
Pancakes (talk | contribs)
m link syntax typo
m Bot: Replace deprecated source tag with syntaxhighlight
 
(25 intermediate revisions by 10 users not shown)
Line 1:
Also be sure to read [[Mouse_Input|Mouse Input]].
===== PS/2 Protocol =====
: http://www.versalent.biz/ps2facts.htm
 
== Overview ==
''Also to avoid your confusion. A PS/2 bus (interface) by standard is limited to only one device. Although, you may hear it is limited to two devices. Do not become confused because your system hosting the interface is considered one of the two, and the keyboard or mouse for instance is actually considered the master (drives the clock line) and the computer (host) the slave.''
 
The PS/2 Mouse is a device that talks to a PS/2 controller using [[PS/2|serial communication]]. Ideally, each different type of PS/2 controller driver should provide some sort of standard/simple "send byte/receive byte" interface, and the PS/2 Mouse driver would use this interface without caring about lower level details (like what type of PS/2 controller the device is plugged into).
You may wish to see the [[PS2_Keyboard|PS2 Keyboard]] page from here. As it stems from the PS/2 protocol.
 
===== Implementation Of The PS/2 Protocol =====
This greatly depends on your board. So for starters your going to need specific code to deal with this hardware that implements the PS/2 protocol or exposes it, then you are going to need to deal with the mouse hardware.
 
== Mouse Device Over PS/2 ==
For example taking a look at:
: $linuxsrc/drivers/input/serio/i8042.c
We can see an actual driver for the I8042 PS2 implementation/hardware. Now, on top of this Linux creates an serial abstraction type layer. This allows all sorts of different implementation of the PS/2 interface to exist but become exposed to for instance the mouse driver as no different than any other device (such s the I8042 or the PL050). I will explain about the PL050 in the next few paragraphs. Otherwise, each mouse driver would have to specifically support each implementation (I8042, PL050, ...) of a PS2 bus interface.
 
Here is the table of command a generic PS/2 compatible mouse understands:
''By taking note of how Linux separated the hardware will allow you to see the programming paradigm that is taking place. But, this is not required for you to fully understand in order to implement your mouse driver''.
 
''If your writing an operating system you always have time to go back and rewrite or expand a part of it. So at first you will be okay just writing a single driver to handle the hardware exposing the PS/2 and the mouse driver in one package. And, in other cases it may actually make more sense to create a single driver for instance for an embedded system.''
 
Another example is the [[ARM_Overview|ARM]] Integrator/CP board which implements the PS/2 interface encapsulated in the PL050 (where the PL050 is analogous to the I8042) except you communicate with the PL050 differently than the I8042. But, after the PL050 is configured you then proceed with the PS/2 mouse protocol. For example:
<pre>
KMI_MMIO volatile *mmio;
uint32 tmp;
mmio = (KMI_MMIO*)KMI_MS_BASE;
mmio->cr = 0x4;
/* talk to the PS2 controller and enable it */
mmio->data = 0xF4;
/* keyboard sends back ACK */
while(!KMI_TXFULL(mmio->stat));
tmp = mmio->data;
</pre>
''The above uses memory mapped input/output (MMIO), but other architectures may use I/O ports instead or a combination of I/O ports and MMIO for example the X84/64. So understanding your platform is very important to understand how to proceed in talking to the devices.''
 
Above, the PL050 is also called the KMI (Keyboard And Mouse Interface). So first we have to configure the PL050 by enabling it. Now, it provides a interface to the PS2 interface which then interfaces with the mouse. So, the next thing I have to do is write the value ''0xF4'' which you can find in the table above to enable the mouse.
 
So, overall the hardware exposing the PS/2 interface may be light weight or heavy and it all depends on the system board (not the processor).
 
===== Mouse Extension =====
: $linuxsrc/drivers/input/mouse/psmouse-base.c
: http://www.computer-engineering.org/ps2mouse/
 
First, you have to enable the mouse on the PS/2 bus. This requires sending one byte which is clocked over the PS/2 interface. You will then get a response regarding the result.
 
{| class="wikitable"
! colspan="23" | Standard PS/2 Mouse Commands
|-
! Byte !! Data byte !! Description
|-
| 0xE6 || None || Set Scaling 1:1
| 0xFF || Reset
|-
| 0xE7 || None || Set Scaling 2:1
| 0xFE || Resend
|-
| 0xE8
| 0xF6 || Set Defaults
|
{| {{wikitable}}
|-
! Byte
! Resolution
|-
| 00
| 1 count/mm
|-
| 01
| 2 count/mm
|-
| 02
| 4 count/mm
|-
| 03
| 8 count/mm
|}
| Set Resolution
|-
| 0xF50xE9 || DisableNone Data|| Status ReportingRequest
|-
| 0xEA || None || Set Stream Mode
| 0xF4 || Enable Data Reporting
|-
| 0xF30xEB || SetNone Sample|| Read RateData
|-
| 0xF20xEC || GetNone Device|| Reset Wrap IDMode
|-
| 0xF00xEE || None || Set RemoteWrap Mode
|-
| 0xEE0xF0 || None || Set WrapRemote Mode
|-
| 0xF2
| 0xEC || Reset Wrap Mode
| None
| Get Device ID. See [["8042" PS/2 Controller#Detecting PS/2 Device Types|Detecting PS/2 Device Types]] for the response bytes.
|-
| 0xF3
| 0xEB || Read Data
| Sample rate
| Set Sample Rate, valid values are 10, 20, 40, 60, 80, 100, and 200.
|-
| 0xEA0xF4 || SetNone Stream|| Enable Data ModeReporting
|-
| 0xF5 || None || Disable Data Reporting
| 0xE9 || Status Request
|-
| 0xF6 || None || Set Defaults
|-
| 0xFE || None || Resend
|-
| 0xFF || None || Reset ('''Note: After the result of the power-on test is sent, the mouse sends its ID (0x00)''')
|-
|}
 
The most common command reply is ''0xFA'' from the master (mouse), which means acknowledge. You may then get a variable number of bytes afterwards depending on the command. You may also receive other command replies which may state that the master (mouse) has encountered an error decoding your command. For a more detailed list check out some of the links above or look through the Linux source tree.
 
First, you have to enable the mouse on the PS/2 bus. This requires sending one byte which is clocked over the PS/2 interface. You will then get a response regarding the result. By sending ''0xF4'' (Enable Data Reporting) the mouse should reply back with a ''0xFA'' which means acknowledgement. Then afterwards as the mouse pointer is moved it will send back the generic packet format like below. Unless you enable an enhanced mode for the mouse (non-standard) this is what you will get when ever the mouse is moved.
''This is just to help get you started until someone comes and expands this page more.''
 
{| class="wikitable"
Line 83 ⟶ 81:
! BYTE!!7!!6!!5!!4!!3!!2!!1!!0
|- align="center"
| 0 || yo || xo || ys || xs || ao1 || bm || br || bl
|- align="center"
| 1 || colspan="8" | xmX-Axis Movement Value
|- align="center"
| 2 || colspan="8" | ymY-Axis Movement Value
|}
{| class="wikitable"
Line 100 ⟶ 98:
| xs || X-Axis Sign Bit (9-Bit X-Axis Relative Offset)
|-
| ao1 || Always One
|-
| bm || Button Middle (Normally Off = 0)
Line 107 ⟶ 105:
|-
| bl || Button Left (Normally Off = 0)
|-
| xm || X-Axis Movement Value
|-
| ym || Y-Axis Movement Value
|}
 
Each X and Y axis value is relative. The mouse device does not track its location in absolute coordinates. This should also be apparent by the 9-bit values. Instead, it sends back saying I moved this far to the left, to the right, down, or up. To keep track of a mouse position you need to accumulate these relative offsets into a absolute position offset in your code:
<pre>
mouse_x = mouse_x + mouse_packet_rel_x
mouse_y = mouse_y + mouse_packet_rel_y
</pre>
''Being these 9-bit values are signed the above pseudo would work.''
 
Also, if you simply read the X- or Y-Axis Movement Value fields you will get an 8-bit unsigned value. Which, if used as unsigned will yield incorrect behavior. If you convert it into a signed 8-bit value you will get behavior that is similar to correct, but strange artifacts will appear when the mouse is moved fast. The correct way to produce a 9-bit or greater signed value is as follows:
<pre>
state = first_byte
d = second_byte
rel_x = d - ((state << 4) & 0x100)
d = third_byte
rel_y = d - ((state << 3) & 0x100)
</pre>
The pseudo code above will cause ''((state << 4) & 0x100)'' to equal ''0x100'' only if the signed bit (9'th bit stored in the first byte) is set. If the 9'th bit is set then the value is deemed negative, but the value in ''second_byte'' is not stored in one or two's complement form. It is instead stored as a positive 8-bit value. So, if ''second_byte'' is say a ''2'' then it will become ''2 minus 0'' since the negative (9'th bit) is off. But, if it is on then it will become ''2 minus 0x100'' which will produce the twos complement, or ''-2''. It will also cause the register to be correctly sign extended no matter its size.
 
=== Set Sample Rate Example ===
 
To set the sample rate for example, which is a command with a data byte, one would need to do:
<syntaxhighlight lang="c">
outb(0xD4, 0x64); // tell the controller to address the mouse
outb(0xF3, 0x60); // write the mouse command code to the controller's data port
while(!(inb(0x64) & 1) asm("pause"); // wait until we can read
ack = inb(0x60); // read back acknowledge. This should be 0xFA
outb(0xD4, 0x64); // tell the controller to address the mouse
outb(100, 0x60); // write the parameter to the controller's data port
while(!(inb(0x64) & 1) asm("pause"); // wait until we can read
ack = inb(0x60); // read back acknowledge. This should be 0xFA
</syntaxhighlight>
 
== Mouse Extensions ==
 
Here, an example of mouse that supports extensions. To maintain backwards compatibility
Line 119 ⟶ 146:
compatibility mode described above.
 
=== Z-axis ===
 
To enable the Intellimouse Z-axis extension, you have to set some magic into the sample rate:
<syntaxhighlight lang="c">
set_mouse_rate(200); // see the example above
set_mouse_rate(100);
set_mouse_rate(80);
mouseid = identify(); // see Get Device ID, 0xF2
</syntaxhighlight>
 
After that the mouse should not return Mouse ID ''0'', but ''3'', and will send 4 bytes data packages as follows:
{| class="wikitable"
! colspan="9" | IntelliMouseIntellimouse Explorer#1 PS/2 Mouse Packet Bits
|-
! BYTE!!7!!6!!5!!4!!3!!2!!1!!0
|- align="center"
| 30 || vsyo || hsxo || ys || xs || 1 || bm || br || bl
|- align="center"
|}
| 1 || colspan="8" | X-Axis Movement Value
|- align="center"
| 2 || colspan="8" | Y-Axis Movement Value
|- align="center"
| 3 || colspan="8" | Z-Axis Movement Value
|}
The Z-axis Movement Value is in "2's complement" format. Valid values are -8 to +7. Other bytes are identical to the PS/2 packet.
 
=== 5 buttons ===
 
To enable the 4th and 5th buttons, first you have to try to enable Z-axis, and you can only follow with this if the identification returned ''3''.
<syntaxhighlight lang="c">
if(mouseid == 3) {
set_mouse_rate(200);
set_mouse_rate(200);
set_mouse_rate(80);
mouseid = identify();
}
</syntaxhighlight>
If this was successful, the identify command should now return Mouse ID ''4'', and the 4 bytes packets will look like this:
{| class="wikitable"
! colspan="9" | Intellimouse #2 PS/2 Mouse Packet Bits
|-
! BYTE!!7!!6!!5!!4!!3!!2!!1!!0
|- align="center"
| 0 || yo || xo || ys || xs || 1 || bm || br || bl
|- align="center"
| 1 || colspan="8" | X-Axis Movement Value
|- align="center"
| 2 || colspan="8" | Y-Axis Movement Value
|- align="center"
| 3 || 0 || 0 || b5 || b4 || colspan="4" | Z-Axis Movement Value
|}
Here the X-Axis Movement Value is stored only on the low 4 bits and the last byte is not sign extended. Bits 4 and 5 represents the pressed status of buttons 4 and 5 in that order, same as with bm, br and bl.
 
=== Emulation ===
 
Normally bochs does only emulate generic PS/2 mouse. To make bochs to handle Z-axis, you should set the proper mouse type in your bochrc file:
<pre>
mouse: type=imps2, enabled=1
</pre>
If you did the sample rate magic right, then you should see this on the bochs console as soon as you issue the last set sample rate command:
<pre>
0000000000i[KBD ] wheel mouse mode enabled
</pre>
Qemu on the other hand understands not only the Z-axis mode, but the 5 buttons mode too, and returns Mouse ID ''4'' if you did everything right.
 
==See Also==
===Articles===
*[[PS/2]]
*[["8042" PS/2 Controller]]
*[[PS/2 Keyboard]]
===External Links===
*[http://www.computer-engineering.org/ps2mouse/ www.Computer-Engineering.org/ps2mouse]
*[http://users.utcluj.ro/~baruch/sie/labor/PS2/PS-2_Mouse_Interface.htm users.utcluj.ro/~baruch/sie/labor/PS2/PS-2_Mouse_Interface.htm]
 
=== Implementations ===
* [http://lxr.linux.no/#linux+v3.5.4/drivers/input/mouse/psmouse-base.c Linux] (C,GPL)
 
[[Category:Human Interface Device]]
[[Category:Common Devices]]
[[Category:Hardware Interfaces]]