Skip to content

USB Rule Files for Ubuntu

Suke0811 edited this page Jun 15, 2022 · 6 revisions

Thanks @Yuki

Scenario:

multiple USB devices plugged via hub to a host (Linux OS based), multiple services/programs interacting with TTY running on top (e.g. GPSd) Problem:

At boot TTY are randomly assigned to devices causing depending services/programs instabilities. They could indeed fail to start because of different TTY configurations.

Solution:

Assign un-mutable TTY names to USB devices by creating symbolic links of physical devices Configure then services/programs to point to these symbolic TTYs

Therefore, the short answer is: customize udev rules.

udev: overview

udev allows a Linux system to use consistent names for devices such as removable drives and printers, which in turn allows users to experience predictable behavior when devices are added or removed from the system. In synthesis, it represents Linux dynamic device manager.

udev consists of:

  • a configuration file /etc/udev/udev.conf,
  • permission files, and
  • rules files

Rules files are used to determine the TTY used for removable drives currently available in the system. Every line within rule files defines how a specific device attribute is mapped to a dedicated device file.

The default udev rules file is /etc/udev/rules.d/50-udev.rules and should not be modified by a user. To create new rules, add a new file in the same directory (/etc/udev/rules.d/) keeping in mind the following conventions:

  • All rules files must have a filename that ends with the .rules extension
  • Files are read in ascending order

Therefore, to create a customized file read before the default one, just type for example /etc/udev/rules.d/49-my.rules.

Use case

Execute lsusb to see all the currently detected USB devices printed out with an essential amount of info.

$ lsusb
 Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
 Bus 001 Device 002: ID 8087:8000 Intel Corp. 
 Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
 Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
 Bus 002 Device 002: ID 2109:2812  
 Bus 002 Device 003: ID 1a40:0101 Terminus Technology Inc. Hub
 Bus 003 Device 002: ID 2109:0812  
 Bus 002 Device 004: ID 1546:01a8 U-Blox AG 
 Bus 002 Device 005: ID 2341:8036 Arduino SA Leonardo (CDC ACM, HID)
 Bus 002 Device 006: ID 12d1:14db Huawei Technologies Co., Ltd. E353/E3131
 Bus 002 Device 007: ID 0529:0001 Aladdin Knowledge Systems HASP v0.06

In this case, two USB devices are connected via hub to the host:

  • a USB GPS Receiver U-Blox AG, and
  • an Arduino platform

This means, they could be connected to either the device /dev/ttyACM0 or /dev/ttyACM1 (randomly selected). Besides, their services require a static configuration of the expected TTY.

Therefore, a solution here is creating a customized udev rule assigning the U-Blox device to a symbolic /dev/ttyGPS.

Write a rule

Execute udevadm info -a -p $(udevadm info -q path -n /dev/ttyACM0) to increase the verbosity of the USB details. The output will look like the one reported below:

looking at device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.2/2-3.2:1.0/tty/ttyACM0':
    KERNEL=="ttyACM0"
    SUBSYSTEM=="tty"
    DRIVER==""

[...]

looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.2':
    KERNELS=="2-3.2"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 2"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="c0"
    ATTRS{bMaxPower}=="100mA"
    ATTRS{urbnum}=="40406"
    ATTRS{idVendor}=="1546"
    ATTRS{idProduct}=="01a8"
    ATTRS{bcdDevice}=="0201"
    ATTRS{bDeviceClass}=="02"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{speed}=="12"
    ATTRS{busnum}=="2"
    ATTRS{devnum}=="4"
    ATTRS{version}==" 1.10"
    ATTRS{maxchild}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{authorized}=="1"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="u-blox AG - www.u-blox.com"
    ATTRS{product}=="u-blox GNSS receiver"

[...]

So, what you need to do eventually is:

  1. get KERNELS info for your hardware setup.
udevadm info -a -n /dev/ttyUSB0 | grep '{serial}'
  1. Update the rule file like:
KERNEL=="ttyUSB*", ATTRS{serial}=="AU6FBYET", SYMLINK+="ft_sensor1" MODE="0666"
KERNEL=="ttyUSB*", ATTRS{serial}=="AU684C7U", SYMLINK+="ft_sensor2" MODE="0666"
KERNEL=="ttyUSB*", ATTRS{serial}=="AU5KEDBG", SYMLINK+="ft_sensor3" MODE="0666"
KERNEL=="ttyUSB*", ATTRS{serial}=="BFT-SP-R1", SYMLINK+="ft_sensor4" MODE="0666"
  1. see if the rule is updated by running: Then, reconnect sensors and connect them again to PC.
sudo udevadm control --reload-rules. 
  1. Now, if everything went correctly you can connect your device and type in your terminal:
ls /dev/ft_sensor3

to see if you successfully created a symlink. Since it’s a symbolic link you will be able to access both /dev/ttyUSB4 and /dev/ft_sensor4 but they will point to the same device.

  1. If you try to access the USB from python and if you get an error that says 'permission denied' then add
MODE="0666"

to the line of USB, you want to provide access always rule file. This make the permission to rw-rw-rw, but default is rw-rw-r

Clone this wiki locally