~ubuntu-branches/ubuntu/utopic/usb-modeswitch/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/01_no_bash_before_tcl.patch/usb_modeswitch.tcl

  • Committer: Bazaar Package Importer
  • Author(s): Didier Raboud
  • Date: 2011-02-09 14:11:13 UTC
  • mfrom: (11.1.3 experimental)
  • Revision ID: james.westby@ubuntu.com-20110209141113-fwe61klmfbc1efjd
Tags: 1.1.6-2
* Upload to unstable.
* Use new dh_installdeb maintscript possibility:
  - Bump debhelper Build-Depends to 8.1.0.
  - Add Pre-Depends on ${misc:Pre-Depends} to usb-modeswitch.
  - Remove usb-modeswitch.preinst.
  - Add usb-modeswitch.maintscript.
* Use my @d.o address and remove the DMUA flag.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/bin/sh
2
 
# next lines for bash, ignored by tclsh, restarting in background \
3
 
( \
4
 
count=120; \
5
 
while [ $count != 0 ]; do \
6
 
        if [ ! -e "/usr/bin/tclsh" ]; then \
7
 
                sleep 1; \
8
 
                count=$(($count - 1)); \
9
 
        else \
10
 
                exec /usr/bin/tclsh "$0" "$@" 2>/dev/null & \
11
 
                exit 0; \
12
 
        fi; \
13
 
done; \
14
 
) & \
15
 
exit 0
16
 
 
17
 
 
18
 
# Wrapper (tcl) for usb_modeswitch, called from
19
 
# /lib/udev/rules.d/40-usb_modeswitch.rules
20
 
# (part of data pack "usb-modeswitch-data") via
21
 
# /lib/udev/usb_modeswitch
22
 
#
23
 
# Does ID check on hotplugged USB devices and calls the
24
 
# mode switching program with the matching parameter file
25
 
# from /etc/usb_modeswitch.d
26
 
#
27
 
# Part of usb-modeswitch-1.1.4 package
28
 
# (C) Josua Dietze 2009, 2010
29
 
 
30
 
 
31
 
# Setting of the these switches is done in the global config
32
 
# file (/etc/usb_modeswitch.conf)
33
 
 
34
 
set logging 0
35
 
set noswitching 0
36
 
 
37
 
 
38
 
 
39
 
set env(PATH) "/bin:/usr/bin"
40
 
 
41
 
# Execution starts at file bottom
42
 
 
43
 
