I have USB cellular modem attached to an ALIX 3d2 board running voyage linux (which is based on Debian Squeeze). The modem registers itself as a TTY device, and so by default, udev will create TTY devices named "ttyUSB0" through "ttyUSB3" in /dev. However, there may be other USB-to-Serial devices attached and I'd like to have a known reference to the modem. So, I wrote a simple udev rule to make a link from the modem to /dev/ttyModem{0-3} however, the only way I could find to automatically handle the numbering was through the %n variable in udev, which has the problem of creating /dev/ttyModem{4-7} if a four port USB-to-Serial adapter is enumerated before the modem. I found some references to a %e variable in old udev documentation that would do just what I need, but it appears to have been removed some time ago.

Luckily, there is a port number that can be referenced from the device for each tty device, so I should be able to handle the numbering manually. I can create a link based on the port number, but whenever I attempt to use both the port number and the USB vendorID+productID, the rule is no longer applied. I suspect that I might be violating the "one single parent device" rule somewhere, as these attributes are recognized in different devices according to udevadm info, but as far as I can tell, all attributes should be coming from one device and its parent.

Here are the rules I've applied:

This rule works, and is what I started with, but the number it generates may not start at 0.

SUBSYSTEMS=="usb", KERNEL=="ttyUSB*", ATTRS{idVendor}=="1199", ATTRS{idProduct}=="0028", SYMLINK+="ttyUSBID%n"

So I attempted to specify the port number using four rules like this one, however, this fails, I think because it violates the "one single parent device" rule.

SUBSYSTEMS=="usb", KERNEL=="ttyUSB*", ATTRS{port_number}=="0", ATTRS{idVendor}=="1199", ATTRS{idProduct}=="0028", SYMLINK+="ttyFailingPort0"

Every condition on this rule should come from the same node, so this rule (which works as you'd expect) should be able to reference a parent node.

SUBSYSTEMS=="usb-serial", KERNELS=="ttyUSB*", ATTRS{port_number}=="0", SYMLINK+="ttyPortNumberChild0"

However, this rule fails, and I have no idea why.

SUBSYSTEMS=="usb-serial", KERNELS=="ttyUSB*", ATTRS{idVendor}=="1199" ATTRS{port_number}=="0", SYMLINK+="ttyFailingPortNumber0

And here is the output of udevadm info --attribute-walk for port0, port1, port2, port3. The second device from the top contains the port number, and the fourth device contains the identifying USB information.

I realize this is a bit of an XY problem, so if you know of a better way to give the modem a constant name, feel free to post that as your answer.

  • Using PROGRAM and RESULT can give a viable solution to making sure the numbering starts at 0 for your symlinks.
    – CivFan
    Sep 30, 2020 at 1:41

4 Answers 4


The modem rules should match ACTION=="add", SUBSYSTEM=="tty" combined with idVendor, idProduct and port_number attributes:

ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="1199", ATTRS{idProduct}=="0028", ATTRS{port_number}=="0", SYMLINK+="ttyPort0"
ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="1199", ATTRS{idProduct}=="0028", ATTRS{port_number}=="1", SYMLINK+="ttyPort1"
ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="1199", ATTRS{idProduct}=="0028", ATTRS{port_number}=="2", SYMLINK+="ttyPort2"
ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="1199", ATTRS{idProduct}=="0028", ATTRS{port_number}=="3", SYMLINK+="ttyPort3"

Also check if any of the existing symlinks in /dev/serial/by-id (helps if your modem has a unique serial number) or /dev/serial/by-path (works if you always plug in your modem in to the same USB port) would work for your purpose.

  • Unfortunately, that didn't work. I also tried the simplest form of that method I could think of ENV{ID_VENDOR_ID}=="1199" SYMLINK+="ttyPortNumber0", but even that didn't get triggered. I confirmed with udevadem info --query=all that the environment variable should be added, but I'm at a loss as to why it doesn't seem to recognize it in the rule. As for the other symlinks, This rule needs to work for any modem of the same model, and when it's plugged in to any USB port, so the only thing I would do with those is copy them and rename them, which is the whole point of using udev.
    – isidor3
    Jun 12, 2013 at 16:10
  • could you try just ACTION=="add", SUBSYSTEM=="tty", ATTRS{port_number}=="0", SYMLINK+="ttyPort0"?
    – Alex P.
    Jun 12, 2013 at 17:40
  • That rule works as you'd expect, it doesn't solve my problem, but it correctly recognized the modem's port0 device.
    – isidor3
    Jun 12, 2013 at 18:04

I ended up working around the "only one parent" limitation by splitting up the configuration between multiple rules. For those interested, here is the code I ended up with:

ACTION!="add", GOTO="modem_rules_end"
SUBSYSTEM!="tty" GOTO="modem_rules_end"

ATTRS{idVendor}=="1199", ATTRS{idProduct}=="0028", GOTO="type1_rules_begin"

ATTRS{port_number}=="0", SYMLINK:="ttyType1_0"
ATTRS{port_number}=="1", SYMLINK:="ttyType1_1"
ATTRS{port_number}=="2", SYMLINK:="ttyType1_2"
ATTRS{port_number}=="3", SYMLINK:="ttyType1_3"


I had a similar problem bringing a USB cellular modem online with consistent numbering in a system along with other USB tty devices vying for /dev/ttyUSB* numbers. In my case it was a EuroTech ReliaCELL 10-20-32 with the Telit chipset. I solved the problem using some ideas from here, ending up with the following excerpt in my .rules:

SUBSYSTEMS=="usb", DRIVERS=="option", ATTRS{bInterfaceNumber}=="00", SYMLINK+="ttyUSB_modem_port_0"
SUBSYSTEMS=="usb", DRIVERS=="option", ATTRS{bInterfaceNumber}=="01", SYMLINK+="ttyUSB_modem_port_1"
SUBSYSTEMS=="usb", DRIVERS=="option", ATTRS{bInterfaceNumber}=="02", SYMLINK+="ttyUSB_modem_port_2"
SUBSYSTEMS=="usb", DRIVERS=="option", ATTRS{bInterfaceNumber}=="03", SYMLINK+="ttyUSB_modem_port_3"

I made a setup with multiple identical usb serial adapters for accessing my unix machines.

I'm guessing the KERNELS attribute in the last line results from my "Prolific Technology Inc." hub existing of two hubs where one is attached to the other.

KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.2.5:1.0", SYMLINK+="ttyUSB_Sol1"
KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.2.6:1.0", SYMLINK+="ttyUSB_Sol2"
KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.2.7:1.0", SYMLINK+="ttyUSB_Sol3"
KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.2.4:1.0", SYMLINK+="ttyUSB_Sol4"
KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.2.3:1.0", SYMLINK+="ttyUSB_HPUX1"
KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.2.2:1.0", SYMLINK+="ttyUSB_HPUX2"
KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-", SYMLINK+="ttyUSB_HPUX3"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .