Table of Contents

Introduction

This page is about my first non-toy Linux device driver. It's purpose is to provide the /dev/psaux device, which was in Linux pre 2.6 kernels. Since version 2.6, this device has been removed. The developers think that everyone would be satisfied with the new input layer, rendering /dev/psaux useless. However, I don't think so. At least, the touchscreen on my Laptop does not work anymore after moving to Linux 2.6. Fortunately, I still kept the kernel image and modules of version 2.4 in the Laptop, and I have configured LILO to be able to boot both. So, I immediately reboot back to 2.4. (This is what everyone should do when upgrading the kernel. Don't delete the old one. Keep it around — it doesn't take up much disk space, given that 40GB disks are now so cheap. For that tiny cost, you've got the invaluable chance to go back.)

Background

One of the annoying things most early migrants from Linux kernel 2.4.x (or even 2.2.x?) to 2.6.x would encounter a problem: The mouse doesn't work any more!? Thanks to a major change from kernel 2.4 to 2.6 — the introduction of the so called ``the input layer'', old gpm and XFree86 settings don't work anymore.

In most cases, this can be cured by changing the configuration files of XFree86 and gpm to use the new /dev/input/mice virtual device instead of the old /dev/psaux (or /dev/ttySn for a serial mouse). What's nice with the new input layer is that it now allows multiple mice (and keyboard, too) to be used attached to the PC and the kernel now combines the input events from all the mice into a single stream of mouse events and repeats it to /dev/input/mice. A nice feature considering some plug&play input devices such as USB mice.

There are also drawbacks, and unfortunately, these drawbacks are very observable. It is unfortunate that behaviour of the mouse is so visible that a slight change would be more noticeable than a change in many other parts of the kernel. Other than having to change the config files of XFree86 and gpm, another big surprises for users is that the mouse pointer on the screen now moves fast or too slow. This is because the kernel now processes the mouse data and recalculates it in the way it thinks is better. This is not that bad, given that you can tune it with certain kernel or module parameters. It is just annoying to have to fix it, when the old thing was not broken on the Linux 2.4.x kernels in the first place.

Moving the mouse driver into the kernel?

With the Linux 2.6 kernel, the developers have moved a function that used to run in userland in pre 2.6 kernels into the kernel. It is the interpretation of various mouse protocols (Mousesystems, PS/2, and various extensions of PS/2 to support wheel mouse, touch-pads and touch-screen). If you use gpm, it is basically this userland program that is now moved into kernel space. For those who are used to configuring XFree86, that means its mouse driver is now moved into kernel. Have a look in linux-2.6.*/drivers/input/mouse and compare the filenames with ``gpm -t help'' and you'll grasp what I mean. The mouse protocols are now interpreted in kernel space!

So, what's wrong then?

A quick comparison of the list of files in linux-2.6.*/drivers/input/mouse and ``gpm -t help'' should have already given you some hints. The kernel as of this writing still supports just a few mouse protocols, whereas gpm has been supporting dozens of protocols for many years. So, what to do with devices that uses a protocol that is not supported by the kernel? Should you just wait for the kernel developes to write a driver for your device? It'd be nice if you could use gpm or the appropriate XFree86 driver like in the old days. But the kernel developers have excluded such a possibility.

In my case, it happens to be the touchscreen on my Fujitsu Lifebook B142 Laptop (see Jörg Hau's and Justin Cormack's pages about this Laptop). It also has a touch-point. The touch-point and touch-screen together emulates a PS/2 mouse. When activated with some magic command sequences sent to the mouse port (i.e. device node /dev/psaux), the touch-screen function is enabled and it now uses a PS/2 extension protocol to give the touchscreen data. The extended protocol is propreitary, but is relatively simple to work out. Throughout the years, many people have discovered the protocol, and written drivers for both gpm and XFree86 to make use of this touchscreen (see Harald Hoyer's gpm and XFree86 3.x driver and Kenan Esau's XFree86 4.x driver). I'm of course no exception. I wrote an XFree86 4.x driver for it. It communicates with the device via the /dev/psaux device.

After moving to Linux kernel 2.6, the touch-screen works no longer. I spent some time searching the Web to see why. OK. I need to load the modules mousedev and psmouse (if not already compiled in) to get a /dev/psaux device. Wow! But when I tried it, I was disappointed that it doesn't work with my touchscreen. It can only handle the PS/2 mouse emulation that the device does. It can't enable the touchscreen functions. How about writing a program to enable that function? No... that won't work. The kernel mouse driver in 2.6 must interpret the data received from the mouse port. It doesn't understand the propreitary protocol of my touchscreen (yet). For this reason, what the kernel now spits out to /dev/psaux is a censored sequence of data. The touch-screen-specific things can't get through.

Of course, it'd be fun to write a kernel-space device driver to support this touch-screen (see Kenan Esau's lbtouch module). But why have they done away the old /dev/psaux? I believe I'm not alone in this planet facing such a problem. Anyone who uses a device connected to the mouse port and uses a protocol not yet supported by the kernel will suffer. The old /dev/psaux device in pre-2.6 kernels did allow me to directly talk to the device. (It provides the mechanism, but lays down no policy.) The mouse driver runs in user space, whether it's gpm or XFree86, and talks to the device directly via /dev/psaux. Why not keep it in 2.6, so that the devices using protocols not yet supported in kernel space can still be driven in user space, using the old programs? That's why I wrote this psaux driver.

