udev rule with few parent device attributes
After many of unsuccessful experiences, i found the solution!
The key feature of it is setting the environment variable:
- On plugging event, we looking the
vendor:id
pair and remember it in environment variable. - On the same event, we compare the saved variable and usb-device tree nodes IDs to assign exact names of ports of certain usb-hub.
This document helped me http://www.reactivated.net/writing_udev_rules.html
KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="05e3", ATTRS{idProduct}=="0610", ENV{USB_HUB_TYPE}="05e3:0610"
KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0835", ATTRS{idProduct}=="8500", ENV{USB_HUB_TYPE}="0835:8500"
#
ENV{USB_HUB_TYPE}=="0835:8500", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].4:1.0", SYMLINK+="port1"
ENV{USB_HUB_TYPE}=="0835:8500", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].3:1.0", SYMLINK+="port2"
ENV{USB_HUB_TYPE}=="0835:8500", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].2:1.0", SYMLINK+="port3"
ENV{USB_HUB_TYPE}=="0835:8500", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].5.5:1.0", SYMLINK+="port4"
ENV{USB_HUB_TYPE}=="0835:8500", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].5.2:1.0", SYMLINK+="port5"
ENV{USB_HUB_TYPE}=="0835:8500", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].5.3:1.0", SYMLINK+="port6"
ENV{USB_HUB_TYPE}=="0835:8500", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].5.4:1.0", SYMLINK+="port7"
#
ENV{USB_HUB_TYPE}=="05e3:0610", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].1.1:1.0" SYMLINK+="port1"
ENV{USB_HUB_TYPE}=="05e3:0610", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].2:1.0", SYMLINK+="port2"
ENV{USB_HUB_TYPE}=="05e3:0610", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].1.2:1.0", SYMLINK+="port3"
ENV{USB_HUB_TYPE}=="05e3:0610", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].3:1.0", SYMLINK+="port4"
ENV{USB_HUB_TYPE}=="05e3:0610", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].1.3:1.0", SYMLINK+="port5"
ENV{USB_HUB_TYPE}=="05e3:0610", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].4:1.0", SYMLINK+="port6"
ENV{USB_HUB_TYPE}=="05e3:0610", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", KERNELS=="1-1.[2-3].1.4:1.0", SYMLINK+="port7"
Perhaps, it will be useful for someone.
UDEV-How to get value of a child device attributes
This is rule I made to create an alias for dual port FTDI chip:
# Internal serial ports
SUBSYSTEMS=="usb", ATTRS{interface}=="Dual RS232", SYMLINK+="sertest%s{bInterfaceNumber}"
According to this post the attributes must be matching on one level. That's why idVendor
and idProduct
won't work with bInterfaceNumber
. Below you can see, that interface
and bInterfaceNumber
belong to the same level:
looking at parent device '/devices/platform/omap/musb-ti81xx/musb-hdrc.1/usb1/1-1/1-1.2/1-1.2:1.0':
KERNELS=="1-1.2:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="ftdi_sio"
ATTRS{bInterfaceNumber}=="00"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bNumEndpoints}=="02"
ATTRS{bInterfaceClass}=="ff"
ATTRS{bInterfaceSubClass}=="ff"
ATTRS{bInterfaceProtocol}=="ff"
ATTRS{supports_autosuspend}=="1"
ATTRS{interface}=="Dual RS232"
Conditionless GOTO in udev rules (and Medion RC-0617)
Indeed, the second line (GOTO="end") was just ignored. It took me some time to figure that out, but the solution is actually pretty simple:
If there are no conditions to match against, udev treats the rule as "always not matching" and therefore does not execute the GOTO at all.
My working udev rules file looked like this:
# Test if the wanted dongle is a parent device
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", GOTO="match"
# If not, skip the next 3 rules. The test against SUBSYSTEM=="hidraw" is there to produce a rule match
SUBSYSTEM=="hidraw", GOTO="end"
LABEL="match"
# Those 3 rules actually assign the right symlink depending on the bInterfaceProtocol property.
# Note that ALL of those rules contain the SUBSYSTEM=="hidraw" check, because the GOTO in the second line
# does not get executed for non-hidraw devices and the rules get evaluated for any non-hidraw device.
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="01", SYMLINK="mdremote0", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="00", SYMLINK="mdremote1", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="02", SYMLINK="mdremote2", MODE="0666"
LABEL="end"
This turned out to work fine. It can still be improved by providing a better match rule for the GOTO="end" statement, but I left it that way.
udev $kernel or %k substitution not expanding correctly
The problem here is the rule match. When a single USB drive is plugged, a series of
udev
event are generated corresponding to all device nodes created (USB tree). The leaf is the partition (block device) and the top parent is a PCI bus.So rule matches two nodes which non of them was the leaf which has kernel name
sdxY
neither its direct parent node (disk)sdx
.To see the whole tree and check when your rule is triggered, run:
udevadm info --attribute-walk --name=/dev/sdb1
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/host7/target7:0:0/7:0:0:0/block/sdb/sdb1':
KERNEL=="sdb1"
SUBSYSTEM=="block"
DRIVER==""
ATTR{ro}=="0"
ATTR{size}=="7892024"
ATTR{stat}==" 174 606 1347 360 0 0 0 0 0 356 356"
ATTR{partition}=="1"
ATTR{start}=="63"
ATTR{discard_alignment}=="0"
ATTR{alignment_offset}=="0"
ATTR{inflight}==" 0 0"
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/host7/target7:0:0/7:0:0:0/block/sdb':
KERNELS=="sdb"
SUBSYSTEMS=="block"
DRIVERS==""
ATTRS{ro}=="0"
ATTRS{size}=="7892087"
ATTRS{stat}==" 189 655 1411 2208 0 0 0 0 0 600 2204"
ATTRS{range}=="16"
ATTRS{discard_alignment}=="0"
ATTRS{events}=="media_change"
ATTRS{ext_range}=="256"
ATTRS{events_poll_msecs}=="2000"
ATTRS{alignment_offset}=="0"
ATTRS{inflight}==" 0 0"
ATTRS{removable}=="1"
ATTRS{capability}=="51"
ATTRS{events_async}==""
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/host7/target7:0:0/7:0:0:0':
KERNELS=="7:0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{rev}=="0.00"
ATTRS{type}=="0"
ATTRS{scsi_level}=="3"
ATTRS{model}=="USB Flash Drive "
ATTRS{state}=="running"
ATTRS{queue_type}=="none"
ATTRS{iodone_cnt}=="0xe7"
ATTRS{iorequest_cnt}=="0xe7"
ATTRS{device_busy}=="0"
ATTRS{evt_capacity_change_reported}=="0"
ATTRS{timeout}=="30"
ATTRS{evt_media_change}=="0"
ATTRS{max_sectors}=="240"
ATTRS{ioerr_cnt}=="0x1"
ATTRS{queue_depth}=="1"
ATTRS{vendor}=="ADATA "
ATTRS{evt_soft_threshold_reached}=="0"
ATTRS{device_blocked}=="0"
ATTRS{evt_mode_parameter_change_reported}=="0"
ATTRS{evt_lun_change_reported}=="0"
ATTRS{evt_inquiry_change_reported}=="0"
ATTRS{iocounterbits}=="32"
ATTRS{eh_timeout}=="10"
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/host7/target7:0:0':
KERNELS=="target7:0:0"
SUBSYSTEMS=="scsi"
DRIVERS==""
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/host7':
KERNELS=="host7"
SUBSYSTEMS=="scsi"
DRIVERS==""
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0':
KERNELS=="2-1.2:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="usb-storage"
ATTRS{bInterfaceClass}=="08"
ATTRS{bInterfaceSubClass}=="06"
ATTRS{bInterfaceProtocol}=="50"
ATTRS{bNumEndpoints}=="02"
ATTRS{supports_autosuspend}=="1"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceNumber}=="00"
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2':
KERNELS=="2-1.2"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{devpath}=="1.2"
ATTRS{idVendor}=="125f"
ATTRS{speed}=="480"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{busnum}=="2"
ATTRS{devnum}=="13"
ATTRS{configuration}==""
ATTRS{bMaxPower}=="98mA"
ATTRS{authorized}=="1"
ATTRS{bmAttributes}=="80"
ATTRS{bNumConfigurations}=="1"
ATTRS{maxchild}=="0"
ATTRS{bcdDevice}=="0100"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{quirks}=="0x0"
ATTRS{serial}=="a01782d293d17d"
ATTRS{version}==" 2.00"
ATTRS{urbnum}=="689"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="ADATA"
ATTRS{removable}=="removable"
ATTRS{idProduct}=="c96a"
ATTRS{bDeviceClass}=="00"
ATTRS{product}=="ADATA USB Flash Drive"
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1':
KERNELS=="2-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}=="2"
ATTRS{devnum}=="2"
ATTRS{configuration}==""
ATTRS{bMaxPower}=="0mA"
ATTRS{authorized}=="1"
ATTRS{bmAttributes}=="e0"
ATTRS{bNumConfigurations}=="1"
ATTRS{maxchild}=="8"
ATTRS{bcdDevice}=="0000"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{quirks}=="0x0"
ATTRS{version}==" 2.00"
ATTRS{urbnum}=="258"
ATTRS{ltm_capable}=="no"
ATTRS{removable}=="unknown"
ATTRS{idProduct}=="0020"
ATTRS{bDeviceClass}=="09"
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2':
KERNELS=="usb2"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{devpath}=="0"
ATTRS{idVendor}=="1d6b"
ATTRS{speed}=="480"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{authorized_default}=="1"
ATTRS{busnum}=="2"
ATTRS{devnum}=="1"
ATTRS{configuration}==""
ATTRS{bMaxPower}=="0mA"
ATTRS{authorized}=="1"
ATTRS{bmAttributes}=="e0"
ATTRS{bNumConfigurations}=="1"
ATTRS{maxchild}=="3"
ATTRS{bcdDevice}=="0313"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{quirks}=="0x0"
ATTRS{serial}=="0000:00:1d.0"
ATTRS{version}==" 2.00"
ATTRS{urbnum}=="26"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Linux 3.13.0-49-generic ehci_hcd"
ATTRS{removable}=="unknown"
ATTRS{idProduct}=="0002"
ATTRS{bDeviceClass}=="09"
ATTRS{product}=="EHCI Host Controller"
looking at parent device '/devices/pci0000:00/0000:00:1d.0':
KERNELS=="0000:00:1d.0"
SUBSYSTEMS=="pci"
DRIVERS=="ehci-pci"
ATTRS{irq}=="17"
ATTRS{subsystem_vendor}=="0x1028"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x0c0320"
ATTRS{companion}==""
ATTRS{consistent_dma_mask_bits}=="32"
ATTRS{dma_mask_bits}=="32"
ATTRS{local_cpus}=="00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f"
ATTRS{device}=="0x3b34"
ATTRS{uframe_periodic_max}=="100"
ATTRS{enable}=="1"
ATTRS{msi_bus}==""
ATTRS{local_cpulist}=="0-3"
ATTRS{vendor}=="0x8086"
ATTRS{subsystem_device}=="0x040a"
ATTRS{numa_node}=="-1"
ATTRS{d3cold_allowed}=="1"
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""SUBSYSTEM=="usb"
matches:usb2
,2-1
,2-1.2
,2-1.2:1.0
ATTRS{idVendor}=="125f"
matches:2-1.2
,2-1.2:1.0
,host7
,target7:0:0
,7:0:0:0
,sdb
,sdb1
ATTRS{idProduct}=="c96a"
matches:2-1.2
,2-1.2:1.0
,host7
,target7:0:0
,7:0:0:0
,sdb
,sdb1
(same asATTRS{idVendor}=="07b4"
)
For a rule to be triggered, all conditions must match. So only
2-1.2
&2-1.2:1.0
nodes will trigger this rule.A way to confirm write new rules as:
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="125f", ATTRS{idProduct}=="c96a", RUN+="/bin/sh -c 'echo `date` %k %p >> /tmp/usb-key-nodes.log' "
After reloading rules and replug the key:
tail /tmp/usb-key-nodes.log
Mon Jul 6 17:08:38 CET 2015 1-2 /devices/pci0000:00/0000:00:14.0/usb1/1-2
Mon Jul 6 17:08:38 CET 2015 1-2:1.0 /devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0
Related Topics
Getting Android Sdk Tools to Work on Raspberry Pi
Apache Httpd VS. Tomcat 7: Port 80 VS. Port 8080
What's The Purpose of Mmap Memory Protection Prot_None
How to Use Systemd to Restart a Service When Down
Adding New System Call to Linux Kernel 3.13 on 64 Bit System
Finding Threading Bottlenecks and Optimizing for Wall-Time with Perf
How Is a Memory Barrier in Linux Kernel Is Used
Scsi Read (10) and Write (10) with The Scsi Generic Interface
Linux: Send Mail After a Process Id Finishes or Is Killed
Get Subnet Mask in Linux Using Bash
How to Disable Non-Breaking Space with Altgr+Space
How to Diff Two Sections of The Same File
How to Print Linux Group Names on Multiple Line Instead of Single Line Output
What Determines The Order Directory Entries Are Returned by Getdents
What Does an Asterisk at The End of a Mv Command Do