proc {Main} {argc argv} {
44
 
 
45
 
global scsi usb config match wc device logging noswitching settings
46
 
 
47
 
# The facility to add a symbolic link pointing to the
48
 
# ttyUSB port which provides interrupt transfer, i.e.
49
 
# the port to connect through; returns a symlink name
50
 
# for udev and exits
51
 
# This is run once for every device interface by an
52
 
# udev rule
53
 
 
54
 
if {[lindex $argv 0] == "--symlink-name"} {
55
 
#       set device [clock clicks]
56
 
        puts [SymLinkName [lindex $argv 1]]
57
 
        SafeExit
58
 
}
59
 
 
60
 
# The facility to bind the driver on-the-fly after a warm
61
 
# boot; the device is still in modem mode but if the
62
 
# driver was bound by the switching script before (ID
63
 
# not yet added to the driver), the device needs to be
64
 
# bound again
65
 
 
66
 
if {[lindex $argv 0] == "--driver-bind"} {
67
 
        CheckDriverBind [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] [lindex $argv 4]
68
 
        SafeExit
69
 
}
70
 
 
71
 
set settings(dbdir)     /etc/usb_modeswitch.d
72
 
set bindir      /usr/sbin
73
 
 
74
 
set devList1 {}
75
 
set devList2 {}
76
 
 
77
 
# argv contains the values provided from the udev rule
78
 
# separated by "/"
79
 
 
80
 
set argList [split [lindex $argv 0] /]
81
 
 
82
 
if [string length [lindex $argList 1]] {
83
 
        set device [lindex $argList 1]
84
 
} else {
85
 
        set device "noname"
86
 
}
87
 
 
88
 
ParseGlobalConfig
89
 
 
90
 
Log "raw args from udev: $argv"
91
 
 
92
 
if {$device == "noname"} {
93
 
        Log "No data from udev. Exiting"
94
 
        SafeExit
95
 
}
96
 
 
97
 
# arg 0: the bus id for the device (udev: %b)
98
 
# arg 1: the "kernel name" for the device (udev: %k)
99
 
#
100
 
# Both together give the top directory where the path
101
 
# to the SCSI attributes can be determined (further down)
102
 
# Addendum: older kernel/udev version seem to differ in
103
 
# providing these attributes - or not. So more probing
104
 
# is needed
105
 
 
106
 
if {[string length [lindex $argList 0]] == 0} {
107
 
        if {[string length [lindex $argList 1]] == 0} {
108
 
                Log "No device number values given from udev! Exiting"
109
 
                SafeExit
110
 
        } else {
111
 
                Log "Bus ID for device not given by udev."
112
 
                Log " Trying to determine it from kernel name ([lindex $argList 1]) ..."
113
 
                if {![regexp {(.*?):} [lindex $argList 1] d dev_top]} {
114
 
                        Log "Could not determine top device dir from udev values! Exiting"
115
 
                        SafeExit
116
 
                }
117
 
        }
118
 
} else {
119
 
        set dev_top [lindex $argList 0]
120
 
        regexp {(.*?):} $dev_top d dev_top
121
 
}
122
 
 
123
 
 
124
 
set devdir /sys/bus/usb/devices/$dev_top
125
 
if {![file isdirectory $devdir]} {
126
 
        Log "Top sysfs directory not found ($devdir)! Exiting"
127
 
        SafeExit
128
 
}
129
 
 
130
 
 
131
 
# Mapping of the short string identifiers (in the config
132
 
# file names) to the long name used here
133
 
#
134
 
# If we need them it's a snap to add new attributes here!
135
 
 
136
 
set match(sVe) scsi(vendor)
137
 
set match(sMo) scsi(model)
138
 
set match(sRe) scsi(rev)
139
 
set match(uMa) usb(manufacturer)
140
 
set match(uPr) usb(product)
141
 
set match(uSe) usb(serial)
142
 
 
143
 
 
144
 
# Now reading the USB attributes
145
 
 
146
 
ReadUSBAttrs $devdir
147
 
 
148
 
if {[string length "$usb(idVendor)$usb(idProduct)"] < 8} {
149
 
        Log "USB IDs not found in sysfs tree. Exiting"
150
 
        SafeExit
151
 
}
152
 
 
153
 
Log "----------------\nUSB values from sysfs:"
154
 
foreach attr {manufacturer product serial} {
155
 
        Log "  $attr\t$usb($attr)"
156
 
}
157
 
Log "----------------"
158
 
 
159
 
if $noswitching {
160
 
        Log "\nSwitching globally disabled. Exiting\n"
161
 
        catch {exec logger -p syslog.notice "usb_modeswitch: switching disabled, no action for $usb(idVendor):$usb(idProduct)" 2>/dev/null}
162
 
        SafeExit
163
 
}
164
 
 
165
 
# Check if there is more than one config file for this USB ID,
166
 
# which would point to a possible ambiguity. If so, check if
167
 
# SCSI values are needed
168
 
 
169
 
set configList [ConfigGet list $usb(idVendor):$usb(idProduct)]
170
 
 
171
 
if {[llength $configList] == 0} {
172
 
        Log "Aargh! Config file missing for $usb(idVendor):$usb(idProduct)! Exiting"
173
 
        SafeExit
174
 
}
175
 
 
176
 
set scsiNeeded 0
177
 
if {[llength $configList] > 1} {
178
 
        if [regexp {:s} $configList] {
179
 
                set scsiNeeded 1
180
 
        }
181
 
}
182
 
if {!$scsiNeeded} {
183
 
        Log "SCSI attributes not needed, moving on"
184
 
}
185
 
 
186
 
 
187
 
# Getting the SCSI values via libusb results in a detached
188
 
# usb-storage driver. Not good for devices that want to be
189
 
# left alone. Fortunately, the sysfs tree provides the values
190
 
# too without need for direct access
191
 
 
192
 
# First we wait until the SCSI data is ready - or timeout.
193
 
# Timeout means: no storage driver was bound to the device.
194
 
# We run 20 times max, every half second (max. 10 seconds
195
 
# total)
196
 
 
197
 
# We also check if the device itself changes, probably
198
 
# because it was switched by the kernel (or even unplugged).
199
 
# Then we do simply nothing and exit quietly ...
200
 
 
201
 
set counter 0
202
 
while {$scsiNeeded && $counter < 20} {
203
 
        after 500
204
 
        incr counter
205
 
        Log "waiting for storage tree in sysfs"
206
 
 
207
 
        set sysdir $devdir/[lindex $argList 1]
208
 
 
209
 
        if {![file isdirectory $sysdir]} {
210
 
                # Device is gone. Unplugged? Switched by kernel?
211
 
                Log "sysfs device tree is gone; exiting"
212
 
                SafeExit
213
 
        }
214
 
        set rc [open $devdir/product r]
215
 
        set newproduct [read -nonewline $rc]
216
 
        close $rc
217
 
        if {![string match $newproduct $usb(product)]} {
218
 
                # Device has just changed. Switched by someone else?
219
 
                Log "device has changed; exiting"
220
 
                SafeExit
221
 
        }
222
 
 
223
 
        # Searching the storage/SCSI tree; might take a while
224
 
        if {[set dirList [glob -nocomplain $sysdir/host*]] != ""} {
225
 
                set sysdir [lindex $dirList 0]
226
 
                if {[set dirList [glob -nocomplain $sysdir/target*]] != ""} {
227
 
                        set sysdir [lindex $dirList 0]
228
 
                        regexp {.*target(.*)} $sysdir d subdir
229
 
                        if {[set dirList [glob -nocomplain $sysdir/$subdir*]] != ""} {
230
 
                                set sysdir [lindex $dirList 0]
231
 
                                if [file exists $sysdir/vendor] {
232
 
                                        # Finally SCSI structure is ready, get the values
233
 
                                        ReadSCSIAttrs $sysdir
234
 
                                        Log "SCSI values read"
235
 
                                        break
236
 
                                }
237
 
                        }
238
 
                }
239
 
        }
240
 
}
241
 
if $scsiNeeded {
242
 
        if {$counter == 20 && [string length $scsi(vendor)] == 0} {
243
 
                Log "SCSI tree not found; you may want to check if this path/file exists:"
244
 
                Log "$sysdir/vendor\n"
245
 
        } else {
246
 
                Log "----------------\nSCSI values from sysfs:"
247
 
                foreach attr {vendor model rev} {
248
 
                        Log " $attr\t$scsi($attr)"
249
 
                }
250
 
                Log "----------------"
251
 
        }
252
 
        Log "Waiting 3 secs. after SCSI device was added"
253
 
        after 3000
254
 
} else {
255
 
        after 500
256
 
}
257
 
 
258
 
# If SCSI tree in sysfs was not identified, try and get the values
259
 
# from a (nonswitching) call of usb_modeswitch; this detaches the
260
 
# storage driver, so it's just the last resort
261
 
 
262
 
if {$scsiNeeded && $scsi(vendor)==""} {
263
 
        set testSCSI [exec $bindir/usb_modeswitch -v 0x$usb(idVendor) -p 0x$usb(idProduct) 2>/dev/null]
264
 
        regexp {  Vendor String: (.*?)\n} $testSCSI d scsi(vendor)
265
 
        regexp {   Model String: (.*?)\n} $testSCSI d scsi(model)
266
 
        regexp {Revision String: (.*?)\n} $testSCSI d scsi(rev)
267
 
        Log "SCSI values from usb_modeswitch:"
268
 
        foreach attr {vendor model rev} {
269
 
                Log " $attr\t$scsi($attr)"
270
 
        }
271
 
}
272
 
 
273
 
# If we don't have the SCSI values by now, we just
274
 
# leave the variables empty; they won't match anything
275
 
 
276
 
# Time to check for a matching config file.
277
 
# Matching itself is done by MatchDevice
278
 
#
279
 
# Sorting the configuration file names reverse so that
280
 
# the ones with matching additions are tried first; the
281
 
# common configs without match attributes are used at the
282
 
# end and provide a fallback
283
 
 
284
 
set report {}
285
 
#set configList [glob -nocomplain $settings(dbdir)/$usb(idVendor):$usb(idProduct)*]
286
 
foreach configuration [lsort -decreasing $configList] {
287
 
 
288
 
        # skipping installer leftovers
289
 
        if [regexp {\.(dpkg|rpm)} $configuration] {continue}
290
 
 
291
 
        Log "checking config: $configuration"
292
 
        if [MatchDevice $configuration] {
293
 
                ParseDeviceConfig [ConfigGet config $configuration]
294
 
                set devList1 [glob -nocomplain /dev/ttyUSB* /dev/ttyACM* /dev/ttyHS*]
295
 
                if {$config(waitBefore) == ""} {
296
 
                        Log "! matched, now switching"
297
 
                } else {
298
 
                        Log "! matched, waiting time set to $config(waitBefore) seconds"
299
 
                        after [expr $config(waitBefore) * 1000]
300
 
                        Log " waiting is over, switching starts now"
301
 
                }
302
 
 
303
 
                # Now we are actually switching
304
 
                if $logging {
305
 
                        Log " (running command: $bindir/usb_modeswitch -I -W -c $settings(tmpConfig))"
306
 
                        set report [exec $bindir/usb_modeswitch -I -W -D -c $settings(tmpConfig) 2>@ stdout]
307
 
                } else {
308
 
                        set report [exec $bindir/usb_modeswitch -I -Q -D -c $settings(tmpConfig) 2>/dev/null]
309
 
                }
310
 
                Log "\nverbose output of usb_modeswitch:"
311
 
                Log "--------------------------------"
312
 
                Log $report
313
 
                Log "--------------------------------"
314
 
                Log "(end of usb_modeswitch output)\n"
315
 
                if [regexp {/tmp/} $settings(tmpConfig)] {
316
 
                        file delete  $settings(tmpConfig)
317
 
                }
318
 
                break
319
 
        } else {
320
 
                Log "* no match, not switching with this config"
321
 
        }
322
 
}
323
 
 
324
 
# We're finished with switching; success checking
325
 
# was done by usb_modeswitch and logged via syslog.
326
 
#
327
 
# If switching was OK we now check for drivers by
328
 
# simply recounting serial devices under /dev
329
 
 
330
 
# If target ID given, driver shall be loaded
331
 
if [regexp -nocase {ok:[0-9a-f]{4}:[0-9a-f]{4}} $report] {
332
 
 
333
 
        # For general driver loading; TODO: add respective device names.
334
 
        # Presently only useful for HSO devices (which are recounted now)
335
 
        if {$config(driverModule) == ""} {
336
 
                set config(driverModule) "option"
337
 
                set config(driverIDPath) "/sys/bus/usb-serial/drivers/option1"
338
 
        } else {
339
 
                if {$config(driverIDPath) == ""} {
340
 
                        set config(driverIDPath) "/sys/bus/usb/drivers/$config(driverModule)"
341
 
                }
342
 
        }
343
 
        Log "Driver module is \"$config(driverModule)\", ID path is $config(driverIDPath)\n"
344
 
 
345
 
        # some settling time in ms
346
 
        after 500
347
 
 
348
 
        Log "Now checking for newly created serial devices ..."
349
 
        set devList2 [glob -nocomplain /dev/ttyUSB* /dev/ttyACM* /dev/ttyHS*]
350
 
 
351
 
        if {[llength $devList1] >= [llength $devList2]} {
352
 
                Log " no new serial devices found"
353
 
 
354
 
                if {![file isdirectory $devdir]} {
355
 
                        Log "Device directory in sysfs is gone! Something went wrong, aborting"
356
 
                        SafeExit
357
 
                }
358
 
 
359
 
                # Give the device annother second if it's not fully back yet
360
 
                if {![file exists $devdir/idProduct]} {
361
 
                        after 1000
362
 
                }
363
 
 
364
 
                ReadUSBAttrs $devdir
365
 
                if {[string length "$usb(idVendor)$usb(idProduct)"] < 8} {
366
 
                        regexp {ok:(\w{4}):(\w{4})} $report d usb(idVendor) usb(idProduct)
367
 
                }
368
 
                set t "$usb(idVendor)$usb(idProduct)"
369
 
                if {[string length $t] == 8 && [string trim $t 0] != ""} {
370
 
                        set idfile $config(driverIDPath)/new_id
371
 
                        if {![file exists $idfile]} {
372
 
                                Log "\nTrying to load driver \"$config(driverModule)\""
373
 
                                set loader /sbin/modprobe
374
 
                                Log " loader is: $loader"
375
 
                                if [file exists $loader] {
376
 
                                        if [catch {set result [exec $loader -v $config(driverModule) 2>/dev/null]} err] {
377
 
                                                Log " Running \"$loader $config(driverModule)\" gave an error:\n  $err"
378
 
                                        }
379
 
                                } else {
380
 
                                        Log " /sbin/modprobe not found"
381
 
                                }
382
 
                        }
383
 
                        if [file exists $idfile] {
384
 
                                Log "Trying to add ID to driver \"$config(driverModule)\""
385
 
                                catch {exec logger -p syslog.notice "usb_modeswitch: adding device ID $usb(idVendor):$usb(idProduct) to driver \"$config(driverModule)\"" 2>/dev/null}
386
 
                                catch {exec echo "$usb(idVendor) $usb(idProduct)" >$idfile 2>/dev/null}
387
 
                                after 600
388
 
                                set devList2 [glob -nocomplain /dev/ttyUSB* /dev/ttyACM* /dev/ttyHS*]
389
 
                                if {[llength $devList1] >= [llength $devList2]} {
390
 
                                        Log " still no new serial devices found"
391
 
                                } else {
392
 
                                        AddLastSeen "$usb(idVendor):$usb(idProduct)"
393
 
                                        Log " driver successfully bound"
394
 
                                }
395
 
                        } else {
396
 
                                Log " \"$idfile\" not found, can't add ID"
397
 
                        }
398
 
                }
399
 
        } else {
400
 
                Log " new serial devices found, driver has bound"
401
 
        }
402
 
}
403
 
 
404
 
 
405
 
 
406
 
if [regexp {ok:$} $report] {
407
 
        Log "Doing no driver checking or binding for this device"
408
 
}
409
 
 
410
 
# In newer kernels there is a switch to avoid the use of a device
411
 
# reset (e.g. from usb-storage) which would likely switch back
412
 
# a mode-switching device
413
 
if [regexp {ok:} $report] {
414
 
        Log "Checking for AVOID_RESET_QUIRK attribute"
415
 
        if [file exists $devdir/avoid_reset_quirk] {
416
 
                if [catch {exec echo "1" >$devdir/avoid_reset_quirk 2>/dev/null} err] {
417
 
                        Log " Error setting the attribute: $err"
418
 
                } else {
419
 
                        Log " AVOID_RESET_QUIRK activated"
420
 
                }
421
 
        } else {
422
 
                Log " AVOID_RESET_QUIRK not present"
423
 
        }
424
 
}
425
 
 
426
 
Log "\nAll done, exiting\n"
427
 
SafeExit
428
 
 
429
 
}
430
 
