I often have multiple devices of different brands, booting in various different ways, plugging and unplugging them frequently. Linux numbers those using the first available number. Plugging the devices in a specific order could still offer some predictability, but if two serial ports are plugged on a single USB hub, and the hub itself is plugged in, the ordering is impossible to predict. What if we could name an adapter based on it’s physical characteristics?

Some serial adapters have a SerialNumber field, and it is possible to use it to distinguish physically the serial adapter and give it a static name.

First, let’s have a look into dmesg output to retrieve the values:

$ sudo dmesg
[ 2876.128133] usb 1-1.4.4.1: new full-speed USB device number 11 using xhci_hcd
[ 2876.291554] usb 1-1.4.4.1: New USB device found, idVendor=0403, idProduct=6015, bcdDevice=10.00
[ 2876.291559] usb 1-1.4.4.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2876.291563] usb 1-1.4.4.1: Product: FT230X Basic UART
[ 2876.291566] usb 1-1.4.4.1: Manufacturer: FTDI
[ 2876.291568] usb 1-1.4.4.1: SerialNumber: DM003668
[ 2876.432108] usb 1-1.4.4.4: new full-speed USB device number 12 using xhci_hcd
[ 2876.587901] usb 1-1.4.4.4: New USB device found, idVendor=0403, idProduct=6015, bcdDevice=10.00
[ 2876.587907] usb 1-1.4.4.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2876.587910] usb 1-1.4.4.4: Product: FT230X Basic UART
[ 2876.587913] usb 1-1.4.4.4: Manufacturer: FTDI
[ 2876.587916] usb 1-1.4.4.4: SerialNumber: DM003HFS

Now it is possible to add some udev rules so that a specific link is attached to any set of parameters.

$ cat /etc/udev/rules.d/99-usb-serial.rules 
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", ATTRS{serial}=="DM003456", SYMLINK+="ttyUSBA"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", ATTRS{serial}=="DM003678", SYMLINK+="ttyUSBB"

Reload udev rules

$ sudo udevadm control --reload-rules
$ sudo udevadm trigger

Now unplug and replug the device, and the appropriate link should appear.

$ ls -l /dev/ttyUSB*
crw-rw---- 1 root dialout 188, 0 nov.  19 18:12 /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 1 nov.  19 18:12 /dev/ttyUSB1
lrwxrwxrwx 1 root root         7 nov.  19 18:12 /dev/ttyUSBA -> ttyUSB1
lrwxrwxrwx 1 root root         7 nov.  19 18:12 /dev/ttyUSBB -> ttyUSB0

If another device is inserted in between, the symbolic still points to the right physical adapter.

$ ls -l /dev/ttyUSB*
crw-rw---- 1 root dialout 188, 0 nov.  19 18:26 /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 1 nov.  19 18:23 /dev/ttyUSB1
crw-rw---- 1 root dialout 188, 2 nov.  19 18:26 /dev/ttyUSB2
lrwxrwxrwx 1 root root         7 nov.  19 18:26 /dev/ttyUSBA -> ttyUSB2
lrwxrwxrwx 1 root root         7 nov.  19 18:26 /dev/ttyUSBB -> ttyUSB0