Alex's Blog

Giving /dev/tty* meaningful names

Got too many USB devices exposing some kind of serial interface? Getting lost in the sea of /dev/ttyUSB* and /dev/ttyACM*? No worries, you can give them more meaningful names and easily correlate /dev entries with the actual devices.

The plan is to add udev rules which match against your specific device in some form or another, and then use the SYMLINK key to automatically create a symlink with a known name.

Let's assume that you have a /dev/ttyUSB0 device plugged in which you would like to create a /dev/tty_xyz symlink to it (a CNC machine that I'm using as an XYZ stage).

We need to combine a set of udev match keys to find the specific device we are interested in. In my case, I wanted the symlink to only be created if I plugged a specific USB device (VID and PID combination) into a specific USB port.

I know that /dev/ttyUSB0 is the entry created for my device. Starting from there, I run udevadm info -a /dev/ttyUSB0, which prints a list of all devices in the tree. In addition, it also prints for each node a bunch of udev keys that can be used to write rules, something similar to:

[...]
  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2.1/3-2.1.2':
    KERNELS=="3-2.1.2"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="ff"
    ATTRS{bDeviceProtocol}=="00"
[...]
    ATTRS{idProduct}=="7523"
    ATTRS{idVendor}=="1a86"
[...]

Through trial and error, I have learned that one needs to select the first device with SUBSYSTEMS=="usb" and some values for ATTRS{idVendor} and ATTRS{idProduct}. The KERNELS keys is furthermore relevant to me since I want to be able to identify the specific USB port.

Lastly, the ACTION key should be used with the values add (when the device is ready to operate) and change (generated for example by udevadm trigger). This ignores events which have the bind action (generated prior to add).

Putting it all together, the udev rule in my case would be

ACTION=="add|change"        \
, KERNELS=="3-2.1.2"        \
, ATTRS{idProduct}=="7523"  \
, ATTRS{idVendor}=="1a86"   \
, SYMLINK="tty_xyz"