Udev re-numbering when creating symlinks

serial portttyudev

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.

Best Answer

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.

Related Question