# end of proc {Main}
431
 
 
432
 
 
433
 
proc {ReadSCSIAttrs} {dir} {
434
 
 
435
 
global scsi
436
 
Log "SCSI dir exists: $dir"
437
 
 
438
 
foreach attr {vendor model rev} {
439
 
        if [file exists $dir/$attr] {
440
 
                set rc [open $dir/$attr r]
441
 
                set scsi($attr) [read -nonewline $rc]
442
 
                close $rc
443
 
        } else {
444
 
                set scsi($attr) ""
445
 
                Log "Warning: SCSI attribute \"$attr\" not found."
446
 
        }
447
 
}
448
 
 
449
 
}
450
 
# end of proc {ReadSCSIAttrs}
451
 
 
452
 
 
453
 
proc {ReadUSBAttrs} {dir} {
454
 
 
455
 
global usb
456
 
Log "USB dir exists: $dir"
457
 
 
458
 
foreach attr {idVendor idProduct manufacturer product serial} {
459
 
        if [file exists $dir/$attr] {
460
 
                set rc [open $dir/$attr r]
461
 
                set usb($attr) [read -nonewline $rc]
462
 
                close $rc
463
 
        } else {
464
 
                set usb($attr) ""
465
 
                Log "Warning: USB attribute \"$attr\" not found."
466
 
        }
467
 
}
468
 
 
469
 
}
470
 
