Permissions for /dev/ttyTHS0

I found that on AGX Xavier:

  • ttyTHS0 is owned by group “tty” with permissions 640
  • ttyTHS1, ttyTHS4 are owned by “dialout” with permissions 660

How can I have ttyTHS0 also be set to group dialout with 660 by default? I’m using the UART GPIO pins to control a RS232 device. chmod/chown does not persist at the next reboot.

FYI, “ttyTHS0” and “ttyS0” are the same hardware, but the “TH” version uses “Tegra High speed” DMA. By default “ttyS0” is configured as a serial console. This is what causes the migration to being owned by tty instead of dialout (the hardware has a driver taking ownership). If you were to disable serial console (which requires disabling in pre-Linux boot stages as well as in Linux), then this should just revert to group tty.

Normally, if you were to force an ownership change, then this would be done with a udev rule. This file is a device special file generated by the kernel in RAM and is not a real file (thus you would need to alter permissions through a non-file permission method).

Btw, Xavier does not use U-Boot, and so I am not aware of what steps would be needed to disable pre-Linux serial console. Generally speaking though, I would consider it a “bad idea” to remove serial console.

Hmm, it seems though that’s the only UART exposed through the GPIO though? I also don’t see any serial console junk getting spewed out of it as I’m controlling a motor controller through that UART … is there a different UART I should be using for RS232 devices other than the one in the GPIO?

I don’t want to go through USB (and especially USB-C) for reliability reasons.

What do you mean exposed through GPIO? I don’t think the UART pin can be GPIO (I believe the UART has no ability to be programmed for other functions…it is SFIO). You can talk to a serial UART without GPIO just by reading/writing to the “/dev/ttyS#” (there are some other setup details so this is oversimplifying, but no GPIO is involved).

In the carrier board specification I see these UARTs:

  • One on the M.2 Key E (probably not the one to use).
  • On the expansion header (probably this is the one to use...as you mentioned there is only one on the header).
  • The micro-USB in device mode has the serial console (definitely not the one to use).
  • There may be more on the micro-USB which are usable, but I have not experimented with that (hopefully someone will comment on the micro-USB serial ports).

In the case of the non-USB ports these are directly set up as 3.3V TTL level (not the general DB-9 RS-232 voltages, but the logic is the same). The USB port UARTs, within the Xavier, are just ordinary serial UARTs. However, instead of providing the separate TX/RX/CTS/RTS and so on the other end needs a USB connector and the FTDI serial UART driver. The FTDI driver on the other end would create a “/dev/ttyS#”.

“Reliability” depends a lot on cable length, quality, and especially the speed. You can reliably get 115200 speed on all of the UARTs. Above that you might be required to use two stop bits.

I meant the expansion header. I am using it successfully, but I am needing to chmod 777 it at every startup.

ttyTHS1 and ttyTHS2 are root, dialout, 660
ttyTHS0 is auto set to root, tty, 600 – this is the problem. How can I chown/chmod ttyTHS0 and have it persist?

Just a note before adding more: As a workaround you could add your user to group “tty”. Changing the actual device permission is probably the “correct” way to go, but might be more difficult…giving your user permission instead of changing the driver is simple since a tty is a driver and not a file. This adds your user to supplemental group “tty”:

sudo usermod -a -G tty <i>whoever_the_user_is</i>

Changing ownership or permissions of a device special file is probably best done via a custom udev rule. However, I have to wonder what was using the port in the first place which caused it to differ from the other UART ports, and whether something is still tied to this (or perhaps is just leftover baggage which was forgotten). In the case of a TX2 with R32.1 “/dev/ttyTHS0” does not even exist unless something triggers this (sorry, my Xavier is R31.1 at the moment, but this does have “/dev/ttyTHS0”).

There are udev differences depending on which L4T release you are using. So this leads to the question “is this R32.1” (see “head -n 1 /etc/nv_tegra_release”)? We can go from there.

I’ll check on my release version later when I get to it, but the issue with this workaround is that the permissions on ttyTHS0 are 600, not 660, so adding to tty would not solve the problem.

ttyTHS1 and ttyTHS2 are 660.

That doubles my curiosity as to what the port might be intended for if not general UART use. Perhaps it is an oversight (in which case the driver might need to be updated…no UART on the 40-pin header should use special permissions unless it has a function such as serial console (I could see this being left over from previous L4T versions since the header used to be serial console). Knowing L4T version will be required in this case, but udev rules are probably the workaround.

Hi, I am running into this exact problem also. With jetpack 4.2:

Linux tegra-ubuntu 4.9.140-tegra #1 SMP PREEMPT Thu Jul 4 12:43:11 MDT 2019 aarch64 aarch64 aarch64 GNU/Linux

I found the permissions for THS0 to be 620, and group tty

crw--w---- 1 root tty     238, 0 Jul 16 16:45 /dev/ttyTHS0
crw-rw---- 1 root dialout 238, 1 Jul 16 16:39 /dev/ttyTHS1
crw-rw---- 1 root dialout 238, 4 Jul 16 16:39 /dev/ttyTHS4

I have tried to add a udev rule with the following but it did not have any effect

KERNEL=="ttyTHS0",MODE="660",GROUP="dialout"

I have an older xavier with and older jetpack release

Linux tegra-ubuntu 4.9.108-tegra #1 SMP PREEMPT Mon Feb 25 18:09:40 UTC 2019 aarch64 aarch64 aarch64 GNU/Linux

where I am using that port and out of boot the permissions and group are correct:

crw-rw---- 1 root dialout 238, 0 Jul 16 20:31 /dev/ttyTHS0
crw-rw---- 1 root dialout 238, 1 Jul 16 20:31 /dev/ttyTHS1
crw-rw---- 1 root dialout 238, 4 Jul 16 20:31 /dev/ttyTHS4

What is even more frustrating is that I could almost swear I had this issue before with that xavier and I fixed it somehow and now I don’t remember how I did that…

any idea on what to look for?

After a few hours of looking I found the issue. There is a service nvgetcy.service that takes over that port, disabling the service did the trick

sudo systemctl disable nvgetty.service

then reboot and fixed.

Do keep in mind that boot stages prior to loading Linux won’t be disabled by this. Since the current R32.1 does not use U-Boot, and CBoot does not allow interaction, this will not cause boot to halt. However, you might still see “garbage” sent to the UART prior to reaching Linux. In some future setup this may also interact with bootloader software.