Problems with USB GSM modem and devd

Colleagues, could you please tell me what I'm doing wrong?
I have a Huawei E1550 USB GSM modem. When turned on, it creates three COM ports. I want the names of the special files to be unique and not change their order when connecting other USB-serial adapters.

Here it is:
ogogon@devel:/usr/local/etc/devd# lsusb
Bus /dev/usb Device /dev/ugen3.4: ID 12d1:1001 Huawei Technologies Co., Ltd. E161/E169/E620/E800 HSDPA Modem


I created a description for devd. Here it is:
Code:
#
# Example devd configuration file for USB printers.
# Uncomment the notify rule below to enable.
#
# Huawei Technologies Co., Ltd. E1550 HSDPA Modem

# Rules for modem Huawei E1550 (Interface 0)
attach 100 {
match "vendor" "0x12d1";
match "product" "0x1001";
match "interface" "0x00";
action "/bin/ln -sf /dev/$device-name /dev/modem_huawei_0";
};

detach 100 {
match "vendor" "0x12d1";
match "product" "0x1001";
match "interface" "0x00";
action "/bin/rm -f /dev/modem_huawei_0";
};

# Rules for modem Huawei E1550 (Interface 1)
attach 101 {
match "vendor" "0x12d1";
match "product" "0x1001";
match "interface" "0x01";
action "/bin/ln -sf /dev/$device-name /dev/modem_huawei_1";
};

detach 101 {
match "vendor" "0x12d1";
match "product" "0x1001";
match "interface" "0x01";
action "/bin/rm -f /dev/modem_huawei_1";
};

# Rules for modem Huawei E1550 (Interface 2)
attach 102 {
match "vendor" "0x12d1";
match "product" "0x1001";
match "interface" "0x02";
action "/bin/ln -sf /dev/$device-name /dev/modem_huawei_2";
};

detach 102 {
match "vendor" "0x12d1";
match "product" "0x1001";
match "interface" "0x02";
action "/bin/rm -f /dev/modem_huawei_2";
};

Unfortunately, the regular special files are created, but the links are not.
I ran devd -d. It outputs a lot of output, but I don't see any attempts to run ln.

What am I doing wrong? How can I solve my problem?

Thank you for your advice,
Ogogon.
 
You will likely need to do the links with devfs. You won't need the rules here if that's all you want to do. also, trying to do anything to the device here is racey since these actions run when the attach routine of the driver returns, but some drivers defer creating the /dev nodes until a tiny time later after they've configured them for use. See devfs(8) and devfs.conf(5) for more details. You can even set permissions, ownership, etc for the device nodes.

But since you want to associate the different kinds of modem with an alias, that may be trickier. There is a cdev event that devfs generates, but that might require the devd event to write some temporary state so that the cdev event can link to the right device. Unfortunately, there's not a good connection between 'tty' and 'device name' so that you can learn about the device. If you had that, you could use devfs(8) to add rules to get the right links.... I tried to add this association some time ago, but it got bogged down in review.
 
Code:
action "/bin/ln -sf /dev/$device-name /dev/modem_huawei_0";

Don't think $device-name is the correct "device" to use here, try $cdev instead.

Code:
     cdev          Device node path if one is created by the devfs(5)
                   filesystem.
devd.conf(5)

And you could try action "logger $device-name,$cdev" that will create a syslog message (logger(1)), or execute a small shell script that dumps the environment variables to a log file.
 
And you could try action "logger $device-name,$cdev" that will create a syslog message (logger(1)),
I think something is wrong, but I can't figure out what...

I replaced the line with "action" with the following action "/usr/bin/logger -tdevd $device-name,$cdev"; and restarted devd.
Unfortunately, no messages appear in /var/log/messages.
To check, I issued the command manually - /usr/bin/logger -tlogger_test test.
And immediately received the expected line - Nov 28 10:19:41 devel logger_test[29368]: test

What could be the reason?
 
