Thursday, July 24, 2008

Input configuration in a nutshell.

Once upon a time, we had a number of free operating systems. Linux, BSDs, emacs, XFree86, you name it. Then one of them chose to be less like one and become a windowing system instead (which was supposed to it's job from the beginning, albeit it kinda forgot about it halfway there). The principle of DTRT was embraced and the almighty xorg.conf file was given the handshake and shown the door. These days, X starts without a config file these days, and everything just works.

Most of the time. When it doesn't it's usually ugly. So here's a guide on how to configure input devices with recent servers. This guide includes
  • a quick overview of the evdev input driver
  • how to set up input hotplugging.
  • what to do in the xorg.conf
First, if you're not running Linux you can stop reading. Keep your config file, make sure you reference your input devices in the ServerLayout section, and start porting the evdev kernel module to your OS of choice.


A quick overview of the evdev input driver
xf86-input-evdev is the hotplugging-capable input driver to be used for mice and keyboards (and other devices, if appropriate). One main difference is that it uses devices files such as /dev/input/event0 instead of /dev/input/mouse0 (like the mouse driver does for example). The other big difference is that it can query the kernel about the capabilities about each device and set up itself correctly. So if you point a device to /dev/input/event0, it will automatically set itself up as mouse or keyboard, as appropriate.
The second important thing is that it puts a grab on the device file (not the same as a pointer/keyboard grab in X!). This grab gives us two benefits: the device will not send events to the collector devices (e.g. /dev/input/mice) anymore. And if anyone else tries to grab the device they will fail. So we can ensure that only one process receives events from this device.

What does all this mean to us now?
We can change our mice and keyboards in the xorg.conf to use the evdev driver instead. As device, we can either specify /dev/input/eventX, but these numbers may change on reboot. Look into the /dev/input/by-id and /dev/input/by-path directory. I recommend to always use /dev/input/by-id/MyMouseName-event-mouse as device instead of the eventX files. Note that you'll find MyMouseName-mouse and MyMouseName-event-mouse, of which only the latter will work with evdev. Ignore the former.
The big benefit is simply that you can configure multiple devices quite easily now. Simply set up InputDevice sections for each device and the X server will treat them as different devices. This is quite useful if you're using MPX.


How to set up input hotplugging

Writing xorg.conf sections is not only boring, it's also quite pointless in most cases. So let's let the server find input devices automagically. The two ingredients are HAL and DBus. At startup, the server queries HAL over DBus for a list of devices and adds them one-by-one.

All you need to do is configure HAL so the server adds the devices with the right options.
You must merge the key input.x11_driver. Look at x11-input.fdi. This file should reside in /etc/hal/fdi/policy/, and it tells HAL to merge the evdev driver for each mouse and keyboard It also merges some Xkb options for keyboards.
Important: the server will not add devices unless they have input.x11_driver set. If you end up with no devices at all, then your HAL setup is probably broken.

To test your installation, run hal-device to obtain a list of all devices and look for the input.x11* keys. If they are not present, modify the fdi file and restart HAL.

Your X server is now hot-plug capable. It will add all mice and keyboards automatically, even if you add/remove them at runtime. There's modified fdi files floating around to add hotplug for wacom tablets and synaptics touchpad, finding them is left as an exercise for the reader.

What to do with the xorg.conf
We have two configuration files now. Yay. One is xorg.conf, the other one is the fdi file. And they both don't know about each other, leading to interesting results. The server parses xorg.conf first, then gets the devices through HAL. And here we have a big culprit: if add a InputDevice section with the mouse driver, it will conflict with the evdev driver. Evdev grabs the files, remember? So when all mice are added through the HAL evdev hotplugging mechanism, all mice stop sending to the /dev/input/mice file. So although you still have a valid input device in the server, it will never emit any events.
The only solution here? Either stop hotplugging alltogether by adding Option "AutoAddDevices" "off" in your ServerLayout, or modify the fdi file that it doesn't merge input.x11_driver for the specific mice you don't want hotplugged (or all mice).

Troubleshooting list:
  • I have no input devices and compiled the server myself. Install libhal-dev and libdbus-dev, re-run configure and recompile.
  • I have no input devices. HAL setup needs to be configured. Make sure the x11-input.fdi file is in /etc/hal/fdi/policy, and that hal-device lists mice and keyboards with input.x11_driver = "evdev".
  • My xorg.conf settings are ignored. HAL adds your devices without settings, and evdev grabs all devices away. Modify the fdi and add your settings there, or add Option "AutoAddDevices" "off" to your ServerLayout. Note that this will stop input hotplugging.
  • I'm getting a "Grab failed" in the logs. You have two evdev input devices pointing to the same device file. This usually only happens if you have a xorg.conf entry with an evdev, and then HAL tries to add the same device again. You can ignore this warning.
  • I have devices in my xorg.conf but still don't get any devices. Your ServerLayout doesn't reference the input devices and your HAL setup is broken. Add Option "AllowEmptyInput" "off" to your ServerLayout or simply reference the InputDevice sections in the ServerLayout. While you're at it, you may also want to configure HAL.
  • My touchpad is slow. Check the logs if the touchpad is added with the evdev driver. If so, modify the fdi file to merge synaptics as input.x11_driver, or add a InputDevice section in your xorg.conf (must be referenced by the ServerLayout).
  • Evdev doesn't support option "XYZ". Add a feature request to X.Org Bug 16699. Bugs with patches get preference.

13 comments:

Dan Nicholson said...

Nice writeup, Peter. You talked about how xorg.conf and the fdi don't know about each other. However, Xorg does know about both of them. I've always wondered, why can't Xorg compare the HAL enumerated devices to the xorg.conf enumerated devices and skip the HAL ones if the exist already from xorg.conf? It seems logical to me that if someone went to the trouble of configuring a device in xorg.conf, then that configuration would be preferred. Am I missing something?

Peter Hutterer said...

Dan:
The problem with that is that the X server doesn't know that /dev/input/mouse0 is the same as /dev/input/event4. Hence the grab on the event device, to stop this from happening if you trying to add the same evdev device twice.

The only "knowledge" you could put into the server is that if there is a keyboard section, then you don't want keyboards hotplugged. But this removes the option of having a keyboard section as fallback in case evdev/HAL screws up.

Really, the best option is to simply
ditch mouse/kbd and replace both with evdev.

bgoglin said...

What if there's no /dev/input/by-id/ ? I only have by-path on my 2.6.26 on a Thinkpad T43:

platform-hdaps-event-joystick -> ../event8
platform-hdaps-joystick -> ../js0
platform-i8042-serio-0-event-kbd -> ../event0
platform-i8042-serio-1-event-mouse -> ../event1
platform-i8042-serio-1-mouse -> ../mouse0
platform-pcspkr-event-spkr -> ../event7

Are these going to change after a reboot with a new external mouse or keyboard plugged?

Peter Hutterer said...

The by-id symlinks are provided by udev.
Here's an example

by-path may change if you're un/re-plugging the device.

Dan Nicholson said...

Here's a corrected link:

http://wiki.linuxfromscratch.org/lfs/browser/trunk/udev-config/60-persistent-input.rules?rev=7799

But more importantly, this has been in the default rules from udev for quite some time:

http://git.kernel.org/?p=linux/hotplug/udev.git;a=commit;h=521e3f78

Of course, if your distro provides their own rules...

bgoglin said...

I found out that I only have a by-path entry for USB devices. If I unplug everything and only use the internal (PS2 mouse and keyboard), they have in by-id entry only, nothin in by-path.

bgoglin said...

Of course, I swapped by-id and by-path in the above comment :)

