Page MenuHomeFreeBSD

Add USB support for location based device unit numbers
Needs ReviewPublic

Authored by hselasky on Oct 3 2019, 12:02 PM.
Tags
None
Referenced Files
Unknown Object (File)
Feb 18 2024, 5:08 AM
Unknown Object (File)
Dec 20 2023, 8:59 AM
Unknown Object (File)
Dec 20 2023, 12:33 AM
Unknown Object (File)
Dec 10 2023, 1:40 PM
Unknown Object (File)
Dec 9 2023, 11:45 AM
Unknown Object (File)
Nov 17 2023, 12:29 AM
Unknown Object (File)
Oct 23 2023, 4:55 PM
Unknown Object (File)
Oct 10 2023, 7:19 PM

Details

Summary

Add USB support for location based device unit numbers.

Sponsored by: Mellanox Technologies

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 26847

Event Timeline

Fix bug in uniq number compuation. Controller number must be last.

Unit numbers are kinda lame. Wouldn't it be better to add aliases?

@imp: We can have both if the TTY layers support it.

Could you implement a tty_makedevalias() function ?

At least with this patch the sysctls are coherent, pointing to only one device.

There is people who expect the first serial device they plug-in to be ttyU0 (me for example) and there are people who would prefer the unit number to stay the same independent of the order the devices are detected (me as well).

I would prefer aliases as well, so we can have both. I didn't check whether it actually is a match to your problem, but how about tty_makealias() in sys/tty.h?

sys/tty.h-int tty_makedevf(struct tty *tp, struct ucred *cred, int flags,
sys/tty.h- const char *fmt, ...) printflike(4, 5);
sys/tty.h-#define TTYMK_CLONING 0x1
sys/tty.h-#define tty_makedev(tp, cred, fmt, ...) \
sys/tty.h- (void )tty_makedevf((tp), (cred), 0, (fmt), __VA_ARGS__) sys/tty.h:#define tty_makealias(tp,fmt,...) \ sys/tty.h- make_dev_alias((tp)->t_dev, fmt,
VA_ARGS__)
sys/tty.h-
sys/tty.h-/* Signalling processes. */
sys/tty.h-void tty_signal_sessleader(struct tty *tp, int signal);
sys/tty.h-void tty_signal_pgrp(struct tty *tp, int signal);

I do remember from way back talks about naming schemes for USB devices in the USB device tree, something like usb-1-3-2 being a device plugged into port 2 of a hub that is plugged into port 3 of a hub plugged into port 1 of the root hub.

There is people who expect the first serial device they plug-in to be ttyU0 (me for example) and there are people who would prefer the unit number to stay the same independent of the order the devices are detected (me as well).

I would prefer aliases as well, so we can have both. I didn't check whether it actually is a match to your problem, but how about tty_makealias() in sys/tty.h?

sys/tty.h-int tty_makedevf(struct tty *tp, struct ucred *cred, int flags,
sys/tty.h- const char *fmt, ...) printflike(4, 5);
sys/tty.h-#define TTYMK_CLONING 0x1
sys/tty.h-#define tty_makedev(tp, cred, fmt, ...) \
sys/tty.h- (void )tty_makedevf((tp), (cred), 0, (fmt), __VA_ARGS__) sys/tty.h:#define tty_makealias(tp,fmt,...) \ sys/tty.h- make_dev_alias((tp)->t_dev, fmt,
VA_ARGS__)
sys/tty.h-
sys/tty.h-/* Signalling processes. */
sys/tty.h-void tty_signal_sessleader(struct tty *tp, int signal);
sys/tty.h-void tty_signal_pgrp(struct tty *tp, int signal);

I do remember from way back talks about naming schemes for USB devices in the USB device tree, something like usb-1-3-2 being a device plugged into port 2 of a hub that is plugged into port 3 of a hub plugged into port 1 of the root hub.

I'd prefer the alias stuff as well. I think we have what we need, but if not I'm happy to fix things that are broken.

There's a number of different ways to have the aliases setup, and at times code in ucom will be the answer, and other times code in devfs and/or devd might be better. The whole device_t vs dev_t stuff will get in the way here, I fear...

Why is this needed at all? What's the motivation?

@avg: It is needed for embedded, where for example tree USB modems control different things and you have apps that should connect to the same modem after boot.

I see.
I think that the problem can be solved quite easily with devd, but maybe it's not good for embedded solutions.
Also, I am not sure how stable the unit numbers are going to be with respect to add-in USB controllers and external USB hubs.

I do not have any objections.

My use case for something like this is a USB-serial console server where I might have 16 different USB-serial adapters attached to various USB hubs; I intended to address it by using the serial number in each device.

@hselasky can you give an example of the unit numbers that would be generated by this patch?