# end of proc {ReadUSBAttrs}
471
 
 
472
 
 
473
 
proc {MatchDevice} {config} {
474
 
 
475
 
global scsi usb match
476
 
 
477
 
set devinfo [file tail $config]
478
 
set infoList [split $devinfo :]
479
 
set stringList [lrange $infoList 2 end]
480
 
if {[llength $stringList] == 0} {return 1}
481
 
 
482
 
foreach teststring $stringList {
483
 
        if {$teststring == "?"} {return 0}
484
 
        set tokenList [split $teststring =]
485
 
        set id [lindex $tokenList 0]
486
 
        set matchstring [lindex $tokenList 1]
487
 
        set blankstring ""
488
 
        regsub -all {_} $matchstring { } blankstring
489
 
        Log "matching $match($id)"
490
 
        Log "  match string1: $matchstring"
491
 
        Log "  match string2: $blankstring"
492
 
        Log " device string: [set $match($id)]"
493
 
        if {!([string match *$matchstring* [set $match($id)]] || [string match *$blankstring* [set $match($id)]])} {
494
 
                return 0
495
 
        }
496
 
}
497
 
return 1
498
 
 
499
 
}
500
 
# end of proc {MatchDevice}
501
 
 
502
 
 
503
 
proc {ParseGlobalConfig} {} {
504
 
 
505
 
global logging noswitching
506
 
 
507
 
set configFile ""
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] {
511
 
                set configFile $cfg
512
 
                break
513
 
        }
