3 # Wrapper (tcl) for usb_modeswitch, called from
4 # /lib/udev/rules.d/40-usb_modeswitch.rules
5 # (part of data pack "usb-modeswitch-data") via
6 # /lib/udev/usb_modeswitch
8 # Does ID check on newly discovered USB devices and calls
9 # the mode switching program with the matching parameter
10 # file from /usr/share/usb_modeswitch
12 # Part of usb-modeswitch-1.2.6 package
13 # (C) Josua Dietze 2009-2013
15 set arg0
[lindex $argv 0]
16 if [regexp {\.tcl
$} $arg0] {
17 if [file exists
$arg0] {
18 set argv
[lrange $argv 1 end
]
24 # Setting of these switches is done in the global config
25 # file (/etc/usb_modeswitch.conf) if available
28 set flags
(noswitching
) 0
29 set flags
(stordelay
) 0
31 # Execution starts at file bottom
33 proc {Main
} {argv argc
} {
35 global scsi usb config match device flags setup devdir
37 set loginit
[ParseGlobalConfig
]
39 # The facility to add a symbolic link pointing to the
40 # ttyUSB port which provides interrupt transfer, i.e.
41 # the port to connect through.
42 # Will check for interrupt endpoint in ttyUSB port (lowest if
43 # there is more than one); if found, return "gsmmodem[n]" name
44 # to udev for symlink creation
46 # This is run once for every port of LISTED devices by
49 if {[lindex $argv 0] == "--symlink-name"} {
50 puts -nonewline [SymLinkName
[lindex $argv 1]]
54 set argList
[split [lindex $argv 1] /]
55 if [string length
[lindex $argList 1]] {
56 set device
[lindex $argList 1]
61 if {$flags(stordelay
) > 0} {
62 SetStorageDelay
$flags(stordelay
)
65 Log
"Raw args from udev: [lindex $argv 1]\n\n$loginit"
66 if {$device == "noname"} {
67 Log
"No data from udev. Exiting"
71 if {[lindex $argv 0] != "--switch-mode"} {
72 Log
"No command given. Exiting"
76 set setup
(dbdir
) /usr
/share
/usb_modeswitch
77 set setup
(dbdir_etc
) /etc
/usb_modeswitch.d
80 if {![file exists
$setup(dbdir
)] && ![file exists
$setup(dbdir_etc
)]} {
81 Log
"Error: no config database found in /usr/share or /etc. Exiting"
90 # arg 0: the bus id for the device (udev: %b)
91 # arg 1: the "kernel name" for the device (udev: %k)
93 # Used to determine the top directory for the device in sysfs
96 if {[string length
[lindex $argList 0]] == 0} {
97 if {[string length
[lindex $argList 1]] == 0} {
98 Log
"No device number values given from udev! Exiting"
101 if {![regexp {(.
*?
):} [lindex $argList 1] d dev_top
]} {
102 if [regexp {([0-9]+-[0-9]+\.?
[0-9]*.
*)} [lindex $argList 1] d dev_top
] {
103 # new udev rules file, got to check class of first interface
104 Log
"Called by new rules file - remember to check class of first interface ..."
107 Log
"Could not determine device dir from udev values! Exiting"
113 set dev_top
[lindex $argList 0]
114 regexp {(.
*?
):} $dev_top d dev_top
118 #set dev_top [lindex $argList 1]
121 set devdir
/sys
/bus
/usb
/devices
/$dev_top
122 if {![file isdirectory
$devdir]} {
123 Log
"Top device directory not found ($devdir)! Exiting"
126 Log
"Using top device dir $devdir"
129 # Mapping of the short string identifiers (in the config
130 # file names) to the long name used here
132 # If we need them it's a snap to add new attributes here!
134 set match
(sVe
) scsi
(vendor
)
135 set match
(sMo
) scsi
(model
)
136 set match
(sRe
) scsi
(rev
)
137 set match
(uMa
) usb
(manufacturer
)
138 set match
(uPr
) usb
(product
)
139 set match
(uSe
) usb
(serial
)
142 # Now reading the USB attributes
143 if {![ReadUSBAttrs
$devdir]} {
144 Log
"USB attributes not found in sysfs tree. Exiting"
150 Log
"Check class of first interface ..."
151 set iface
[ChkIface
0]
153 set iface
[ChkIface
9]
156 if {$usb(idVendor
)=="19d2" && $usb(idProduct
)=="2000"} {
157 set iface
[ChkIface
3]
159 # Corrected, was wrongly reported
160 # if {$usb(idVendor)=="16d8" && $usb(idProduct)=="6803"} {
161 # set iface [ChkIface 3]
165 Log
" Device is not in install mode. Exiting"
168 Log
" Device is in install mode."
171 set ifdir
[file tail
[IfDir
$iface]]
172 regexp {:([0-9]+\.
[0-9]+)$} $ifdir d iface
174 Log
"Using interface $iface"
178 Log
"----------------\nUSB values from sysfs:"
179 foreach attr
{manufacturer product serial
} {
180 Log
" $attr\t$usb($attr)"
182 Log
"----------------"
185 if $flags(noswitching
) {
186 Log
"\nSwitching globally disabled. Exiting\n"
187 SysLog
"usb_modeswitch: switching disabled, no action for $usb(idVendor):$usb(idProduct)"
191 if {$usb(bNumConfigurations
) == "1"} {
192 set configParam
"-u -1"
193 Log
"bNumConfigurations is 1 - don't check for active configuration"
198 # Check if there is more than one config file for this USB ID,
199 # which would make an attribute test necessary. If so, check if
200 # SCSI values are needed
202 set configList
[ConfigGet conflist
$usb(idVendor
):$usb(idProduct
)]
204 if {[llength $configList] == 0} {
205 Log
"Aargh! Config file missing for $usb(idVendor):$usb(idProduct)! Exiting"
210 if {[llength $configList] > 1} {
211 if [regexp {:s
} $configList] {
216 if [ReadSCSIAttrs
$devdir:$iface] {
217 Log
"----------------\nSCSI values from sysfs:"
218 foreach attr
{vendor model rev
} {
219 Log
" $attr\t$scsi($attr)"
221 Log
"----------------"
223 Log
"Could not get SCSI attributes, exclude devices with SCSI match"
226 Log
"SCSI attributes not needed, moving on"
229 # General wait - this is important
232 # Now check for a matching config file. Matching is done
236 foreach configuration
$configList {
238 # skipping installer leftovers
239 if [regexp {\.
(dpkg|rpm
)} $configuration] {continue}
241 Log
"checking config: $configuration"
242 if [MatchDevice
$configuration] {
243 Log
"! matched. Reading config data"
244 if [string length
$usb(busnum
)] {
245 set busParam
"-b [string trimleft $usb(busnum) 0]"
246 set devParam
"-g [string trimleft $usb(devnum) 0]"
251 set configBuffer
[ConfigGet conffile
$configuration]
252 ParseDeviceConfig
$configBuffer
253 if {$config(waitBefore
) == ""} {
255 Log
" waiting time set to $config(waitBefore) seconds"
256 append config
(waitBefore
) "000"
257 after $config(waitBefore
)
258 Log
" waiting is over, switching starts now"
260 if {$config(noMBIMCheck
)==0 && $usb(bNumConfigurations
) > 1} {
261 Log
"Device may have an MBIM configuration, checking driver ..."
263 Log
" driver for MBIM devices is available"
264 Log
"Finding MBIM configuration number ..."
265 if [catch {set cfgno
[exec /usr
/sbin
/usb_modeswitch
-j -Q $busParam $devParam -v $usb(idVendor
) -p $usb(idProduct
)]} err
] {
266 Log
"Error when trying to find MBIM configuration, switch to legacy modem mode"
268 set cfgno
[string trim
$cfgno]
270 set config
(Configuration
) $cfgno
271 set config
(driverModule
) ""
272 set configBuffer
"Configuration=$cfgno"
274 Log
" No MBIM configuration found, switch to legacy modem mode"
278 Log
" no MBIM driver found, switch to legacy modem mode"
282 # Now we are actually switching
284 Log
"Command to be run:\nusb_modeswitch -W -D -s 20 $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f \$configBuffer"
285 set report
[exec /usr
/sbin
/usb_modeswitch
-W -D -s 20 $configParam $busParam $devParam -v $usb(idVendor
) -p $usb(idProduct
) -f "$configBuffer" 2>@ stdout
]
286 Log
"\nVerbose debug output of usb_modeswitch and libusb follows"
287 Log
"(Note that some USB errors are to be expected in the process)"
288 Log
"--------------------------------"
290 Log
"--------------------------------"
291 Log
"(end of usb_modeswitch output)\n"
293 set report
[exec /usr
/sbin
/usb_modeswitch
-Q -D -s 20 $configParam $busParam $devParam -v $usb(idVendor
) -p $usb(idProduct
) -f "$configBuffer" 2>@ stdout
]
297 Log
"* no match, not switching with this config"
301 # Switching is complete; success checking was either
302 # done by usb_modeswitch and logged via syslog OR bus/dev
303 # parameter were used; then we do check for success HERE
305 if [regexp {ok
:busdev
} $report] {
306 if [CheckSuccess
$devdir] {
307 Log
"Mode switching was successful, found $usb(idVendor):$usb(idProduct) ($usb(manufacturer): $usb(product))"
308 SysLog
"usb_modeswitch: switched to $usb(idVendor):$usb(idProduct) on [format %03d $usb(busnum)]/[format %03d $usb(devnum)]"
310 Log
"\nTarget config not matching - current values are"
311 set attrList
{idVendor idProduct bConfigurationValue manufacturer product serial
}
312 foreach attr
[lsort [array names usb
]] {
313 Log
" [format %-26s $attr:] $usb($attr)"
315 Log
"\nMode switching may have failed. Exiting\n"
319 if {![file isdirectory
$devdir]} {
320 Log
"Device directory in sysfs is gone! Something went wrong, aborting"
323 if {![regexp {ok
:} $report]} {
324 Log
"\nCore program reported switching failure. Exiting\n"
327 # Give the device another second if it's not fully back yet
328 if {![file exists
$devdir/idProduct
]} {
331 ReadUSBAttrs
$devdir $ifdir
334 # Now checking for bound drivers (only for class 0xff)
336 if {$config(driverModule
) != "" && $usb($ifdir/bInterfaceClass
) != "" && [regexp {ok
:} $report]} {
337 if {$usb($ifdir/bInterfaceClass
) != "ff"} {
338 set config
(driverModule
) ""
339 Log
" No vendor-specific class found, skip driver checking"
343 # If module is set (it is by default), driver shall be loaded.
344 # If not, then NoDriverLoading is active
346 if {$config(driverModule
) != ""} {
347 if {[string length
"$usb(idVendor)$usb(idProduct)"] < 8} {
348 if {![regexp {ok
:(\w
{4}):(\w
{4})} $report d usb
(idVendor
) usb
(idProduct
)]} {
349 Log
"No target vendor/product ID found or given, can't continue. Aborting"
353 # wait for any drivers to bind automatically
355 Log
"Now checking for bound driver ..."
356 if {![file exists
$devdir/$ifdir/driver
]} {
357 Log
" no driver has bound to interface 0 yet"
358 AddToList link_list
$usb(idVendor
):$usb(idProduct
)
360 # If device is known, the sh wrapper will take care, else:
361 if {[InBindList
$usb(idVendor
):$usb(idProduct
)] == 0} {
362 Log
"Device is not in \"bind_list\" yet, bind it now"
365 CheckDriverBind
$usb(idVendor
) $usb(idProduct
)
367 # Old/slow systems may take a while to create the devices
369 while {![file exists
$devdir/$ifdir/driver
]} {
370 if {$counter == 14} {break}
374 if {$counter == 14} {
375 Log
" driver binding failed"
377 Log
" driver was bound to the device"
378 AddToList bind_list
$usb(idVendor
):$usb(idProduct
)
382 Log
" driver has bound, device is known"
383 if {[llength [glob -nocomplain $devdir/$ifdir/ttyUSB
*]] > 0} {
384 AddToList link_list
$usb(idVendor
):$usb(idProduct
)
388 # Just in case "NoDriverLoading" was added after the first bind
389 RemoveFromBindList
$usb(idVendor
):$usb(idProduct
)
392 if [regexp {ok
:$} $report] {
393 # "NoDriverLoading" was set
394 Log
"Doing no driver checking or binding for this device"
397 # In newer kernels there is a switch to avoid the use of a device
398 # reset (e.g. from usb-storage) which would possibly switch back
399 # a mode-switching device to initial mode
400 if [regexp {ok
:} $report] {
401 Log
"Checking for AVOID_RESET_QUIRK kernel attribute"
402 if [file exists
$devdir/avoid_reset_quirk
] {
403 if [catch {exec echo
"1" >$devdir/avoid_reset_quirk
2>/dev
/null
} err
] {
404 Log
" Error setting the attribute: $err"
406 Log
" AVOID_RESET_QUIRK activated"
409 Log
" not present in this kernel"
413 Log
"\nAll done, exiting\n"
420 proc {ReadSCSIAttrs
} {topdir
} {
425 Log
"Checking storage tree in sysfs ..."
426 while {$counter < 20} {
427 Log
" loop $counter/20"
428 if {![file isdirectory
$sysdir]} {
429 # Device is gone. Unplugged? Switched by kernel?
430 Log
" sysfs device tree is gone; abort SCSI value check"
433 # Searching the storage/SCSI tree; might take a while
434 if {[set dirList
[glob -nocomplain $topdir/host
*]] != ""} {
435 set sysdir
[lindex $dirList 0]
436 if {[set dirList
[glob -nocomplain $sysdir/target
*]] != ""} {
437 set sysdir
[lindex $dirList 0]
438 regexp {.
*target
(.
*)} $sysdir d subdir
439 if {[set dirList
[glob -nocomplain $sysdir/$subdir*]] != ""} {
440 set sysdir
[lindex $dirList 0]
441 if [file exists
$sysdir/vendor
] {
442 Log
" Storage tree is ready"
451 if {$counter == 20} {
452 Log
"SCSI tree not found; you may want to check if this path/file exists:"
453 Log
"$sysdir/vendor\n"
457 Log
"Reading SCSI values ..."
458 foreach attr
{vendor model rev
} {
459 if [file exists
$sysdir/$attr] {
460 set rc
[open $sysdir/$attr r
]
461 set scsi
($attr) [read -nonewline $rc]
465 Log
"Warning: SCSI attribute \"$attr\" not found."
471 # end of proc {ReadSCSIAttrs}
474 proc {ReadUSBAttrs
} {dir args
} {
478 set attrList
{idVendor idProduct bConfigurationValue manufacturer product serial devnum busnum bNumConfigurations
}
479 set mandatoryList
{idVendor idProduct bNumConfigurations
}
482 lappend attrList
"$args/bInterfaceClass"
483 lappend mandatoryList
"$args/bInterfaceClass"
485 foreach attr
$attrList {
486 if [file exists
$dir/$attr] {
487 set rc
[open $dir/$attr r
]
488 set usb
($attr) [string trim
[read -nonewline $rc]]
492 if {[lsearch $mandatoryList $attr] > -1} {
495 if {$attr == "serial"} {continue}
496 Log
" Warning: USB attribute \"$attr\" not found"
502 # end of proc {ReadUSBAttrs}
505 proc {MatchDevice
} {config
} {
507 global scsi usb match
509 set devinfo
[file tail
$config]
510 set infoList
[split $devinfo :]
511 set stringList
[lrange $infoList 2 end
]
512 if {[llength $stringList] == 0} {return 1}
514 foreach teststring
$stringList {
515 if {$teststring == "?"} {return 0}
516 set tokenList
[split $teststring =]
517 set id
[lindex $tokenList 0]
518 set matchstring
[lindex $tokenList 1]
520 regsub -all {_
} $matchstring { } blankstring
521 Log
"matching $match($id)"
522 Log
" match string1 (exact): $matchstring"
523 Log
" match string2 (blanks): $blankstring"
524 Log
" device string: [set $match($id)]"
525 if {!([string match
*$matchstring* [set $match($id)]] ||
[string match
*$blankstring* [set $match($id)]])} {
532 # end of proc {MatchDevice}
535 proc {ParseGlobalConfig
} {} {
539 set places
[list /etc
/usb_modeswitch.conf
/etc
/sysconfig
/usb_modeswitch
/etc
/default/usb_modeswitch
]
540 foreach cfg
$places {
541 if [file exists
$cfg] {
546 if {$configFile == ""} {return}
548 set rc
[open $configFile r
]
551 if [regexp {^
#} [string trim $line]] {continue}
552 if [regexp {DisableSwitching
\s
*=\s
*([^
\s
]+)} $line d val
] {
553 if [regexp -nocase {1|yes|true
} $val] {
554 set flags
(noswitching
) 1
557 if [regexp {EnableLogging
\s
*=\s
*([^
\s
]+)} $line d val
] {
558 if [regexp -nocase {1|yes|true
} $val] {
562 if [regexp {SetStorageDelay
\s
*=\s
*([^
\s
]+)} $line d val
] {
563 if [regexp {\d
+} $val] {
564 set flags
(stordelay
) $val
569 return "Using global config file: $configFile"
572 # end of proc {ParseGlobalConfig}
575 proc ParseDeviceConfig
{configContent
} {
578 set config
(driverModule
) ""
579 set config
(driverIDPath
) ""
580 set config
(waitBefore
) ""
581 set config
(targetVendor
) ""
582 set config
(targetProduct
) ""
583 set config
(targetClass
) ""
584 set config
(Configuration
) ""
585 set config
(noMBIMCheck
) 0
586 set config
(checkSuccess
) 20
589 if [regexp -line {^
[^
#]*?TargetVendor.*?=.*?0x(\w+).*?$} $configContent d config(targetVendor)] {
590 Log
"config: TargetVendor set to $config(targetVendor)"
592 if [regexp -line {^
[^
#]*?TargetProduct.*?=.*?0x(\w+).*?$} $configContent d config(targetProduct)] {
593 Log
"config: TargetProduct set to $config(targetProduct)"
595 if [regexp -line {^
[^
#]*?TargetProductList.*?=.*?"([0-9a-fA-F,]+).*?$} $configContent d config(targetProduct)] {
596 Log
"config: TargetProductList set to $config(targetProduct)"
598 if [regexp -line {^
[^
#]*?TargetClass.*?=.*?0x(\w+).*?$} $configContent d config(targetClass)] {
599 Log
"config: TargetClass set to $config(targetClass)"
601 if [regexp -line {^
[^
#]*?Configuration.*?=.*?([0-9]+).*?$} $configContent d config(Configuration)] {
602 Log
"config: Configuration (target) set to $config(Configuration)"
604 if [regexp -line {^
[^
#]*?DriverModule.*?=.*?(\w+).*?$} $configContent d config(driverModule)] {
605 Log
"config: DriverModule set to $config(driverModule)"
607 if [regexp -line {^
[^
#]*?DriverIDPath.*?=.*?"?([/\-\w]+).*?$} $configContent d config(driverIDPath)] {
608 Log
"config: DriverIDPath set to $config(driverIDPath)"
610 if [regexp -line {^
[^
#]*?CheckSuccess.*?=.*?([0-9]+).*?$} $configContent d config(checkSuccess)] {
611 Log
"config: CheckSuccess set to $config(checkSuccess)"
613 if [regexp -line {^
[^
#]*?WaitBefore.*?=.*?([0-9]+).*?$} $configContent d config(waitBefore)] {
614 Log
"config: WaitBefore set to $config(waitBefore)"
616 if [regexp -line {^
[^
#]*?NoMBIMCheck.*?=.*?([0-9]+).*?$} $configContent d config(noMBIMCheck)] {
617 Log
"config: noMBIMCheck set to $config(noMBIMCheck)"
619 if [regexp -line {^
[^
#]*?NoDriverLoading.*?=.*?(1|yes|true).*?$} $configContent] {
621 Log
"config: NoDriverLoading is set to active"
624 # For general driver loading; TODO: add respective device names.
625 # Presently only useful for HSO devices (which are recounted now)
627 if {$config(driverModule
) == ""} {
628 set config
(driverModule
) "option"
629 set config
(driverIDPath
) "/sys/bus/usb-serial/drivers/option1"
631 if {$config(driverIDPath
) == ""} {
632 set config
(driverIDPath
) "/sys/bus/usb/drivers/$config(driverModule)"
635 Log
"Driver module is \"$config(driverModule)\", ID path is $config(driverIDPath)\n"
637 Log
"Driver will not be handled by usb_modeswitch"
639 set config
(waitBefore
) [string trimleft
$config(waitBefore
) 0]
642 # end of proc {ParseDeviceConfig}
645 proc ConfigGet
{command config
} {
652 # Unpackaged configs first; sorting is essential for priority
653 set configList
[lsort -decreasing [glob -nocomplain $setup(dbdir_etc
)/$config*]]
654 set configList
[concat $configList [lsort -decreasing [glob -nocomplain $setup(dbdir
)/$config*]]]
655 if [file exists
$setup(dbdir
)/configPack.tar.gz
] {
656 Log
"Found packed config collection $setup(dbdir)/configPack.tar.gz"
657 if [catch {set packedList
[exec tar
-tzf $setup(dbdir
)/configPack.tar.gz
2>/dev
/null
]} err
] {
658 Log
"Error: problem opening config package; tar returned\n $err"
661 set packedList
[split $packedList \n]
662 set packedConfigList
[lsort -decreasing [lsearch -glob -all -inline $packedList $config*]]
663 # Now add packaged configs with a mark, again sorted for priority
664 foreach packedConfig
$packedConfigList {
665 lappend configList
"pack/$packedConfig"
672 if [regexp {^
pack/} $config] {
673 set config
[regsub {pack/} $config {}]
674 Log
"Extracting config $config from collection $setup(dbdir)/configPack.tar.gz"
675 set configContent
[exec tar
-xzOf $setup(dbdir
)/configPack.tar.gz
$config 2>/dev
/null
]
677 if [regexp [list $setup(dbdir_etc
)] $config] {
678 Log
"Using config file from override folder $setup(dbdir_etc)"
679 SysLog
"usb_modeswitch: using overriding config file $config; make sure this is intended"
680 SysLog
"usb_modeswitch: please report any new or corrected settings; otherwise, check for outdated files"
682 set rc
[open $config r
]
683 set configContent
[read $rc]
686 return $configContent
691 # end of proc {ConfigGet}
697 if {$flags(logging
) == 0} {return}
698 if {![info exists flags
(wc
)]} {
699 if [catch {set flags
(wc
) [open /var
/log
/usb_modeswitch_
$device w
]} err
] {
700 if [catch {set flags
(wc
) [open /dev
/console w
]} err
] {
701 set flags
(wc
) "error"
704 puts $flags(wc
) "Error opening log file ($err), redirect to console"
707 puts $flags(wc
) "\n\nUSB_ModeSwitch log from [clock format [clock seconds]]\n"
709 if {$flags(wc
) == "error"} {return}
716 # Closing the log file if open and exit
720 if [info exists flags
(wc
)] {
721 catch {close $flags(wc
)}
726 # end of proc {SafeExit}
729 proc {SymLinkName
} {path
} {
732 proc {hasInterrupt
} {ifDir
} {
733 if {[llength [glob -nocomplain $ifDir/ttyUSB
*]] == 0} {
734 Log
" no ttyUSB interface - skip checking endpoints"
737 foreach epDir
[glob -nocomplain $ifDir/ep_
*] {
738 set e
[file tail
$epDir]
739 Log
" checking $e ..."
740 if [file exists
$epDir/type
] {
741 set rc
[open $epDir/type r
]
744 if [regexp {Interrupt
} $type] {
745 Log
" $e has interrupt transfer type"
753 set loginit
"usb_modeswitch called with --symlink-name\n parameter: $path\n"
755 # In case the device path is returned as /class/tty/ttyUSB,
756 # get the USB device path from linked tree "device"
757 set linkpath
/sys
$path/device
758 if [file exists
$linkpath] {
759 if {[file type
$linkpath] == "link"} {
760 set rawpath
[file readlink
$linkpath]
761 set trimpath
[regsub -all {\.
\.
/} $rawpath {}]
762 if [file isdirectory
/sys
/$trimpath] {
763 append loginit
"\n Using path $path\n"
769 if {![regexp {ttyUSB
[0-9]+} $path myPort
]} {
771 set device
[clock clicks
]
772 Log
"$loginit\nThis is not a ttyUSB port. Aborting"
778 Log
"$loginit\nMy name is $myPort\n"
780 if {![regexp {(.
*?
[0-9]+)\.
([0-9]+)/ttyUSB
} /sys
$path d ifRoot ifNum
]} {
781 Log
"Could not find interface in path\n $path. Aborting"
785 set ifDir
$ifRoot.
$ifNum
787 Log
"Checking my endpoints ...\n in $ifDir"
788 if [hasInterrupt
$ifDir] {
789 Log
"\n--> I am an interrupt port"
792 Log
"\n--> I am not an interrupt port\n"
796 # There are devices with more than one interrupt interface.
797 # Assume that the lowest of these is usable. Check all
798 # possible lower interfaces
800 if { $rightPort && ($ifNum > 0) } {
801 Log
"\nLooking for lower ports with interrupt endpoints"
802 for {set i
0} {$i < $ifNum} {incr i
} {
804 Log
" in ifDir $ifDir ..."
805 if [hasInterrupt
$ifDir] {
806 Log
"\n--> found an interrupt interface below me\n"
812 if {$rightPort == 0} {
813 Log
"Return empty name and exit"
817 Log
"\n--> No interrupt interface below me\n"
821 set symlinkName
"gsmmodem"
823 if {![file exists
$symlinkName]} {
824 set placeholder
[open /dev
/$symlinkName w
]
828 set symlinkName gsmmodem
$idx
831 if {$idx == 256} {return ""}
833 Log
"Return symlink name \"$symlinkName\" and exit"
837 # end of proc {SymLinkName}
840 # Load and bind driver (default "option")
842 proc {CheckDriverBind
} {vid
pid} {
845 foreach fn
{/sbin
/modprobe
/usr
/sbin
/modprobe
} {
846 if [file exists
$fn] {
850 Log
"Module loader is $loader"
852 set idfile
$config(driverIDPath
)/new_id
853 if {![file exists
$idfile]} {
855 Log
"Can't do anymore without module loader; get \"modtools\"!"
858 Log
"\nTrying to load module \"$config(driverModule)\""
859 if [catch {set result
[exec $loader -v $config(driverModule
)]} err
] {
860 Log
" Running \"$loader $config(driverModule)\" gave an error:\n $err"
862 Log
" Module was loaded successfully:\n$result"
865 Log
"Module is active already"
869 if [file exists
$idfile] {
876 Log
"Trying to add ID to driver \"$config(driverModule)\""
877 SysLog
"usb_modeswitch: adding device ID $vid:$pid to driver \"$config(driverModule)\""
878 SysLog
"usb_modeswitch: please report the device ID to the Linux USB developers!"
879 if [catch {exec echo
"$vid $pid ff" >$idfile} err
] {
880 Log
" Error adding ID to driver:\n $err"
882 Log
" ID added to driver; check for new devices in /dev"
885 Log
" \"$idfile\" not found, check if kernel version is at least 2.6.27"
886 Log
"Falling back to \"usbserial\""
887 set config
(driverModule
) usbserial
888 Log
"\nTrying to unload driver \"usbserial\""
889 if [catch {exec $loader -r usbserial
} err
] {
890 Log
" Running \"$loader -r usbserial\" gave an error:\n $err"
891 Log
"No more fallbacks"
895 Log
"\nTrying to load driver \"usbserial\" with device IDs"
896 if [catch {set result
[exec $loader -v usbserial vendor
=0x
$vid product
=0x
$pid]} err
] {
897 Log
" Running \"$loader usbserial\" gave an error:\n $err"
899 Log
" Driver was loaded successfully:\n$result"
904 # end of proc {CheckDriverBind}
907 # Check if USB ID is listed as needing driver binding
908 proc {InBindList
} {id
} {
910 set listfile
/var
/lib
/usb_modeswitch
/bind_list
911 if {![file exists
$listfile]} {return 0}
912 set rc
[open $listfile r
]
913 set buffer
[read $rc]
915 if [string match
*$id* $buffer] {
916 Log
"Found $id in bind_list"
919 Log
"No $id in bind_list"
924 # end of proc {InBindList}
926 # Add USB ID to list of devices needing later treatment
927 proc {AddToList
} {name id
} {
929 set listfile
/var
/lib
/usb_modeswitch
/$name
930 set oldlistfile
/etc
/usb_modeswitch.d
/bind_list
932 if {($name == "bind_list") && [file exists
$oldlistfile] && ![file exists
$listfile]} {
933 if [catch {file rename $oldlistfile $listfile} err
] {
934 Log
"Error renaming the old bind list file ($err)"
939 if [file exists
$listfile] {
940 set rc
[open $listfile r
]
941 set buffer
[read $rc]
943 if [string match
*$id* $buffer] {
946 set idList
[split [string trim
$buffer] \n]
949 set buffer
[join $idList "\n"]
950 if [catch {set lc
[open $listfile w
]}] {return}
955 # end of proc {AddToList}
958 # Remove USB ID from bind list (NoDriverLoading is set)
959 proc {RemoveFromBindList
} {id
} {
961 set listfile
/var
/lib
/usb_modeswitch
/bind_list
962 if [file exists
$listfile] {
963 set rc
[open $listfile r
]
964 set buffer
[read $rc]
966 set idList
[split [string trim
$buffer] \n]
970 set idx
[lsearch $idList $id]
972 set idList
[lreplace $idList $idx $idx]
976 if {[llength $idList] == 0} {
977 file delete
$listfile
980 set buffer
[join $idList "\n"]
981 if [catch {set lc
[open $listfile w
]}] {return}
986 # end of proc {RemoveFromBindList}
989 proc {CheckSuccess
} {devdir
} {
992 set ifdir
[file tail
[IfDir
0]]
994 if {[string length
$config(targetClass
)] ||
[string length
$config(Configuration
)]} {
995 set config
(targetVendor
) $usb(idVendor
)
996 set config
(targetProduct
) $usb(idProduct
)
998 Log
"Checking success of mode switch for max. $config(checkSuccess) seconds ..."
1000 for {set i
1} {$i <= $config(checkSuccess
)} {incr i
} {
1002 if {![file isdirectory
$devdir]} {
1003 Log
" Waiting for device file system ($i sec.) ..."
1006 Log
" Reading attributes ..."
1009 if {$ifdir == ""} {continue}
1010 set ifdir
[file tail
$ifdir]
1011 if {![ReadUSBAttrs
$devdir $ifdir]} {
1012 Log
" Essential attributes are missing, continue wait ..."
1015 if [string length
$config(targetClass
)] {
1016 if {![regexp $usb($ifdir/bInterfaceClass
) $config(targetClass
)]} {continue}
1018 if [string length
$config(Configuration
)] {
1019 if {$usb(bConfigurationValue
) != $config(Configuration
)} {continue}
1021 if {![regexp $usb(idVendor
) $config(targetVendor
)]} {continue}
1022 if {![regexp $usb(idProduct
) $config(targetProduct
)]} {continue}
1023 Log
" All attributes matched"
1032 # end of proc {CheckSuccess}
1035 proc {ChkIface
} {iface
} {
1037 if {[IfClass
$iface] == 8} {
1044 # end of proc {ChkIface}
1046 proc {IfDir
} {iface
} {
1049 set allfiles
[glob -nocomplain $devdir/*]
1050 set files
[glob -nocomplain $devdir/*.
$iface]
1051 if {[llength $files] == 0} {
1054 set ifdir
[lindex $files 0]
1055 if {![file isdirectory
$ifdir]} {
1061 # end of proc {IfDir}
1063 proc {IfClass
} {iface
} {
1065 set ifdir
[IfDir
$iface]
1067 if {![file exists
$ifdir/bInterfaceClass
]} {
1070 set rc
[open $ifdir/bInterfaceClass r
]
1073 return [string trimleft
[string trim
$c] 0]
1076 # end of proc {IfClass}
1079 proc {SysLog
} {msg
} {
1082 if {![info exists flags
(logger
)]} {
1083 set flags
(logger
) ""
1084 foreach fn
{/bin
/logger
/usr
/bin
/logger
} {
1085 if [file exists
$fn] {
1086 set flags
(logger
) $fn
1089 Log
"Logger is $flags(logger)"
1091 if {$flags(logger
) == ""} {
1092 Log
"Can't add system message, no syslog helper found"
1095 catch {exec $flags(logger
) -p syslog.notice
"$msg" 2>/dev
/null
}
1098 # end of proc {SysLog}
1100 proc {SetStorageDelay
} {secs
} {
1102 Log
"Adjusting delay for USB storage devices ..."
1103 set attrib
/sys
/module
/usb_storage
/parameters
/delay_use
1104 if {![file exists
$attrib]} {
1105 Log
"Error: could not find delay_use attribute"
1108 if [catch {set ch
[open $attrib r
+]} err
] {
1109 Log
"Error: could not access delay_use attribute: $err"
1112 if {[read $ch] < $secs} {
1114 puts -nonewline $ch $secs
1115 Log
" Delay set to $secs seconds\n"
1117 Log
" Current value is higher than $secs. Leave it alone\n"
1122 # end of proc {SetStorageDelay}
1124 proc {CheckMBIM
} {} {
1126 set kversion
[exec uname
-r]
1127 if [file exists
/lib
/modules
/$kversion/kernel
/drivers
/net
/usb
/cdc_mbim.ko
] {return 1}
1128 if [file exists
/sys
/bus
/usb
/drivers
/cdc_mbim
] {return 1}
1134 # The actual entry point