From cf2afa734597ef88b8f5871bf18cf849b105e51d Mon Sep 17 00:00:00 2001
From: Lubomir Rintel <lkundrak@v3.sk>
Date: Mon, 25 Jul 2016 12:03:22 +0200
Subject: [PATCH] Bring back the module binding
We still need it for some devices.
http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?f=2&t=2560
---
usb_modeswitch.sh | 23 +++++-
usb_modeswitch.tcl | 214 +++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 221 insertions(+), 16 deletions(-)
diff --git a/usb_modeswitch.sh b/usb_modeswitch.sh
index b126ec3..f4b76dd 100755
--- a/usb_modeswitch.sh
+++ b/usb_modeswitch.sh
@@ -40,7 +40,27 @@ fi
PATH=/sbin:/usr/sbin:$PATH
case "$1" in
--driver-bind)
- # driver binding code removed
+ (
+ dir=$(ls -d /sys$2/ttyUSB* 2>/dev/null)
+ sleep 1
+ if [ ! -z "$dir" ]; then
+ exit 0
+ fi
+ set +e
+ device_in "bind_list" $v_id $p_id
+ if [ "$?" = "1" ]; then
+ id_attr="/sys/bus/usb-serial/drivers/option1/new_id"
+ if [ ! -e "$id_attr" ]; then
+ modprobe option 2>/dev/null || true
+ fi
+ if [ -e "$id_attr" ]; then
+ echo "$v_id $p_id ff" > $id_attr
+ else
+ modprobe -r usbserial 2>/dev/null
+ modprobe usbserial "vendor=0x$v_id" "product=0x$p_id" 2>/dev/null
+ fi
+ fi
+ ) &
exit 0
;;
--symlink-name)
@@ -53,7 +73,6 @@ case "$1" in
exit 0
;;
esac
-
IFS='/' read -r p1 p2 <<EOF
$1
EOF
diff --git a/usb_modeswitch.tcl b/usb_modeswitch.tcl
index 3e590fd..b74d46c 100755
--- a/usb_modeswitch.tcl
+++ b/usb_modeswitch.tcl
@@ -276,6 +276,7 @@ foreach mconfig $configList {
set cfgno [string trim $cfgno]
if {$cfgno > 0} {
set config(Configuration) $cfgno
+ set config(DriverModule) ""
set flags(config) "Configuration=$cfgno"
} else {
Log " No MBIM configuration found, switch to legacy modem mode"
@@ -290,10 +291,6 @@ foreach mconfig $configList {
set report "ok:busdev"
break
}
- if {$config(Configuration) == 0} {
- Log "Config file contains dummy method, do nothing. Exit"
- SafeExit
- }
UnbindDriver $devdir $ifdir
# Now we are actually switching
if $flags(logging) {
@@ -348,19 +345,68 @@ if [regexp {ok:busdev} $report] {
ReadUSBAttrs $devdir $ifdir
}
-# driver binding removed !!
+# Checking for bound drivers if there is an interface with class 0xff
-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. Abort"
- SafeExit
+if {$config(DriverModule) != "" && [regexp {ok:} $report]} {
+ if [HasFF $devdir] {
+ AddToList link_list $usb(idVendor):$usb(idProduct)
+ } else {
+ set config(DriverModule) ""
+ Log " No vendor-specific class found, skip driver check"
}
}
-# wait for drivers to bind
-after 500
-if {[llength [glob -nocomplain $devdir/$ifdir/ttyUSB*]] > 0} {
- Log "Serial USB driver bound to interface 0\n will try to guess and symlink modem port on next connect"
- AddToList link_list $usb(idVendor):$usb(idProduct)
+
+# 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. Abort"
+ SafeExit
+ }
+ }
+ # wait for any drivers to bind automatically
+ after 1500
+ Log "Now check for bound driver ..."
+ if {![file exists $devdir/$ifdir/driver]} {
+ Log " no driver has bound to interface 0 yet"
+
+ # 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 "No driver check or bind for this device"
}
# In newer kernels there is a switch to avoid the use of a device
@@ -553,6 +599,8 @@ return "Use global config file: $configFile"
proc ParseDeviceConfig {cfg} {
global config
+set config(DriverModule) ""
+set config(DriverIDPath) ""
set config(WaitBefore) ""
set config(TargetVendor) ""
set config(TargetProduct) ""
@@ -561,6 +609,7 @@ set config(Configuration) ""
set config(NoMBIMCheck) 0
set config(PantechMode) 0
set config(CheckSuccess) 20
+set loadDriver 1
foreach pname [lsort [array names config]] {
if [regexp -line "^\[^# \]*?$pname.*?= *(0x(\\w+)|\"(\[0-9a-fA-F,\]+)\"|(\[0-9\]+)) *\$" $cfg d config($pname)] {
@@ -568,6 +617,26 @@ foreach pname [lsort [array names config]] {
}
}
+if [regexp -line {^[^#]*?NoDriverLoading.*?=.*?(1|yes|true).*?$} $cfg] {
+ 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]
}
@@ -768,6 +837,92 @@ 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 "\nTry 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 "Try to add ID to driver \"$config(DriverModule)\""
+ SysLog "usb_modeswitch: add 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 "Fall back to \"usbserial\""
+ set config(DriverModule) usbserial
+ Log "\nTry 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 "\nTry 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} {
@@ -791,6 +946,37 @@ 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 flags
--
2.7.4