Friday, October 19, 2012

Lenovo x220t Tablet and the broken Wacom 0xE6 tablet

I noticed that my tablet didn't work anymore. In fact, the tablet itself didn't even show up in /proc/bus/input/devices. At first I suspected a kernel bug and rebooted into a variety of different Fedora kernels, but to no avail.

Looking at various logs, I discovered:
:: whot@yabbi:~> dmesg | grep 56a
[    2.291841] usb 2-1.5: New USB device found, idVendor=056a, idProduct=0094
Wacom's vendor ID is 056a, but the tablet in the x220 is a 0xE6, not a 0x94 (the latter of which doesn't exist). With that info, googling for a solution was a bit easier. As suggested in the thread on linuxwacom-devel a power off did indeed fix the issue for me.
:: whot@yabbi:~> dmesg | grep 56a
[    2.291841] usb 2-1.5: New USB device found, idVendor=056a, idProduct=00e6
It turns out this is an issue with kernel 3.5.3 and 3.5.4, but it is fixed in 3.5.5. kernel bug. As Ping states:
The root cause is somewhere in the kernel tablet is set to a wrong mode. Once it is in that mode, a reboot won't reset it to normal. We have to power it off and wait a few seconds for all bits to reset. That's why I tell people to even unplug the power cable since bits may stay as long as they get power.

update 20/10/12: list kernel versions affected, add Ping's quote

The X.Org joystick driver (xf86-input-joystick)

At XDC2012, Sascha Hlusiak, maintainer of the xf86-input-joystick module, gave a talk (slides) outlining the joystick driver's current state and future directions. There were quite a few tidbits of information in there that I want to repeat here, a slightly more public place.

The most important bit about the xf86-input-joystick module is what it is not: it is not a joystick driver. If you want to use your joystick in a game under X, you don't need that driver. The xf86-input-joystick module is designed to control the pointer with a joystick device. Sascha gave the example of using an XBox controller to control a Linux-driven media-center. The controller can serve as a cheap remote control (especially if you already have the controller but you'd need to buy a remote ;)

So why is the joystick module not a joystick driver? The evdev driver handles most input devices with arbitrary axes and games can use those devices through evdev. But this is a game-specific application, and the game likely knows what features of the joystick it wants.

For pointer control, it's not quite as obvious. Your average joystick has a couple of axes, four or more buttons and possibly even force feedback. The joystick module's configuration must determine which axis controls the pointer motion (and must be mapped from absolute to relative) and which button generates button (or key) events. Because no two joysticks are the same, there cannot be a sane default for the joystick driver configuration. The default install is thus almost certainly useless and may even interfere with your normal X install.

For example, a joystick sending absolute input events that does not have the mapping configured correctly will force the mouse pointer onto a specific position.That may make it impossible to move the pointer with the mouse.

For this reason, any distribution that ships the joystick module should add Option "Floating" "on" into the default configuration. This way the joystick is detected and enabled in X, but it won't actually control the cursor. This means the joystick may look like it's not working initially to the users who want it, but it's not breaking anything for those that install the module unintentionally. The joystick module should not be part of a default install, it's use-case is too narrow.

Once you're happy using the joystick module for it's intended purpose, there are vast configuration options to suit all tastes:

  • Option "MapButton1" "button=3" maps the first joystick button into a right-click (X logical button 3)
  • Option "MapButton2" "axis=+5x" maps the second joystick button to a x movement by 5 units
  • Option "MapButton3" "keycode=50,40" maps to Shift +d, though you may want to read about keycodes vs keysyms first
  • Option  "MapAxis2"      "mode=relative    keylow=111  keyhigh=116" will map the second axis to key events up/down
I recommend reading the joystick(4) man page for further examples on configuration options. Note, the linked man page isn't the latest one, but it's at least rendered in html, not plain roff.

Friday, September 28, 2012

Never use a "Questions?" slide in your presentation

Most presenters do this. Give a presentation, finishing with a "questions?" slide. Except, that's a really bad idea.

You give a talk at a conference? You have 20, maybe 45 minutes to get your topic into the mind of the audience? Then don't let your audience stare at "Questions?" for 10, 20 minutes (however long the question time takes). Even if there are no questions, it usually takes a few minutes for applause, saying thanks and until you leave the podium. And the whole time your audience is staring at a meaningless word.

So, skip the useless "Questions?" slide. You can invite your audience to ask questions without it too. The whole point of being a speaker is that you're allowed to also say things that are not on the slides.

Finish with a slide that reminds your audience what you just talked about. A summary of the talk, the one point you really wanted to drive home. Maybe even a joke, if you have one that gets the point across.

And your contact details. It gives those without questions enough time to write it down.

Tuesday, August 28, 2012

X.Org integration test suite