eolo999 said...

hi i'm working on a software implementation of a musical instrument called theremin [ http://en.wikipedia.org/wiki/Theremin ]. It would really be great to have two mouse pointers working on that app. I'd really appreciate to find a tutorial on how to enable multi-point in my X...

F3lip3 said...

Hi i can not get the hotplugging support, hal-device show my mouse, /dev/input/by-id/ show my conected mouse and /dev/input/ show new mouseX when i connect one.
the only clue I have is that an error at the end of the log of Xorg

"[dbus] couldn't take over org.x.config: org.freedesktop.DBus.Error.AccessDenied (Connection ":1.8" is not allowed to own the service "org.x.config.display0" due to security policies in the configuration file)" This error is repeated several times. Any idea?

Dan Nicholson said...

F3lip3,

It sounds like maybe Xorg is not running as root, and dbus is denying it from creating a system bus. Is your Xorg setuid to root?

F3lip3 said...

dan nicholson,

hi, thanks for you help, but the problem persist.
I use chown root:root and chmod u+s over /opt/xorg/bin/Xorg, the only change is that now the error message is shorter:

"[dbus] couldn't take over org.x.config: org.freedesktop.DBus.Error.AccessDenied"

Mumblyjoe said...

"You must merge the key input.x11_driver. Look at x11-input.fdi. This file should reside in /etc/hal/fdi/policy/..."

Yeah, under Fedora 10 there aren't any files under /etc/hal/fdi/policy/

Looking around, there is something like it here:

/usr/share/hal/fdi/policy/10osvendor/10-x11-input.fdi

Did the Fedora folk stray from the true path? :)

Peter Hutterer said...

Mumblyjoe:

/usr/share/hal/ is system-wide configuration and will be overwritten next time an update is installed.

/etc/hal/ is persistent. copy the fdi file from /usr into /etc and then edit it to get persistent configuration.