Notify and priority are missing. Try something like this and see what's in /var/log/messages:
Code:
notify 300 {
   match "system"   "USB";
   match "type"     "ATTACH";
   match "vendor"   "0x12d1";
   match "product"  "0x1001";
   action "logger detach: 1-$device 2-$devclass 3-$devsubclass 4-$interface 5-$intclass 6-$intprotocol 7-$mode 8-$notify 9-$cdev";
};
 
Notify and priority are missing. Try something like this and see what's in /var/log/messages:
Code:
notify 300 {
   match "system"   "USB";
   match "type"     "ATTACH";
   match "vendor"   "0x12d1";
   match "product"  "0x1001";
   action "logger detach: 1-$device 2-$devclass 3-$devsubclass 4-$interface 5-$intclass 6-$intprotocol 7-$mode 8-$notify 9-$cdev";
};
This is great! Devd has stopped pretending that none of this concerns him...
Nov 28 11:57:11 devel ogogon[1128]: detach: 1- 2-0x00 3-0x00 4- 5- 6- 7-host 8- 9-ugen3.4
Nov 28 11:57:11 devel ogogon[1132]: detach: 1- 2-0x00 3-0x00 4-0 5-0xff 6-0xff 7-host 8- 9-ugen3.4
Nov 28 11:57:11 devel ogogon[1136]: detach: 1- 2-0x00 3-0x00 4-1 5-0xff 6-0xff 7-host 8- 9-ugen3.4
Nov 28 11:57:11 devel ogogon[1140]: detach: 1- 2-0x00 3-0x00 4-2 5-0xff 6-0xff 7-host 8- 9-ugen3.4


Why four times? It would seem that there are only three special files...

And what is the right thing to do now? I still need each device to have a slightly different logic...
Do I need to write some kind of script, or will the 'attach' sections work now?

Another practical question: all the information the logger returned is undoubtedly important and interesting. But how can we tell from them that the special file is actually called /dev/сuaU0.X? And not cuaU1.X?
 
And what is the right thing to do now? I still need each device to have a slightly different logic...
You can use item number 4, which is var $interface. The output shows 3 interfacesnumbered 0, 1 and 2. So for instance, add a line match "interface" "0"; for the first interface.
 
You can use item number 4, which is var $interface. The output shows 3 interfacesnumbered 0, 1 and 2. So for instance, add a line match "interface" "0"; for the first interface.
Thank you. But I'm more interested in something else: how to determine the common device number of the cuaUX and ttyUX. Where can I find out this X?
 
how to determine the common device number of the cuaUX and ttyUX
Try this command in a terminal as root: # cat /var/run/devd.pipe. Then plug in your USB modem and look at the output.
I suppose these entries will be created by DEVFS, as bsdimp wrote earlier. If so, you will need something with match "system" "DEVFS" to pick up the creation of the devices.
 
