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.1.9 package
13 # (C) Josua Dietze 2009, 2010, 2011
16 # Setting of the these switches is done in the global config
17 # file (/etc/usb_modeswitch.conf) if available
23 set env
(PATH
) "/bin:/usr/bin"
25 # Execution starts at file bottom
27 proc {Main
} {argc argv
} {
29 global scsi usb config match wc device logging noswitching settings
31 set loginit
[ParseGlobalConfig
]
33 # The facility to add a symbolic link pointing to the
34 # ttyUSB port which provides interrupt transfer, i.e.
35 # the port to connect through; returns a symlink name
37 # This is run once for every known device interface by
40 if {[lindex $argv 0] == "--symlink-name"} {
42 set device
[clock clicks
]
44 puts -nonewline [SymLinkName
[lindex $argv 1]]
48 set settings
(dbdir
) /usr
/share
/usb_modeswitch
49 set settings
(dbdir_etc
) /etc
/usb_modeswitch.d
51 if {![file exists
$settings(dbdir
)] && ![file exists
$settings(dbdir_etc
)]} {
53 Log
"Error: no config database found in /usr/share or /etc. Exiting"
61 # argv contains the values provided from the udev rule
64 set argList
[split [lindex $argv 0] /]
66 if [string length
[lindex $argList 1]] {
67 set device
[lindex $argList 1]
72 Log
"Raw args from udev: $argv\n\n$loginit"
74 if {$device == "noname"} {
75 Log
"No data from udev. Exiting"
79 # arg 0: the bus id for the device (udev: %b)
80 # arg 1: the "kernel name" for the device (udev: %k)
82 # Both together give the top directory where the path
83 # to the SCSI attributes can be determined (further down)
84 # Addendum: older kernel/udev version seem to differ in
85 # providing these attributes - or not. So more probing
88 if {[string length
[lindex $argList 0]] == 0} {
89 if {[string length
[lindex $argList 1]] == 0} {
90 Log
"No device number values given from udev! Exiting"
93 Log
"Bus ID for device not given by udev."
94 Log
" Trying to determine it from kernel name ([lindex $argList 1]) ..."
95 if {![regexp {(.
*?
):} [lindex $argList 1] d dev_top
]} {
96 Log
"Could not determine top device dir from udev values! Exiting"
101 set dev_top
[lindex $argList 0]
102 regexp {(.
*?
):} $dev_top d dev_top
106 set devdir
/sys
/bus
/usb
/devices
/$dev_top
107 if {![file isdirectory
$devdir]} {
108 Log
"Top sysfs directory not found ($devdir)! Exiting"
113 # Mapping of the short string identifiers (in the config
114 # file names) to the long name used here
116 # If we need them it's a snap to add new attributes here!
118 set match
(sVe
) scsi
(vendor
)
119 set match
(sMo
) scsi
(model
)
120 set match
(sRe
) scsi
(rev
)
121 set match
(uMa
) usb
(manufacturer
)
122 set match
(uPr
) usb
(product
)
123 set match
(uSe
) usb
(serial
)
126 # Now reading the USB attributes
130 if {[string length
"$usb(idVendor)$usb(idProduct)"] < 8} {
131 Log
"USB IDs not found in sysfs tree. Exiting"
135 Log
"----------------\nUSB values from sysfs:"
136 foreach attr
{manufacturer product serial
} {
137 Log
" $attr\t$usb($attr)"
139 Log
"----------------"
142 Log
"\nSwitching globally disabled. Exiting\n"
143 catch {exec logger
-p syslog.notice
"usb_modeswitch: switching disabled, no action for $usb(idVendor):$usb(idProduct)" 2>/dev
/null
}
147 if {$usb(bNumConfigurations
) == "1"} {
148 set configParam
"-u -1"
149 Log
"bNumConfigurations is 1 - don't check for active configuration"
154 # Check if there is more than one config file for this USB ID,
155 # which would make an attribute test necessary. If so, check if
156 # SCSI values are needed
158 set configList
[ConfigGet conflist
$usb(idVendor
):$usb(idProduct
)]
160 if {[llength $configList] == 0} {
161 Log
"Aargh! Config file missing for $usb(idVendor):$usb(idProduct)! Exiting"
166 if {[llength $configList] > 1} {
167 if [regexp {:s
} $configList] {
172 Log
"SCSI attributes not needed, moving on"
176 # Getting the SCSI values via libusb results in a detached
177 # usb-storage driver. Not good for devices that want to be
178 # left alone. Fortunately, the sysfs tree provides the values
179 # too without need for direct access
181 # First we wait until the SCSI data is ready - or timeout.
182 # Timeout means: no storage driver was bound to the device.
183 # We run 20 times max, every half second (max. 10 seconds
186 # We also check if the device itself changes, probably
187 # because it was switched by the kernel (or even unplugged).
188 # Then we do simply nothing and exit quietly ...
191 while {$scsiNeeded && $counter < 20} {
194 Log
"waiting for storage tree in sysfs"
196 set sysdir
$devdir/[lindex $argList 1]
198 if {![file isdirectory
$sysdir]} {
199 # Device is gone. Unplugged? Switched by kernel?
200 Log
"sysfs device tree is gone; exiting"
203 set rc
[open $devdir/product r
]
204 set newproduct
[read -nonewline $rc]
206 if {![string match
$newproduct $usb(product
)]} {
207 # Device has just changed. Switched by someone else?
208 Log
"device has changed; exiting"
212 # Searching the storage/SCSI tree; might take a while
213 if {[set dirList
[glob -nocomplain $sysdir/host
*]] != ""} {
214 set sysdir
[lindex $dirList 0]
215 if {[set dirList
[glob -nocomplain $sysdir/target
*]] != ""} {
216 set sysdir
[lindex $dirList 0]
217 regexp {.
*target
(.
*)} $sysdir d subdir
218 if {[set dirList
[glob -nocomplain $sysdir/$subdir*]] != ""} {
219 set sysdir
[lindex $dirList 0]
220 if [file exists
$sysdir/vendor
] {
221 # Finally SCSI structure is ready, get the values
222 ReadSCSIAttrs
$sysdir
223 Log
"SCSI values read"
231 if {$counter == 20 && [string length
$scsi(vendor
)] == 0} {
232 Log
"SCSI tree not found; you may want to check if this path/file exists:"
233 Log
"$sysdir/vendor\n"
235 Log
"----------------\nSCSI values from sysfs:"
236 foreach attr
{vendor model rev
} {
237 Log
" $attr\t$scsi($attr)"
239 Log
"----------------"
241 Log
"Waiting 3 secs. after SCSI device was added"
247 # If SCSI tree in sysfs was not identified, try and get the values
248 # from a (nonswitching) call of usb_modeswitch; this detaches the
249 # storage driver, so it's just the last resort
251 if {$scsiNeeded && $scsi(vendor
)==""} {
252 set testSCSI
[exec $bindir/usb_modeswitch
-v 0x
$usb(idVendor
) -p 0x
$usb(idProduct
) 2>/dev
/null
]
253 regexp { Vendor String
: (.
*?
)\n} $testSCSI d scsi
(vendor
)
254 regexp { Model String
: (.
*?
)\n} $testSCSI d scsi
(model
)
255 regexp {Revision String
: (.
*?
)\n} $testSCSI d scsi
(rev
)
256 Log
"SCSI values from usb_modeswitch:"
257 foreach attr
{vendor model rev
} {
258 Log
" $attr\t$scsi($attr)"
262 # If we don't have the SCSI values by now, we just
263 # leave the variables empty; they won't match anything
265 # Time to check for a matching config file.
266 # Matching itself is done by MatchDevice
268 # The configuration file names are sorted reverse so that
269 # the ones with matching additions are tried first; the
270 # common configs without match attributes are used at the
271 # end and provide a fallback
274 foreach configuration
$configList {
276 # skipping installer leftovers
277 if [regexp {\.
(dpkg|rpm
)} $configuration] {continue}
279 Log
"checking config: $configuration"
280 if [MatchDevice
$configuration] {
281 ParseDeviceConfig
[ConfigGet conffile
$configuration]
282 set devList1
[ListSerialDevs
]
283 if {$config(waitBefore
) == ""} {
284 Log
"! matched, now switching"
286 Log
"! matched, waiting time set to $config(waitBefore) seconds"
287 append config
(waitBefore
) "000"
288 after $config(waitBefore
)
289 Log
" waiting is over, switching starts now"
292 # Now we are actually switching
294 Log
" (running command: $bindir/usb_modeswitch -I -W -c $settings(tmpConfig))"
295 set report
[exec $bindir/usb_modeswitch
-I -W -D -c $settings(tmpConfig
) $configParam 2>@ stdout
]
297 set report
[exec $bindir/usb_modeswitch
-I -Q -D -c $settings(tmpConfig
) $configParam 2>/dev
/null
]
299 Log
"\nVerbose debug output of usb_modeswitch and libusb follows"
300 Log
"(Note that some USB errors are expected in the process)"
301 Log
"--------------------------------"
303 Log
"--------------------------------"
304 Log
"(end of usb_modeswitch output)\n"
305 if [regexp {/var
/lib
/usb_modeswitch
} $settings(tmpConfig
)] {
306 file delete
$settings(tmpConfig
)
310 Log
"* no match, not switching with this config"
314 # We're finished with switching; success checking
315 # was done by usb_modeswitch and logged via syslog.
317 # If switching was OK we now check for drivers by
318 # simply recounting serial devices under /dev
320 if {![file isdirectory
$devdir]} {
321 Log
"Device directory in sysfs is gone! Something went wrong, aborting"
324 # Give the device annother second if it's not fully back yet
325 if {![file exists
$devdir/idProduct
]} {
328 if {![file exists
$devdir/idProduct
]} {
332 set ifdir
"[file tail $devdir]:1.0"
333 ReadUSBAttrs
$devdir $ifdir
335 if {$usb($ifdir/bInterfaceClass
) != "" && [regexp {ok
:} $report]} {
336 if {$usb($ifdir/bInterfaceClass
) == "02"} {
338 Log
" Found CDC ACM device, skip driver checking"
342 # If target ID given, driver shall be loaded
343 if [regexp -nocase {ok
:[0-9a-f
]{4}:[0-9a-f
]{4}|ok
:no_data
} $report] {
345 if {[string length
"$usb(idVendor)$usb(idProduct)"] < 8} {
346 regexp {ok
:(\w
{4}):(\w
{4})} $report d usb
(idVendor
) usb
(idProduct
)
348 set t
"$usb(idVendor)$usb(idProduct)"
349 if {[string length
$t] != 8 ||
[string trim
$t 0] == ""} {
350 if {$report == "ok:no_data"} {
351 Log
"Libusb1 bug prevented device searching, and device ID not found afterwards."
353 Log
"No vendor/product ID found or given, can't continue. Aborting"
357 # For general driver loading; TODO: add respective device names.
358 # Presently only useful for HSO devices (which are recounted now)
359 if {$config(driverModule
) == ""} {
360 set config
(driverModule
) "option"
361 set config
(driverIDPath
) "/sys/bus/usb-serial/drivers/option1"
363 if {$config(driverIDPath
) == ""} {
364 set config
(driverIDPath
) "/sys/bus/usb/drivers/$config(driverModule)"
367 Log
"Driver module is \"$config(driverModule)\", ID path is $config(driverIDPath)\n"
369 # some settling time in ms
372 Log
"Now checking for newly created serial devices ..."
373 set devList2
[ListSerialDevs
]
375 if {[llength $devList1] >= [llength $devList2]} {
376 Log
" no new serial devices found"
377 AddToList link_list
$usb(idVendor
):$usb(idProduct
)
379 # If device is known, the sh wrapper will take care, else:
380 if {[InBindList
$usb(idVendor
):$usb(idProduct
)] == 0} {
381 Log
"Device not in bind_list"
384 CheckDriverBind
$usb(idVendor
) $usb(idProduct
)
387 # Old/slow systems may take a while to create the devices
388 while {[llength $devList1] >= [llength $devList2] && $counter < 14} {
390 set devList2
[ListSerialDevs
]
393 if {$counter == 14} {
394 Log
" still no new serial devices found"
396 Log
" driver successfully bound"
397 AddToList bind_list
$usb(idVendor
):$usb(idProduct
)
401 Log
" new serial devices found, driver has bound"
402 if {[llength [lsearch -glob -all $devList2 *ttyUSB
*]] > [llength [lsearch -glob -all $devList1 *ttyUSB
*]]} {
403 AddToList link_list
$usb(idVendor
):$usb(idProduct
)
407 # Just in case "NoDriverLoading" was added after the first bind
408 RemoveFromBindList
$usb(idVendor
):$usb(idProduct
)
411 if [regexp {ok
:$} $report] {
412 # "NoDriverLoading" was set
413 Log
"Doing no driver checking or binding for this device"
416 # In newer kernels there is a switch to avoid the use of a device
417 # reset (e.g. from usb-storage) which would possibly switch back
418 # a mode-switching device to initial mode
419 if [regexp {ok
:} $report] {
420 Log
"Checking for AVOID_RESET_QUIRK attribute"
421 if [file exists
$devdir/avoid_reset_quirk
] {
422 if [catch {exec echo
"1" >$devdir/avoid_reset_quirk
2>/dev
/null
} err
] {
423 Log
" Error setting the attribute: $err"
425 Log
" AVOID_RESET_QUIRK activated"
428 Log
" AVOID_RESET_QUIRK not present"
432 Log
"\nAll done, exiting\n"
439 proc {ReadSCSIAttrs
} {dir
} {
442 Log
"SCSI dir exists: $dir"
444 foreach attr
{vendor model rev
} {
445 if [file exists
$dir/$attr] {
446 set rc
[open $dir/$attr r
]
447 set scsi
($attr) [read -nonewline $rc]
451 Log
"Warning: SCSI attribute \"$attr\" not found."
456 # end of proc {ReadSCSIAttrs}
459 proc {ReadUSBAttrs
} {dir args
} {
463 set attrList
{idVendor idProduct manufacturer product serial bNumConfigurations
}
465 lappend attrList
"$args/bInterfaceClass"
467 foreach attr
$attrList {
468 if [file exists
$dir/$attr] {
469 set rc
[open $dir/$attr r
]
470 set usb
($attr) [read -nonewline $rc]
474 Log
"Warning: USB attribute \"$attr\" not found."
479 # end of proc {ReadUSBAttrs}
482 proc {MatchDevice
} {config
} {
484 global scsi usb match
486 set devinfo
[file tail
$config]
487 set infoList
[split $devinfo :]
488 set stringList
[lrange $infoList 2 end
]
489 if {[llength $stringList] == 0} {return 1}
491 foreach teststring
$stringList {
492 if {$teststring == "?"} {return 0}
493 set tokenList
[split $teststring =]
494 set id
[lindex $tokenList 0]
495 set matchstring
[lindex $tokenList 1]
497 regsub -all {_
} $matchstring { } blankstring
498 Log
"matching $match($id)"
499 Log
" match string1 (exact): $matchstring"
500 Log
" match string2 (blanks): $blankstring"
501 Log
" device string: [set $match($id)]"
502 if {!([string match
*$matchstring* [set $match($id)]] ||
[string match
*$blankstring* [set $match($id)]])} {
509 # end of proc {MatchDevice}
512 proc {ParseGlobalConfig
} {} {
514 global logging noswitching
517 set places
[list /etc
/usb_modeswitch.conf
/etc
/sysconfig
/usb_modeswitch
/etc
/default/usb_modeswitch
]
518 foreach cfg
$places {
519 if [file exists
$cfg] {
525 if {$configFile == ""} {return}
527 set rc
[open $configFile r
]
530 if [regexp {DisableSwitching
\s
*=\s
*([^
\s
]+)} $line d val
] {
531 if [regexp -nocase {1|yes|true
} $val] {
535 if [regexp {EnableLogging
\s
*=\s
*([^
\s
]+)} $line d val
] {
536 if [regexp -nocase {1|yes|true
} $val] {
542 return "Using global config file: $configFile"
545 # end of proc {ParseGlobalConfig}
548 proc ParseDeviceConfig
{configFile
} {
551 set config
(driverModule
) ""
552 set config
(driverIDPath
) ""
553 set config
(waitBefore
) ""
554 set rc
[open $configFile r
]
555 set lineList
[split [read $rc] \n]
557 foreach line
$lineList {
558 if [regexp {^DriverModule
[[:blank
:]]*=[[:blank
:]]*"?(\w+)"?
} [string trim
$line] d config
(driverModule
)] {
559 Log
"config: DriverModule set to $config(driverModule)"
561 if [regexp {^DriverIDPath
[[:blank
:]]*=[[:blank
:]]*?
"?([/\-\w]+)"?
} [string trim
$line] d config
(driverIDPath
)] {
562 Log
"config: DriverIDPath set to $config(driverIDPath)"
564 if [regexp {^WaitBefore
[[:blank
:]]*=[[:blank
:]]*?
([0-9]+)} [string trim
$line] d config
(waitBefore
)] {
565 Log
"config: WaitBefore set to $config(waitBefore)"
568 set config
(waitBefore
) [string trimleft
$config(waitBefore
) 0]
571 # end of proc {ParseDeviceConfig}
574 proc ConfigGet
{command config
} {
581 # Unpackaged configs first; sorting is essential for priority
582 set configList
[lsort -decreasing [glob -nocomplain $settings(dbdir_etc
)/$config*]]
583 set configList
[concat $configList [lsort -decreasing [glob -nocomplain $settings(dbdir
)/$config*]]]
584 if [file exists
$settings(dbdir
)/configPack.tar.gz
] {
585 Log
"Found packed config collection $settings(dbdir)/configPack.tar.gz"
586 if [catch {set packedList
[exec tar
-tzf $settings(dbdir
)/configPack.tar.gz
2>/dev
/null
]} err
] {
587 Log
"Error: problem opening config package; tar returned\n $err"
590 set packedList
[split $packedList \n]
591 set packedConfigList
[lsort -decreasing [lsearch -glob -all -inline $packedList $config*]]
592 # Now add packaged configs with a mark, again sorted for priority
593 foreach packedConfig
$packedConfigList {
594 lappend configList
"pack/$packedConfig"
601 if [regexp {^
pack/} $config] {
602 set config
[regsub {pack/} $config {}]
603 set settings
(tmpConfig
) /var
/lib
/usb_modeswitch
/current_cfg
604 Log
"Extracting config $config from collection $settings(dbdir)/configPack.tar.gz"
605 set wc
[open $settings(tmpConfig
) w
]
606 puts -nonewline $wc [exec tar
-xzOf $settings(dbdir
)/configPack.tar.gz
$config 2>/dev
/null
]
609 if [regexp [list $settings(dbdir_etc
)] $config] {
610 Log
"Using config file from override folder $settings(dbdir_etc)"
611 set syslog_text
"usb_modeswitch: using overriding config file $config; make sure this is intended"
612 catch {exec logger
-p syslog.notice
$syslog_text 2>/dev
/null
}
613 set syslog_text
"usb_modeswitch: please report any new or corrected settings; otherwise, check for outdated files"
614 catch {exec logger
-p syslog.notice
$syslog_text 2>/dev
/null
}
616 set settings
(tmpConfig
) $config
618 return $settings(tmpConfig
)
623 # end of proc {ConfigGet}
627 global wc logging device
628 if {$logging == 0} {return}
629 if {![info exists wc
]} {
630 if [catch {set wc
[open /var
/log
/usb_modeswitch_
$device w
]} err
] {
634 puts $wc "\n\nUSB_ModeSwitch log from [clock format [clock seconds]]\n"
636 if {$wc == "error"} {return}
643 # Closing the log file if open and exit
647 if [info exists wc
] {
653 # end of proc {SafeExit}
656 # Checking for interrupt endpoint in ttyUSB port (lowest if there is
657 # more than one); if found, check for unused "gsmmodem[n]" name.
658 # Link for first modem will be "gsmmodem", then "gsmmodem2" and up
660 proc {SymLinkName
} {path
} {
663 set loginit
"* called with --symlink-name: params $path *\n"
665 # Internal proc, used only here
666 proc {hasInterrupt
} {ifDir
} {
667 if {[llength [glob -nocomplain $ifDir/ttyUSB
*]] == 0} {
668 Log
" no ttyUSB interface - skip checking endpoints"
671 foreach epDir
[glob -nocomplain $ifDir/ep_
*] {
672 Log
" in epDir $epDir ..."
673 if [file exists
$epDir/type
] {
674 set rc
[open $epDir/type r
]
677 if [regexp {Interrupt
} $type] {
678 Log
" $epDir has interrupt transfer type"
686 # In case the device path is returned as /class/tty/ttyUSB,
687 # we need to extract the USB device path from symlink "device"
688 set linkpath
/sys
$path/device
689 if [file exists
$linkpath] {
690 if {[file type
$linkpath] == "link"} {
691 set rawpath
[file readlink
$linkpath]
692 set trimpath
[regsub -all {\.
\.
/} $rawpath {}]
693 if [file isdirectory
/sys
/$trimpath] {
700 if {![regexp {ttyUSB
[0-9]+} $path myPort
]} {
701 Log
"$loginit\nCould not find port name in path\n $path. Aborting"
705 Log
"$loginit\nMy name is $myPort"
707 if {![regexp {usb
[0-9]+/([0-9]+-[0-9]+)/} $path d dev_top
]} {
708 Log
"Could not find device directory in path\n $path. Aborting"
712 if {![regexp "\[0-9\]+\\.(\[0-9\]+)/$myPort" $path d myIf
]} {
713 Log
"Could not find interface number in path\n $path. Aborting"
717 if {![regexp "$dev_top:\[0-9\]" /sys
$path ifRoot
]} {
718 Log
"Could not find interface number in path\n $path. Aborting"
722 set dirList
[split $path /]
723 set idx
[lsearch $dirList $dev_top]
725 set devDir
/sys
[join [lrange $dirList 0 $idx] /]
727 Log
"My port is $myPort, my interface is $myIf
728 devDir: $devDir\n dev_top: $dev_top\nsysPath: /sys$path"
730 regexp "$devDir/$dev_top:\[0-9\]" /sys
$path ifRoot
732 set ifDir
$ifRoot.
$myIf
734 Log
"Checking my endpoints in $ifDir"
735 if [hasInterrupt
$ifDir] {
736 Log
"\n--> I am an interrupt port\n"
739 Log
"\n--> I am not an interrupt port\n"
743 # Unfortunately, there are devices with more than one interrupt
744 # port. The assumption so far is that the lowest of these is
745 # right. Check all lower interfaces for annother one (if interface)
746 # is bigger than 0). If found, don't return any name.
748 if { $rightPort && ($myIf > 0) } {
749 Log
"Looking for lower ports with interrupt endpoints"
750 for {set i
0} {$i < $myIf} {incr i
} {
752 Log
" in ifDir $ifDir ..."
753 if [hasInterrupt
$ifDir] {
754 Log
"\n--> found an interrupt interface below me\n"
761 if {$rightPort == 0} {
762 Log
"Return empty name and exit"
766 Log
"\n--> No interrupt interface below me\n"
770 set symlinkName
"gsmmodem"
772 if {![file exists
$symlinkName]} {
775 set symlinkName gsmmodem
$idx
778 Log
"Return symlink name \"$symlinkName\" and exit"
782 # end of proc {SymLinkName}
785 # Load and bind (serial) driver
787 proc {CheckDriverBind
} {vid
pid} {
791 if [file exists
/sbin
/modprobe
] {
792 set loader
/sbin
/modprobe
794 Log
" /sbin/modprobe not found"
797 set idfile
$config(driverIDPath
)/new_id
798 if {![file exists
$idfile]} {
800 Log
"Can't do anymore without module loader; get \"modtools\"!"
803 Log
"\nTrying to load driver \"$config(driverModule)\""
804 if [catch {set result
[exec $loader -v $config(driverModule
)]} err
] {
805 Log
" Running \"$loader $config(driverModule)\" gave an error:\n $err"
807 Log
" Driver was loaded successfully:\n$result"
810 Log
"Driver was loaded already"
814 if [file exists
$idfile] {
821 Log
"Trying to add ID to driver \"$config(driverModule)\""
822 catch {exec logger
-p syslog.notice
"usb_modeswitch: adding device ID $vid:$pid to driver \"$config(driverModule)\"" 2>/dev
/null
}
823 catch {exec logger
-p syslog.notice
"usb_modeswitch: please report the device ID to the Linux USB developers!" 2>/dev
/null
}
824 if [catch {exec echo
"$vid $pid" >$idfile} err
] {
825 Log
"Error adding ID to driver: $err"
827 Log
" ID added to driver; check for new devices in /dev"
830 Log
" \"$idfile\" not found, can't add ID to driver;\n check if kernel version is at least 2.6.27"
831 Log
"Falling back to \"usbserial\""
832 set config
(driverModule
) usbserial
833 Log
"\nTrying to unload driver \"$config(driverModule)\""
834 if [catch {exec $loader -r $config(driverModule
)} err
] {
835 Log
" Running \"$loader $config(driverModule)\" gave an error:\n $err"
836 Log
"Can't unload usbserial. No more fallbacks"
839 Log
"\nTrying to load driver \"usbserial\" with device IDs"
840 if [catch {set result
[exec $loader -v usbserial vendor
=0x
$vid product
=0x
$pid]} err
] {
841 Log
" Running \"$loader $config(driverModule)\" gave an error:\n $err"
843 Log
" Driver was loaded successfully:\n$result"
848 # end of proc {CheckDriverBind}
851 # Check if USB ID is listed as needing driver binding
852 proc {InBindList
} {id
} {
854 set listfile
/var
/lib
/usb_modeswitch
/bind_list
855 if {![file exists
$listfile]} {return 0}
856 set rc
[open $listfile r
]
857 set buffer
[read $rc]
859 if [string match
*$id* $buffer] {
860 Log
"Found $id in bind_list"
863 Log
"No $id in bind_list"
868 # end of proc {InBindList}
870 # Add USB ID to list of devices needing later treatment
871 proc {AddToList
} {name id
} {
873 set listfile
/var
/lib
/usb_modeswitch
/$name
874 set oldlistfile
/etc
/usb_modeswitch.d
/bind_list
876 if {($name == "bind_list") && [file exists
$oldlistfile] && ![file exists
$listfile]} {
877 if [catch {file rename $oldlistfile $listfile} err
] {
878 Log
"Error renaming the old bind list file ($err)"
883 if [file exists
$listfile] {
884 set rc
[open $listfile r
]
885 set buffer
[read $rc]
887 if [string match
*$id* $buffer] {
890 set idList
[split [string trim
$buffer] \n]
893 set buffer
[join $idList "\n"]
894 if [catch {set wc
[open $listfile w
]}] {return}
899 # end of proc {AddToList}
902 # Remove USB ID from bind list (NoDriverLoading is set)
903 proc {RemoveFromBindList
} {id
} {
905 set listfile
/var
/lib
/usb_modeswitch
/bind_list
906 if [file exists
$listfile] {
907 set rc
[open $listfile r
]
908 set buffer
[read $rc]
910 set idList
[split [string trim
$buffer] \n]
914 set idx
[lsearch $idList $id]
916 set idList
[lreplace $idList $idx $idx]
920 if {[llength $idList] == 0} {
921 file delete
$listfile
924 set buffer
[join $idList "\n"]
925 if [catch {set wc
[open $listfile w
]}] {return}
930 # end of proc {RemoveFromBindList}
932 # Return a list with all relevant serial devices that are present
933 proc {ListSerialDevs
} {} {
935 set devList
[glob -nocomplain /dev
/ttyUSB
* /dev
/ttyACM
* /dev
/ttyHS
*]
936 if [file isdirectory
/dev
/tts
] {
937 eval lappend devList
[glob -nocomplain /dev
/tts
/*]
942 # end of proc {ListSerialDevs}
945 # The actual entry point