home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/tclsh
-
- # Wrapper (tcl) for usb_modeswitch, called from
- # /lib/udev/rules.d/40-usb_modeswitch.rules
- # (part of data pack "usb-modeswitch-data") via
- # /lib/udev/usb_modeswitch
- #
- # Does ID check on newly discovered USB devices and calls
- # the mode switching program with the matching parameter
- # file from /usr/share/usb_modeswitch
- #
- # Part of usb-modeswitch-1.2.3 package
- # (C) Josua Dietze 2009-2012
-
- set arg0 [lindex $argv 0]
- if [regexp {\.tcl$} $arg0] {
- if [file exists $arg0] {
- set argv [lrange $argv 1 end]
- source $arg0
- exit
- }
- }
-
- # Setting of these switches is done in the global config
- # file (/etc/usb_modeswitch.conf) if available
-
- set flags(logging) 0
- set flags(noswitching) 0
-
- #set env(PATH) "/bin:/sbin:/usr/bin:/usr/sbin"
-
- # Execution starts at file bottom
-
- proc {Main} {argv argc} {
-
- global scsi usb config match device flags settings
-
- set loginit [ParseGlobalConfig]
-
- # The facility to add a symbolic link pointing to the
- # ttyUSB port which provides interrupt transfer, i.e.
- # the port to connect through.
- # Will check for interrupt endpoint in ttyUSB port (lowest if
- # there is more than one); if found, return "gsmmodem[n]" name
- # to udev for symlink creation
-
- # This is run once for every port of LISTED devices by
- # an udev rule
-
- if {[lindex $argv 0] == "--symlink-name"} {
- puts -nonewline [SymLinkName [lindex $argv 1]]
- SafeExit
- }
-
- set argList [split [lindex $argv 1] /]
-
- if [string length [lindex $argList 1]] {
- set device [lindex $argList 1]
- } else {
- set device "noname"
- }
-
- Log "Raw args from udev: [lindex $argv 1]\n\n$loginit"
-
- if {$device == "noname"} {
- Log "No data from udev. Exiting"
- SafeExit
- }
-
- if {[lindex $argv 0] != "--switch-mode"} {
- Log "No command given. Exiting"
- SafeExit
- }
-
- if {![regexp /lib/udev/usb_modeswitch [lindex $argv 2]]} {
- Log "Dispatcher was not run from call script. Exiting"
- SafeExit
- }
-
- set settings(dbdir) /usr/share/usb_modeswitch
- set settings(dbdir_etc) /etc/usb_modeswitch.d
-
-
- if {![file exists $settings(dbdir)] && ![file exists $settings(dbdir_etc)]} {
- Log "Error: no config database found in /usr/share or /etc. Exiting"
- SafeExit
- }
- set bindir /usr/sbin
-
- set devList1 {}
- set devList2 {}
-
-
- # arg 0: the bus id for the device (udev: %b)
- # arg 1: the "kernel name" for the device (udev: %k)
- #
- # Both together give the top directory where the path
- # to the SCSI attributes can be determined (further down)
- # Addendum: older kernel/udev version seem to differ in
- # providing these attributes - or not. So more probing
- # is needed
-
- if {[string length [lindex $argList 0]] == 0} {
- if {[string length [lindex $argList 1]] == 0} {
- Log "No device number values given from udev! Exiting"
- SafeExit
- } else {
- if {![regexp {(.*?):} [lindex $argList 1] d dev_top]} {
- Log "Could not determine top device dir from udev values! Exiting"
- SafeExit
- }
- }
- } else {
- set dev_top [lindex $argList 0]
- regexp {(.*?):} $dev_top d dev_top
- }
-
- set devdir /sys/bus/usb/devices/$dev_top
- if {![file isdirectory $devdir]} {
- Log "Top device directory not found ($devdir)! Exiting"
- SafeExit
- }
- Log "Using top device dir $devdir"
- set ifdir "[file tail $devdir]:1.0"
-
-
- # Mapping of the short string identifiers (in the config
- # file names) to the long name used here
- #
- # If we need them it's a snap to add new attributes here!
-
- set match(sVe) scsi(vendor)
- set match(sMo) scsi(model)
- set match(sRe) scsi(rev)
- set match(uMa) usb(manufacturer)
- set match(uPr) usb(product)
- set match(uSe) usb(serial)
-
-
- # Now reading the USB attributes
- if {![ReadUSBAttrs $devdir]} {
- Log "USB attributes not found in sysfs tree. Exiting"
- SafeExit
- }
-
- if $flags(logging) {
- Log "----------------\nUSB values from sysfs:"
- foreach attr {manufacturer product serial} {
- Log " $attr\t$usb($attr)"
- }
- Log "----------------"
- }
-
- if $flags(noswitching) {
- Log "\nSwitching globally disabled. Exiting\n"
- SysLog "usb_modeswitch: switching disabled, no action for $usb(idVendor):$usb(idProduct)"
- SafeExit
- }
-
- if {$usb(bNumConfigurations) == "1"} {
- set configParam "-u -1"
- Log "bNumConfigurations is 1 - don't check for active configuration"
- } else {
- set configParam ""
- }
-
- # Check if there is more than one config file for this USB ID,
- # which would make an attribute test necessary. If so, check if
- # SCSI values are needed
-
- set configList [ConfigGet conflist $usb(idVendor):$usb(idProduct)]
-
- if {[llength $configList] == 0} {
- Log "Aargh! Config file missing for $usb(idVendor):$usb(idProduct)! Exiting"
- SafeExit
- }
-
- set scsiNeeded 0
- if {[llength $configList] > 1} {
- if [regexp {:s} $configList] {
- set scsiNeeded 1
- }
- }
- if $scsiNeeded {
- if [ReadSCSIAttrs $devdir:1.0] {
- Log "----------------\nSCSI values from sysfs:"
- foreach attr {vendor model rev} {
- Log " $attr\t$scsi($attr)"
- }
- Log "----------------"
- } else {
- Log "Could not get SCSI attributes, exclude devices with SCSI match"
- }
- } else {
- Log "SCSI attributes not needed, moving on"
- }
-
- # General wait - this is important
- after 500
-
- # Now check for a matching config file. Matching is done
- # by MatchDevice
-
- set report {}
- foreach configuration $configList {
-
- # skipping installer leftovers
- if [regexp {\.(dpkg|rpm)} $configuration] {continue}
-
- Log "checking config: $configuration"
- if [MatchDevice $configuration] {
- Log "! matched. Reading config data"
- if [string length $usb(busnum)] {
- set busParam "-b [string trimleft $usb(busnum) 0]"
- set devParam "-g [string trimleft $usb(devnum) 0]"
- } else {
- set busParam ""
- set devParam ""
- }
- set configBuffer [ConfigGet conffile $configuration]
- ParseDeviceConfig $configBuffer
- if {$config(waitBefore) == ""} {
- } else {
- Log " waiting time set to $config(waitBefore) seconds"
- append config(waitBefore) "000"
- after $config(waitBefore)
- Log " waiting is over, switching starts now"
- }
-
- # Now we are actually switching
- if $flags(logging) {
- Log "Command to be run:\nusb_modeswitch -I -W -D -s 20 $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f \$configBuffer"
- set report [exec /usr/sbin/usb_modeswitch -I -W -D -s 20 $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f "$configBuffer" 2>@ stdout]
- Log "\nVerbose debug output of usb_modeswitch and libusb follows"
- Log "(Note that some USB errors are to be expected in the process)"
- Log "--------------------------------"
- Log $report
- Log "--------------------------------"
- Log "(end of usb_modeswitch output)\n"
- } else {
- set report [exec /usr/sbin/usb_modeswitch -I -Q -D -s 20 $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct) -f "$configBuffer" 2>@ stdout]
- }
- break
- } else {
- Log "* no match, not switching with this config"
- }
- }
-
- # Switching is complete; success checking was either
- # done by usb_modeswitch and logged via syslog OR bus/dev
- # parameter were used; then we do check for success HERE
-
- if [regexp {ok:busdev} $report] {
- if [CheckSuccess $devdir] {
- Log "Mode switching was successful, found $usb(idVendor):$usb(idProduct) ($usb(manufacturer): $usb(product))"
- SysLog "usb_modeswitch: switched to $usb(idVendor):$usb(idProduct) on [format %03d $usb(busnum)]/[format %03d $usb(devnum)]"
- } else {
- Log "\nTarget config not matching - current values are"
- set attrList {idVendor idProduct bConfigurationValue manufacturer product serial}
- foreach attr [lsort [array names usb]] {
- Log " [format %-26s $attr:] $usb($attr)"
- }
- Log "\nMode switching may have failed. Exiting\n"
- SafeExit
- }
- } else {
- if {![file isdirectory $devdir]} {
- Log "Device directory in sysfs is gone! Something went wrong, aborting"
- SafeExit
- }
- if {![regexp {ok:} $report]} {
- Log "\nCore program reported switching failure. Exiting\n"
- SafeExit
- }
- # Give the device another second if it's not fully back yet
- if {![file exists $devdir/idProduct]} {
- after 1000
- }
- ReadUSBAttrs $devdir $ifdir
- }
-
- # Now checking for bound drivers (only for class 0xff)
-
- if {$usb($ifdir/bInterfaceClass) != "" && [regexp {ok:} $report]} {
- if {$usb($ifdir/bInterfaceClass) != "ff"} {
- set config(driverModule) ""
- Log " No vendor-specific class found, skip driver checking"
- }
- }
-
- # If module is set (it is by default), driver shall be loaded.
- # If not, then NoDriverLoading is active
-
- if {$config(driverModule) != ""} {
- if {[string length "$usb(idVendor)$usb(idProduct)"] < 8} {
- if {![regexp {ok:(\w{4}):(\w{4})} $report d usb(idVendor) usb(idProduct)]} {
- Log "No target vendor/product ID found or given, can't continue. Aborting"
- SafeExit
- }
- }
- # wait for any drivers to bind automatically
- after 1000
- Log "Now checking for bound driver ..."
- if {![file exists $devdir/$ifdir/driver]} {
- Log " no driver has bound to interface 0 yet"
- AddToList link_list $usb(idVendor):$usb(idProduct)
-
- # If device is known, the sh wrapper will take care, else:
- if {[InBindList $usb(idVendor):$usb(idProduct)] == 0} {
- Log "Device is not in \"bind_list\" yet, bind it now"
-
- # Load driver
- CheckDriverBind $usb(idVendor) $usb(idProduct)
-
- # Old/slow systems may take a while to create the devices
- set counter 0
- while {![file exists $devdir/$ifdir/driver]} {
- if {$counter == 14} {break}
- after 500
- incr counter
- }
- if {$counter == 14} {
- Log " driver binding failed"
- } else {
- Log " driver was bound to the device"
- AddToList bind_list $usb(idVendor):$usb(idProduct)
- }
- }
- } else {
- Log " driver has bound, device is known"
- if {[llength [glob -nocomplain $devdir/$ifdir/ttyUSB*]] > 0} {
- AddToList link_list $usb(idVendor):$usb(idProduct)
- }
- }
- } else {
- # Just in case "NoDriverLoading" was added after the first bind
- RemoveFromBindList $usb(idVendor):$usb(idProduct)
- }
-
- if [regexp {ok:$} $report] {
- # "NoDriverLoading" was set
- Log "Doing no driver checking or binding for this device"
- }
-
- # In newer kernels there is a switch to avoid the use of a device
- # reset (e.g. from usb-storage) which would possibly switch back
- # a mode-switching device to initial mode
- if [regexp {ok:} $report] {
- Log "Checking for AVOID_RESET_QUIRK kernel attribute"
- if [file exists $devdir/avoid_reset_quirk] {
- if [catch {exec echo "1" >$devdir/avoid_reset_quirk 2>/dev/null} err] {
- Log " Error setting the attribute: $err"
- } else {
- Log " AVOID_RESET_QUIRK activated"
- }
- } else {
- Log " not present in this kernel"
- }
- }
-
- Log "\nAll done, exiting\n"
- SafeExit
-
- }
- # end of proc {Main}
-
-
- proc {ReadSCSIAttrs} {topdir} {
-
- global scsi
- set counter 0
- set sysdir $topdir
- Log "Checking storage tree in sysfs ..."
- while {$counter < 20} {
- Log " loop $counter/20"
- if {![file isdirectory $sysdir]} {
- # Device is gone. Unplugged? Switched by kernel?
- Log " sysfs device tree is gone; abort SCSI value check"
- return 0
- }
- # Searching the storage/SCSI tree; might take a while
- if {[set dirList [glob -nocomplain $topdir/host*]] != ""} {
- set sysdir [lindex $dirList 0]
- if {[set dirList [glob -nocomplain $sysdir/target*]] != ""} {
- set sysdir [lindex $dirList 0]
- regexp {.*target(.*)} $sysdir d subdir
- if {[set dirList [glob -nocomplain $sysdir/$subdir*]] != ""} {
- set sysdir [lindex $dirList 0]
- if [file exists $sysdir/vendor] {
- Log " Storage tree is ready"
- break
- }
- }
- }
- }
- after 500
- incr counter
- }
- if {$counter == 20} {
- Log "SCSI tree not found; you may want to check if this path/file exists:"
- Log "$sysdir/vendor\n"
- return 0
- }
-
- Log "Reading SCSI values ..."
- foreach attr {vendor model rev} {
- if [file exists $sysdir/$attr] {
- set rc [open $sysdir/$attr r]
- set scsi($attr) [read -nonewline $rc]
- close $rc
- } else {
- set scsi($attr) ""
- Log "Warning: SCSI attribute \"$attr\" not found."
- }
- }
- return 1
-
- }
- # end of proc {ReadSCSIAttrs}
-
-
- proc {ReadUSBAttrs} {dir args} {
-
- global usb
-
- set attrList {idVendor idProduct bConfigurationValue manufacturer product serial devnum busnum bNumConfigurations}
- set mandatoryList {idVendor idProduct bNumConfigurations}
- set result 1
- if {$args != ""} {
- lappend attrList "$args/bInterfaceClass"
- lappend mandatoryList "$args/bInterfaceClass"
- }
- foreach attr $attrList {
- if [file exists $dir/$attr] {
- set rc [open $dir/$attr r]
- set usb($attr) [string trim [read -nonewline $rc]]
- close $rc
- } else {
- set usb($attr) ""
- if {[lsearch $mandatoryList $attr] > -1} {
- set result 0
- }
- if {$attr == "serial"} {continue}
- Log " Warning: USB attribute \"$attr\" not found"
- }
- }
- return $result
-
- }
- # end of proc {ReadUSBAttrs}
-
-
- proc {MatchDevice} {config} {
-
- global scsi usb match
-
- set devinfo [file tail $config]
- set infoList [split $devinfo :]
- set stringList [lrange $infoList 2 end]
- if {[llength $stringList] == 0} {return 1}
-
- foreach teststring $stringList {
- if {$teststring == "?"} {return 0}
- set tokenList [split $teststring =]
- set id [lindex $tokenList 0]
- set matchstring [lindex $tokenList 1]
- set blankstring ""
- regsub -all {_} $matchstring { } blankstring
- Log "matching $match($id)"
- Log " match string1 (exact): $matchstring"
- Log " match string2 (blanks): $blankstring"
- Log " device string: [set $match($id)]"
- if {!([string match *$matchstring* [set $match($id)]] || [string match *$blankstring* [set $match($id)]])} {
- return 0
- }
- }
- return 1
-
- }
- # end of proc {MatchDevice}
-
-
- proc {ParseGlobalConfig} {} {
-
- global flags
- set configFile ""
- set places [list /etc/usb_modeswitch.conf /etc/sysconfig/usb_modeswitch /etc/default/usb_modeswitch]
- foreach cfg $places {
- if [file exists $cfg] {
- set configFile $cfg
- break
- }
- }
- if {$configFile == ""} {return}
-
- set rc [open $configFile r]
- while {![eof $rc]} {
- gets $rc line
- if [regexp {DisableSwitching\s*=\s*([^\s]+)} $line d val] {
- if [regexp -nocase {1|yes|true} $val] {
- set flags(noswitching) 1
- }
- }
- if [regexp {EnableLogging\s*=\s*([^\s]+)} $line d val] {
- if [regexp -nocase {1|yes|true} $val] {
- set flags(logging) 1
- }
- }
-
- }
- return "Using global config file: $configFile"
-
- }
- # end of proc {ParseGlobalConfig}
-
-
- proc ParseDeviceConfig {configContent} {
-
- global config
- set config(driverModule) ""
- set config(driverIDPath) ""
- set config(waitBefore) ""
- set config(targetVendor) ""
- set config(targetProduct) ""
- set config(targetClass) ""
- set config(Configuration) ""
- set config(checkSuccess) 20
- set loadDriver 1
-
- if [regexp -line {^[^#]*?TargetVendor.*?=.*?0x(\w+).*?$} $configContent d config(targetVendor)] {
- Log "config: TargetVendor set to $config(targetVendor)"
- }
- if [regexp -line {^[^#]*?TargetProduct.*?=.*?0x(\w+).*?$} $configContent d config(targetProduct)] {
- Log "config: TargetProduct set to $config(targetProduct)"
- }
- if [regexp -line {^[^#]*?TargetProductList.*?=.*?"([0-9a-fA-F,]+).*?$} $configContent d config(targetProduct)] {
- Log "config: TargetProductList set to $config(targetProduct)"
- }
- if [regexp -line {^[^#]*?TargetClass.*?=.*?0x(\w+).*?$} $configContent d config(targetClass)] {
- Log "config: TargetClass set to $config(targetClass)"
- }
- if [regexp -line {^[^#]*?Configuration.*?=.*?([0-9]+).*?$} $configContent d config(Configuration)] {
- Log "config: Configuration (target) set to $config(Configuration)"
- }
- if [regexp -line {^[^#]*?DriverModule.*?=.*?(\w+).*?$} $configContent d config(driverModule)] {
- Log "config: DriverModule set to $config(driverModule)"
- }
- if [regexp -line {^[^#]*?DriverIDPath.*?=.*?"?([/\-\w]+).*?$} $configContent d config(driverIDPath)] {
- Log "config: DriverIDPath set to $config(driverIDPath)"
- }
- if [regexp -line {^[^#]*?CheckSuccess.*?=.*?([0-9]+).*?$} $configContent d config(checkSuccess)] {
- Log "config: CheckSuccess set to $config(checkSuccess)"
- }
- if [regexp -line {^[^#]*?WaitBefore.*?=.*?([0-9]+).*?$} $configContent d config(waitBefore)] {
- Log "config: WaitBefore set to $config(waitBefore)"
- }
- if [regexp -line {^[^#]*?NoDriverLoading.*?=.*?(1|yes|true).*?$} $configContent] {
- set loadDriver 0
- Log "config: NoDriverLoading is set to active"
- }
-
- # For general driver loading; TODO: add respective device names.
- # Presently only useful for HSO devices (which are recounted now)
- if $loadDriver {
- if {$config(driverModule) == ""} {
- set config(driverModule) "option"
- set config(driverIDPath) "/sys/bus/usb-serial/drivers/option1"
- } else {
- if {$config(driverIDPath) == ""} {
- set config(driverIDPath) "/sys/bus/usb/drivers/$config(driverModule)"
- }
- }
- Log "Driver module is \"$config(driverModule)\", ID path is $config(driverIDPath)\n"
- } else {
- Log "Driver will not be handled by usb_modeswitch"
- }
- set config(waitBefore) [string trimleft $config(waitBefore) 0]
-
- }
- # end of proc {ParseDeviceConfig}
-
-
- proc ConfigGet {command config} {
-
- global settings
-
- switch $command {
-
- conflist {
- # Unpackaged configs first; sorting is essential for priority
- set configList [lsort -decreasing [glob -nocomplain $settings(dbdir_etc)/$config*]]
- set configList [concat $configList [lsort -decreasing [glob -nocomplain $settings(dbdir)/$config*]]]
- if [file exists $settings(dbdir)/configPack.tar.gz] {
- Log "Found packed config collection $settings(dbdir)/configPack.tar.gz"
- if [catch {set packedList [exec tar -tzf $settings(dbdir)/configPack.tar.gz 2>/dev/null]} err] {
- Log "Error: problem opening config package; tar returned\n $err"
- return {}
- }
- set packedList [split $packedList \n]
- set packedConfigList [lsort -decreasing [lsearch -glob -all -inline $packedList $config*]]
- # Now add packaged configs with a mark, again sorted for priority
- foreach packedConfig $packedConfigList {
- lappend configList "pack/$packedConfig"
- }
- }
-
- return $configList
- }
- conffile {
- if [regexp {^pack/} $config] {
- set config [regsub {pack/} $config {}]
- Log "Extracting config $config from collection $settings(dbdir)/configPack.tar.gz"
- set configContent [exec tar -xzOf $settings(dbdir)/configPack.tar.gz $config 2>/dev/null]
- } else {
- if [regexp [list $settings(dbdir_etc)] $config] {
- Log "Using config file from override folder $settings(dbdir_etc)"
- SysLog "usb_modeswitch: using overriding config file $config; make sure this is intended"
- SysLog "usb_modeswitch: please report any new or corrected settings; otherwise, check for outdated files"
- }
- set rc [open $config r]
- set configContent [read $rc]
- close $rc
- }
- return $configContent
- }
- }
-
- }
- # end of proc {ConfigGet}
-
- proc {Log} {msg} {
-
- global flags device
- if {$flags(logging) == 0} {return}
-
- if {![info exists flags(wc)]} {
- if [catch {set flags(wc) [open /var/log/usb_modeswitch_$device w]} err] {
- if [catch {set flags(wc) [open /dev/console w]} err] {
- set flags(wc) "error"
- return
- } else {
- puts $flags(wc) "Error opening log file ($err), redirect to console"
- }
- }
- puts $flags(wc) "\n\nUSB_ModeSwitch log from [clock format [clock seconds]]\n"
- }
- if {$flags(wc) == "error"} {return}
- puts $flags(wc) $msg
-
- }
- # end of proc {Log}
-
-
- # Closing the log file if open and exit
- proc {SafeExit} {} {
-
- global flags
- if [info exists flags(wc)] {
- catch {close $flags(wc)}
- }
- exit
-
- }
- # end of proc {SafeExit}
-
-
- proc {SymLinkName} {path} {
- global device
-
- proc {hasInterrupt} {ifDir} {
- if {[llength [glob -nocomplain $ifDir/ttyUSB*]] == 0} {
- Log " no ttyUSB interface - skip checking endpoints"
- return 0
- }
- foreach epDir [glob -nocomplain $ifDir/ep_*] {
- set e [file tail $epDir]
- Log " checking $e ..."
- if [file exists $epDir/type] {
- set rc [open $epDir/type r]
- set type [read $rc]
- close $rc
- if [regexp {Interrupt} $type] {
- Log " $e has interrupt transfer type"
- return 1
- }
- }
- }
- return 0
- }
-
- set loginit "usb_modeswitch called with --symlink-name\n parameter: $path\n"
-
- # In case the device path is returned as /class/tty/ttyUSB,
- # get the USB device path from linked tree "device"
- set linkpath /sys$path/device
- if [file exists $linkpath] {
- if {[file type $linkpath] == "link"} {
- set rawpath [file readlink $linkpath]
- set trimpath [regsub -all {\.\./} $rawpath {}]
- if [file isdirectory /sys/$trimpath] {
- append loginit "\n Using path $path\n"
- set path /$trimpath
- }
- }
- }
-
- if {![regexp {ttyUSB[0-9]+} $path myPort]} {
- if $flags(logging) {
- set device [clock clicks]
- Log "$loginit\nThis is not a ttyUSB port. Aborting"
- }
- return ""
- }
-
- set device $myPort
- Log "$loginit\nMy name is $myPort\n"
-
- if {![regexp {(.*?[0-9]+)\.([0-9]+)/ttyUSB} /sys$path d ifRoot ifNum]} {
- Log "Could not find interface in path\n $path. Aborting"
- return ""
- }
-
- set ifDir $ifRoot.$ifNum
-
- Log "Checking my endpoints ...\n in $ifDir"
- if [hasInterrupt $ifDir] {
- Log "\n--> I am an interrupt port"
- set rightPort 1
- } else {
- Log "\n--> I am not an interrupt port\n"
- set rightPort 0
- }
-
- # There are devices with more than one interrupt interface.
- # Assume that the lowest of these is usable. Check all
- # possible lower interfaces
-
- if { $rightPort && ($ifNum > 0) } {
- Log "\nLooking for lower ports with interrupt endpoints"
- for {set i 0} {$i < $ifNum} {incr i} {
- set ifDir $ifRoot.$i
- Log " in ifDir $ifDir ..."
- if [hasInterrupt $ifDir] {
- Log "\n--> found an interrupt interface below me\n"
- set rightPort 0
- break
- }
- }
- }
- if {$rightPort == 0} {
- Log "Return empty name and exit"
- return ""
- }
-
- Log "\n--> No interrupt interface below me\n"
-
- cd /dev
- set idx 2
- set symlinkName "gsmmodem"
- while {$idx < 256} {
- if {![file exists $symlinkName]} {
- set placeholder [open /dev/$symlinkName w]
- close $placeholder
- break
- }
- set symlinkName gsmmodem$idx
- incr idx
- }
- if {$idx == 256} {return ""}
-
- Log "Return symlink name \"$symlinkName\" and exit"
- return $symlinkName
-
- }
- # end of proc {SymLinkName}
-
-
- # Load and bind driver (default "option")
- #
- proc {CheckDriverBind} {vid pid} {
- global config
-
- foreach fn {/sbin/modprobe /usr/sbin/modprobe} {
- if [file exists $fn] {
- set loader $fn
- }
- }
- Log "Module loader is $loader"
-
- set idfile $config(driverIDPath)/new_id
- if {![file exists $idfile]} {
- if {$loader == ""} {
- Log "Can't do anymore without module loader; get \"modtools\"!"
- return
- }
- Log "\nTrying to load module \"$config(driverModule)\""
- if [catch {set result [exec $loader -v $config(driverModule)]} err] {
- Log " Running \"$loader $config(driverModule)\" gave an error:\n $err"
- } else {
- Log " Module was loaded successfully:\n$result"
- }
- } else {
- Log "Module is active already"
- }
- set i 0
- while {$i < 50} {
- if [file exists $idfile] {
- break
- }
- after 20
- incr i
- }
- if {$i < 50} {
- Log "Trying to add ID to driver \"$config(driverModule)\""
- SysLog "usb_modeswitch: adding device ID $vid:$pid to driver \"$config(driverModule)\""
- SysLog "usb_modeswitch: please report the device ID to the Linux USB developers!"
- if [catch {exec echo "$vid $pid ff" >$idfile} err] {
- Log " Error adding ID to driver:\n $err"
- } else {
- Log " ID added to driver; check for new devices in /dev"
- }
- } else {
- Log " \"$idfile\" not found, check if kernel version is at least 2.6.27"
- Log "Falling back to \"usbserial\""
- set config(driverModule) usbserial
- Log "\nTrying to unload driver \"usbserial\""
- if [catch {exec $loader -r usbserial} err] {
- Log " Running \"$loader -r usbserial\" gave an error:\n $err"
- Log "No more fallbacks"
- return
- }
- after 50
- Log "\nTrying to load driver \"usbserial\" with device IDs"
- if [catch {set result [exec $loader -v usbserial vendor=0x$vid product=0x$pid]} err] {
- Log " Running \"$loader usbserial\" gave an error:\n $err"
- } else {
- Log " Driver was loaded successfully:\n$result"
- }
- }
-
- }
- # end of proc {CheckDriverBind}
-
-
- # Check if USB ID is listed as needing driver binding
- proc {InBindList} {id} {
-
- set listfile /var/lib/usb_modeswitch/bind_list
- if {![file exists $listfile]} {return 0}
- set rc [open $listfile r]
- set buffer [read $rc]
- close $rc
- if [string match *$id* $buffer] {
- Log "Found $id in bind_list"
- return 1
- } else {
- Log "No $id in bind_list"
- return 0
- }
-
- }
- # end of proc {InBindList}
-
- # Add USB ID to list of devices needing later treatment
- proc {AddToList} {name id} {
-
- set listfile /var/lib/usb_modeswitch/$name
- set oldlistfile /etc/usb_modeswitch.d/bind_list
-
- if {($name == "bind_list") && [file exists $oldlistfile] && ![file exists $listfile]} {
- if [catch {file rename $oldlistfile $listfile} err] {
- Log "Error renaming the old bind list file ($err)"
- return
- }
- }
-
- if [file exists $listfile] {
- set rc [open $listfile r]
- set buffer [read $rc]
- close $rc
- if [string match *$id* $buffer] {
- return
- }
- set idList [split [string trim $buffer] \n]
- }
- lappend idList $id
- set buffer [join $idList "\n"]
- if [catch {set lc [open $listfile w]}] {return}
- puts $lc $buffer
- close $lc
-
- }
- # end of proc {AddToList}
-
-
- # Remove USB ID from bind list (NoDriverLoading is set)
- proc {RemoveFromBindList} {id} {
-
- set listfile /var/lib/usb_modeswitch/bind_list
- if [file exists $listfile] {
- set rc [open $listfile r]
- set buffer [read $rc]
- close $rc
- set idList [split [string trim $buffer] \n]
- } else {
- return
- }
- set idx [lsearch $idList $id]
- if {$idx > -1} {
- set idList [lreplace $idList $idx $idx]
- } else {
- return
- }
- if {[llength $idList] == 0} {
- file delete $listfile
- return
- }
- set buffer [join $idList "\n"]
- if [catch {set lc [open $listfile w]}] {return}
- puts $lc $buffer
- close $lc
-
- }
- # end of proc {RemoveFromBindList}
-
- proc {CheckSuccess} {devdir} {
-
- global config usb
- set ifdir "[file tail $devdir]:1.0"
-
- if {[string length $config(targetClass)] || [string length $config(Configuration)]} {
- set config(targetVendor) $usb(idVendor)
- set config(targetProduct) $usb(idProduct)
- }
- Log "Checking success of mode switch for max. $config(checkSuccess) seconds ..."
-
- for {set i 1} {$i <= $config(checkSuccess)} {incr i} {
- after 1000
- if {![file isdirectory $devdir]} {
- Log " Waiting for device file system ($i sec.) ..."
- continue
- } else {
- Log " Reading attributes ..."
- }
- if {![ReadUSBAttrs $devdir $ifdir]} {
- Log " Essential attributes are missing, continue wait ..."
- continue
- }
- if [string length $config(targetClass)] {
- if {![regexp $usb($ifdir/bInterfaceClass) $config(targetClass)]} {continue}
- }
- if [string length $config(Configuration)] {
- if {$usb(bConfigurationValue) != $config(Configuration} {continue}
- }
- if {![regexp $usb(idVendor) $config(targetVendor)]} {continue}
- if {![regexp $usb(idProduct) $config(targetProduct)]} {continue}
- Log " All attributes matched"
- break
- }
- if {$i > 20} {
- return 0
- }
- return 1
-
- }
- # end of proc {CheckSuccess}
-
- proc {SysLog} {msg} {
-
- global flags
- if {![info exists flags(logger)]} {
- set flags(logger) ""
- foreach fn {/bin/logger /usr/bin/logger} {
- if [file exists $fn] {
- set flags(logger) $fn
- }
- }
- Log "Logger is $flags(logger)"
- }
- if {$flags(logger) == ""} {
- Log "Can't add system message, no syslog helper found"
- return
- }
- catch {exec $flags(logger) -p syslog.notice "$msg" 2>/dev/null}
-
- }
- # end of proc {SysLog}
-
-
-
- # The actual entry point
- Main $argv $argc
-