writing udev rule for USB device

I have 3 USB to serial devices connected via an USB hub to the PC.They are assigned device paths (ie; /dev/ttyUSB0 or /dev/ttyUSB1 or /dev/ttyUSB2 ) based on the order of plugging in. My application will be lot easier to work with if the device paths remain static for a given USB device.

The plan is to write udev rules that uses an unique serial attribute to identify the device and then symlink it under a static name. The attributes of the device are :

user->/dev:udevadm info -a -p $(udevadm info -q path -n /dev/ttyUSB1)

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

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

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.2':
    KERNELS=="3-1.2"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{devpath}=="1.2"
    ATTRS{idVendor}=="0403"
    ATTRS{speed}=="12"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bMaxPacketSize0}=="8"
    ATTRS{busnum}=="3"
    ATTRS{devnum}=="18"
    ATTRS{configuration}==""
    ATTRS{bMaxPower}=="90mA"
    ATTRS{authorized}=="1"
    ATTRS{bmAttributes}=="a0"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{maxchild}=="0"
    ATTRS{bcdDevice}=="0600"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{serial}=="AL01QGTY"  ===> This attribute is unique to each device
    ATTRS{version}==" 2.00"
    ATTRS{urbnum}=="15"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="FTDI"
    ATTRS{removable}=="unknown"
    ATTRS{idProduct}=="6001"
    ATTRS{bDeviceClass}=="00"
    ATTRS{product}=="FT232R USB UART"

  ...

  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""

The ATTRS{serial} attribute is unique for each device. However this is available under parent device only. I wrote the rules in a file called usb_d.rules located at user->/etc/udev/rules.d. The rule looks like below :

#matching parent device to access serial number
SUBSYSTEM=="usb", KERNEL=="3-1.1", DRIVERS=="usb", ATTRS{serial}=="AL01QGTY", SYMLINK+=”device_AL01QGTY”

This should create a symlink in my /dev directory with name device_AL01QGTY but no such symlink was created. I am not sure where I went wrong.

P.S : Attaching output of udevadm test :

user->/etc/udev/rules.d:udevadm test $(udevadm info -q path -n /dev/ttyUSB1)
calling: test
version 204

