Thursday, December 12, 2013

Wacom Serial devices and inputattach in a systemd world

If you don't have one of the Wacom serial devices, you probably don't need to worry about the below. If you do, read on.

Wacom serial devices are supported by the xf86-input-wacom driver directly, but a much nicer way is to have the kernel deal with it and thus the device exposed as a normal evdev device to userspace. This way, the device is also picked up by libwacom and, in turn, by the GNOME Wacom panel for configuration and calibration. For the device to work as evdev device you need inputattach (in the linuxconsoletools package on Fedora).

The simplest approach if your device is connected to /dev/ttyS0 is:

$> inputattach --daemon --w8001 /dev/ttyS0
but of course we want to automate this. We used to have a udev rule that fires up inputattach but recent changes [1] in udev broke that ability: udev is now decidedly for short-running processes only, long-running processes started by a udev rule will be killed. The solution to that is a udev rule paired with a systemd service.

First, the systemd wacom-inputtattach@.service service file, which is quite simple:

[Unit]
Description=inputattach for Wacom ISDv4-compatible serial devices

[Service]
Type=simple
ExecStart=/usr/bin/inputattach -w8001 /dev/%I
Note the @ in the name, we use what comes after through the %I directive as the device file, e.g. ttyS0. Note also that we don't use the --daemon flag because we want systemd to take care of our process instead of forking it and letting it guess what the PID is, etc. This service can now be started with
$> systemctl start wacom-inputattach@ttyS0.service
and of course the information is available in the journal, etc.

Now we just need something to start the service automatically, and that's handled in a simple udev rule. Here's the whole udev file for easy copy/paste:

ACTION!="add|change", GOTO="wacom_end"

SUBSYSTEM=="tty|pnp", SUBSYSTEMS=="pnp", ATTRS{id}=="WACf*", \
  ENV{ID_MODEL}="Serial Wacom Tablet $attr{id}", \
  ENV{ID_INPUT}="1", ENV{ID_INPUT_TABLET}="1", \
  ENV{NAME}="Serial Wacom Tablet $attr{id}"
SUBSYSTEM=="tty|pnp", SUBSYSTEMS=="pnp", ATTRS{id}=="FUJ*", \
  ENV{ID_MODEL}="Serial Wacom Tablet $attr{id}", \
  ENV{ID_INPUT}="1", ENV{ID_INPUT_TABLET}="1", \
  ENV{NAME}="Serial Wacom Tablet $attr{id}"

SUBSYSTEM=="tty|pnp", KERNEL=="ttyS[0-9]*", ATTRS{id}=="WACf*", \
  TAG+="systemd", ENV{SYSTEMD_WANTS}+="wacom-inputattach@%k.service"

LABEL="wacom_end"
Wacom's serial devices have IDs starting with WACf, so we match on that. The first two "SUBSYSTEM..." lines match and set the name and some ID_foo tags so that the server recognises the tablet as input device and can match against xorg.conf.d InputClass snippets. With just those first two lines, we will have the xf86-input-wacom driver work for serial devices, even if inputattach didn't start. These two lines haven't changed in years either. The new and systemd-specific bit is the third line. Again we match but this time we set the systemd tag, tell systemd the service we want to start (%k is replaced with the kernel device, e.g. ttyS0) and we're done. Reboot [2] and you should be the happy viewer of something like this:
$> systemctl status wacom-inputattach@ttyS0.service   
wacom-inputattach@ttyS0.service - "inputattach for Wacom ISDv4-compatible serial devices"
   Loaded: loaded (/usr/lib/systemd/system/wacom-inputattach@.service; static)
   Active: active (running) since Thu 2013-12-12 08:03:00 EST; 24min ago
 Main PID: 562 (inputattach)
   CGroup: /system.slice/system-wacom\x2dinputattach.slice/wacom-inputattach@ttyS0.service
           └─562 /usr/bin/inputattach -w8001 /dev/ttyS0

[1] I say recent but really, it could've been any time since F18 or so, I don't test this particular device very often
[2] yeah yeah, there's a command to trigger this directly, you don't need to reboot, I know

Update 2013/12/13: remove quotes around Description in unit file

1 comment:

Lennart said...

The Description string should not be in "quotes".