Try this command in a terminal as root: # cat /var/run/devd.pipe. Then plug in your USB modem and look at the output.
I followed these steps. Here they are:
root@devel:/home/ogogon # cat /var/run/devd.pipe
---=== Next I disconnect the modem ===---
!system=USB subsystem=DEVICE type=DETACH ugen=ugen3.4 cdev=ugen3.4 vendor=0x12d1 product=0x1001 devclass=0x00 devsubclass=0x00 sernum="" release=0x0000 mode=host port=4 parent=ugen3.2
!system=USB subsystem=INTERFACE type=DETACH ugen=ugen3.4 cdev=ugen3.4 vendor=0x12d1 product=0x1001 devclass=0x00 devsubclass=0x00 sernum="" release=0x0000 mode=host interface=0 endpoints=3 intclass=0xff intsubclass=0xff intprotocol=0xff
!system=USB subsystem=INTERFACE type=DETACH ugen=ugen3.4 cdev=ugen3.4 vendor=0x12d1 product=0x1001 devclass=0x00 devsubclass=0x00 sernum="" release=0x0000 mode=host interface=1 endpoints=2 intclass=0xff intsubclass=0xff intprotocol=0xff
!system=USB subsystem=INTERFACE type=DETACH ugen=ugen3.4 cdev=ugen3.4 vendor=0x12d1 product=0x1001 devclass=0x00 devsubclass=0x00 sernum="" release=0x0000 mode=host interface=2 endpoints=2 intclass=0xff intsubclass=0xff intprotocol=0xff
!system=DEVFS subsystem=CDEV type=DESTROY cdev=ugen3.4
!system=DEVFS subsystem=CDEV type=DESTROY cdev=usb/3.4.0
!system=DEVFS subsystem=CDEV type=DESTROY cdev=cuaU0.0.lock
!system=DEVFS subsystem=CDEV type=DESTROY cdev=cuaU0.0.init
!system=DEVFS subsystem=CDEV type=DESTROY cdev=cuaU0.0
!system=DEVFS subsystem=CDEV type=DESTROY cdev=ttyU0.0.lock
!system=DEVFS subsystem=CDEV type=DESTROY cdev=ttyU0.0.init
!system=DEVFS subsystem=CDEV type=DESTROY cdev=ttyU0.0
!system=DEVFS subsystem=CDEV type=DESTROY cdev=cuaU0.1.lock
!system=DEVFS subsystem=CDEV type=DESTROY cdev=cuaU0.1.init
!system=DEVFS subsystem=CDEV type=DESTROY cdev=cuaU0.1
!system=DEVFS subsystem=CDEV type=DESTROY cdev=ttyU0.1.lock
!system=DEVFS subsystem=CDEV type=DESTROY cdev=ttyU0.1.init
!system=DEVFS subsystem=CDEV type=DESTROY cdev=ttyU0.1
!system=DEVFS subsystem=CDEV type=DESTROY cdev=cuaU0.2.lock
!system=DEVFS subsystem=CDEV type=DESTROY cdev=cuaU0.2.init
!system=DEVFS subsystem=CDEV type=DESTROY cdev=cuaU0.2
!system=DEVFS subsystem=CDEV type=DESTROY cdev=ttyU0.2.lock
!system=DEVFS subsystem=CDEV type=DESTROY cdev=ttyU0.2.init
!system=DEVFS subsystem=CDEV type=DESTROY cdev=ttyU0.2
-u3g0 at on uhub9
!system=DEVFS subsystem=CDEV type=DESTROY cdev=usb/3.4.4
!system=DEVFS subsystem=CDEV type=DESTROY cdev=usb/3.4.3
!system=DEVFS subsystem=CDEV type=DESTROY cdev=usb/3.4.2
!system=DEVFS subsystem=CDEV type=DESTROY cdev=usb/3.4.1
---=== Next I connect the modem ===---
!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/3.4.0
!system=DEVFS subsystem=CDEV type=CREATE cdev=ugen3.4
!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/3.4.1
!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/3.4.2
!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/3.4.3
!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/3.4.4
!system=USB subsystem=DEVICE type=ATTACH ugen=ugen3.4 cdev=ugen3.4 vendor=0x12d1 product=0x1001 devclass=0x00 devsubclass=0x00 sernum="" release=0x0000 mode=host port=4 parent=ugen3.2
!system=USB subsystem=INTERFACE type=ATTACH ugen=ugen3.4 cdev=ugen3.4 vendor=0x12d1 product=0x1001 devclass=0x00 devsubclass=0x00 sernum="" release=0x0000 mode=host interface=0 endpoints=3 intclass=0xff intsubclass=0xff intprotocol=0xff
!system=USB subsystem=INTERFACE type=ATTACH ugen=ugen3.4 cdev=ugen3.4 vendor=0x12d1 product=0x1001 devclass=0x00 devsubclass=0x00 sernum="" release=0x0000 mode=host interface=1 endpoints=2 intclass=0xff intsubclass=0xff intprotocol=0xff
!system=USB subsystem=INTERFACE type=ATTACH ugen=ugen3.4 cdev=ugen3.4 vendor=0x12d1 product=0x1001 devclass=0x00 devsubclass=0x00 sernum="" release=0x0000 mode=host interface=2 endpoints=2 intclass=0xff intsubclass=0xff intprotocol=0xff
!system=DEVFS subsystem=CDEV type=CREATE cdev=ttyU0.0
!system=DEVFS subsystem=CDEV type=CREATE cdev=ttyU0.0.init
!system=DEVFS subsystem=CDEV type=CREATE cdev=ttyU0.0.lock
!system=DEVFS subsystem=CDEV type=CREATE cdev=cuaU0.0
!system=DEVFS subsystem=CDEV type=CREATE cdev=cuaU0.0.init
!system=DEVFS subsystem=CDEV type=CREATE cdev=cuaU0.0.lock
!system=DEVFS subsystem=CDEV type=CREATE cdev=ttyU0.1
!system=DEVFS subsystem=CDEV type=CREATE cdev=ttyU0.1.init
!system=DEVFS subsystem=CDEV type=CREATE cdev=ttyU0.1.lock
!system=DEVFS subsystem=CDEV type=CREATE cdev=cuaU0.1
!system=DEVFS subsystem=CDEV type=CREATE cdev=cuaU0.1.init
!system=DEVFS subsystem=CDEV type=CREATE cdev=cuaU0.1.lock
!system=DEVFS subsystem=CDEV type=CREATE cdev=ttyU0.2
!system=DEVFS subsystem=CDEV type=CREATE cdev=ttyU0.2.init
!system=DEVFS subsystem=CDEV type=CREATE cdev=ttyU0.2.lock
!system=DEVFS subsystem=CDEV type=CREATE cdev=cuaU0.2
!system=DEVFS subsystem=CDEV type=CREATE cdev=cuaU0.2.init
!system=DEVFS subsystem=CDEV type=CREATE cdev=cuaU0.2.lock
+u3g0 at bus=3 hubaddr=2 port=4 devaddr=4 interface=0 ugen=ugen3.4 vendor=0x12d1 product=0x1001 devclass=0x00 devsubclass=0x00 devproto=0x00 sernum="" release=0x0000 mode=host intclass=0xff intsubclass=0xff intprotocol=0xff ttyname=U0 ttyports=3 on uhub9

