Device targeted mode switching
I'm working on a device that requires supporting and connecting multiple modems simultaneously, and I noticed that usb_modeswitch currently receives info about exactly what device needs mode switching from udev, but then simply switches the last device it finds with the same USB IDs. The result of this is if I use three of the same type of modem, when udev starts it will mode switch one of the modems three times. Not exactly the desired effect.
I think a way to target a single device, maybe using its devnum, would be useful. Especially for manufacturers like Huawei who use the same USB IDs for many of their modems.
I think a way to target a single device, maybe using its devnum, would be useful. Especially for manufacturers like Huawei who use the same USB IDs for many of their modems.
The usb_modeswitch "framework" will do fine if modems are inserted one at a time. But you are right, a simultaneous addition of similar devices may not be handled very well.
Anyway, this application case has not come up until now ...
I will give it some thought - it should be possible to retrieve and pass the bus/dev address from wrapper to binary.
Anyway, this application case has not come up until now ...
I will give it some thought - it should be possible to retrieve and pass the bus/dev address from wrapper to binary.
I have done some work and changed the handling to use the bus/device number. No more ambiguity.
If you want, check out the test versions of data and program package:
http://www.draisberghof.de/usb_modeswit ... ta.tar.bz2
http://www.draisberghof.de/usb_modeswit ... xx.tar.bz2
I tested with two Huaweis (same default ID) on a powered hub that I inserted with the modems powered up already. That's as close as I can simulate your setup ...
If you want, check out the test versions of data and program package:
http://www.draisberghof.de/usb_modeswit ... ta.tar.bz2
http://www.draisberghof.de/usb_modeswit ... xx.tar.bz2
I tested with two Huaweis (same default ID) on a powered hub that I inserted with the modems powered up already. That's as close as I can simulate your setup ...
Installed the beta on our device and initial testing looks good. I'll do some more testing with it, but this seems to handle multiple modem mode switches, and resolves the issue I was having with modems attached to USB hubs chained 2 deep.
I did see another issue with multiple modems, but this has to do with creating the gsmmodem symlinks. Because usb_modeswitch checks if the symlink exists, and then passes the name back to udev, if udev then runs usb_modeswitch again it could return the same symlink because it hasn't been created yet for the other device. My initial though on how to fix this was to have usb_modeswitch_dispatcher create the symlink itself, but the jimsh version I have doesn't include the 'file link' command. Instead I just created a placeholder regular file where the symlink would be created, so then usb_modeswitch would know if that symlink is taken, and when udev got around to installing the symlink, it would just replace the regular file with the correct symlink.
One other issue I noticed was with a modem I have at work: Sierra Wireless Aircard 250U. Now, I know this device isn't mode switched, but I use usb_modeswitch to detect which ttyUSB* port to attempt PPP on, using the gsmmodem symlinks. However, with the 250U, it has 4 ttyUSB* ports on the same USB interface 0.
In this case, the proper tty to use is ttyUSB0. However, the symlink creation in usb_modeswitch would assign the symlinks haphazardly (different ttys and different amount on each power cycle). The different number of symlinks created for this device is probably explained by the previous issue I noted, but when that is resolved then it would just create a symlink for every tty in that interface instead.
I wrote some code to check if there are any lower enumerated ttys in the same interface:
Probably not super useful until there's a mode switched modem that exhibits the same interface, but I thought I'd throw it out there.
Thanks for the help. The less I have to patch the software packages I port to our device, the easier it is to upgrade and maintain them later.
I did see another issue with multiple modems, but this has to do with creating the gsmmodem symlinks. Because usb_modeswitch checks if the symlink exists, and then passes the name back to udev, if udev then runs usb_modeswitch again it could return the same symlink because it hasn't been created yet for the other device. My initial though on how to fix this was to have usb_modeswitch_dispatcher create the symlink itself, but the jimsh version I have doesn't include the 'file link' command. Instead I just created a placeholder regular file where the symlink would be created, so then usb_modeswitch would know if that symlink is taken, and when udev got around to installing the symlink, it would just replace the regular file with the correct symlink.
Code: Select all
@@ -746,6 +764,9 @@
}
if {$idx == 256} {return ""}
+set placeholder [open /dev/$symlinkName w]
+close $placeholder
+
Log "Return symlink name \"$symlinkName\" and exit"
return $symlinkName
Code: Select all
# ls /sys/bus/usb/devices/1-2.2.2:1.0/
bAlternateSetting ep_05 power
bInterfaceClass ep_08 subsystem
bInterfaceNumber ep_81 supports_autosuspend
bInterfaceProtocol ep_82 ttyUSB0
bInterfaceSubClass ep_84 ttyUSB1
bNumEndpoints ep_85 ttyUSB2
driver ep_88 ttyUSB3
ep_02 interface uevent
ep_04 modalias
I wrote some code to check if there are any lower enumerated ttys in the same interface:
Code: Select all
@@ -727,6 +727,24 @@
}
}
}
+
+# Also, some devices have multiple TTYs assocated with a single
+# interface. Check for any lower indexed TTYs, and if found
+# don't return any name. ttyUSB0, of course, needn't worry.
+
+if { $rightPort && ![string equal $myPort "ttyUSB0"] } {
+ Log "\nLooking for lower TTYs in the same interface"
+ set ifDir $ifRoot.$ifNum
+ set otherPorts [glob -nocomplain $ifDir/ttyUSB\[0-9\]*]
+ foreach thisPort $otherPorts {
+ if { [string compare $myPort [file tail $thisPort]] > 0 } {
+ Log "\n--> found a port below me\n"
+ set rightPort 0
+ break
+ }
+ }
+}
+
if {$rightPort == 0} {
Log "Return empty name and exit"
return ""
Thanks for the help. The less I have to patch the software packages I port to our device, the easier it is to upgrade and maintain them later.
That's clever - if it works all the time. I will test on various (some very old) systems.rjenkins wrote:Instead I just created a placeholder regular file where the symlink would be created, so then usb_modeswitch would know if that symlink is taken, and when udev got around to installing the symlink, it would just replace the regular file with the correct symlink.
I'd rather leave the handling of symlinks to udev - no worries about the unplugging process.
Very peculiar, indeed. Didn't know this was even possible ...rjenkins wrote:However, with the 250U, it has 4 ttyUSB* ports on the same USB interface 0.
Anyway, I think there are some improvements possible for your code. It might not be neccessary to check all other interface ttys. Just check if there is one that's lower than your's or not.
Also, "ifDir" is set already when arriving at that point.
Code: Select all
@@ -727,6 +727,24 @@
}
}
}
+
+# Also, some devices have multiple TTYs assocated with a single
+# interface. Check for any lower indexed TTYs, and if found
+# don't return any name. ttyUSB0, of course, needn't worry.
+
+if { $rightPort } {
+ regexp {.*?([0-9]+)$} $myPort d portNum
+ if {$portNum > 0} {
+ Log "\nLooking for lower TTYs in the same interface"
+ if [file exists $ifDir/ttyUSB[incr $portNum -1]] {
+ Log "\n--> found a port below me\n"
+ set rightPort 0
+ }
+ }
+}
+
if {$rightPort == 0} {
Log "Return empty name and exit"
return ""
To be honest, that ambiguity issue was one of the things I knew I would not get through with forever.rjenkins wrote:Thanks for the help. The less I have to patch the software packages I port to our device, the easier it is to upgrade and maintain them later.
So I'm actually grateful for the little push from the real world.
One more thing regarding symlink numbering: I just tested the approach to let udev put a number to the link. In the "rules" file:Then make the script always return just "gsmmodem", and you get the number attached according to the port number.
Example (three modems): "gsmmodem0", "gsmmodem4", "gsmmodem8".
Not very neat, but guaranteed to prevent races.
Code: Select all
... SYMLINK="%c%n"
Example (three modems): "gsmmodem0", "gsmmodem4", "gsmmodem8".
Not very neat, but guaranteed to prevent races.
That's clever, but it does assume that the TTY names allocated to the device will be sequential. I'm not sure if that's a good assumption to make, because it's possible to connect and remove USB devices and end up with non-sequential TTY device names on a multiport USB serial converter. Example:Josh wrote:Anyway, I think there are some improvements possible for your code. It might not be neccessary to check all other interface ttys. Just check if there is one that's lower than your's or not.
Connect two 1-port USB serial adapters, which get enumerated ttyUSB0 & ttyUSB1. Remove the USB serial adapter associated with ttyUSB0, now plug in a 4-port USB serial adapter, which will get enumerated ttyUSB0 & ttyUSB2-4. If you used modems instead of serial adapters then you'd get two symlinks for the 4-port USB modem: ttyUSB0 and ttyUSB2, because they both don't have an interface one index beneath them on the same device.
That said, the 250U does seem to require sequential TTY names, as when I did the above on my workstation it was enumerated ttyUSB2-5 and ttyUSB0 was left un-allocated. I'm not sure if that's a requirement of the sierra driver or the USB subsystem, but it seems safer to check all the other TTYs on the same interface just in case they get allocated differently on some device.
Thanks for that, that will also make it much easier to tell if ttyUSBX is a proper PPP serial port if I only have to check for gsmmodemX, instead of readlink on every gsmmodem link in /dev.Josh wrote:One more thing regarding symlink numbering: I just tested the approach to let udev put a number to the link. In the "rules" file:Then make the script always return just "gsmmodem", and you get the number attached according to the port number.Code: Select all
... SYMLINK="%c%n"
Aw, you have a point there - the ports may not be sequential.
I just stubbornly refuse to accept that a loop is required for that task - can't help it ...
How about this ():BTW, string compare (like in your first version) may run into trouble with higher tty numbers (e.g. above 9) because it sees ttyUSB10 below ttyUSB9 (lexicographical).
lsort does it better with "-dictionary" - unfortunately jimsh doesn't seem to have it.
Oh well, back to square one.
I just stubbornly refuse to accept that a loop is required for that task - can't help it ...
How about this ():
Code: Select all
if { $rightPort } {
Log "\nLooking for lower TTYs in the same interface"
set lowPort [lindex [lsort -dictionary [glob $ifDir/ttyUSB\[0-9\]*]] 0]
regexp {ttyUSB([0-9]+)ttyUSB([0-9]+)} $lowPort$myPort d low my
if { $low < $my } {
Log "\n--> found a port below me\n"
set rightPort 0
}
}
lsort does it better with "-dictionary" - unfortunately jimsh doesn't seem to have it.
Oh well, back to square one.