514
 
}
515
 
 
516
 
if {$configFile == ""} {return}
517
 
 
518
 
set rc [open $configFile r]
519
 
while {![eof $rc]} {
520
 
        gets $rc line
521
 
        if [regexp {DisableSwitching\s*=\s*([^\s]+)} $line d val] {
522
 
                if [regexp -nocase {1|yes|true} $val] {
523
 
                        set noswitching 1
524
 
                }
525
 
        }
526
 
        if [regexp {EnableLogging\s*=\s*([^\s]+)} $line d val] {
527
 
                if [regexp -nocase {1|yes|true} $val] {
528
 
                        set logging 1
529
 
                }
530
 
        }
531
 
 
532
 
}
533
 
Log "Using global config file: $configFile"
534
 
 
535
 
}
536
 
# end of proc {ParseGlobalConfig}
537
 
 
538
 
 
539
 
proc ParseDeviceConfig {configFile} {
540
 
 
541
 
global config
542
 
set config(driverModule) ""
543
 
set config(driverIDPath) ""
544
 
set config(waitBefore) ""
545
 
set rc [open $configFile r]
546
 
set lineList [split [read $rc] \n]
547
 
close $rc
548
 
foreach line $lineList {
549
 
        regexp {DriverModule[[:blank:]]*=[[:blank:]]*"?(\w+)"?} $line d config(driverModule)
550
 
        regexp {DriverIDPath[[:blank:]]*=[[:blank:]]*?"?([/\-\w]+)"?} $line d config(driverIDPath)
551
 
        regexp {WaitBefore[[:blank:]]*=[[:blank:]]*?(\d+)} $line d config(waitBefore)
552
 
}
553
 
set config(waitBefore) [string trimleft $config(waitBefore) 0]
554
 
 
555
 
}
556
 
