You are not logged in.

#1 2012-06-23 16:47:57

jwatte
Member
Registered: 2012-06-22
Posts: 58

udev ignores my rule for second endpoint! What am I getting wrong?

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

#2 2012-06-23 17:32:52

falconindy
Developer
From: New York, USA
Registered: 2009-10-22
Posts: 4,110
Website

Re: udev ignores my rule for second endpoint! What am I getting wrong?

You want ATTR, not ATTRS, and DRIVER, not DRIVERS. ATTR matches the device the rule was fired for, ATTRS matches parent devices. Similar for singular/plural of all the keywords.

Offline

#3 2012-06-24 06:34:18

jwatte
Member
Registered: 2012-06-22
Posts: 58

Re: udev ignores my rule for second endpoint! What am I getting wrong?

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

#4 2013-07-04 18:57:03

agentx3r
Member
Registered: 2013-07-04
Posts: 2

Re: udev ignores my rule for second endpoint! What am I getting wrong?

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

#5 2013-07-04 19:48:26

agentx3r
Member
Registered: 2013-07-04
Posts: 2

Re: udev ignores my rule for second endpoint! What am I getting wrong?

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

Board footer

Powered by FluxBB