User-space touchpad driver for ALPS in Latitude D800

06 July 2005, 16:34 UTC

# Tricky bits
# losing sync
# Mousepad interpretation details
# Requirements
# Hack for broken point stick

Over the past few months (too many!) I've playing with a user-space driver for the touchpad on my Dell Lattitude D800 note-book - an ALPS touchpad.

The 2.6 Linux kernel does contain a driver for the ALPS touchpad, but I am unconvinced that the kernel is the right place for such a driver, and it doesn't let me do interesting things and experiment easily.

Anyway, I now have a user-space ALPS driver that does what I want. I supports corner-taps which give me access to all 3 X11 button, and side-stroking to get a scroll wheel. It also allows me to continue dragging something after my finger hits the edge of the pad.

The sourcecode is at http://www.cse.unsw.edu.au/~neilb/D800/ALPSmouse.c. It should compile quite easily. You just run it (as root) and tell X11:

        Option          "Device"                "/dev/input/mice"
        Option          "Protocol"              "ImPS/2"

Tricky bits

One of the difficult parts of getting the driver right is understanding exactly how taps should be interpretted. I eventually figured that the trick is to never produce button events when the finger touches the pad - only to produce them when the finger comes off, or after a timeout.

So the basic tapping algorithm is:

This allows tap, double-tap, tap-and-drag all quite well.

When recording the location of the initial finger-down, we can choose between different buttons based on the location. I choose RightButton if 'near' the bottom of the pad, MiddleButton if near the top, or LeftButton if anywhere else. This makes all the button available. However tap-and-drag with Right or Middle buttons can be awkward if the desired direction is towards the edge of the pad.

To fix this I allow the if the button is down and the finger is near the edge of the pad, I generate a steady stream of relative events in the direction of the edge. Thus an edge need never be a barrier.

However this introduces another complication. When you corner-tap, the finger is immediately near the edge, so it starts moving straight away, which isn't expected. Again, this is easily handled by only enabling the "drift" if the finger has been somewhere not near and edge. So you tap-and-hold, move to the middle of the pad, then move in whichever direction you want.

losing sync

2.6 on laptops seems to still have a latency problem. I had a major latency problem whenever an applet read the battery status from /proc. Any music playying would skip. I managed to avoid this by recompilng the kernel without ACPI_DEBUG, which clearly isn't fixing the problem, only avoiding it.

Many people have reported having their mouse jump around on laptops, and I believe this is due to interrupts being lost. I suspect ACPI is disabling interrupts for too long, though I have no hard evidence.

Anyway, I definitely loose bytes from the touchpad sometimes. Each event from the touchpad is 6 bytes, and there is one interrupt each. I believe (without hard evidence) that the bytes come in about every millisecond, so disabling interrupts for longer than that will loose bytes and hence corrupt events.

There is not a lot of redundancy in the 6byte commands to allow missing bytes to be noticed, but there is some. Whenever I detect a byte that is definitely wrong (e.g. bit8 sert on any non-initial byte) or a byte that is probably wrong (e.g. suggesting a very large relative mouse movement) I abort the current event and flush the input queue until there is a pause with nothing from the touchpad. This means that the mouse will occasionally stall and stop working for a new moment, but at least it means that the mouse doesn't jump wildly around the screen and synthesis random button presses!

Mousepad interpretation details

My mousepad is actually a 'dualpoint', meaning there is a touchpad and a point stick. There are also 4 buttons, two beneath the touchpad and two beneath the point stick. It is also possible to plug a regular ps2 mouse in via the base-station. Events from this mouse come in the same way as events from the dualpoint.

pointstick events and ps/2 mouse events are indistinguishable and come as 3 byte relative events. touchpad events come as 6byte absolute events.

The 4 button are intended to be two left-buttons and two right-buttons. However I want a middle button. I can just use corner-taps, but sometimes I like a realy button, and as there are some many available, it seems a reasonable desire.

I mostly use the touch pad, so I want the two touchpad buttons to be 'left' and 'right', and the two pointstick buttons to both be 'middle'.

This works OK (you can tell which button is which most of the time) but as external-mouse events look just like point-stick events, this makes the left and right buttons on an external mouse look like the middle-button - no good.

So, I interpret the buttons differently depending on which sort of movement event I got most recently. If it was a touchpad movement, then interpet the buttons as above. If it was a relative event (could be pointstick or mouse) then switch the interpretation so the pointstick (or mouse) buttons are left or right, and the touch-pad buttons are both middle. This can cause a little bit of confusion when transitioning from mouse to touchpad if you don't move the mouse or tap the touchpad first, but I don't find it a big problem.

So, with that background, the touchpad works like this:

And that is about it. There is no config file support as yet, but that could easily be added if required.


Requirements

This ALPS driver requires a reasonably recent 2.6 kernel (I'm using 2.6.11) and the SERIO_RAW and INPUT_UINPUT drivers. These can be set to 'y' or 'm' in the .config file for the kernel. The names of the modules are serio_raw and uinput.

In order to enabvle the SERIO_RAW module, thus getting raw access to the PS/2 device, the /sys filesystem must be mounted: mount -t sysfs sys /sys.

As the SERIO_RAW module doesn't always give the same major/minor device numbers for the PS/2 device, ALPSmouse hunts through /sys to figure out which device was allocated, and creates /dev/ALPStouchpad with the correct device number.

Hack for broken point stick

It seems that the point-stick in the Dualpoint in the D800 (And possibly the D600) is prone to failure. The failure mode is that it will spontaneously generate movement events. In my experience they are usually to the lower-left, though occasionally to the upper-right.

The partially alleviate this problem ALPSmouse can be told to ignore events from the point-stick. If the name "Broken" is set in the environment (e.g. export Broken=yes) then movement events from the point-stick are ignored.

Note that this isn't a perfect solution. The point-stick seems to take precedence and while it is generating a stream of movement events, the touch pad cannot get any events through.

When I reported this to Dell Service they were very helpful can came and replaced the whole keyboard unit under warranty. That is definitely the best option if available.






[æ]