# end of proc {ParseDeviceConfig}
557
 
 
558
 
 
559
 
proc {ConfigGet} {command config} {
560
 
 
561
 
global settings
562
 
 
563
 
switch $command {
564
 
 
565
 
        list {
566
 
                if [file exists $settings(dbdir)/configPack.tar.gz] {
567
 
                        Log "Found packed config collection $settings(dbdir)/configPack.tar.gz"
568
 
                        if [catch {set configList [exec tar -tzf $settings(dbdir)/configPack.tar.gz 2>/dev/null]} err] {
569
 
                                Log "Error: problem opening config package; tar returned\n $err"
570
 
                                return {}
571
 
                        }
572
 
                        set configList [split $configList \n]
573
 
                        set configList [lsearch -all -inline $configList $config*]
574
 
                } else {
575
 
                        set configList [glob -nocomplain $settings(dbdir)/$config*]
576
 
                }
577
 
 
578
 
                return $configList
579
 
        }
580
 
        config {
581
 
                if [file exists $settings(dbdir)/configPack.tar.gz] {
582
 
                        set settings(tmpConfig) /tmp/usb_modeswitch.current_cfg
583
 
                        Log "Extracting config $config from collection $settings(dbdir)/configPack.tar.gz"
584
 
                        set wc [open $settings(tmpConfig) w]
585
 
                        puts -nonewline $wc [exec tar -xzOf $settings(dbdir)/configPack.tar.gz $config 2>/dev/null]
586
 
                        close $wc
587
 
                } else {
588
 
                        set settings(tmpConfig) $config
589
 
                }
590
 
                return $settings(tmpConfig)
591
 
        }
592
 
}
593
 
 
594
 
}
595
 