It seems like a lot of information. But it doesn't allow us to clearly identify the connected device and the special COM port files that were created.
Is it really so poorly thought out that even knowing the name of a ugen-device I can't get the name of the com ports associated with it and vice versa? Logically, all this information is present in kernel structures, and there should be some utility that displays it. Some kind of u3gstat...

Here's another oddity, in my opinion.
When I connected the modem, the device ugen3.4 was created, and five more devices: ugen3.4.0-ugen3.4.4.
But there are three COM ports, but six special files. (We do not count lock and init devices.) Why such discrepancies?
 
But it doesn't allow us to clearly identify the connected device and the special COM port files that were created.
I don't know what exactly you are trying to achieve, but if device nodes ttyU0.[0-2] and cuaU0.[0-2] pop up, then you likely plugged in that particular modem. Use something like this to handle the newly created device nodes:
Code:
             device-name "(ttyU0|cuaU0).[0-2].*";
             action "/scripts/gsm_modem $device-name start";

Should you really need data from the earlier USB event, see what options .. set .. can do. You could even write those things to a temporary file that will be created on ATTACH and removed on DETACH. See devd.conf() and file /etc/devd.conf for examples.
 
I don't know what exactly you are trying to achieve,
I apologize if I didn't explain this very well. However, what I'm trying to achieve is perfectly natural for any system administrator and programmer.
I want to get a solution that works flawlessly and unambiguously in all operational variants.

Under different operating conditions, a computer may have a different number of USB-serial devices connected. They may be connected and disconnected during operation. The computer may reboot.
There may be several similar devices. They may be connected to different USB ports.

This isn't an abstract whim. I can list the devices on a real computer that's currently stand next to me: a 3G modem for internet, a 3G modem with an unlocked voice path (a channel for Asterisk), a Watchdog serial port, and a UPS serial port. Sometimes, a regular USB-serial cable is connected to it to set up any hardware. Sometimes, during operation, their cables are swapped in the USB ports. This constantly leads to the com port numbers changing and daemons losing connection with their hardware.