One of the problems we face in X is that testing can be incredibly painful. Somebugs only happen with a specific server state, a specific device and a specific application. Sometimes we don't spot regressions for several releases, and in some cases that means we can't easily go back and fix it either - users may have gotten used to the new behaviour already.

A few months ago, Chase Douglas announced the xorg-gtest framework. I started extending xorg-gtest and writing tests against it. Olivier Fourdan soon joined in with his own tests. The result of that are the xorg integration tests (XIT) found here:

http://cgit.freedesktop.org/~whot/xorg-integration-tests/

This post is an outline of what the XIT do and what we could potentially make it do. We currently have over 50 tests in the XIT repository. Most of the tests are still quite simple, but I've already added some that test for a specific bug and that certainly helped testing. In one case, a failing test reminded me that I forgot to send a pull request :)

googletest and xorg-gtest

xorg-gtest is based on the googletest C++ framework. It provides a bunch of classes with virtual functions that are called set up or tear down a test. For the tests, it provides a set of assertion macros. xorg-gtest provides a set of classes on top of googletest that make starting an X server simpler. The XServer class provided hooks up config and log files, waits for the server to accept connections and terminates the server gracefully. It also includes a class for starting evemu devices and re-playing input event sequences. There are a few additional helper classes in the XIT, for example one that makes writing configurations easier. They may move to xorg-gtest at some point in the future.

Example tests

Your average test now essentially consists of three steps: write out a specific config, start the server and then query that server for information or test it for behaviour.

A straightforward test is the acecad driver test below.

TEST(AcecadInputDriver, WithOptionDevice)
{
    XOrgConfig config;
    xorg::testing::XServer server;

    config.AddInputSection("acecad", "--device--",
                           "Option \"CorePointer\" \"on\"\n"
                           "Option \"Device\" \"/dev/input/event0\"\n");
    config.AddDefaultScreenWithDriver();
    StartServer("acecad-type-stylus", server, config);

    ::Display *dpy = XOpenDisplay(server.GetDisplayString().c_str());

    int ndevices;
    XIDeviceInfo *info;
    info = XIQueryDevice(dpy, XIAllDevices, &ndevices);
    XIFreeDeviceInfo(info);

    ASSERT_EQ(ndevices, 7);

    config.RemoveConfig();
    server.Terminate(3000);
    server.RemoveLogFile();
}

A slightly more involved test that makes use of the googletest class hierarchy would be the void driver test below. It makes use of a InputDriverTest class that starts the server for us and tears it down afterwards. So all we need is a couple of lines for the class definition and then the test itself.

class VoidInputDriverTest : public InputDriverTest {
public:
    /**
     * Initialize an xorg.conf with a single CorePointer void device.
     */
    virtual void SetUp() {
        InputDriverTest::SetUp("void");
    }
};

TEST_F(VoidInputDriverTest, VoidDriver)
{
    ASSERT_EQ(FindInputDeviceByName(Display(), "--device--"), 1);
}

These two are just examples as used in the integration test suite. I recommend reading the googletest documentation for a bit more info on test fixtures and assertions. xorg-gtest also is well-documented though I recommend building the doxygen sources.

Emulating input devices

xorg-gtest provides a Device class that, based on evemu recordings, can simulate input devices. So with the current implementation, this as simple as:

  SetDevice("keyboards/AT-Translated-Set-2-Keyboard.desc");
  dev->Play("keyboards/qwerty.events");
  ...
  dev->PlayOne(EV_KEY, KEY_Q, 1, true); // press
  dev->PlayOne(EV_KEY, KEY_Q, 0, true); // release

If you now check for the keysym received, you can easily write a few simple XKB layout tests.

Fighting the build system

As convenient as tests are to write, googletest is not the easiest thing to deal with. The piles of macros subclass your classes and the C++ ODR essentially prevents googletest from being built into a library. Autotools on the other hand make it difficult to compile an external project into your own file. That is the main reason for one big collection of tests instead of a per-driver test suite. Copying Makefile.am's around is painful enough, but at least manageable when only one project does it.

The current need for three different repositories (googletest, xorg-gtest and XIT) doesn't make things easier. I'm somewhat tempted to merge XIT into xorg-gtest, be it as git submodule or some other means.

Having said that, since starting to write the tests I'm also really tempted to merge the drivers into the server, it would make things a lot easier

ifdefs maze

To make the tests useful, they should be able to run on most systems. Right now, I've got some simple defines to test for RHEL6 and also XI 2.2. But I don't think this will scale too well. Every system may have different defaults, and short of having platform-specific tests (which may only be different in one single line) I don't know what the good answer is. I do want it answered soon, before it gets out of hand.

Scalability

Running all tests takes a while. In the current test design, every single test starts a new server and thus it takes a couple of seconds for even the quickest test to succeed. This works with 50 test cases, but it won't work with 500 and even less with 5000. So we need some solution for that. Not re-starting the server is the obvious one and there will be tests that won't require that.

