You are not logged in.
I have one USB device with two serial port endpoints (a Pololu AVR programmer.)
These both show up as ttyACM# (typically ttyACM0 and 1)
I also have an Arduino board plugged in, which typically shows up as ttyACM2.
Sometimes, I get the reverse order -- Arduino is ttyACM0, and programmer is ttyACM1/2.
I want the first of these two Pololu endpoints to be linked to /dev/_avrisp2.
Unfortunately, no matter what I try, udev will pick up both the endpoints in order, and symlink the second endpoint to that name.
Here are the rules I've created:
1) /etc/udev/rules.d/10-programmer-port2.rules
# exclude the second port on the Pololu programmer
SUBSYSTEM=="tty", DRIVERS=="cdc_acm", ATTRS{bInterfaceNumber}=="02", OPTIONS+="ignore_device"
2) /etc/udev/rules.d/11-programmer.rules
# The hardware bus IDs move around :-(
ATTRS{product}=="Pololu USB AVR Programmer", ATTRS{manufacturer}=="Pololu Corporation", SYMLINK+="_avrisp2"
It seems that udev applies the SYMLINK to the ttyACM1 device, even though it should match the rule above saying ignore_device.
How can I make it not apply the SYMLINK rule to endpoint 02? Note that I can't just look for bInterfaceNumber==00 where assigning the symlink, because I also need to select on the product/manufacturer, and I can only select properties from the base device (which are very scarce) and one parent record.
Here is the output of "udevadm test /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/tty/ttyACM1":
calling: test
version 185
load module index
read rules file: /usr/lib/udev/rules.d/10-dm.rules
read rules file: /etc/udev/rules.d/10-programmer-port2.rules
read rules file: /usr/lib/udev/rules.d/11-dm-lvm.rules
read rules file: /etc/udev/rules.d/11-gps.rules
read rules file: /etc/udev/rules.d/11-programmer.rules
read rules file: /etc/udev/rules.d/11-usbboard.rules
read rules file: /etc/udev/rules.d/11-webcams.rules
read rules file: /usr/lib/udev/rules.d/13-dm-disk.rules
read rules file: /usr/lib/udev/rules.d/40-gphoto.rules
read rules file: /usr/lib/udev/rules.d/42-usb-hid-pm.rules
read rules file: /usr/lib/udev/rules.d/50-udev-default.rules
read rules file: /usr/lib/udev/rules.d/53-sane.rules
read rules file: /usr/lib/udev/rules.d/60-cdrom_id.rules
read rules file: /usr/lib/udev/rules.d/60-pcmcia.rules
read rules file: /usr/lib/udev/rules.d/60-persistent-alsa.rules
read rules file: /usr/lib/udev/rules.d/60-persistent-input.rules
read rules file: /usr/lib/udev/rules.d/60-persistent-serial.rules
read rules file: /usr/lib/udev/rules.d/60-persistent-storage-tape.rules
read rules file: /usr/lib/udev/rules.d/60-persistent-storage.rules
read rules file: /usr/lib/udev/rules.d/60-persistent-v4l.rules
read rules file: /usr/lib/udev/rules.d/61-accelerometer.rules
read rules file: /usr/lib/udev/rules.d/64-md-raid.rules
read rules file: /usr/lib/udev/rules.d/69-cd-sensors.rules
IMPORT found builtin 'usb_id --export %p', replacing /usr/lib/udev/rules.d/69-cd-sensors.rules:78
IMPORT found builtin 'usb-db %p', replacing /usr/lib/udev/rules.d/69-cd-sensors.rules:79
read rules file: /usr/lib/udev/rules.d/70-infrared.rules
read rules file: /usr/lib/udev/rules.d/70-power-switch.rules
read rules file: /usr/lib/udev/rules.d/70-uaccess.rules
read rules file: /usr/lib/udev/rules.d/70-udev-acl.rules
read rules file: /usr/lib/udev/rules.d/71-seat.rules
read rules file: /usr/lib/udev/rules.d/73-seat-late.rules
read rules file: /usr/lib/udev/rules.d/75-net-description.rules
read rules file: /usr/lib/udev/rules.d/75-probe_mtd.rules
read rules file: /usr/lib/udev/rules.d/75-tty-description.rules
read rules file: /usr/lib/udev/rules.d/78-sound-card.rules
read rules file: /usr/lib/udev/rules.d/80-drivers.rules
read rules file: /usr/lib/udev/rules.d/80-udisks.rules
IMPORT found builtin 'pci-db %p', replacing /usr/lib/udev/rules.d/80-udisks.rules:6
read rules file: /usr/lib/udev/rules.d/80-udisks2.rules
read rules file: /usr/lib/udev/rules.d/85-usbmuxd.rules
specified user 'usbmux' unknown
read rules file: /usr/lib/udev/rules.d/90-alsa-restore.rules
read rules file: /usr/lib/udev/rules.d/95-cd-devices.rules
read rules file: /usr/lib/udev/rules.d/95-dm-notify.rules
read rules file: /usr/lib/udev/rules.d/95-keyboard-force-release.rules
read rules file: /usr/lib/udev/rules.d/95-keymap.rules
read rules file: /usr/lib/udev/rules.d/95-udev-late.rules
read rules file: /usr/lib/udev/rules.d/95-upower-battery-recall-dell.rules
read rules file: /usr/lib/udev/rules.d/95-upower-battery-recall-fujitsu.rules
read rules file: /usr/lib/udev/rules.d/95-upower-battery-recall-gateway.rules
read rules file: /usr/lib/udev/rules.d/95-upower-battery-recall-ibm.rules
read rules file: /usr/lib/udev/rules.d/95-upower-battery-recall-lenovo.rules
read rules file: /usr/lib/udev/rules.d/95-upower-battery-recall-toshiba.rules
read rules file: /usr/lib/udev/rules.d/95-upower-csr.rules
read rules file: /usr/lib/udev/rules.d/95-upower-hid.rules
read rules file: /usr/lib/udev/rules.d/95-upower-wup.rules
read rules file: /usr/lib/udev/rules.d/97-bluetooth-hid2hci.rules
read rules file: /etc/udev/rules.d/99-SaleaeLogic.rules
read rules file: /usr/lib/udev/rules.d/99-gpsd-usb.rules
read rules file: /usr/lib/udev/rules.d/99-systemd.rules
rules use 174516 bytes tokens (14543 * 12 bytes), 29944 bytes buffer
temporary index used 54700 bytes (2735 * 20 bytes)
LINK '_avrisp2' /etc/udev/rules.d/11-programmer.rules:2
GROUP 14 /usr/lib/udev/rules.d/50-udev-default.rules:9
IMPORT builtin 'path_id' /usr/lib/udev/rules.d/60-persistent-serial.rules:9
ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.2
ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_2
LINK 'serial/by-path/pci-0000:00:1a.0-usb-0:1.1:1.2' /usr/lib/udev/rules.d/60-persistent-serial.rules:10
IMPORT builtin 'usb_id' /usr/lib/udev/rules.d/60-persistent-serial.rules:13
/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2: if_class 2 protocol 0
ID_VENDOR=Pololu_Corporation
ID_VENDOR_ENC=Pololu\x20Corporation
ID_VENDOR_ID=1ffb
ID_MODEL=Pololu_USB_AVR_Programmer
ID_MODEL_ENC=Pololu\x20USB\x20AVR\x20Programmer
ID_MODEL_ID=0081
ID_REVISION=0107
ID_SERIAL=Pololu_Corporation_Pololu_USB_AVR_Programmer_00033960
ID_SERIAL_SHORT=00033960
ID_TYPE=generic
ID_BUS=usb
ID_USB_INTERFACES=:020201:0a0000:ff0101:
ID_USB_INTERFACE_NUM=02
ID_USB_DRIVER=cdc_acm
LINK 'serial/by-id/usb-Pololu_Corporation_Pololu_USB_AVR_Programmer_00033960-if02' /usr/lib/udev/rules.d/60-persistent-serial.rules:17
IMPORT builtin 'usb-db' /usr/lib/udev/rules.d/75-tty-description.rules:7
handling device node '/dev/ttyACM1', devnum=c166:1, mode=0660, uid=0, gid=14
preserve permissions /dev/ttyACM1, 020660, uid=0, gid=14
preserve already existing symlink '/dev/char/166:1' to '../ttyACM1'
found 'c166:1' claiming '/run/udev/links/\x2f_avrisp2'
found 'c166:0' claiming '/run/udev/links/\x2f_avrisp2'
found 'c189:2' claiming '/run/udev/links/\x2f_avrisp2'
creating link '/dev/_avrisp2' to '/dev/ttyACM1'
preserve already existing symlink '/dev/_avrisp2' to 'ttyACM1'
found 'c166:1' claiming '/run/udev/links/\x2fserial\x2fby-id\x2fusb-Pololu_Corporation_Pololu_USB_AVR_Programmer_00033960-if02'
creating link '/dev/serial/by-id/usb-Pololu_Corporation_Pololu_USB_AVR_Programmer_00033960-if02' to '/dev/ttyACM1'
preserve already existing symlink '/dev/serial/by-id/usb-Pololu_Corporation_Pololu_USB_AVR_Programmer_00033960-if02' to '../../ttyACM1'
found 'c166:1' claiming '/run/udev/links/\x2fserial\x2fby-path\x2fpci-0000:00:1a.0-usb-0:1.1:1.2'
creating link '/dev/serial/by-path/pci-0000:00:1a.0-usb-0:1.1:1.2' to '/dev/ttyACM1'
preserve already existing symlink '/dev/serial/by-path/pci-0000:00:1a.0-usb-0:1.1:1.2' to '../../ttyACM1'
unload module index
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.
ACTION=add
DEVLINKS=/dev/_avrisp2 /dev/serial/by-id/usb-Pololu_Corporation_Pololu_USB_AVR_Programmer_00033960-if02 /dev/serial/by-path/pci-0000:00:1a.0-usb-0:1.1:1.2
DEVNAME=/dev/ttyACM1
DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/tty/ttyACM1
ID_BUS=usb
ID_MODEL=Pololu_USB_AVR_Programmer
ID_MODEL_ENC=Pololu\x20USB\x20AVR\x20Programmer
ID_MODEL_ID=0081
ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.2
ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_2
ID_REVISION=0107
ID_SERIAL=Pololu_Corporation_Pololu_USB_AVR_Programmer_00033960
ID_SERIAL_SHORT=00033960
ID_TYPE=generic
ID_USB_DRIVER=cdc_acm
ID_USB_INTERFACES=:020201:0a0000:ff0101:
ID_USB_INTERFACE_NUM=02
ID_VENDOR=Pololu_Corporation
ID_VENDOR_ENC=Pololu\x20Corporation
ID_VENDOR_ID=1ffb
MAJOR=166
MINOR=1
SUBSYSTEM=tty
TAGS=:systemd:
UDEV_LOG=6
USEC_INITIALIZED=26154
Here is the output of "udevadm info --export-db" when looking for the ttyACM1 node:
P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/tty/ttyACM1
N: ttyACM1
S: _avrisp2
S: serial/by-id/usb-Pololu_Corporation_Pololu_USB_AVR_Programmer_00033960-if02
S: serial/by-path/pci-0000:00:1a.0-usb-0:1.1:1.2
E: DEVLINKS=/dev/_avrisp2 /dev/serial/by-id/usb-Pololu_Corporation_Pololu_USB_AVR_Programmer_00033960-if02 /dev/serial/by-path/pci-0000:00:1a.0-usb-0:1.1:1.2
E: DEVNAME=/dev/ttyACM1
E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/tty/ttyACM1
E: ID_BUS=usb
E: ID_MODEL=Pololu_USB_AVR_Programmer
E: ID_MODEL_ENC=Pololu\x20USB\x20AVR\x20Programmer
E: ID_MODEL_ID=0081
E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.2
E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_2
E: ID_REVISION=0107
E: ID_SERIAL=Pololu_Corporation_Pololu_USB_AVR_Programmer_00033960
E: ID_SERIAL_SHORT=00033960
E: ID_TYPE=generic
E: ID_USB_DRIVER=cdc_acm
E: ID_USB_INTERFACES=:020201:0a0000:ff0101:
E: ID_USB_INTERFACE_NUM=02
E: ID_VENDOR=Pololu_Corporation
E: ID_VENDOR_ENC=Pololu\x20Corporation
E: ID_VENDOR_ID=1ffb
E: MAJOR=166
E: MINOR=1
E: SUBSYSTEM=tty
E: TAGS=:systemd:
E: UDEV_LOG=6
E: USEC_INITIALIZED=26154
And, finally, here's the output of udevadm info -a -n /dev/ttyACM1:
looking at device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/tty/ttyACM1':
KERNEL=="ttyACM1"
SUBSYSTEM=="tty"
DRIVER==""
looking at parent device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2':
KERNELS=="1-1.1:1.2"
SUBSYSTEMS=="usb"
DRIVERS=="cdc_acm"
ATTRS{bInterfaceClass}=="02"
ATTRS{iad_bFunctionClass}=="02"
ATTRS{bmCapabilities}=="2"
ATTRS{iad_bFirstInterface}=="02"
ATTRS{bInterfaceSubClass}=="02"
ATTRS{bInterfaceProtocol}=="01"
ATTRS{bNumEndpoints}=="01"
ATTRS{iad_bFunctionSubClass}=="02"
ATTRS{iad_bFunctionProtocol}=="01"
ATTRS{supports_autosuspend}=="1"
ATTRS{iad_bInterfaceCount}=="02"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceNumber}=="02"
looking at parent device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1':
KERNELS=="1-1.1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{bDeviceSubClass}=="02"
ATTRS{bDeviceProtocol}=="01"
ATTRS{devpath}=="1.1"
ATTRS{idVendor}=="1ffb"
ATTRS{speed}=="12"
ATTRS{bNumInterfaces}==" 5"
ATTRS{bConfigurationValue}=="1"
ATTRS{bMaxPacketSize0}=="8"
ATTRS{busnum}=="1"
ATTRS{devnum}=="3"
ATTRS{configuration}==""
ATTRS{bMaxPower}=="100mA"
ATTRS{authorized}=="1"
ATTRS{bmAttributes}=="80"
ATTRS{bNumConfigurations}=="1"
ATTRS{maxchild}=="0"
ATTRS{bcdDevice}=="0107"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{quirks}=="0x0"
ATTRS{serial}=="00033960"
ATTRS{version}==" 2.00"
ATTRS{urbnum}=="18"
ATTRS{manufacturer}=="Pololu Corporation"
ATTRS{removable}=="unknown"
ATTRS{idProduct}=="0081"
ATTRS{bDeviceClass}=="ef"
ATTRS{product}=="Pololu USB AVR Programmer"
looking at parent device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1':
KERNELS=="1-1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="01"
ATTRS{devpath}=="1"
ATTRS{idVendor}=="8087"
ATTRS{speed}=="480"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{busnum}=="1"
ATTRS{devnum}=="2"
ATTRS{configuration}==""
ATTRS{bMaxPower}==" 0mA"
ATTRS{authorized}=="1"
ATTRS{bmAttributes}=="e0"
ATTRS{bNumConfigurations}=="1"
ATTRS{maxchild}=="4"
ATTRS{bcdDevice}=="0000"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{quirks}=="0x0"
ATTRS{version}==" 2.00"
ATTRS{urbnum}=="52"
ATTRS{removable}=="unknown"
ATTRS{idProduct}=="0024"
ATTRS{bDeviceClass}=="09"
*shortened*
compared to the device I do want the symlink for, /dev/ttyACM0:
looking at device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/tty/ttyACM0':
KERNEL=="ttyACM0"
SUBSYSTEM=="tty"
DRIVER==""
looking at parent device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0':
KERNELS=="1-1.1:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="cdc_acm"
ATTRS{bInterfaceClass}=="02"
ATTRS{iad_bFunctionClass}=="02"
ATTRS{bmCapabilities}=="2"
ATTRS{iad_bFirstInterface}=="00"
ATTRS{bInterfaceSubClass}=="02"
ATTRS{bInterfaceProtocol}=="01"
ATTRS{bNumEndpoints}=="01"
ATTRS{iad_bFunctionSubClass}=="02"
ATTRS{iad_bFunctionProtocol}=="01"
ATTRS{supports_autosuspend}=="1"
ATTRS{iad_bInterfaceCount}=="02"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceNumber}=="00"
looking at parent device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1':
KERNELS=="1-1.1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{bDeviceSubClass}=="02"
ATTRS{bDeviceProtocol}=="01"
ATTRS{devpath}=="1.1"
ATTRS{idVendor}=="1ffb"
ATTRS{speed}=="12"
ATTRS{bNumInterfaces}==" 5"
ATTRS{bConfigurationValue}=="1"
ATTRS{bMaxPacketSize0}=="8"
ATTRS{busnum}=="1"
ATTRS{devnum}=="3"
ATTRS{configuration}==""
ATTRS{bMaxPower}=="100mA"
ATTRS{authorized}=="1"
ATTRS{bmAttributes}=="80"
ATTRS{bNumConfigurations}=="1"
ATTRS{maxchild}=="0"
ATTRS{bcdDevice}=="0107"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{quirks}=="0x0"
ATTRS{serial}=="00033960"
ATTRS{version}==" 2.00"
ATTRS{urbnum}=="18"
ATTRS{manufacturer}=="Pololu Corporation"
ATTRS{removable}=="unknown"
ATTRS{idProduct}=="0081"
ATTRS{bDeviceClass}=="ef"
ATTRS{product}=="Pololu USB AVR Programmer"
looking at parent device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1':
KERNELS=="1-1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="01"
ATTRS{devpath}=="1"
ATTRS{idVendor}=="8087"
ATTRS{speed}=="480"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{busnum}=="1"
ATTRS{devnum}=="2"
ATTRS{configuration}==""
ATTRS{bMaxPower}==" 0mA"
ATTRS{authorized}=="1"
ATTRS{bmAttributes}=="e0"
ATTRS{bNumConfigurations}=="1"
ATTRS{maxchild}=="4"
ATTRS{bcdDevice}=="0000"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{quirks}=="0x0"
ATTRS{version}==" 2.00"
ATTRS{urbnum}=="52"
ATTRS{removable}=="unknown"
ATTRS{idProduct}=="0024"
ATTRS{bDeviceClass}=="09"
*shortened*
Last edited by jwatte (2012-06-23 16:52:49)
Offline
Offline
This makes no sense to me. The only attributes for the device itself are:
KERNEL=="ttyACM1"
SUBSYSTEM=="tty"
DRIVER==""
What "ATTR" or "DRIVER" is there to match against here?
Offline
I have a similar problem, with two serial endpoints. I came up with a workaround to assign individual names to both endpoints with a modulo operator, but this breaks with a mix of single/double endpoint devices:
KERNEL=="ttyACM*", SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="1ffb", ATTRS{idProduct}=="008[0-f]", MODE="666", PROGRAM="/usr/bin/python -c 'print %n % 2'", SYMLINK+="polulu_servo_$attr{serial}_%c", GROUP="dialout"
Did you ever find a more elegant solution?
Offline
Figured it out, using standard commands:
#Polulu Micro Maestro multiple-endpoint udev
KERNEL=="ttyACM*", SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="1ffb", ATTRS{idProduct}=="008[0-f]", MODE="666", PROGRAM="/bin/bash -c '/bin/echo %p | /bin/grep -c :1.0", RESULT=="1", SYMLINK+="polulu_servo_serial_$attr{serial}", GROUP="dialout"
KERNEL=="ttyACM*", SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="1ffb", ATTRS{idProduct}=="008[0-f]", MODE="666", PROGRAM="/bin/bash -c '/bin/echo %p | /bin/grep -c :1.2", RESULT=="1", SYMLINK+="polulu_servo_ttl_$attr{serial}", GROUP="dialout"
Since you can't get the endpoint number AND product/vendor id via udev (breaks single-parent rule), use grep to filter endpoint number from the devpath. Example, on this peripheral, endpoint 0 and 2 are two separate serial endpoints. Not perfect, but works for this use case.
Offline