I "trying to achieve", what every COM port, no matter situation, to have a predetermined name so I don't have to figure out why it doesn't have internet today, or Asterisk lost the channel, or NUT is complaining about not seeing the UPS, or Watchdog is overloading the system every minute.

Sorry for being verbose, but this is important to me.
 
I completely understand your problem, and I have faced it too. But there is unfortunately no generic solution that an OS can implement. It can't look at a (serial) device and give it a name like /dev/tty_ogogon_3g_modem_voice, because it can't guess what you want to use the device for. What it can SOMETIMES do is to give you some identifying information. But not always. For example, on my FreeBSD server, I have two traditional (16550 style) serial ports, which turn into /dev/ttyu[01]. Only I happen to know what is plugged into them. On other machines, I use USB serial interfaces; those could in theory be identified by a combination of manufacturer / model / serial, but that can be operationally dangerous: For example, if I quickly replace my USB-to-RS485 adapter with another one (because it has a longer cable), then any system that relies on the serial number of the adapter will break, or have to be updated.

The path you are using (changing the devd configuration to make sure you get the expected /dev/ttyXXX device names for devices known by manufacturer/model/serial) can be made to work, although as you have discovered, the configuration is quite fragile and requires great accuracy. I used to do that (albeit on Linux) to distinguish two USB-serial data acquisition devices. After a while, I gave up, and used a completely different approach instead:

Any serial device that you want to communicate with uses some sort of protocol: send a certain message, receive a certain answer. Part of the protocol is the choice of baud rate / word length and such. Different devices use wildly different and incompatible protocols. If devices can be distinguished, the protocol usually allows doing that. So what I do is that any program that wants to use serial devices, at startup promiscuously contacts all currently unused serial ports (by enumerating /dev/ttyXXX). It attempts to send a message to the device, and if it succeeds it asks questions such as "what is your serial number, your model, your firmware version". Only if it gets a perfect match to its expectation does it then attach to the serial port and use it; otherwise it drops (closes) the serial port again, and tries another one. If it finds a good port, it marks it as in use (so other parts of the software stack don't disrupt communication by probing it).

For me, this is relatively easy (still hundreds of lines of code), because all uses of serial ports on each host are in a single executable that I control. Since you seem to be using canned software, this is not as easy, but it would be doable. You would have to create wrapper scripts around all your apps, which perform the function of probing all unused serial devices, determining whether they are the correct one for this app (which requires knowing the protocol the underlying device speaks), if yes reserving it, and then starting the app with the name of the correct serial device as an argument. And when the app ends, release the port again. It's a bit of work, but I think in the long run it will be more stable, as it is self-healing against configuration changes, and you can get good diagnostic messages when failures occur.
 
I completely understand your problem, and I have faced it too. But there is unfortunately no generic solution that an OS can implement.
I'll try to answer briefly, if I can.

Let's make it clear right away: I'm not a FreeBSD kernel or driver developer; I do other things entirely. But that doesn't negate or invalidate my right to note significant shortcomings, discuss them, and even attract the community's attention to them. (In fact, I once tried writing simple drivers and translated a book about drivers from English, and I remember fragments of it. But that was a long time ago.)

Now, to the point.
25 years have passed since USB support appeared in FreeBSD. During this time, there's undoubtedly been time to reflect on this, refine the concept, and implement convenient and practical workflows for devices connected via this bus.
Currently, there's a very significant shortcoming that makes automated administration of bus hardware absurd and prevents its full implementation. Knowing the USB device special file name (/dev/cuaU1.2, /dev/ttyU0.1), I can't determine which actual physical device they belong to. I can't automatically create unique names for them, set file owners and access masks, or perform other actions. I can make some guesses, but I can't get any definitive information.
Some time ago, I thought this was a knowledge gap on my part, but it turns out it's an objective lack of capability. Moreover, what I want isn't some strange whim, but an objective system administrator need. (Indeed, USB-based peripherals are very popular these days. In this thread, I listed the important devices of one typical communications device. And everyone should have different settings.)

Again, I'm not a kernel architect, but I understand that this is a very serious oversight. I sincerely hope that the developers working on these issues will address this issue and modify the kernel data structures to ensure complete and unambiguous clarity on this matter. I understand that this is a lot of work, but now that the problem is not solved, the difficulties in use are also quite big.
 
The problem is that "the computer" (including the kernel) doesn't have an important piece of information: they human user's intent.

I plug in a certain USB-to-serial dongle into the USB port of the computer. All the computer can know: it is a certain USB device. I then plug in some device (such as in my case a pressure or water volume measurement device). The computer simply does not know what thing is connected to the serial port. And it has no general way of knowing that. Say for example I connect the pressure measurement device first: I would love to have the device name /dev/tty_ralph_pressure, but I (the human) has to tell the computer that this is my intent. There is also another device /dev/tty_ralph_tank_volume, which uses a similar USB device (same model, different serial number).

The next day I unplug the first USB-to-serial dongle again, because it had a short cable, which makes the wiring in my control box very ugly, and instead plug in a different one (same general type, same manufacturer, same chip, different model, the only difference is the cable length). I want the computer to know that this new device is REPLACING the old one, and should take over the name /dev/tty_ralph_pressure. The computer simply can not know that. It can also not know that the old device (which was just unplugged) will not reappear, because its cable is too short. Actually it might reappear in a month, when I add new hardware to the system, and now I want it (with the same serial number!) to be called /dev/tty_ralph_cell_modem ... which again the computer has no way of guessing. All it knows is that there are three USB-serial things, which seem to come and go at random.

What you are requesting is a way for the human user to tell the computer what its intent is. Today, that mechanism is the devd configuration file. The problem with this is that the configuration file is fragile, the syntax and semantics are difficult, and the whole process is quite overwhelming. But all the complexity of devd configuration exists for reasons, namely to support a gigantic zoo of a lot of incompatible, strange, bizarre, and non-standardized devices. Sadly, short of mind-reading, there is no way for the computer to know what my intent was when I plugged in that new device with the longer cable. While I understand your complaint, you can't be asking the kernel developers to start reading your (or my) mind.

I could be cynical and say "AI will solve it, just tell ChatFoo what you want, and it will write the required config files". Fortunately, I happen to know that this statement is bullshit. None of the AI bots have this capability, and will never get it using today's technology (which is scraping everything on the internet and turning it into a hodgepodge of word transition probabilities).
 
The problem is that "the computer" (including the kernel) doesn't have an important piece of information: they human user's intent.
...
What you are requesting is a way for the human user to tell the computer what its intent is.
Perhaps I didn't explain what I wanted very clearly. I apologize, I'm not a native English speaker.

I absolutely don't want to communicate my intentions to the computer. (I'm the boss here, not the computer.) My desires are diametrically opposed: I want the computer to be able to accurately communicate all aspects of the devices connected to it via USB. Then, as an engineer, I can use this information to solve the problem at hand, with varying degrees of elegance.

