The Ever-Shifting Sands of udev.rules

I use Telldus Tellstick to do home automation *cough* I mean control the lights:

It’s an unassuming USB stick that implements a serial interface so that you can talk to it by just sending some strings to it and read the response. Ideal for Linux! Yes!

But.

You do want the device to show up at a default space so that you can find it, and if you have more than one serial USB interface thing, which one of /dev/ttyUSB0, /dev/ttyUSB1 og /dev/ttyUSB2 is it?

udev to the rescue!

And here your woes begin, because every fucking time you upgrade Linux, the fucking udev people change the fucking syntax vaguely and how you fucking refer to fucking devices. Fucking.

In the really olden days you said

KERNEL=="ttyUSB*", SYSFS{idVendor}=="1781", SYSFS{idProduct}=="0c31", 
  MODE="0666", NAME="tellstick"

But then they changed SYSFS to ATTR in the slightly less olden days:

KERNEL=="ttyUSB*", ATTR{idVendor}=="1781", ATTR{idProduct}=="0c31", 
  MODE="0666", NAME="tellstick"

Then they disallowed renaming devices, and instead you add symbolic links to the device:

KERNEL=="ttyUSB*", ATTR{idVendor}=="1781", ATTR{idProduct}=="0c31", 
  MODE="0666", SYMLINK+="tellstick"

Then they changed ATTR to ATTRS:

ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c31", MODE="0666",
  SYMLINK+="tellstick"

Then they changed what the attributes refer to, so instead of getting this:

[larsi@stories ~]$ ls -l /dev/tellstick 
blrwxrwxrwx 1 root root 7 Feb 25 16:12 /dev/tellstick -> ttyUSB1

you get this:

root@stories:/home/larsi# ls -l /dev/tellstick 
lrwxrwxrwx 1 root root 15 Feb 25 16:27 /dev/tellstick -> bus/usb/001/014

And that doesn’t work, because that’s not a serial USB interface, but a raw USB interface of some kind which can’t be opened like a serial interface.

And, remember, you can’t refer to /dev/ttyUSB*, because that’s the problem you’re trying to solve.

The solution to these problems is this following command:

 # udevadm info -a -n /dev/ttyUSB1

You’ll get output like

 looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.0/ttyUSB1/tty/ttyUSB1':
    KERNEL=="ttyUSB1"
    SUBSYSTEM=="tty"
    DRIVER==""

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.0/ttyUSB1':
    KERNELS=="ttyUSB1"
    SUBSYSTEMS=="usb-serial"
    DRIVERS=="ftdi_sio"
    ATTRS{latency_timer}=="16"
    ATTRS{port_number}=="0"

Well, nothing there to distinguish the Tellstick from anything else, to continue down the output…

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.0':
    KERNELS=="1-10:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="ftdi_sio"
    ATTRS{authorized}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceClass}=="ff"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{bInterfaceProtocol}=="ff"
    ATTRS{bInterfaceSubClass}=="ff"
    ATTRS{bNumEndpoints}=="02"
    ATTRS{interface}=="TellStick"
    ATTRS{supports_autosuspend}=="1"

Yes! The ATTRS{interface}==”TellStick” thing looks like it’s something we can use to distinguish between Tellsticks and other devices, and it’s not so far down in the device hierarchy that we’re not talking about serial interfaces any more, and presto!

[larsi@stories ~]$ ls -l /dev/tellstick 
lrwxrwxrwx 1 root root 7 Feb 25 16:33 /dev/tellstick -> ttyUSB1

Here’s the magical setup file, for reference if anybody wants to write a udev rule for Tellstick devices that works on February 26th 2018, but probably not the week after:

$ cat /etc/udev/rules.d/10-tellstick.rules 
ATTRS{interface}=="TellStick", MODE="0666", SYMLINK+="tellstick"

You can also refer to the parent attributes by saying SUBSYSTEMS at a strategic point, so the following also works today:

KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", 
  SUBSYSTEMS=="usb", ATTRS{idVendor}=="1781", 
  ATTRS{idProduct}=="0c30", 
  MODE="0666", SYMLINK+="tellstick"

Basically, when upgrading a Linux machine, most everything just works; all the peripherals and all the software. But I always end up twiddling the udev setup for half an hour.

Leave a Reply