My use case for something like this is a USB-serial console server where I might have 16 different USB-serial adapters attached to various USB hubs; I intended to address it by using the serial number in each device.

Yes, I am doing something like that now.

attach 1001 {
        match "vendor"          "0x12d1";
        match "product"         "0x1506";
        action "ln -sf /dev/cua$ttyname.0 /dev/3g";
};

notify 1001 {
        match "system"          "USB";
        match "subsystem"       "DEVICE";
        match "type"            "DETACH";
        match "vendor"          "0x12d1";
        match "product"         "0x1506";
        action "unlink /dev/3g";
};

attach 1001 {
        match "vendor"          "0x2341";
        match "product"         "0x0043";
        action "ln -sf /dev/cua$ttyname /dev/arduino";
};

notify 1001 {
        match "system"          "USB";
        match "subsystem"       "DEVICE";
        match "type"            "DETACH";
        match "vendor"          "0x2341";
        match "product"         "0x0043";
        action "unlink /dev/arduino";
};

Requires manual configuration though.
At the same time, it's quite flexible.
Of course, totally identical devices (down to serial numbers) can still cause confusion.

Of course, totally identical devices (down to serial numbers) can still cause confusion.

Indeed; most of the cheap USB-serial adapters (e.g. the ones available on aliexpress.com for about $1 USD) have the same (often empty) serial number. I found that the cp210x devices can be reprogrammed. https://github.com/emaste/cp210x-cfg is my trivial FreeBSD port of a configuration tool I use to give them unique serial numbers.

I took Daniel O'Connor's script from: https://www.mail-archive.com/freebsd-usb@freebsd.org/msg14258.html

and did a minor improvement to support creating a USB path via the hub ports, and have this script now:
https://www.funkthat.com/~jmg/FreeBSD/usbserialsn

It creates symlinks for devices:
freebsd@generic:~ $ ls -l /dev/*.usb.2.* /dev/*370*
lrwxr-xr-x 1 root wheel 5 Jun 6 22:40 /dev/cu.XXX370XXXXXX -> cuaU4
lrwxr-xr-x 1 root wheel 5 Jun 6 22:20 /dev/cu.usb.2.1.1 -> cuaU1
lrwxr-xr-x 1 root wheel 5 Jun 6 22:32 /dev/cu.usb.2.1.3 -> cuaU0
lrwxr-xr-x 1 root wheel 5 Jun 6 22:32 /dev/cu.usb.2.1.4.1.4 -> cuaU2
lrwxr-xr-x 1 root wheel 5 Jun 6 22:40 /dev/tty.XXX370XXXXXX -> ttyU4
lrwxr-xr-x 1 root wheel 5 Jun 6 22:20 /dev/tty.usb.2.1.1 -> ttyU1
lrwxr-xr-x 1 root wheel 5 Jun 6 22:32 /dev/tty.usb.2.1.3 -> ttyU0
lrwxr-xr-x 1 root wheel 5 Jun 6 22:32 /dev/tty.usb.2.1.4.1.4 -> ttyU2

Cool script. It would be better to add the alias with devfs. Then it would disappear w/o devd needing all the info...

In D21886#554614, @imp wrote:

Cool script. It would be better to add the alias with devfs. Then it would disappear w/o devd needing all the info...

How do you propose to do it? It looks like devfs.conf is the only part of devfs that supports link, and that is done via /etc/rc.d/devfs on boot. devfs.rules and devfs do not have the option to specify links.

I've been using this script for about a week, and it does exactly what it says on the tin.
Since devfs.conf only gets read on boot, I think handling this script via devd is the perfect way to handle devices that can disappear and reappear.

Would be fantastic if it could be merged, others can enjoy it. :)

I've been using this script for about a week, and it does exactly what it says on the tin.
Since devfs.conf only gets read on boot, I think handling this script via devd is the perfect way to handle devices that can disappear and reappear.

Would be fantastic if it could be merged, others can enjoy it. :)

Are you using this patch or script?

I've been using this script for about a week, and it does exactly what it says on the tin.
Since devfs.conf only gets read on boot, I think handling this script via devd is the perfect way to handle devices that can disappear and reappear.

Would be fantastic if it could be merged, others can enjoy it. :)

Are you using this patch or script?

Yes, I'm using the script jmg@ modified - it works exactly as I would expect it to:

ls -l /dev/tty.* /dev/cu.*
lrwxr-xr-x  1 root  wheel  5 Jun 12 12:54 /dev/cu.A0AC1F827C641630 -> cuaU2
lrwxr-xr-x  1 root  wheel  5 Jun 12 12:54 /dev/tty.A0AC1F827C641630 -> ttyU2

Hello world :-) +1 and thank you for this unique tty/cua with USBSERIAL in node name :-) Also thank you for the hints for DEVD :-) Highly demanded in complex embedded systems and electronics testing scenarios :-)

FYI, I wasn't aware of this but there was more to do to conner's script; I have a 4-port USB-serial dongle (1 USB, 4 cuaU*)..
I had put it onto the wiki the other day https://wiki.freebsd.org/BjoernZeeb/USBSerialConsole

rpokala added inline comments.
sys/dev/usb/serial/usb_serial.c
306

location isn't a variable in this function; did you mean ssc->sc_unit?

In D21886#554613, @jmg wrote:

I took Daniel O'Connor's script from: https://www.mail-archive.com/freebsd-usb@freebsd.org/msg14258.html

and did a minor improvement to support creating a USB path via the hub ports, and have this script now:
https://www.funkthat.com/~jmg/FreeBSD/usbserialsn

Cool!

The only thing where it falls short is for multi-port serial devices.:

# ls -l /dev/cu.74301246 /dev/cuaU2.?
lrwxr-xr-x  1 root  wheel       5 Mar  5 21:24 /dev/cu.74301246 -> cuaU2
crw-rw----  1 uucp  dialer  0x208 Mar  5 21:30 /dev/cuaU2.0
crw-rw----  1 uucp  dialer  0x20e Mar  5 21:24 /dev/cuaU2.1
crw-rw----  1 uucp  dialer  0x218 Mar  5 21:24 /dev/cuaU2.2
crw-rw----  1 uucp  dialer  0x24a Mar  5 21:24 /dev/cuaU2.3

I'll see whether I could modify it for that, but otherwise, it's what I've been looking for.
For devices without a serial number, it falls back to a kind of "location ID" which is probably the best that could be had for those.

I'll see whether I could modify it for that, but otherwise, it's what I've been looking for.
For devices without a serial number, it falls back to a kind of "location ID" which is probably the best that could be had for those.

Suggested change:

--- usbserialsn~        2023-03-05 14:23:15.625410000 +0100
+++ usbserialsn 2023-03-06 22:27:01.397518000 +0100
@@ -99,6 +99,8 @@
 '      "DEV=$1")
 }

+ttyports=$(devinfo -v | sed -ne '/^ *'"${devname}"'/s/.*ttyports=\([0-9][0-9]*\).*/\1/p')
+
 if [ x"$sernum" = x"auto" ]; then
        sernum=usb.$(getdevpath "$devname")
 fi