Output testing

Most of the test runs I do either on my laptop or on a virtual machine. For input tests, this is easy since we only need to set up the dummy driver and the rest can be emulated. For output tests, not so much so a good approach of only running tests applicable for the hardware would be useful. I haven't thought too much about this yet.

Testing XIT

Right now, it sits in my personal home directory but I hope that after XDC this year, we can decide what the future of this test suite can be and where to host it proper.

In the meantime, grab it from here:

http://cgit.freedesktop.org/~whot/xorg-integration-tests/

Monday, August 20, 2012

screen configuration for automatic session names

screen is an immensely useful program, but once you start running multiple sessions at the same time, it gets tricky to find the right one again.  For example, which one was offlineimap again?


 :: whot@salty:~> screen -ls
There are screens on:
    5238.pts-3.salty    (Detached)
    5229.pts-3.salty    (Detached)

The -S argument allows to specify a session name but I couldn't find a configuration to set this automatically. So I've added this little script:


$> cat $HOME/scripts/screen
#!/bin/bash
/usr/bin/screen $([[ ($1 != -*) && ($# > 0) ]] && echo "-S $1") "$@"


Explanation: if called with 1 or more parameters and the first parameter does not start with a dash, replace a call in the form of screen command ... with screen -S command command ...

This results in screen sessions having useful names, allowing for more effective reattaching. And the obligatory, ahem, screenshots: 
:: whot@yabbi:~> screen foo
[detached from 17755.foo]
:: whot@yabbi:~> screen bar
[detached from 17766.bar]
:: whot@yabbi:~> screen -ls
There are screens on:
    17766.bar    (Detached)
    17755.foo    (Detached)
2 Sockets in /var/run/screen/S-whot.

Wednesday, July 11, 2012

Daily tmp directory

My $HOME/tmp directory got a bit messy, especially with building test rpms or testing tarballs. My solution was to just change the directory to automatically change daily. Scripts below:
:: whot@yabbi:~> cat scripts/tmp-today 
#!/bin/bash
date=`date +%Y-%m-%d-%a`

tmpdir=$HOME/tmp/$date
tmplink=$HOME/tmp/today

if [ -e "$tmpdir" ]; then
    exit 0
fi

mkdir $tmpdir
ln -sf $tmpdir $tmplink
And the crontab entries to run this script:
0 2 * * * /home/whot/scripts/tmp-today
@reboot /home/whot/scripts/tmp-today
So run the thing at 2.00 am and on every reboot in case the box was shut off overnight. I had it on midnight first, but I think 2 am is better. If I'm still up at 2 and working, then mentally I'm still in on the day before and I don't want files to end up in different directories just because midnight clocked over. And because the laptop may be suspended overnight, we run the script on resume as well:
:: whot@yabbi:~> cat /etc/pm/sleep.d/00-tmp-dir 
#!/bin/bash

case "$1" in
 thaw|resume)
  su -c - whot /home/whot/scripts/tmp-today
  ;;
 *)
  ;;
esac
This obviously works for other directories as well, e.g. your daily download directory.

Friday, July 6, 2012

elographics touchscreen setup

This is a tutorial of sorts on how to set up an elographics serial touchscreen. I don't actually have such a device but the question pops up every couple of months. Together with Tom Munro Glass and Tias Guns, we got one working properly.

Edit: 18/09/2014 - add systemd description

A bit of history first: not too long ago, the X server was talking to serial devices directly and thus had several drivers for specific input devices. The elographics X drivers is one of them. Unfortunately, due to lack of hardware we, the upstream maintainers, can only perform cursory testing of that driver. The Linux kernel however supports a large amount of serial devices too, so for this tutorial I'll explain how to use the linux kernel to talk to the device. I'll show how to set up udev rules to use inputattach and then the X.Org evdev driver, thus making the device utilise a well-tested driver that has some client-stack support not found for the X.Org elographics driver [1].

Kernel setup

USB devices are automagically detected by the kernel and it will load the right drivers. Serial devices on the other hand require some manual configuration. Elographics devices have serial kernel drivers and inputattach can be used to hook serial devices up with those kernel drivers. First we need to load the kernel module, then call inputattach with the right options for our device:
root@localhost:~> modprobe elo
root@localhost:~> inputattach -elo /dev/ttyS0 --daemon
The path to the device may need to be changed on your box. Do look up the inputattach man page, depending on your device you may need a different flag.

Once inputattach is running, the device should be visible in /proc/bus/input/devices. You can run evtest against it and see the event stream.

udev setup pre systemd

Since we don't want to run inputattach manually each time, we'll now set up udev to run this command for us. According to Tom, the elographics device does not have a pnpid, so he configured it with a fixed device path on ttyS4:
$> cat /lib/udev/rules.d/99-elographics.rules
ACTION=="add|change", SUBSYSTEM=="tty|pnp", KERNEL=="ttyS4", \
        RUN+="/sbin/modprobe elo", \
        RUN+="/sbin/inputattach -elo /dev/%k --daemon"
If a device has a pnpid, the rule can be more flexible in what ttyS* the device needs to appear on. For example, a Wacom serial tablet may have the id WACf004 so we can use the match rule below.
$> cat /lib/udev/rules.d/99-wacom-w8001.rules
ACTION=="add|change", SUBSYSTEM=="tty|pnp", KERNEL=="ttyS[0-9]*", \
        ATTRS{id}=="WACf*", \ 
        RUN+="/sbin/modprobe wacom_w8001", \
        RUN+="/sbin/inputattach -w8001 /dev/%k --daemon"
Once this rule is in place, inputattach will be started for us at boot time (of course the device needs to be connected at boot time too). The next step is to configure X to see the device.

udev setup with systemd

Newer udev (for some value of new, we're talking about Fedora 18 or so) won't let RUN start long-running processes, such processes get killed off. If you are on system with systemd you're best off setting up a systemd service file for inputattach (see also this post). In that case, your udev rule becomes
SUBSYSTEM=="tty|pnp", KERNEL=="ttyS4",  \
      RUN+="/sbin/modprobe elo", \
      TAG+="systemd", ENV{SYSTEMD_WANTS}+="elo-inputattach@%k.service"
So we tag the device for systemd and tell it to start a servirce. The %k gets replaced with the ttySx device. The matching systemd unit file looks like this:
$> cat /etc/systemd/system/elo-inputattach@.service
[Unit]
Description=inputattach for elo serial devices

[Service]
Type=simple
ExecStart=/usr/bin/inputattach -elo /dev/%I
Once both of these are in place, a reboot will initialise inputattach, and the device is available as kernel device.

X.Org configuration

X requires the udev properties ID_INPUT and one of ID_INPUT_MOUSE, ID_INPUT_TABLET, etc. to to recognise an input device. Each of those triggers the respective MatchIsPointer, MatchIsTablet, etc. directive in the xorg.conf.d snippets. On modern systems, the udev properties should be assigned automatically [2]. If that doesn't happen on your box, you can modify the above udev rules to add it manually:
$> cat /lib/udev/rules.d/99-elographics.rules
ACTION=="add|change", SUBSYSTEM=="tty|pnp", KERNEL=="ttyS4", \
        RUN+="/sbin/modprobe elo", \
        RUN+="/sbin/inputattach -elo /dev/%k --daemon", \
        ENV{ID_INPUT}="1", ENV{ID_INPUT_TOUCHSCREEN}="1"
Once this is done, the X server will pick up the device, and the default configuration [3] will assign the evdev driver to it. Restart X, and you're done.

If you require additional options, set up an xorg.conf.d snippet. There you can add any options found in evdev(4):
$> cat /etc/X11/xorg.conf.d/99-elographics.conf
Section "InputClass"
  Identifier "elographics config"
  MatchProduct "Elo Serial TouchScreen"
  Option "EmulateThirdButton" "on"
EndSection
This snippet will match any device with the product name containing "Elo Serial Touchscreen" and enable the right button emulation feature in the evdev driver. If you are unsure about the name of your device, check /proc/bus/input/devices once inputattach is running.

X.Org configuration on Red Hat Enterprise Linux (RHEL) 6.x

This section applies to derivatives as well, e.g. CentOS 6. On RHEL 6.x, we use HAL as a configuration backend. So you will need an fdi snippet to match the device up with the driver. The snippet below is the one Tom ended up using, and it also shows the Calibration option being merged.
$> cat /etc/hal/fdi/policy/10-elographics.fdi
<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
  <device>
    <match key="info.category" contains="input">
      <match key="info.product" contains="Elo Serial TouchScreen">
        <merge key="input.x11_driver" type="string">evdev</merge>
        <!-- next line is equivalent to an xorg.conf.d statement of
                Option "Calibration "40 4000 40 4000" -->
        <merge key="input.x11_options.calibration" type="string">40 4000
40 4000</merge>
      </match>
    </match>
  </device>
</deviceinfo>
Note the "match key" statement. Apparently, this particular device does not set "input.touchscreen", so we match on just "input" instead. Not too big a deal, since we then also match on the product name.

Once this file is in place, restart haldaemon and check with lshal that the right options are assigned. Then restart X and the device should work.

Good luck!

Many thanks to Tias and Tom for proof-reading this article multiple times.

[1] for example, evdev supports dynamic recalibration with the xinput_calibrator tool
[2] check the output of udevadm info --export-db
[3] your distribution should ship /usr/share/X11/xorg.conf.d/10-evdev.conf which assigns evdev to MatchIsTablet.

[edit 22 Feb 13: fix typo in MatchProduct name]