Updates

Neil Brown mentioned in the Linux Kernel Mailing List (LKML) that he also hacked direct access to the /dev/psaux port. He wrote a userland program to talk to that port directly, and then re-feed the interpreted input data into the kernel's input layer via the uinput facility.

NEW: usespace replacements of the atkbd and psmouse modules

Eventually, I've ported the two kernel space input drivers atkbd and psmouse to user space. Those interested can download atkbd.c or psmouse.tgz and have a try. They require the SERIO_USERDEV patch to gain direct access to the PS/2 keyboard and mouse ports. (For simplicity, PS/2 keyboards are the same as AT keyboards.) Moreover, they are still in alpha stage. Expect bugs, etc. (But bugs in userland programs can't bring down the whole OS :), unless some OS bugs are triggered (e.g. select()ing on the uinput char device created by the uinput module.)

In my opinion, this is the way the input layer should be implemented. The raw device ports should be left freely accessible by daemon programs running in userland. The interpretation of the input protocols should be implemented in daemon programs, which then re-feed the interpreted data to the input layer, which then provides a unified interface for other programs to access the input events. Implementing the protocols in userland daemons offers many advantages, such as more flexibility in the protocol interpretation code (e.g. emulating the wheels with the keyboard's scroll-lock?), ease of development and debugging, getting virtual input events from TCP connections, etc. It is plain wrong and inflexible for the kernel to dictate how it the input ports (e.g. PS2 mouse port) should be used.

The Driver

This driver, named ``psaux'' creates a device node with major number 10, minor 1 in Linux kernel 2.6. This device is conventionally named /dev/psaux in pre-2.6 kernels. If you're using devfs, then it appears as /dev/misc/psaux.

With this device node, mouse drivers that works on pre-2.6 kernels would work again in 2.6 without changes (subject to my bugs, of course). E.g. my home-brewed XFree86 for my Laptop works again with this psaux module. I can keep my old XFree86 configurations, and do not have to wait for someone to write a driver for it in kernel space.

New development: SERIO_USERDEV

NEWER!!!

Tuukka Toivonen took the idea further and came up with the SERIO_USERDEV patch (dated 2004-06-03), which was posted to the LKML. In this patch, my psaux code plus Tuukka's improvements has been reimplemented as linux/drivers/input/serio/serio-dev.c to provide more functionalities. In particular, it is now possible to implement keyboard and mouse drivers in user space. See my userspace atkbd and psmouse drivers for details. Tuukka and I have polished the code to remove many early bugs or undesirable behaviours. We also thank our testers, who helped us test the patch on various hardware that we do not possess.

SERIO_USERDEV provides a user-space interface to not only the PS2 mouse port (/dev/misc/isa0060/serio1), but all ports that are handled by the serio module (cat /proc/misc for a complete list after loading the patched serio module). The patch was developed for Linux 2.6.5, but I've personally tested it on 2.6.6 and 2.6.7-rc1, too.

Development of psaux has since stopped, with the time and energy devoted to SERIO_USERDEV instead. SERIO_USERDEV is a more general method of providing direct port access to PS2 mouse as well as keyboard. This patch has also been reported to work with multiplexed PS2 mouse ports, found on some recent hardwares (esp. notebooks with stocking stations).

Tuukka Toivonen's improvments on psaux

Tuukka Toivonen has taken my code and made some improvements on it. I admit that he is a better Linux kernel hacker than I am. (I'm just a beginner anyway.) His version include the following improvements: Some minor difference from my module (for those who have been using my version):

My Old Code

NEW!!! Please use the SERIO_USERDEV patch, initiated by Tuukka Toivonen. I consider my own psaux deprecated from now on (2004-04-19).

The file drivers/input/misc/psaux.c contains the code. To compile it, you still need a modified drivers/input/misc/Makefile file and a modified drivers/input/misc/Kconfig file to configure the kernel to compile it. Alternatively, apply the patch file ``patch-2.6.2-psaux'' to kernel version 2.6.2. It is reported to work with 2.6.3, and it also compiles with 2.6.0, 2.6.1, 2.6.4. It may also work with other versions in the 2.6 series. However, it is still well tested on SMP kernels and systems. If you are encountering problems when you use this driver on SMP systems, please first try again with a non-SMP kernel (or boot your kernel with the option ``nosmp'' or ``maxcpus=1''). I would of course like to make it SMP-correct. However, I do not have an SMP system to try the driver with. So, your help would definitely be needed.

After applying the patch to the Linux kernel source code, or putting the above files into it directly, do a ``make config'' (or ``make menuconfig'' or ``make xconfig''). Click the configuation item ``Device Drivers/Input device support/Misc/Compatibility `/dev/psaux''' to compile it as a module (tested) or into the kernel (not tested). In addition, the existing mouse driver also emulates a /dev/psaux which conflicts with my module. You have to disable that feature. Edit .config and disable the entries INPUT_MOUSEDEV_PSAUX by commenting out that line. Now, do what you would normally do to compile the kernel (e.g. ``make'').

After booting the new kernel or loading the psaux module, you can access the mouse port again with the device node /dev/psaux. If that node is not there already, make it with the command ``mknod /dev/psaux c 10 1''. If you're using devfs, the device node /dev/misc/psaux should already be there. Now, you can start gpm or XFree86 in the old way. :)

Known issues (or bugs)

Thanks to all those who have reported bugs and helped me found fixes or workarounds.

Arguments against kernel-space drivers

Finally, I'd like to conclude by presenting my arguments against the current approach of the Linux 2.6 kernel to move mouse drivers into kernel-space.

First, one important principle of a successful OS design is to separate policies from mechanism. One of the factors of the success of unix is that it follows this principle very closely. E.g. it provides a mechanism for you to name files (in the filesystem code), but doesn't impose a policy on how the files should be named (other than using ``/'' as the directory separator and ASCII NUL (0) as the name terminator. This allows flexible file naming schemes, only limited by the users' imaginations (and practical implementation limits, of course.) Contrast this with the 8.3 filename of DOS! Or the base_name.extension;version naming scheme in VMS. Now, what happens to the mouse drivers? In pre-2.6 kernels, the kernel drivers are minimal: they only provide a mechanism for userland programs to communicate with the mouse-like device. There is even no policy imposed on what protocols should be used for this communication channel. Mouse drivers such as those gpm or XFree86 use this mechanism to implement the various protocols (the policies) used by the devices. The principle of separation of policy and machenism is followed. On the other hand, kernel 2.6 now moves the drivers into kernel space. The kernel now not only provides a mechanism for programs to interact with the device, but also imposes a policy on what protocols should be used. Other protocols are not allowed. (They could be added, but not effortlessly.)

Every technical people know why Windows NT is so unstable. One (of the many many) reason is that the GUI — Graphical User Interface — runs in kernel space. (This is equivalent to implementing XFree86 and the KDE/Gnome desktop as kernel code.) Since kernel code executes in special (but dangerous) environment that allows the code to access (and abuse) many other parts of the system, bugs (such as using wrong pointers) can spread to other parts of the system easily. It is agreed (other than by Microsoft) that the kernel should be kept as simple and small as possible. Anything that can be implemented in userland without significant loss of efficiency should be implemented in userland. This keeps the kenel small and simple, making it less easy for problems to spread out. Userland programs are run in a protected environment, which does not allow the program to touch other parts of the system. So, when a process in unix crashes, it won't hang the whole system. Other processes and the kernel still keep on going without problems. Now what is with the mouse drivers in kernel 2.6? The approach is to move them from userland (e.g. gpm) into the kernel. I can't see any advantage of doing that. There is no performance problems with mouse drivers in gpm or XFree86, because the volumn of data passed between the device and the driver is very small. Yes, the new input layer in the kernel allows several mice to be used concurrently. But gpm has been able to do that for a long time. (See the -M option of ``man gpm''.) Since it can be done in userland (by gpm) without performance problems, it shouldn't be moved into the kernel. The only advantage that I can see in implementing mouse drivers in kernel space is for embedded systems. But why forgo gpm, with it dozens of already maturely implemented mouse drivers, with fresh kernel code? (It is non-trival to port the gpm drivers into kernel code. Kernel programming is different because kernel code runs in a different environment. Debugging is also more challenging when developing kernel code.)

In a nutshell, I consider it to be a backward development for the Linux kernel 2.6 to move mouse drivers from userland into the kernel.

Updates

Since Tuukka Toivonen
posted his version of psaux module (which is an updated version of mine) on the Linux Kernel Mailing List (LKML), an interesting debate about the design of the Input Layer in 2.6 kernsl has started.
Last updated $Date: 2004/06/03 11:40:26 $ (UTC)