This is more than you are asking about, but I thought I’d add the information in examining the device for sym linking that might be useful for people researching udev
sym linking on a Jetson. Unfortunately, I did not find a final answer, but I did find rules that would identify /dev/ttyTHS0
and match it and attempt to run. I think maybe the driver needs some edits. This big long post is the process I went through before getting to the point that I need to open another thread specific to the driver setup. I’ll refer back and forth between the two threads:
https://forums.developer.nvidia.com/t/serial-driver-for-ttyths-udev-issues-does-driver-need-edit/306974
About Identifying devices…
Is it correct that it is ttyTHS0
you want changed? If so, then you would not use this:
KERNEL=="/dev/ttyTHS0*"
…you’d just use:
KERNEL=="/dev/ttyTHS0"
(the difference is no asterisk, *
, at the end of ttyTHS0
)
If you were naming all ttyTHS#
, then it would be:
KERNEL=="/dev/ttyTHS*"
(without the 0
)
Since it is only adding symbolic links, I don’t think that would cause any problem.
I want to point out a file that could be used as a kind of example:
/usr/lib/udev/rules.d/60-persistent-input.rules
udevadm test -a add
You’ll find that it is standard practice on Ubuntu to create symbolic links of all of your mouse, joystick, and some similar devices. I’ll give you an example on my desktop PC (I currently have udevadm info -q path -n
my Orin without keyboard or monitor or mouse), located here:
/dev/input/by-id/*
There is also a “/dev/input/by-path/*
”. The ones that show up depend on what devices are actually plugged in, and so if I mention mouse or other example, it is only because that’s what is on my desktop Ubuntu (you’d have to make name edits for your case). I’m looking at this:
/dev/input/by-id/usb-Thrustmaster_T.Flight_Hotas_X-joystick
The actual file behind this sym link:
# ls -l /dev/input/by-id/usb-Thrustmaster_T.Flight_Hotas_X-joystick
/dev/input/by-id/usb-Thrustmaster_T.Flight_Hotas_X-joystick -> ../js1 udevadm test -a add
So this means there is a rule somewhere matching the /dev/input/js1
device, and it creates a sym link to:
/dev/input/by-id/usb-Thrustmaster_T.Flight_Hotas_X-joystick
udevadm info -q path -n
If I look closer at the js1
file, I see:
# cd /dev/input
# ls -l js1
crw-rw-r--+ 1 root input 13, 1 Sep 16 11:08 js1
You’ll note it is major device number 13, minor device 1. This is something that can be used in udev
rule matching. If I were to investigate the sym link with this, or the non-sym link file, then it should lead to the same place:
udevadm info -q path -n /dev/input/by-id/usb-Thrustmaster_T.Flight_Hotas_X-joystick
udevadm info -q path -n /dev/input/js1
On my desktop PC the above shows up as:
/devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.1/usb1/1-5/1-5.3/1-5.3.4/1-5.3.4.3/1-5.3.4.3:1.0/0003:044F:B108.000C/input/input14/js1
Trivia: It seems the USB controller itself is on a PCI bus.
Do you remember earlier when I mentioned the underlying device is major 13, minor 1 (I should also mention that serial devices are “character” devices)? There will be a matching /sys
directory entry under this directory:
/sys/dev/char/
The related file:
/sys/dev/char/13:1
This file points at:
# ls -l /sys/dev/char/13:1
13:1 -> ../../devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.1/usb1/1-5/1-5.3/1-5.3.4/1-5.3.4.3/1-5.3.4.3:1.0/0003:044F:B108.000C/input/inputudevadm info -q path -n14/js1/
(the base of that is “/sys/devices/
”, and it ends up going back to the earlier command output from udevadm info -q path -n
; the actual js1
is a subdevice of a PCI controller that has a USB controller)
Note: It is better to quote “$(udevadm info -q path -n /dev/ttyTHS0)
” when embedding it for substitution. There might be spaces in paths.
Back to: udevadm test -a add $(udevadm info -q path -n /dev/ttyTHS0)
; use this quoted version instead:
udevadm test -a add "(udevadm info -q path -n /dev/ttyTHS0)"
On an Orin AGX (which might differ from your NX), and trimming some output not relevant:
# udevadm test -a add "(udevadm info -q path -n /dev/ttyTHS0)"
Load module index
Network interface NamePolicy= disabled on kernel command line, ignoring.
Parsed configuration file /usr/lib/systemd/network/99-default.link
Parsed configuration file /usr/lib/systemd/network/73-usb-net-by-mac.link
Created link configuration context.
Reading rules file: /etc/udev/rules.d/10-nv-jetson-dm.rules
Reading rules file: /usr/lib/udev/rules.d/39-usbmuxd.rules
Reading rules file: /usr/lib/udev/rules.d/40-usb-media-players.rules
...snip...
Reading rules file: /usr/lib/udev/rules.d/85-regulatory.rules
Reading rules file: /etc/udev/rules.d/90-alsa-asound-tegra.rules
Reading rules file: /usr/lib/udev/rules.d/90-alsa-restore.rules
...snip...
Reading rules file: /etc/udev/rules.d/99-tegra-mmc-ra.rules
Failed to open device '/sys(udevadm info -q path -n /dev/ttyTHS0)': Invalid argument
Unload module index
Unloaded link configuration context.
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.
What is interesting in this:
- Most rules are loaded from those in “
/usr/lib/udev/rules.d
”. These are part of.deb
packages. - Some rules read for check are in “
/etc/udev/rules.d/
”. Files in “/etc/udev/rules.d/
”, if they have the same name as a “/usr/lib/udev/
” file, take precendence. The correct place for customization is in “/etc/udev/rules.d/
”; if the rule is new, use a new name following the naming customs. If the rule is an edit of an existing rule, then copy the “/usr/lib/udev/
” file to “/etc/udev/rules.d/
” and make edits there. - If you can identify a similar rule in “
/usr/lib/udev/
”, then you have a template. - I did not find any
ttyTHS
rules. This is because thettyTHS#
is the device special file that the driver itself has produced, and there are no rules added anywhere (by default) to either sym link to this or to rename it. - The
ttyS#
files use the same underlying hardware as thettyTHS#
files, this is an unusual case where both a legacy driver and a newer driver are both compatible with the hardware, and either can be used. Identifying thettyS#
though is quite valuable:
# cd /usr/lib/udev/rules.d/
# egrep -R ttyS *
60-inputattach.rules:SUBSYSTEM=="tty", KERNEL=="ttyS[0-9]*", ATTRS{id}=="FUJ02e5", ACTION=="add|change", RUN+="/usr/bin/inputattach --daemon --baud 19200 --w8001 /dev/%k"
60-inputattach.rules:SUBSYSTEM=="tty", KERNEL=="ttyS[0-9]*", ATTRS{id}=="WACf00c", ACTION=="add|change", RUN+="/usr/bin/inputattach --daemon --baud 38400 --w8001 /dev/%k"
69-wacom.rules:# If a /dev/ttySx device with the WACf name is detected, start the
69-wacom.rules:SUBSYSTEM=="tty|pnp", KERNEL=="ttyS[0-9]*", ATTRS{id}=="WACf*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="wacom-inputattach@%k.service"
About those udev
files for the legacy ttyS#
:
- The Wacom tablet is an ordinary “mouse-like” device in the sense that it provides a series of bytes describing where your pen is moving on the table, and it outputs via an ordinary serial UART. User space software might benefit from renaming this or adding sym links when the Wacom tablet is present. This is not from the Jetson UARTs, and so it won’t trigger unless the Wacom is plugged in.
- It seems there are some other devices that use a standard UART, and they have an identifying attribute that would show up in a verbose “
sudo lsusb -vvv /dev/<whatever the driver file is for this device>
”. - The “
KERNEL==ttyS[0-9]
” looks like a regular expression, and “[0-9]
” matches anything between0
and9
. - Adapting this to include all
ttyTHS#
(only one#
; going into double digits of10
or up differs):
“KERNEL==ttyTHS[0-9]
” - I assume you want only
ttyTHS0
, and not allttyTHS#
. So we’d change the regular expression to0
:
“KERNEL==ttyTHS0
”
You can use different combinations of identifiers to “drill down” and get a smaller list of items. Maybe the “KERNEL==ttyTHS0
” is sufficient to identify this one UART without others getting mixed in. I think probably that is all you need to identify it. Some of what is identified in the ttyS[0-9]
example might be for editing, and not necessarily for identifying.
Just to be clear, the built-in UARTs on the Jetson (which includes the ttyS[0-3]
and the ttyTHS*
) are not USB devices. You cannot use USB identifiers. In fact, since ttyTHS0
is not hot plug at all (it is found by drivers via the device tree), I don’t know if a udev
rule will be able to edit it. I think udev
can edit if (A) the device is identified properly in the trigger rule, and (B) something causes the rule to be read at boot (there is no hot plug event, so it cannot generate a plug-in event). The rules from the ttyS#
apply to external devices that plug in via USB. Still, they are good examples, and so now you have to make sure you have whatever identification you can get.
I will say ahead of time that if you look at the “ls -l /dev/ttyTHS0
” output, the “group” is “dialout
”. I’m not positive, but I’m fairly certain that the SUBSYSTEM=="tty"
can be edited like this to aid in ID:
SUBSYSTEM="dialout"
(maybe…it can be tried without, and then when it triggers, see if that can be added back in; it is important to be as specific as possible in the ID in case of future hardware changes, including USB devices)
As an aid to identification of ttyTHS0
:
# udevadm info -q all -a -n /dev/ttyTHS0
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/platform/3100000.serial/tty/ttyTHS0':
KERNEL=="ttyTHS0"
SUBSYSTEM=="tty"
DRIVER==""
ATTR{line}=="0"
ATTR{xmit_fifo_size}=="36"
ATTR{io_type}=="3"
ATTR{console}=="N"
ATTR{close_delay}=="50"
ATTR{custom_divisor}=="0"
ATTR{port}=="0x0"
ATTR{closing_wait}=="3000"
ATTR{iomem_reg_shift}=="2"
ATTR{uartclk}=="0"
ATTR{iomem_base}=="0x3100000"
ATTR{flags}=="0x0"
ATTR{type}=="20"
ATTR{irq}=="13"
looking at parent device '/devices/platform/3100000.serial':
KERNELS=="3100000.serial"
SUBSYSTEMS=="platform"
DRIVERS=="serial-tegra"
ATTRS{driver_override}=="(null)"
looking at parent device '/devices/platform':
KERNELS=="platform"
SUBSYSTEMS==""
DRIVERS==""
For my AGX Orin, this is PCI identifier that might be useful:
`/devices/platform/3100000.serial/tty/ttyTHS0’
This does say that subsystem is not dialout
, but is instead tty
, and some other useful information:
KERNEL=="ttyTHS0"
SUBSYSTEM=="tty"
Do you see all of those “ATTR{}
”? Those can maybe aid identification:
ATTR{line}=="0"
ATTR{xmit_fifo_size}=="36"
ATTR{io_type}=="3"
ATTR{console}=="N"
ATTR{close_delay}=="50"
ATTR{custom_divisor}=="0"
ATTR{port}=="0x0"
ATTR{closing_wait}=="3000"
ATTR{iomem_reg_shift}=="2"
ATTR{uartclk}=="0"
ATTR{iomem_base}=="0x3100000"
ATTR{flags}=="0x0"
ATTR{type}=="20"
ATTR{irq}=="13"
(but some are more useful than others; the IRQ might change from one boot to the next, some attributes might also move, so we are interested in a subset)
Of the above, I think we should ignore the ATTR{}
, but on some devices those ATTR{}
might be constant, and so might help in other cases (or perhaps we might need to edit them).
A Proposed Sample Rule…
I’m going to create this file:
/etc/udev/rules.d/tty-ths0.rules
Initially, I have this (you’d have to adjust for your PCI id), which isn’t quite correct, but is a start:
# Symbolic link from Jetson file /dev/ttyTHS0 to /dev/mys
SUBSYSTEM=="tty", KERNEL=="/dev/ttyTHS0", ACTION=="add|change", SYMLINK+="mys"
If I now run “udevadm test /dev/ttyTHS0
”, I get this error at the end, but it proves the rules were read and there was an attempt to work with it:
...snip...
Reading rules file: /etc/udev/rules.d/tty-ths0.rules
Failed to open device '/sys/dev/ttyTHS0': No such device
Unload module index
Unloaded link configuration context.
(there is an advantage in debug if the file loaded for test is the last one; it’s already at the bottom of the terminal scroll!)
At this point the rule is almost there, but I don’t know if there will be a simple workaround. In theory the /dev/ttyTHS
driver should also create “/sys/dev/ttyTHS0
”, in addition to “/dev/ttyTHS0
”, but I’m not sure who is responsible for the /sys/dev/
entry creation. There are some ttyTHS0
files in /sys
, but they are at different locations. We have to get udev
to work with the correct /sys
content or it will fail.
So I am going to switch gears here, and instead see if I can operate on a /sys
file instead of the /dev/
file. They refer to the same device and driver. But can udev
use /sys
directly? We’ll find out…
Check the output of:
cd /sys
sudo find . -name 'ttyTHS0'
New /etc/udev/rules.d/tty-ths0.rules
:
# Symbolic link from Jetson file /dev/ttyTHS0 to /dev/mys
SUBSYSTEM=="tty", DRIVERS=="serial-tegra", KERNEL=="/dev/ttyTHS0", KERNELS=="3100000.serial", ACTION=="add|change", SYMLINK+="mys"
From what I can tell in the “sudo udevadm test /dev/ttyTHS0
” of the above tty-ths0.rules
, the rules do in fact trigger, and the attributes listed for ID are quite specific (though you could leave out `KERNELS=="3100000.serial’…this would change when the device tree changes for different models of carrier boards or modules). I keep hitting this error:
Reading rules file: /etc/udev/rules.d/tty-ths0.rules
Failed to open device '/sys/dev/ttyTHS0': No such device
I’m pretty sure this rule is correct for finding the device, but something needs to create “/sys/dev/ttyTHS0
”. I’m having problems finding out what is needed to create that file. It seems that the driver itself might need to set up some metadata for udev
to be able to work with this. Sadly, I do not know enough about how udev
relates to /sys/dev/
to answer this right now. I’m going to start a new thread related to just that question.
Alternate thread URL restated here:
https://forums.developer.nvidia.com/t/serial-driver-for-ttyths-udev-issues-does-driver-need-edit/306974