# end of proc {ConfigGet}
596
 
 
597
 
proc {Log} {msg} {
598
 
 
599
 
global wc logging device
600
 
if {$logging == 0} {return}
601
 
if {![info exists wc]} {
602
 
        if [catch {set wc [open /var/log/usb_modeswitch_$device a]} err] {
603
 
                set wc "error"
604
 
                puts "Error: Can't write to log file, $err"
605
 
                return
606
 
        }
607
 
        puts $wc "\n\nUSB_ModeSwitch log from [clock format [clock seconds]]\n"
608
 
}
609
 
if {$wc == "error"} {return}
610
 
puts $wc $msg
611
 
 
612
 
}
613
 
# end of proc {Log}
614
 
 
615
 
 
616
 
# Closing the log file if open and exit
617
 
proc {SafeExit} {} {
618
 
 
619
 
global wc
620
 
if [info exists wc] {
621
 
        catch {close $wc}
622
 
}
623
 
exit
624
 
 
625
 
}
626
 
# end of proc {SafeExit}
627
 
 
628
 
 
629
 
# Checking for interrupt endpoint in ttyUSB port (lowest if there is
630
 
# more than one); if found, check for unused "gsmmodem[n]" name.
631
 
# Link for first modem will be "gsmmodem", then "gsmmodem2" and up
632
 
 
633
 
proc {SymLinkName} {path} {
634
 
 
635
 
# Internal proc, used only here
636
 
proc {hasInterrupt} {ifDir} {
637
 
        if {[llength [glob -nocomplain $ifDir/ttyUSB*]] == 0} {return 0}
638
 
        foreach epDir [glob -nocomplain $ifDir/ep_*] {
639
 
                if [file exists $epDir/type] {
640
 
                        set rc [open $epDir/type r]
641
 
                        set type [read $rc]
642
 
                        close $rc
643
 
                        if [regexp {Interrupt} $type] {
644
 
                                return 1
645
 
                        }
646
 
                }
647
 
        }
648
 
        return 0
649
 
}
650
 
 
651
 
# In case the device path is returned as /class/tty/ttyUSB,
652
 
# we need to extract the USB device path from symlink "device"
653
 
set linkpath /sys$path/device
654
 
if [file exists $linkpath] {
655
 
        if {[file type $linkpath] == "link"} {
656
 
                set rawpath [file link $linkpath]
657
 
                set trimpath [regsub -all {\.\./} $rawpath {}]
658
 
                if [file isdirectory /sys/$trimpath] {
659
 
                        set path /$trimpath
660
 
                }
661
 
        }
662
 
}
663
 
 
664
 
if {![regexp {ttyUSB\d+?} $path myPort]} {
665
 
        return ""
666
 
}
667
 
if {![regexp "\\d+\\.(\\d+)/$myPort" $path d myIf]} {
668
 
        return ""
669
 
}
670
 
if {![regexp {usb\d*/(\d+-\d+)/} $path d dev_top]} {
671
 
        return ""
672
 
}
673
 
 
674
 
set dirList [split $path /]
675
 
set idx [lsearch $dirList $dev_top]
676
 
set devDir /sys[join [lrange $dirList 0 $idx] /]
677
 
 
678
 
if {![regexp "$devDir/$dev_top:\[0-9\]" /sys$path ifRoot]} {
679
 
        return ""
680
 
}
681
 
set ifDir $ifRoot.$myIf
682
 
 
683
 
set rightPort 0
684
 
if [hasInterrupt $ifDir] {
685
 
        set rightPort 1
686
 
}
687
 
 
688
 
# Unfortunately, there are devices with more than one interrupt
689
 
# port. The assumption so far is that the lowest of these is
690
 
# right. Check all lower interfaces for annother one (if interface)
691
 
# is bigger than 0). If found, don't return any name.
692
 
if { $rightPort && ($myIf > 0) } {
693
 
        for {set i 0} {$i < $myIf} {incr i} {
694
 
                set ifDir $ifRoot.$i
695
 
                if [hasInterrupt $ifDir] {
696
 
                        set rightPort 0
697
 
                        break
698
 
                }
699
 
        }
700
 
}
701
 
if {$rightPort == 0} {
702
 
        return ""
703
 
}
704
 
 
705
 
# Use first free "gsmmodem[n]" name
706
 
cd /dev
707
 
set idx 2
708
 
set symlinkName "gsmmodem"
709
 
while {$idx < 256} {
710
 
        if {![file exists $symlinkName]} {
711
 
                break
712
 
        }
713
 
        set symlinkName gsmmodem$idx
714
 
        incr idx
715
 
}
716
 
return $symlinkName
717
 
 
718
 
}
719
 