@@ -113,8 +115,18 @@
       echo "Bad usage"
       exit 1
     fi
-    ln -sf cua${ttyname} /dev/cu.${sernum}
-    ln -sf tty${ttyname} /dev/tty.${sernum}
+    if [ $ttyports -eq 1 ]; then
+      ln -sf cua${ttyname} /dev/cu.${sernum}
+      ln -sf tty${ttyname} /dev/tty.${sernum}
+    else
+      # multi-port board, create links for sub-devices
+      portno=0
+      while [ $portno -lt $ttyports ]; do
+        ln -sf cua${ttyname}.${portno} /dev/cu.${sernum}.${portno}
+        ln -sf tty${ttyname}.${portno} /dev/tty.${sernum}.${portno}
+        portno=$(( $portno + 1 ))
+      done
+    fi
     echo ${sernum} >/var/run/usbserialsn.${devname}
     ;;

@@ -127,6 +139,7 @@
       exit 0
     fi
     sernum=$(cat /var/run/usbserialsn.${devname})
+    rm -f /dev/cu.${sernum}.* /dev/tty.${sernum}.* # multi-port case
     rm -f /dev/cu.${sernum} /dev/tty.${sernum} /var/run/usbserialsn.${devname}
     ;;

@joerg : There are some ideas spreading that using usbconfig or making a new libusbconfig or adding something to libusb may be better than just, making custom scripts to handle things.

What do you think?

@joerg : There are some ideas spreading that using usbconfig or making a new libusbconfig or adding something to libusb may be better than just, making custom scripts to handle things.

What do you think?

Well, I do not really care much about the way to get there. ;-)

What I need:

  • fixed names (similar to Linux' /dev/serial/by-id/) for those devices that provide a serial number, so regardless of which port they are plugged into (or whether another hub was plugged in between), they are always accessible the same way
  • no changes to all applications (there are way too many), which basically means to have it somewhere under /dev

For devices that do not provide serial number information, I'm fine with any of the suggested ways for a "location-based" name, or with just "inventing" a pseudo-serial number (as MacOS does).

Nevertheless, once we decided for a method, it is more than likely that we at least have to provide upstream patches to projects like PySerial so they can recognize the names we've chosen.

Fixed names - yes, but there is something missing in the USB specification, that you can give your own name to USB devices.
That would be very helpful! Let's see what happens. Use what is there for now!

--HPS