Now, as it turns out, the situation has a very strange and unfortunate appearance.
1. I connect a peripheral device to the USB bus. (For now, I'm talking about serial ports—they're the main source of headaches.) The kernel detects and connects the device, adding it to its data structures. (It also generates events and reports them to DEVD.)
2. Having figured out that these are COM ports (albeit with some adventures), the kernel creates special files like cuaU and ttyU. As many as six of them for each COM port. It also enters information about this into kernel structures. And it also generates events for the DEVD.
3. It would seem that everything is fine. The COM ports have appeared and are fully functional. But I need to do some post-processing – ln, chown, chmod, and other routine things. For this, I need a mere trifle – to know the names of special files of a specific peripheral device. And everything is fine – I went to do my job, writing configuration files for the DEVD and scripts that they might run.
4. Once again, I don't plan to tell the computer anything about my plans at this stage. I plan to issue a series of precise, clear, and unambiguous commands: create a file link, set its owner, assign it a mask. I just need to know exactly which file I'm talking about.
5. This is where the main piquant detail of this whole story comes to light. It turns out that even knowing the name of the ugenX.Y USB device, I can't get a list of the cuaU and ttyU files created for it. It would seem that this connection is absolutely unambiguous. These files were created specifically for this device and only support this device. But I can't get this information. The reverse path also doesn't work—the cuaU file can't clearly indicate which specific USB device it originated from. (I wrote a C program using the libdevinfo library. It shows by cuaU name a U3G driver with a number, but it doesn't match the major of this terminal special file.)
6. The only thing I can ask is a serious question. Why, in 25 years, has no one figured out that the kernel data structures need to have some kind of cross-references that clearly link all the USB device's special files to the device itself, and vice versa?
 
Interesting. I fear you are correct, but the problem is not isolated to USB.

If I understand you right: Given a /dev/ttyXXX or /dev/cuaXXX device name, you want to know the corresponding /dev/ugenA.B name, or the /dev/usb/A.B.C name. Honestly, I have no idea how to do that. It should be possible, since (as you keep explaining) the kernel knows internally, but I see no interfaces to get that out.

But the problem is more generic, and more complex. For fun, I just plugged in a USB-serial interface into my FreeBSD system (it usually has none), and it was correctly recognized, from dmesg:
Code:
ugen2.2: <FTDI FT232R USB UART> at usbus2
uftdi0 on uhub3
uftdi0: <FT232R USB UART> on usbus2
And a new tty named /dev/ttyU0 and /dev/cuaU0 did appear. Note that uftdi0 is not a device entry. Other than by observing when the ugen and tty/cua devices show up and vanish, I don't know of a way to correlate them with each other.

BUT: exactly the same problem happens to other tty devices. For example, my system has two motherboard serial ports:
Code:
uart0: <16550 or compatible> port 0x3f8-0x3ff irq 4 flags 0x10 on acpi0
uart0: forcing active-hi polarity for IRQ 4
uart1: <16550 or compatible> port 0x2f8-0x2ff irq 3 on acpi0
uart1: forcing active-hi polarity for IRQ 3
And I know of no way other than watching which order they are created in to connect them to /dev/ttyu0 and /dev/ttyu1 (and cua). So this is not specific to USB at all.

It is actually a pretty generic problem: Many devices are simply enumerated. The classic example are disk drives: How do you know which disk drive is /dev/ada0 and which one is /dev/ada1? In that particular case, there are lots of technologies to deal with that, my favorite being to put GPT partition tables with partition names on them, and only ever use the long names for partitions, if necessary embedding in them human-understandable hardware id (like /dev/gpt/seagate_12tb_home or /dev/wd_4tb_boot and variations of that).

And on the other hand, the problem you describe as USB specific does not exist for other USB devices. For example, I can identify the device entries for my keyboard by using usbconfig:
Code:
# usbconfig -d 0.3 -v
ugen0.3: <Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint> at usbus0, cfg=0 md=HOST spd=LOW (1.5Mbps) pwr=ON (100mA)
ugen0.3.0: ukbd0: <Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint, class 0/0, rev 1.10/1.22, addr 3>
ugen0.3.1: uhid0: <Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint, class 0/0, rev 1.10/1.22, addr 3>
and /dev/ukbd0 and /dev/uhid0 are device entries. I think the lack of connection between ugen and actual devices only exists for USB devices that are re-enumerated as a different device class, such as tty and disks. Here is an example, my external disk /dev/da0:
Code:
# usbconfig -d 4.2 -v
ugen4.2: <Seagate Ultra Slim MT> at usbus4, cfg=0 md=HOST spd=SUPER (5.0Gbps) pwr=ON (36mA)
ugen4.2.0: umass0: <Seagate Ultra Slim MT, class 0/0, rev 3.00/1.00, addr 1>
and umass0 then becomes da0.
 
Back
Top