# end of proc {SymLinkName}
720
 
 
721
 
 
722
 
# Add serial driver after warm boot
723
 
proc {CheckDriverBind} {path vid pid prod} {
724
 
 
725
 
if {$vid == ""} {set vid $prod}
726
 
if [regexp {/} $vid] {
727
 
        set id_list [split $vid /]
728
 
        set vid [format %04s [lindex $id_list 0]]
729
 
        set pid [format %04s [lindex $id_list 1]]
730
 
}
731
 
 
732
 
set dirList [glob -nocomplain /sys$path/*]
733
 
if [string match *ttyUSB* $dirList] {return}
734
 
 
735
 
if {[WasLastSeen $vid:$pid] == 0} {return}
736
 
 
737
 
set config(driverModule) "option"
738
 
set config(driverIDPath) "/sys/bus/usb-serial/drivers/option1"
739
 
set idfile $config(driverIDPath)/new_id
740
 
if {![file exists $idfile]} {
741
 
        set loader /sbin/modprobe
742
 
        if {![file exists $loader]} {return}
743
 
        if [catch {exec $loader $config(driverModule) 2>/dev/null}] {return}
744
 
        set i 0
745
 
        while {$i < 50} {
746
 
                if [file exists $idfile] {
747
 
                        break
748
 
                }
749
 
                after 20
750
 
                incr i
751
 
        }
752
 
        if {$i == 50} {return}
753
 
}
754
 
catch {exec echo "$vid $pid" >$idfile 2>/dev/null}
755
 
 
756
 
}
757
 
# end of proc {CheckDriverBind}
758
 
 
759
 
 
760
 
# Add USB ID to list of devices needing driver binding
761
 
proc {AddLastSeen} {id} {
762
 
 
763
 
set lastseen /etc/usb_modeswitch.d/last_seen
764
 
if [file exists $lastseen] {
765
 
        set rc [open $lastseen r]
766
 
        set buffer [read $rc]
767
 
        close $rc
768
 
        if [string match *$id* $buffer] {
769
 
                return
770
 
        }
771
 
        set idList [split [string trim $buffer] \n]
772
 
}
773
 
lappend idList $id
774
 
set buffer [join $idList "\n"]
775
 
if [catch {set wc [open $lastseen w]}] {return}
776
 
puts -nonewline $wc $buffer
777
 
close $wc
778
 
 
779
 
}
780
 
# end of proc {AddLastSeen}
781
 
 
782
 
 
783
 
# Check if USB ID is listed as needing driver binding
784
 
proc {WasLastSeen} {id} {
785
 
 
786
 
set lastseen /etc/usb_modeswitch.d/last_seen
787
 
if {![file exists $lastseen]} {return 0}
788
 
set rc [open $lastseen r]
789
 
set buffer [read $rc]
790
 
close $rc
791
 
if [string match *$id* $buffer] {
792
 
        return 1
793
 
} else {
794
 
        return 0
795
 
}
796
 
 
797
 
}
798
 
# end of proc {WasLastSeen}
799
 
 
800
 
 
801
 
# The actual entry point
802
 
Main $argc $argv
803