Mouse Input

From OSDev.wiki
Revision as of 02:53, 11 November 2007 by osdev>Bewing
Jump to navigation Jump to search

PC Mouse Interfaces

Current PCs generally use PS2 mice, or a similar format that emulates a PS2 mouse. Serial mice are a much older technology that is no longer common.

USB Mouse

A USB mouse generally emulates a PS2 mouse, except that it generates IRQs from the USB bus, and not IRQ 12.

PS2 Mouse -- Basic Operation

Once a mouse has been initialized (see below), the mouse sends 3 or 4 byte packets to communicate mouse movement, and mouse button press/release events. These packets show up asynchronously as data on IO port 0x60. Even though the data shows up on port 0x60 (the keyboard port), it does not trigger an IRQ1. The only way that you will know that mouse data has arrived is if you handle an appropriate IRQ (generally IRQ12), or if you occasionally poll bit number 0 (value=1) of port 0x64, to see if data is available on port 0x60. It is not necessary to handle all of the following things inside the driver, but doing so can make things work faster.

Keyboard/Aux Data Bit

Since both keyboard and mouse data is showing up to be read on port 0x60, it is necessary to be able to tell which is which. To tell if there is any available data on port 0x60 at all, it is necessary to read a byte from port 0x64. In that byte from port 0x64, bit number 0 (value=1) indicates that a byte is available to be read on port 0x60. An additional bit, bit number 5 (value=0x20), indicates that this next byte came from the mouse, if the bit is set. If you look at RBIL, it says that this "mouse bit" is MCA specific, but this is no longer true. All PCs that support PS2 mice use this bit to indicate that the incoming byte was generated by the auxiliary PS2 input port.

Mouse Subtypes

There are several types of mice, but they can be separated into two groups, depending on whether they have a scroll wheel. Mice with scroll wheels can send an additional byte in each mouse packet, indicating the status of mouse wheels and extra buttons.

Mice with no scroll wheels use 3 byte packets exclusively. Mice with scroll wheeels, and up to 5 buttons (currently) can send 4 byte packets, if they are initialized properly.

Mouse Packet Info

For even greater detail on PS2 mouse packets than what is presented next: reference the links below, or search for the Adam Chapweske article.

Timing/Generation of Mouse Packets

A mouse is initialized to only generate movement packets at a particular rate. The default rate is 100 packets per second, if the mouse is being moved. A mouse also generates a packet if a button is either pressed or released. If the mouse is not moving, and no buttons are being clicked, a mouse will not generate any automatic packets.

Format of First 3 Packet Bytes