=== trie on-disk ===
tool version:          204
file size:         5774636 bytes
header size             80 bytes
strings            1271756 bytes
nodes              4502800 bytes
load module index
read rules file: /lib/udev/rules.d/40-crda.rules
read rules file: /lib/udev/rules.d/40-gnupg.rules
read rules file: /lib/udev/rules.d/40-hyperv-hotadd.rules
read rules file: /lib/udev/rules.d/40-inputattach.rules
read rules file: /lib/udev/rules.d/40-joystick.rules
read rules file: /lib/udev/rules.d/40-libgphoto2-6.rules
GOTO 'libgphoto2_usb_end' has no matching label in: '/lib/udev/rules.d/40-libgphoto2-6.rules'
read rules file: /lib/udev/rules.d/40-libopenni-sensor-pointclouds0.rules
read rules file: /lib/udev/rules.d/40-libopenni2-0.rules
read rules file: /lib/udev/rules.d/40-libsane.rules
read rules file: /lib/udev/rules.d/40-usb-media-players.rules
read rules file: /lib/udev/rules.d/40-usb_modeswitch.rules
read rules file: /lib/udev/rules.d/40-xdiagnose.rules
read rules file: /lib/udev/rules.d/42-usb-hid-pm.rules
read rules file: /lib/udev/rules.d/50-firmware.rules
read rules file: /lib/udev/rules.d/50-udev-default.rules
read rules file: /lib/udev/rules.d/55-dm.rules
read rules file: /lib/udev/rules.d/56-hpmud.rules
read rules file: /lib/udev/rules.d/60-cdrom_id.rules
read rules file: /lib/udev/rules.d/60-keyboard.rules
read rules file: /lib/udev/rules.d/60-pcmcia.rules
read rules file: /lib/udev/rules.d/60-persistent-alsa.rules
read rules file: /lib/udev/rules.d/60-persistent-input.rules
read rules file: /lib/udev/rules.d/60-persistent-serial.rules
read rules file: /lib/udev/rules.d/60-persistent-storage-dm.rules
read rules file: /lib/udev/rules.d/60-persistent-storage-tape.rules
read rules file: /lib/udev/rules.d/60-persistent-storage.rules
read rules file: /lib/udev/rules.d/60-persistent-v4l.rules
read rules file: /lib/udev/rules.d/61-accelerometer.rules
read rules file: /lib/udev/rules.d/61-gnome-bluetooth-rfkill.rules
read rules file: /lib/udev/rules.d/62-google-cloudimg.rules
read rules file: /lib/udev/rules.d/64-btrfs.rules
read rules file: /lib/udev/rules.d/64-xorg-xkb.rules
read rules file: /lib/udev/rules.d/66-xorg-synaptics-quirks.rules
read rules file: /lib/udev/rules.d/69-cd-sensors.rules
IMPORT found builtin 'usb_id --export %p', replacing /lib/udev/rules.d/69-cd-sensors.rules:89
read rules file: /lib/udev/rules.d/69-libmtp.rules
read rules file: /lib/udev/rules.d/69-wacom.rules
read rules file: /lib/udev/rules.d/69-xorg-vmmouse.rules
read rules file: /etc/udev/rules.d/70-persistent-net.rules
read rules file: /lib/udev/rules.d/70-power-switch.rules
read rules file: /lib/udev/rules.d/70-printers.rules
read rules file: /lib/udev/rules.d/70-resolvconf-initramfs-copy.rules
read rules file: /lib/udev/rules.d/70-uaccess.rules
read rules file: /lib/udev/rules.d/71-nvidia.rules
read rules file: /lib/udev/rules.d/71-seat.rules
read rules file: /lib/udev/rules.d/71-u-d-c-gpu-detection.rules
read rules file: /lib/udev/rules.d/73-idrac.rules
read rules file: /lib/udev/rules.d/73-seat-late.rules
read rules file: /lib/udev/rules.d/75-net-description.rules
read rules file: /lib/udev/rules.d/75-persistent-net-generator.rules
read rules file: /lib/udev/rules.d/75-probe_mtd.rules
read rules file: /lib/udev/rules.d/75-tty-description.rules
read rules file: /lib/udev/rules.d/77-mm-ericsson-mbm.rules
read rules file: /lib/udev/rules.d/77-mm-huawei-net-port-types.rules
read rules file: /lib/udev/rules.d/77-mm-longcheer-port-types.rules
read rules file: /lib/udev/rules.d/77-mm-nokia-port-types.rules
read rules file: /lib/udev/rules.d/77-mm-pcmcia-device-blacklist.rules
read rules file: /lib/udev/rules.d/77-mm-platform-serial-whitelist.rules
read rules file: /lib/udev/rules.d/77-mm-qdl-device-blacklist.rules
read rules file: /lib/udev/rules.d/77-mm-simtech-port-types.rules
read rules file: /lib/udev/rules.d/77-mm-usb-device-blacklist.rules
read rules file: /lib/udev/rules.d/77-mm-usb-serial-adapters-greylist.rules
read rules file: /lib/udev/rules.d/77-mm-x22x-port-types.rules
read rules file: /lib/udev/rules.d/77-mm-zte-port-types.rules
read rules file: /lib/udev/rules.d/77-nm-olpc-mesh.rules
read rules file: /lib/udev/rules.d/78-graphics-card.rules
read rules file: /lib/udev/rules.d/78-sound-card.rules
read rules file: /lib/udev/rules.d/80-drivers.rules
read rules file: /lib/udev/rules.d/80-mm-candidate.rules
read rules file: /lib/udev/rules.d/80-udisks2.rules
read rules file: /lib/udev/rules.d/85-brltty.rules
read rules file: /lib/udev/rules.d/85-hdparm.rules
read rules file: /lib/udev/rules.d/85-hplj10xx.rules
read rules file: /lib/udev/rules.d/85-keyboard-configuration.rules
read rules file: /lib/udev/rules.d/85-regulatory.rules
read rules file: /lib/udev/rules.d/85-usbmuxd.rules
read rules file: /lib/udev/rules.d/90-alsa-restore.rules
read rules file: /lib/udev/rules.d/90-alsa-ucm.rules
read rules file: /lib/udev/rules.d/90-libgpod.rules
read rules file: /lib/udev/rules.d/90-pulseaudio.rules
read rules file: /lib/udev/rules.d/95-cd-devices.rules
read rules file: /lib/udev/rules.d/95-udev-late.rules
read rules file: /lib/udev/rules.d/95-upower-battery-recall-dell.rules
read rules file: /lib/udev/rules.d/95-upower-battery-recall-fujitsu.rules
read rules file: /lib/udev/rules.d/95-upower-battery-recall-gateway.rules
read rules file: /lib/udev/rules.d/95-upower-battery-recall-ibm.rules
read rules file: /lib/udev/rules.d/95-upower-battery-recall-lenovo.rules
read rules file: /lib/udev/rules.d/95-upower-battery-recall-toshiba.rules
read rules file: /lib/udev/rules.d/95-upower-csr.rules
read rules file: /lib/udev/rules.d/95-upower-hid.rules
read rules file: /lib/udev/rules.d/95-upower-wup.rules
read rules file: /lib/udev/rules.d/97-bluetooth-hid2hci.rules
read rules file: /etc/udev/rules.d/usb_dxl.rules
rules contain 393216 bytes tokens (32768 * 12 bytes), 35051 bytes strings
21673 strings (185736 bytes), 18321 de-duplicated (154038 bytes), 3353 trie nodes used
IMPORT builtin 'usb_id' /lib/udev/rules.d/40-libgphoto2-6.rules:3
/sys/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.2/3-1.2:1.0: if_class 255 protocol 0
PROGRAM 'usb_modeswitch --symlink-name /devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.2/3-1.2:1.0/ttyUSB1/tty/ttyUSB1 0403 6001 ' /lib/udev/rules.d/40-usb_modeswitch.rules:9
starting 'usb_modeswitch --symlink-name /devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.2/3-1.2:1.0/ttyUSB1/tty/ttyUSB1 0403 6001 '
'usb_modeswitch --symlink-name /devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.2/3-1.2:1.0/ttyUSB1/tty/ttyUSB1 0403 6001 ' [4549] exit with return code 0
GROUP 20 /lib/udev/rules.d/50-udev-default.rules:19
IMPORT builtin 'path_id' /lib/udev/rules.d/60-persistent-serial.rules:9
LINK 'serial/by-path/pci-0000:00:14.0-usb-0:1.2:1.0-port0' /lib/udev/rules.d/60-persistent-serial.rules:11
IMPORT builtin skip 'usb_id' /lib/udev/rules.d/60-persistent-serial.rules:13
LINK 'serial/by-id/usb-FTDI_FT232R_USB_UART_AL01QGTY-if00-port0' /lib/udev/rules.d/60-persistent-serial.rules:18
IMPORT builtin skip 'usb_id' /lib/udev/rules.d/75-tty-description.rules:6
IMPORT builtin 'hwdb' /lib/udev/rules.d/75-tty-description.rules:6
handling device node '/dev/ttyUSB1', devnum=c188:1, mode=0660, uid=0, gid=20
preserve permissions /dev/ttyUSB1, 020660, uid=0, gid=20
preserve already existing symlink '/dev/char/188:1' to '../ttyUSB1'
found 'c188:1' claiming '/run/udev/links/\x2fserial\x2fby-id\x2fusb-FTDI_FT232R_USB_UART_AL01QGTY-if00-port0'
creating link '/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AL01QGTY-if00-port0' to '/dev/ttyUSB1'
preserve already existing symlink '/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AL01QGTY-if00-port0' to '../../ttyUSB1'
found 'c188:1' claiming '/run/udev/links/\x2fserial\x2fby-path\x2fpci-0000:00:14.0-usb-0:1.2:1.0-port0'
creating link '/dev/serial/by-path/pci-0000:00:14.0-usb-0:1.2:1.0-port0' to '/dev/ttyUSB1'
preserve already existing symlink '/dev/serial/by-path/pci-0000:00:14.0-usb-0:1.2:1.0-port0' to '../../ttyUSB1'
unable to create temporary db file '/run/udev/data/c188:1.tmp': Permission denied
.ID_PORT=0
ACTION=add
DEVLINKS=/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AL01QGTY-if00-port0 /dev/serial/by-path/pci-0000:00:14.0-usb-0:1.2:1.0-port0
DEVNAME=/dev/ttyUSB1
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.2/3-1.2:1.0/ttyUSB1/tty/ttyUSB1
ID_BUS=usb
ID_MM_CANDIDATE=1
ID_MODEL=FT232R_USB_UART
ID_MODEL_ENC=FT232R\x20USB\x20UART
ID_MODEL_FROM_DATABASE=FT232 USB-Serial (UART) IC
ID_MODEL_ID=6001
ID_PATH=pci-0000:00:14.0-usb-0:1.2:1.0
ID_PATH_TAG=pci-0000_00_14_0-usb-0_1_2_1_0
ID_REVISION=0600
ID_SERIAL=FTDI_FT232R_USB_UART_AL01QGTY
ID_SERIAL_SHORT=AL01QGTY
ID_TYPE=generic
ID_USB_DRIVER=ftdi_sio
ID_USB_INTERFACES=:ffffff:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=FTDI
ID_VENDOR_ENC=FTDI
ID_VENDOR_FROM_DATABASE=Future Technology Devices International, Ltd
ID_VENDOR_ID=0403
MAJOR=188
MINOR=1
SUBSYSTEM=tty
USEC_INITIALIZED=53659802
unload module index

The original rule:

SUBSYSTEM=="usb", KERNEL=="3-1.1", DRIVERS=="usb", ATTRS{serial}=="AL01QGTY", SYMLINK+=”device_AL01QGTY”

  • SUBSYSTEM=="usb" is in parent node, so use SUBSYSTEMS=="usb"
  • KERNEL=="3-1.1" should be removed, you don't want a rule for specific USB port. Notice your udevadm info output 3-1.2!

    By the way, if it was really needed, then it's KERNELS not KERNEL. Because it is a match from a parent node.

  • SYMLINK+=”device_AL01QGTY” copy-n-paste issue. It should be "" not ””
  • The NAME, SYMLINK, PROGRAM, OWNER, GROUP, MODE, and RUN fields support simple string substitutions.

    Reference: man udev

Solution:

SUBSYSTEM=="tty",SUBSYSTEMS=="usb",DRIVERS=="usb",SYMLINK+="device_%s{serial}"