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-2.4.0 package
13 # (C) Josua Dietze 2009-2016
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 # also settable in device config files
34 # Execution starts at file bottom
36 proc {Main
} {argv argc
} {
38 global scsi usb config match device flags setup devdir loginit
41 Log
"[ParseGlobalConfig]"
43 # The facility to add a symbolic link pointing to the
44 # ttyUSB port which provides interrupt transfer, i.e.
45 # the port to connect through.
46 # Will check for interrupt endpoint in ttyUSB port (lowest if
47 # there is more than one); if found, return "gsmmodem[n]" name
48 # to udev for symlink creation
50 # This is run once for every port of LISTED devices by
53 if {[lindex $argv 0] == "--symlink-name"} {
54 puts -nonewline [SymLinkName
[lindex $argv 1]]
58 if {[lindex $argv 0] == "--switch-systemd"} {
59 set argList
[split [lindex $argv 1] _
]
60 Log
"\nStarted via systemd"
62 if {[lindex $argv 0] == "--switch-upstart"} {
63 Log
"\nStarted via upstart"
65 set argList
[split [lindex $argv 1] /]
67 if [string length
[lindex $argList 1]] {
68 set device
[lindex $argList 1]
72 if {$flags(stordelay
) > 0} {
73 SetStorageDelay
$flags(stordelay
)
76 Log
"Raw args from udev: [lindex $argv 1]\n"
78 if {$device == "noname"} {
79 Log
"\nNo data from udev. Exit"
83 if {![regexp -- {--switch-} [lindex $argv 0]]} {
84 Log
"\nNo command given. Exit"
88 set setup
(dbdir
) /usr
/share
/usb_modeswitch
89 set setup
(dbdir_etc
) /etc
/usb_modeswitch.d
92 if {![file exists
$setup(dbdir
)] && ![file exists
$setup(dbdir_etc
)]} {
93 Log
"\nError: no config database found in /usr/share or /etc. Exit"
102 # arg 0: the bus id for the device (udev: %b), often ommitted
103 # arg 1: the "kernel name" for the device (udev: %k)
105 # Used to determine the top directory for the device in sysfs
108 if {[string length
[lindex $argList 0]] == 0} {
109 if {[string length
[lindex $argList 1]] == 0} {
110 Log
"No device number values given from udev! Exit"
113 if {![regexp {(.
*?
):} [lindex $argList 1] d dev_top
]} {
114 if {![regexp {([0-9]+-[0-9]+\.?
[0-9]*.
*)} [lindex $argList 1] d dev_top
]} {
115 Log
"Could not determine device dir from udev values! Exit"
121 set dev_top
[lindex $argList 0]
122 regexp {(.
*?
):} $dev_top d dev_top
125 set devdir
/sys
/bus
/usb
/devices
/$dev_top
126 if {![file isdirectory
$devdir]} {
127 Log
"Top device directory not found ($devdir)! Exit"
130 Log
"Use top device dir $devdir"
133 Log
"Check class of first interface ..."
134 set config
(class
) [IfClass
0 $devdir]
135 if {$config(class
) < 0} {
136 Log
" No access to interface 0. Exit"
139 Log
" Interface 0 class is $config(class)."
141 set ifdir
[file tail
[IfDir
$iface $devdir]]
142 regexp {:([0-9]+\.
[0-9]+)$} $ifdir d iface
144 set flags
(logwrite
) 1
146 # Mapping of the short string identifiers (in the config
147 # file names) to the long name used here
149 # If we need them it's a snap to add new attributes here!
151 set match
(sVe
) scsi
(vendor
)
152 set match
(sMo
) scsi
(model
)
153 set match
(sRe
) scsi
(rev
)
154 set match
(uMa
) usb
(manufacturer
)
155 set match
(uPr
) usb
(product
)
156 set match
(uSe
) usb
(serial
)
159 # Now reading the USB attributes
160 if {![ReadUSBAttrs
$devdir]} {
161 Log
"USB attributes not found in sysfs tree. Exit"
164 set config
(vendor
) $usb(idVendor
)
165 set config
(product
) $usb(idProduct
)
169 Log
"\n----------------\nUSB values from sysfs:"
170 foreach attr
{manufacturer product serial
} {
171 Log
" $attr\t$usb($attr)"
173 Log
"----------------"
176 if $flags(noswitching
) {
177 SysLog
"usb_modeswitch: switching disabled, no action for $usb(idVendor):$usb(idProduct)"
178 Log
"\nSwitching globally disabled. Exit"
182 if {$usb(bNumConfigurations
) == "1"} {
183 set configParam
"-u -1"
184 Log
"bNumConfigurations is 1 - don't check for active configuration"
189 # Check (and switch) for operating system if Huawei device present
191 set flags
(os
) "linux"
192 if {$usb(idVendor
) == "12d1" && [regexp -nocase {android
} [exec cat
/proc/version
]]} {
193 set flags
(os
) "android"
195 if {$flags(os
) == "android"} {
196 set configList
[ConfigGet conflist
$usb(idVendor
):#android]
198 set configList
[ConfigGet conflist
$usb(idVendor
):$usb(idProduct
)]
201 if {[llength $configList] == 0} {
202 Log
"Aargh! Config file missing for $usb(idVendor):$usb(idProduct)! Exit"
205 Log
"ConfigList: $configList"
207 # Check if there is more than one config file for this USB ID,
208 # which would make an attribute test necessary. If so, check if
209 # SCSI values are needed
212 if {[llength $configList] > 1} {
213 if [regexp {:s
} $configList] {
218 if [ReadSCSIAttrs
$devdir:$iface] {
219 Log
"----------------\nSCSI values from sysfs:"
220 foreach attr
{vendor model rev
} {
221 Log
" $attr\t$scsi($attr)"
223 Log
"----------------"
225 Log
"Could not get SCSI attributes, exclude devices with SCSI match"
228 Log
"SCSI attributes not needed, move on"
231 # General wait - some devices need this
234 # Now check for a matching config file. Matching is done
238 foreach mconfig
$configList {
240 # skipping installer leftovers like "*.rpmnew"
241 if [regexp {\.
(dpkg|rpm
)} $mconfig] {continue}
243 Log
"Check config: $mconfig"
244 if [MatchDevice
$mconfig] {
245 Log
"! matched. Read config data"
246 # set flags(config) $mconfig
247 if [string length
$usb(busnum
)] {
248 set busParam
"-b [string trimleft $usb(busnum) 0]"
249 set devParam
"-g [string trimleft $usb(devnum) 0]"
254 set flags
(config
) [ConfigGet conffile
$mconfig]
255 ParseDeviceConfig
$flags(config
)
256 if [regexp -nocase {/[0-9a-f
]+:#} $flags(config)] {
257 Log
"Note: Using generic manufacturer configuration for \"$flags(os)\""
260 set config
(NoMBIMCheck
) 1
262 if {$config(WaitBefore
) != ""} {
263 Log
"Delay time of $config(WaitBefore) seconds"
264 append config
(WaitBefore
) "000"
265 after $config(WaitBefore
)
266 Log
" wait is over, start mode switch"
268 if {$config(NoMBIMCheck
)==0 && $usb(bNumConfigurations
) > 1} {
269 Log
"Device may have an MBIM configuration, check driver ..."
271 Log
" driver for MBIM devices is available"
272 Log
"Find MBIM configuration number ..."
273 if [catch {set cfgno
[exec /usr
/sbin
/usb_modeswitch
-j -Q $busParam $devParam -v $usb(idVendor
) -p $usb(idProduct
)]} err
] {
274 Log
"Error when trying to find MBIM configuration, switch to legacy modem mode"
276 set cfgno
[string trim
$cfgno]
278 set config
(Configuration
) $cfgno
279 set flags
(config
) "Configuration=$cfgno"
281 Log
" No MBIM configuration found, switch to legacy modem mode"
285 Log
" no MBIM driver found, switch to legacy modem mode"
288 if [PantechAutoSwitch
] {
289 Log
"Waiting for Pantech auto-modeswitch"
290 set report
"ok:busdev"
293 if {$config(Configuration
) == 0} {
294 Log
"Config file contains dummy method, do nothing. Exit"
297 UnbindDriver
$devdir $ifdir
298 # Now we are actually switching
300 Log
"Command to be run:\nusb_modeswitch -W -D $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f \$flags(config)"
301 set report
[exec /usr
/sbin
/usb_modeswitch
-W -D $configParam $busParam $devParam -v $usb(idVendor
) -p $usb(idProduct
) -f "$flags(config)" 2>@1]
302 Log
"\nVerbose debug output of usb_modeswitch and libusb follows"
303 Log
"(Note that some USB errors are to be expected in the process)"
304 Log
"--------------------------------"
306 Log
"--------------------------------"
307 Log
"(end of usb_modeswitch output)\n"
309 set report
[exec /usr
/sbin
/usb_modeswitch
-Q -D $configParam $busParam $devParam -v $usb(idVendor
) -p $usb(idProduct
) -f "$flags(config)" 2>@1]
313 Log
"* no match, don't use this config"
317 # Switching is complete; success checking was either
318 # done by usb_modeswitch and logged via syslog OR bus/dev
319 # parameter were used; then we do check for success HERE
321 if {$config(Configuration
) != ""} {
322 set ifdir
[regsub {(\d
):\d
+\.0} $ifdir "\\1:$config(Configuration).0"]
325 if [regexp {ok
:busdev
} $report] {
326 if [CheckSuccess
$devdir] {
327 Log
"Mode switching was successful, found $usb(idVendor):$usb(idProduct) ($usb(manufacturer): $usb(product))"
328 SysLog
"usb_modeswitch: switched to $usb(idVendor):$usb(idProduct) on [format %03d $usb(busnum)]/[format %03d $usb(devnum)]"
330 Log
"\nTarget config not matching - current values are"
332 Log
"\nMode switching may have failed. Exit"
336 if {![file isdirectory
$devdir]} {
337 Log
"Device directory in sysfs is gone! Something went wrong, abort"
340 if {![regexp {ok
:} $report]} {
341 Log
"\nCore program reported switching failure. Exit"
344 # Give the device another second if it's not fully back yet
345 if {![file exists
$devdir/idProduct
]} {
348 ReadUSBAttrs
$devdir $ifdir
351 # driver binding removed !!
353 if {[string length
"$usb(idVendor)$usb(idProduct)"] < 8} {
354 if {![regexp {ok
:(\w
{4}):(\w
{4})} $report d usb
(idVendor
) usb
(idProduct
)]} {
355 Log
"No target vendor/product ID found or given, can't continue. Abort"
359 # wait for drivers to bind
361 if {[llength [glob -nocomplain $devdir/$ifdir/ttyUSB
*]] > 0} {
362 Log
"Serial USB driver bound to interface 0\n will try to guess and symlink modem port on next connect"
363 AddToList link_list
$usb(idVendor
):$usb(idProduct
)
366 # In newer kernels there is a switch to avoid the use of a device
367 # reset (e.g. from usb-storage) which would possibly switch back
368 # a mode-switching device to initial mode
369 if [regexp {ok
:} $report] {
370 Log
"Check for AVOID_RESET_QUIRK kernel attribute"
371 if [file exists
$devdir/avoid_reset_quirk
] {
372 if [catch {exec echo
"1" >$devdir/avoid_reset_quirk
2>/dev
/null
} err
] {
373 Log
" Error setting the attribute: $err"
375 Log
" AVOID_RESET_QUIRK activated"
378 Log
" not present in this kernel"
382 Log
"\nAll done, exit\n"
389 proc {ReadSCSIAttrs
} {topdir
} {
394 Log
"Check storage tree in sysfs ..."
395 while {$counter < 20} {
396 Log
" loop $counter/20"
397 if {![file isdirectory
$sysdir]} {
398 # Device is gone. Unplugged? Switched by kernel?
399 Log
" sysfs device tree is gone; abort SCSI value check"
402 # Searching the storage/SCSI tree; might take a while
403 if {[set dirList
[glob -nocomplain $topdir/host
*]] != ""} {
404 set sysdir
[lindex $dirList 0]
405 if {[set dirList
[glob -nocomplain $sysdir/target
*]] != ""} {
406 set sysdir
[lindex $dirList 0]
407 regexp {.
*target
(.
*)} $sysdir d subdir
408 if {[set dirList
[glob -nocomplain $sysdir/$subdir*]] != ""} {
409 set sysdir
[lindex $dirList 0]
410 if [file exists
$sysdir/vendor
] {
411 Log
" Storage tree is ready"
420 if {$counter == 20} {
421 Log
"SCSI tree not found; you may want to check if this path/file exists:"
422 Log
"$sysdir/vendor\n"
426 Log
"Read SCSI values ..."
427 foreach attr
{vendor model rev
} {
428 if [file exists
$sysdir/$attr] {
429 set rc
[open $sysdir/$attr r
]
430 set scsi
($attr) [read -nonewline $rc]
434 Log
"Warning: SCSI attribute \"$attr\" not found."
440 # end of proc {ReadSCSIAttrs}
443 proc {ReadUSBAttrs
} {dir args
} {
447 set attrList
{idVendor idProduct bConfigurationValue manufacturer product serial devnum busnum bNumConfigurations
}
448 set mandatoryList
{idVendor idProduct bNumConfigurations
}
451 lappend attrList
"$args/bInterfaceClass"
452 lappend mandatoryList
"$args/bInterfaceClass"
454 foreach attr
$attrList {
455 if [file exists
$dir/$attr] {
456 set rc
[open $dir/$attr r
]
457 set usb
($attr) [string trim
[read -nonewline $rc]]
461 if {[lsearch $mandatoryList $attr] > -1} {
464 if {$attr == "serial"} {continue}
465 Log
" Warning: USB attribute \"$attr\" not found"
471 # end of proc {ReadUSBAttrs}
474 proc {MatchDevice
} {config
} {
476 global scsi usb match
478 set devinfo
[file tail
$config]
479 set infoList
[split $devinfo :]
480 set stringList
[lrange $infoList 2 end
]
481 if {[llength $stringList] == 0} {return 1}
483 foreach teststring
$stringList {
484 if {$teststring == "?"} {return 0}
485 set tokenList
[split $teststring =]
486 set id
[lindex $tokenList 0]
487 set matchstring
[lindex $tokenList 1]
489 regsub -all {_
} $matchstring { } blankstring
490 Log
"match $match($id)"
491 Log
" string1 (exact): $matchstring"
492 Log
" string2 (blanks): $blankstring"
493 Log
" device string: [set $match($id)]"
494 if {!([string match
*$matchstring* [set $match($id)]] ||
[string match
*$blankstring* [set $match($id)]])} {
501 # end of proc {MatchDevice}
504 proc {ParseGlobalConfig
} {} {
508 set places
[list /etc
/usb_modeswitch.conf
/etc
/sysconfig
/usb_modeswitch
/etc
/default/usb_modeswitch
]
509 foreach cfg
$places {
510 if [file exists
$cfg] {
515 if {$configFile == ""} {return}
517 set rc
[open $configFile r
]
520 if [regexp {^
#} [string trim $line]] {continue}
521 if [regexp {DisableMBIMGlobal
\s
*=\s
*([^
\s
]+)} $line d val
] {
522 if [regexp -nocase {1|yes|true
} $val] {
528 if [regexp {DisableSwitching
\s
*=\s
*([^
\s
]+)} $line d val
] {
529 if [regexp -nocase {1|yes|true
} $val] {
530 set flags
(noswitching
) 1
533 if [regexp {EnableLogging
\s
*=\s
*([^
\s
]+)} $line d val
] {
534 if [regexp -nocase {1|yes|true
} $val] {
540 if [regexp {SetStorageDelay
\s
*=\s
*([^
\s
]+)} $line d val
] {
541 if [regexp {\d
+} $val] {
542 set flags
(stordelay
) $val
547 return "Use global config file: $configFile"
550 # end of proc {ParseGlobalConfig}
553 proc ParseDeviceConfig
{cfg
} {
556 set config
(WaitBefore
) ""
557 set config
(TargetVendor
) ""
558 set config
(TargetProduct
) ""
559 set config
(TargetClass
) ""
560 set config
(Configuration
) ""
561 set config
(NoMBIMCheck
) 0
562 set config
(PantechMode
) 0
563 set config
(CheckSuccess
) 20
565 foreach pname
[lsort [array names config
]] {
566 if [regexp -line "^\[^# \]*?$pname.*?= *(0x(\\w+)|\"(\[0-9a-fA-F,\]+)\"|(\[0-9\]+)) *\$" $cfg d config
($pname)] {
567 # Log "config: $pname set to $config($pname)"
571 set config
(WaitBefore
) [string trimleft
$config(WaitBefore
) 0]
574 # end of proc {ParseDeviceConfig}
577 proc ConfigGet
{command config
} {
579 global setup usb flags
584 # Unpackaged configs first; sorting is essential for priority
585 set configList
[lsort -decreasing [glob -nocomplain $setup(dbdir_etc
)/$config*]]
586 set configList
[concat $configList [lsort -decreasing [glob -nocomplain $setup(dbdir
)/$config*]]]
587 eval lappend configList
[glob -nocomplain $setup(dbdir
)/$usb(idVendor
):#$flags(os)]
588 if [file exists
$setup(dbdir
)/configPack.tar.gz
] {
589 Log
"Found packed config collection $setup(dbdir)/configPack.tar.gz"
590 if [catch {set packedList
[exec tar
-tzf $setup(dbdir
)/configPack.tar.gz
2>/dev
/null
]} err
] {
591 Log
"Error: problem opening config package; tar returned\n $err"
594 set packedList
[split $packedList \n]
595 set packedConfigList
[lsort -decreasing [lsearch -glob -all -inline $packedList $config*]]
596 lappend packedConfigList
[lsearch -inline $packedList $usb(idVendor
):#$flags(os)]
597 # Now add packaged configs with a mark, again sorted for priority
598 foreach packedConfig
$packedConfigList {
599 lappend configList
"pack/$packedConfig"
605 if [regexp {^
pack/} $config] {
606 set config
[regsub {pack/} $config {}]
607 Log
"Extract config $config from collection $setup(dbdir)/configPack.tar.gz"
608 set configContent
[exec tar
-xzOf $setup(dbdir
)/configPack.tar.gz
$config 2>/dev
/null
]
610 if [regexp [list $setup(dbdir_etc
)] $config] {
611 Log
"Use config file from override folder $setup(dbdir_etc)"
612 SysLog
"usb_modeswitch: use overriding config file $config; make sure this is intended"
613 SysLog
"usb_modeswitch: please report any new or corrected settings; otherwise, check for outdated files"
615 set rc
[open $config r
]
616 set configContent
[read $rc]
619 return $configContent
624 # end of proc {ConfigGet}
628 global flags device loginit
630 if {$flags(logging
) == 0} {return}
632 if $flags(logwrite
) {
633 if [string length
$loginit] {
634 exec echo
"\nUSB_ModeSwitch log from [clock format [clock seconds]]" >/var
/log
/usb_modeswitch_
$device
635 exec echo
"$loginit" >>/var
/log
/usb_modeswitch_
$device
638 exec echo
$msg >>/var
/log
/usb_modeswitch_
$device
640 append loginit
"\n$msg"
647 # Writing the log file and exit
651 set flags
(logwrite
) 1
656 # end of proc {SafeExit}
659 proc {SymLinkName
} {path
} {
662 proc {hasInterrupt
} {ifDir
} {
663 if {[llength [glob -nocomplain $ifDir/ttyUSB
*]] == 0} {
664 Log
" no ttyUSB interface - skip endpoint check"
667 foreach epDir
[glob -nocomplain $ifDir/ep_
*] {
668 set e
[file tail
$epDir]
670 if [file exists
$epDir/type
] {
671 set rc
[open $epDir/type r
]
674 if [regexp {Interrupt
} $type] {
675 Log
" $e has interrupt transfer type"
683 set loginit
"usb_modeswitch called with --symlink-name\n parameter: $path\n"
685 # In case the device path is returned as /class/tty/ttyUSB,
686 # get the USB device path from linked tree "device"
687 set linkpath
/sys
$path/device
688 if [file exists
$linkpath] {
689 if {[file type
$linkpath] == "link"} {
690 set rawpath
[file readlink
$linkpath]
691 set trimpath
[regsub -all {\.
\.
/} $rawpath {}]
692 if [file isdirectory
/sys
/$trimpath] {
693 append loginit
"\n Use path $path\n"
698 if {![regexp {([0-9]+-[0-9]+[\.0-9]*:[^
/]*).
*(ttyUSB
[0-9]+)} $path d myDev myPort
]} {
700 set device
[clock clicks
]
701 set flags
(logwrite
) 1
702 Log
"$loginit\nThis is not a ttyUSB port. Abort"
707 set device ttyUSB_
$myDev
708 set flags
(logwrite
) 1
709 Log
"$loginit\nMy name is $myPort\n"
711 if {![regexp {(.
*?
[0-9]+)\.
([0-9]+)/ttyUSB
} /sys
$path d ifRoot ifNum
]} {
712 Log
"Could not find interface in path\n $path. Abort"
716 set ifDir
$ifRoot.
$ifNum
718 Log
"Check my endpoints ...\n in $ifDir"
719 if [hasInterrupt
$ifDir] {
720 Log
"\n--> I am an interrupt port"
723 Log
"\n--> I am not an interrupt port\n"
727 # There are devices with more than one interrupt interface.
728 # Assume that the lowest of these is usable. Check all
729 # possible lower interfaces
731 if { $rightPort && ($ifNum > 0) } {
732 Log
"\nLook for lower ports with interrupt endpoints"
733 for {set i
0} {$i < $ifNum} {incr i
} {
735 Log
" in ifDir $ifDir ..."
736 if [hasInterrupt
$ifDir] {
737 Log
"\n--> found an interrupt interface below me\n"
743 if {$rightPort == 0} {
744 Log
"Return empty name and exit"
748 Log
"\n--> No interrupt interface below me\n"
752 set symlinkName
"gsmmodem"
754 if {![file exists
$symlinkName]} {
755 set placeholder
[open /dev
/$symlinkName w
]
759 set symlinkName gsmmodem
$idx
762 if {$idx == 256} {return ""}
764 Log
"Return symlink name \"$symlinkName\" and exit"
768 # end of proc {SymLinkName}
771 # Add USB ID to list of devices needing later treatment
772 proc {AddToList
} {name id
} {
774 set listfile
/var
/lib
/usb_modeswitch
/$name
775 if [file exists
$listfile] {
776 set rc
[open $listfile r
]
777 set buffer
[read $rc]
779 if [string match
*$id* $buffer] {
782 set idList
[split [string trim
$buffer] \n]
785 set buffer
[join $idList "\n"]
786 if [catch {set lc
[open $listfile w
]}] {return}
791 # end of proc {AddToList}
794 proc {CheckSuccess
} {devdir
} {
796 global config usb flags
798 # For Cisco AM10, target device not on same port
799 if {$usb(idVendor
) == "1307" && $usb(idProduct
) == "1169"} {
800 set devdir
[string range
$devdir 0 end-1
]2
802 set ifdir
[file tail
[IfDir
0 $devdir]]
803 if {[string length
$config(TargetClass
)] ||
[string length
$config(Configuration
)]} {
804 set config
(TargetVendor
) $usb(idVendor
)
805 set config
(TargetProduct
) $usb(idProduct
)
807 Log
"Check success of mode switch for max. $config(CheckSuccess) seconds ..."
810 for {set i
1} {$i <= $config(CheckSuccess
)} {incr i
} {
812 if {![file isdirectory
$devdir]} {
813 Log
" Wait for device file system ($i sec.) ..."
816 Log
" Read attributes ..."
818 set ifdir
[IfDir
0 $devdir]
819 if {$ifdir == ""} {continue}
820 set ifdir
[file tail
$ifdir]
821 if {![ReadUSBAttrs
$devdir $ifdir]} {
822 Log
" Essential attributes are missing, continue wait ..."
825 if [string length
$config(Configuration
)] {
826 if {$usb(bConfigurationValue
) != $config(Configuration
)} {continue}
828 if [string length
$config(TargetClass
)] {
829 if {![regexp $usb($ifdir/bInterfaceClass
) $config(TargetClass
)]} {
830 if {$config(class
) != $usb($ifdir/bInterfaceClass
} {
835 if {![regexp $usb(idVendor
) $config(TargetVendor
)]} {
836 if {![regexp $usb(idVendor
) $config(vendor
)]} {
840 if {![regexp $usb(idProduct
) $config(TargetProduct
)]} {
841 if {![regexp $usb(idProduct
) $config(product
)]} {
845 # Arriving here means that device attributes have changed
847 Log
" All attributes matched"
849 if [regexp -nocase {/[0-9a-f
]+:#} $flags(config)] {
850 Log
" idProduct has changed after generic mode-switch, assume success"
852 Log
" Attributes are different but target values are unexpected:"
858 if {$i > 20} {return 0} else {return 1}
861 # end of proc {CheckSuccess}
864 proc {IfDir
} {iface devdir
} {
866 set allfiles
[glob -nocomplain $devdir/*]
867 set files
[glob -nocomplain $devdir/*.
$iface]
868 if {[llength $files] == 0} {
871 set ifdir
[lindex $files 0]
872 if {![file isdirectory
$ifdir]} {
878 # end of proc {IfDir}
880 proc {IfClass
} {iface devdir
} {
882 set ifdir
[IfDir
$iface $devdir]
884 if {![file exists
$ifdir/bInterfaceClass
]} {
887 set rc
[open $ifdir/bInterfaceClass r
]
890 return [string trim
$c]
893 # end of proc {IfClass}
896 proc {SysLog
} {msg
} {
899 if {![info exists flags
(logger
)]} {
901 foreach fn
{/bin
/logger
/usr
/bin
/logger
} {
902 if [file exists
$fn] {
903 set flags
(logger
) $fn
906 Log
"Logger is $flags(logger)"
908 if {$flags(logger
) == ""} {
909 Log
"Can't add system message, no syslog helper found"
912 catch {exec $flags(logger
) -p syslog.notice
"$msg" 2>/dev
/null
}
915 # end of proc {SysLog}
917 proc {SetStorageDelay
} {secs
} {
919 Log
"Adjust delay for USB storage devices ..."
920 set attrib
/sys
/module
/usb_storage
/parameters
/delay_use
921 if {![file exists
$attrib]} {
922 Log
"Error: could not find delay_use attribute"
925 if [catch {set ch
[open $attrib r
+]} err
] {
926 Log
"Error: could not access delay_use attribute: $err"
929 if {[read $ch] < $secs} {
931 puts -nonewline $ch $secs
932 Log
" Delay set to $secs seconds\n"
934 Log
" Current value is higher than $secs. Leave it alone\n"
939 # end of proc {SetStorageDelay}
941 proc {CheckMBIM
} {} {
943 set kversion
[exec uname
-r]
944 if [llength [glob -nocomplain /lib
/modules
/$kversion/kernel
/drivers
/net
/usb
/cdc_mbim
*]] {return 1}
945 if [file exists
/sys
/bus
/usb
/drivers
/cdc_mbim
] {return 1}
952 set kversion
[exec uname
-r]
953 if [llength [glob -nocomplain /lib
/modules
/$kversion/kernel
/drivers
/net
/usb
/qmi_wwan
*]] {return 1}
954 if [file exists
/sys
/bus
/usb
/drivers
/cdc_mbim
] {return 1}
959 proc {PantechAutoSwitch
} {} {
962 if {$config(PantechMode
) == 3} {return 1}
963 if {$config(PantechMode
) == 1} {
964 if {"$config(vendor):$config(product)" == "10a9:6080"} {
965 set flags
(config
) [regsub {PantechMode
*= *1} $flags(config
) "PantechMode=2"]
966 Log
" PantechMode changed to 2"
968 } elseif
[CheckQMI
] {
969 set flags
(config
) [regsub {PantechMode
*= *1} $flags(config
) "PantechMode=4"]
970 Log
" PantechMode changed to 4"
979 proc UnbindDriver
{devdir ifdir
} {
981 set att
$devdir/$ifdir/driver
/unbind
982 if [file exists
$att] {
983 Log
"Unbinding driver"
984 exec echo
-n "$ifdir" > $att
989 proc {LogAttributes
} {} {
993 set attrList
{idVendor idProduct bConfigurationValue manufacturer product serial
}
994 foreach attr
[lsort [array names usb
]] {
995 Log
" [format %-26s $attr:] $usb($attr)"
1001 proc {HasFF
} {devdir
} {
1004 while {[set dir
[IfDir
$i $devdir]] != ""} {
1005 set c
[exec cat
$dir/bInterfaceClass
]
1006 if {$c == "ff"} {return 1}
1014 # The actual entry point