Even if your mouse is sending 4 byte packets, the first 3 bytes always have the same format. The first byte has a bunch of bit flags. The second byte is the "delta X" value -- that is, it measures horizontal mouse movement, with left being negative. The third byte is "delta Y", with down (toward the user) being negative. Typical values for deltaX and deltaY are one or two for slow movement, and perhaps 20 for very fast movement. Maximum possible values are +255 to -256 (they are 9-bit quantities, two's complement).

The top two bits of the first byte (values 0x80 and 0x40) supposedly show Y and X overflows, respectively. They are not useful. If they are set, you should probably just discard the entire packet.

Bit number 5 of the first byte (value 0x20) indicates that delta Y (the 3rd byte) is a negative number, if it is set. This means that you should OR 0xFFFFFF00 onto the value of delta Y, as a sign extension (if using 32 bits).

Bit number 4 of the first byte (value 0x10) indicates that delta X (the 2nd byte) is a negative number, if it is set. This means that you should OR 0xFFFFFF00 onto the value of delta X, as a sign extension (if using 32 bits).

Bit number 3 of the first byte (value 0x8) is supposed to be always set. This helps to maintain and verify packet alignment. Unfortunately, some older mice (such as 10 year old Microspeed 2 button trackballs) do not set this bit. RBIL claims that this bit should be 0, but it is wrong.

The bottom 3 bits of the first byte indicate whether the middle, right, or left mouse buttons are currently being held down, if the respective bit is set. Middle = bit 2 (value=4), right = bit 1 (value=2), left = bit 0 (value=1).

Formats of Optional 4th Packet Byte

If the mouse has been initalized so that its mouseID is 3 or 4, it will send a 4th byte in each packet. On all current mice, the top two bits should be ignored. On some mice, the bits will flip between 0 and 1, based on scroll wheeel movement. If the mouse has a 4th and 5th mouse button, then their state is indicated by bit 4 (value=0x10), and bit 5 (value=0x20), respectively. Note: if the buttons do not exist, then these bits may flip based on scroll wheel movement! (ie. Be careful that this does not generate spurious "mouse button click" events for buttons that do not exist.)

Currently, the bottom nibble of the 4th byte might have the following values:

  • 0 -- no scroll wheel movement
  • 1 -- vertical scroll up one click
  • 0xF -- vertical scroll down one click
  • 2 -- horizontal scroll right one click
  • 0xE -- horizontal scroll left one click

Non-Linear Movement

When a user is trying to point at something on a screen, they will quickly move the mouse in the general direction of the target, and then slow down to accurately point at it. The deltaX/Y values from the mouse packets can be used directly, but will force the user to move the mouse very far to get the cursor from one area of the screen to another -- since "rapid movement" of a mouse will only generate packets with deltaX/Y values of perhaps 20. One good answer is to scale the mouse movement by additional multiples, based on how fast the mouse is moving. If the mouse is moving slowly, the scale factor can be 1 -- to allow the highest possible sensitivity. When the mouse is (or has been) moving fast, the scale factor could be 5 or 10, to allow the cursor to move across large distances on the screen, quickly.

There are many ways to do such scaling, obviously. If you are coding the driver in assembler, one suggestion might be to use the BSR command to generate an approximate log base2 of deltaX and deltaY, and use that as your scaling factor.

Doubleclicks

If you intend to implement a doubleclick, you will need to record timestamps of mousedown events to high accuracy. The only way to know if a doubleclick has occurred is to know how long ago the previous click of the mouse button happened. If the delay between the two clicks was less than some threshhold, then it was a doubleclick. The problem here is that you need to be able to measure very short delays, and there may be extremely long delays between clicks (days, perhaps) -- long enough that your timestamp measurement might overflow. This needs to be handled carefully.

Timeouts/Mouse Disconnect

If a mouse is operating normally, but is not being moved or clicked, it will not send any packets. If a mouse has been unplugged, it will also not send any packets. If you want to support "hot plugging" of PS2 mice, then you might want to know when a mouse has become disconnected. So, if you have not seen any packets from the mouse for awhile, you can query the mouse to see if it is still alive. A convenient way to do this is to send a request for a mouse packet (mouse command 0xEB). You will get back an ACK (0xFA) from the mouse, and then a mouse packet (with everything set to 0, probably). Please note that you need to make sure that the 0xFA does not cause a misalignment of your input mouse packet. Also please note that if the contents of the mouse packet are not 0, then that means that somehow your mouse packets have become disabled.

In general, it is a good idea to also have timeouts everywhere that the system is waiting for a response from the mouse, because it may never come.

PS2 Mouse Commands

After the PS2 Aux port has been enabled, you can send commands to the mouse.

Waiting to Send Bytes to Port 60 and 64

All output to port 0x60 or 0x64 must be preceded by waiting for bit number 1 (value=2) of port 0x64 to clear. Similarly, bytes cannot be read from port 0x60 until bit number 0 (value=1) of port 0x64 is set. See PS2 Keyboard for further details.

0xD4 Byte and Command Byte

Sending a command byte to the mouse (to port 0x60) must be preceded by sending a 0xD4 byte to port 0x64 (with appropriate waits on port 0x64, bit 1, before sending each output byte). Note: this 0xD4 byte does not generate any ACK, from either the keyboard or mouse.

Wait for ACK from Mouse

It is required to wait until the mouse sends back a 0xFA acknowledgement byte, after each command byte, before sending the next 0xD4. (Note: reset commands might not be ACK'ed -- wait for the 0xAA after a reset.)

Partial Command Set

  • 0xFF -- reset (mouse responds with 0xAA, 0x00, and needs to be reinitialized)
  • 0xEB -- request mouse packet
  • 0xF4 -- enable automatic packets
  • 0xF5 -- disable packets
  • 0xF3 -- set packet "sample rate"

{possible values are 80 (0x50), 100 (0x64), or 200 (0xC8) samples per second}

  • 0xF2 -- get mouseID
  • 0xE8 -- set resolution (pixels/mm)

(possible values are 0, 1, 2, or 3 -- meaning 1, 2, 4, or 8 pixels/mm)

Initializing a PS2 Mouse

The PS2 mouse port on a PC is attached to the auxiliary input of the PS2 keyboard controller. That input is disabled at bootup, and needs to be enabled. It is usually also desirable to have the mouse generate IRQ12 interrupts when it sends bytes through the keyboard controller to IO port 0x60. Additionally, it is necessary to tell the mouse to enable the transmission of packets. Optionally, you may also want to enable additional mouse features, such as scroll wheels, faster response times, increased resolution, or additional mouse buttons.

PS/2 Device Unplugging/Hot Plugging

Some idiot who created the PS/2 device specs did not specify that PS/2 devices can be unplugged and replugged while the computer is turned on ("hot plugging"). A long time ago, some other idiots actually designed motherboards that would be damaged if PS2 hot plugging occurs. However, mice and keyboards have cords that were made to be tripped over, and sometimes it is very logical to try moving a mouse from one machine to another, temporarily, without powering the systems down. So all computers made in the last 15 years should, in fact, support hot plugging of PS2 devices. When a mouse is plugged into a running system, it may send a 0xAA, then a 0x00 byte, and then it will go into default state (see below).

PS2 Aux Port Initialization

When a computer is booted, the auxiliary port of the PS2 controller may need to be enabled, and IRQ12 may also need to be enabled. This should only need to be done once.

Set Compaq Status/Enable IRQ12

On some systems, the PS2 aux port is disabled at boot. Data coming from the aux port will not generate any interrupts. To know that data has arrived, you need to enable the aux port to generate IRQ12. There is only one way to do that, which involves getting/modifying the "compaq status" byte. You need to send the command byte 0x20 ("Get Compaq Status Byte") to the PS2 controller on port 0x64. If you look at RBIL, it says that this command is Compaq specific, but this is no longer true. This command does not generate a 0xFA ACK byte. The very next byte returned should be the Status byte. (Note: on some versions of Bochs, you will get a second byte, with a value of 0xD8, after sending this command, for some reason.) After you get the Status byte, you need to set bit number 1 (value=2, Enable IRQ12), and clear bit number 5 (value=0x20, Disable Mouse Clock). Then send command byte 0x60 ("Set Compaq Status") to port 0x64, followed by the modified Status byte to port 0x60. This might generate a 0xFA ACK byte from the keyboard.

Aux Input Enable Command

Send the Enable Auxiliary Device command (0xA8) to port 0x64. This will generate an ACK response from the keyboard, which you must wait to receive.

Mouse State at Power-on

When the mouse is reset, either by applying power or with a reset command (0xFF), it always goes into the following default state:

  • streaming mode
  • packets disabled
  • emulate 3 button mouse (buttons 4, 5, and scroll wheels disabled)
  • 3 byte packets
  • 4 pixel/mm resolution
  • 100 packets per second sample rate

MouseID Byte

During initialization, a mouse indicates that it has various features (a scroll wheel, a 4th and 5th mouse button) by changing its mouseID in response to initialization commands. So you send a set of mouse commands, and then ask for the mouseID byte, with the Read MouseID command (0xF2). If it changed, then the mouse has changed modes. Then send another set of commands, and maybe change modes again. The mouseID byte is the next byte sent after the ACK for the Read MouseID command. At initialization, the mouseID is always 0. Other current legal values are 3 and 4.

Init/Detection Command Sequences

If mouseID is 0, send: Set Samplerate 200, Set Samplerate 100, Set Samplerate 80, Get MouseID. If mouseID changed to 3, mouse has a scroll wheel, and is now in 4 byte packet mode. If mouseID is 3, send: Set Samplerate 200, Set Samplerate 200, Set Samplerate 80, Get MouseID. If mouseID changed to 4, mouse has 5 mouse buttons -- otherwise only 3.

Enable Packets

After the mouse has been initialized to the correct mouseID, its Samplerate is probably 80 samples per second, its Resolution is probably 4 pixels/mm, and packets are still disabled. You may want to modify the Samplerate and Resolution, and then you need to send a 0xF4 command to the mouse, to make the mouse generate movement packets.

PC Serial Mouse

For info on running a serial mouse on an RS232 port, see this document.

Mac Mouse Interface

(stub - to be written later)


See Also

Threads

External Links