usb-modeswitch: add from /packages, merge usb-modeswitch-data, use libusb-compat...
[openwrt.git] / package / system / utils / usb-modeswitch / files / modeswitch.hotplug
1 #!/bin/sh
2
3 local uVid uPid uMa uPr uSe
4 local sVe sMo sRe
5
6 local modeswitch="/usr/bin/usb_modeswitch"
7
8
9 log() {
10         logger -t "usb-modeswitch" "$@"
11 }
12
13 sanitize() {
14         sed -e 's/[[:space:]]\+$//; s/[[:space:]]\+/_/g' "$@"
15 }
16
17 find_scsi_attrs() {
18         [ -n "$DEVPATH" ] && [ -d /sys/$DEVPATH/host* ] && {
19                 log "$DEVICENAME is a SCSI device, waiting for it to settle..."
20                 local timeout=20
21                 while [ $((--timeout)) -ge 0 ]; do
22                         [ -d /sys/$DEVPATH/host*/target* ] && {
23                                 local scsi_dir
24                                 for scsi_dir in /sys/$DEVPATH/host*/target*/*; do
25                                         [ -d "$scsi_dir" ] || break
26                                         case "$scsi_dir" in
27                                                 */host*/target*/*:*:*:*)
28                                                         sVe=$(sanitize "$scsi_dir/vendor")
29                                                         sMo=$(sanitize "$scsi_dir/model")
30                                                         sRe=$(sanitize "$scsi_dir/rev")
31
32                                                         log "$DEVICENAME: Vendor=${sVe:-?} Model=${sMo:-?} Revision=${sRe:-?}"
33                                                         return 0
34                                                 ;;
35                                         esac
36                                 done
37                         } || {
38                                 sleep 1
39                         }
40                 done
41                 log "$DEVICENAME: Failed to get SCSI attributes!"
42         }
43
44         return 1
45 }
46
47 find_usb_attrs() {
48         local usb_dir="/sys/$DEVPATH"
49         [ -f "$usb_dir/idVendor" ] || usb_dir="${usb_dir%/*}"
50
51         uVid=$(cat "$usb_dir/idVendor")
52         uPid=$(cat "$usb_dir/idProduct")
53         uMa=$(sanitize "$usb_dir/manufacturer")
54         uPr=$(sanitize "$usb_dir/product")
55         uSe=$(sanitize "$usb_dir/serial")
56
57         log "$DEVICENAME: Manufacturer=${uMa:-?} Product=${uPr:-?} Serial=${uSe:-?}"
58 }
59
60 match_config_tag() {
61         local conf="$1"
62         local tag="$2"
63
64         case "${conf##*/}" in
65                 *:*$tag=*)
66                         local cmp; eval "cmp=\$$tag"
67                         local pat="${conf#*:$tag=}"; pat="${pat%%:*}"
68                         case "$cmp" in
69                                 *$pat*) return 0 ;;
70                                 *) return 1 ;;
71                         esac
72                 ;;
73         esac
74
75         return 0
76 }
77
78 match_config() {
79         local conf="$1"
80         local tag
81
82         for tag in uMa uPr uSe sVe sMo sRe; do
83                 match_config_tag "$conf" "$tag" || return 1
84         done
85
86         return 0
87 }
88
89
90
91 if [ "$ACTION" = add ]; then
92         [ -d "/etc/usb_modeswitch.d" ] && [ -x "$modeswitch" ] && {
93                 case "$DEVICENAME" in
94                         *-*:*.*) : ;;
95                         *) exit 0 ;;
96                 esac
97
98                 find_usb_attrs
99
100                 local candidates=0
101                 local conf configs
102                 for conf in /etc/usb_modeswitch.d/$uVid:$uPid*; do
103                         [ -f "$conf" ] || break
104                         configs="${configs:+$configs }$conf"
105                         $((candidates++))
106                 done
107
108                 # Found more than one candidate, read SCSI attributes and find the best match
109                 [ $candidates -gt 1 ] && {
110                         find_scsi_attrs
111                         for conf in $configs; do
112                                 match_config "$conf" && {
113                                         configs="$conf"
114                                         candidates=1
115                                         break
116                                 }
117                         done
118                 }
119
120                 # If a candidate is remaining, start usb-modeswitch
121                 [ -n "$configs" ] && {
122                         log "$DEVICENAME: Selecting ${configs%% *} for mode switching"
123                         # ugly workaround, but working for all hw we got for testing
124                         switching_done=0
125                         switching_tries=0
126                         local usb_dir="/sys/$DEVPATH"
127                         [ -f "$usb_dir/idVendor" ] || usb_dir="${usb_dir%/*}"
128                         while [ $switching_done -lt 1 -a $switching_tries -le 6 ]; do
129                                 $modeswitch -v $uVid -p $uPid -I -D -n -s 30 -c "${configs%% *}"
130                                 if [ $(sanitize "$usb_dir/idProduct") = $uPid ]; then
131                                         log "$DEVICENAME: Switching seemingly failed"
132                                         sleep 1
133                                 else
134                                         switching_done=1
135                                 fi
136                                 switching_tries=$(( $switching_tries + 1 ))
137                         done
138                 }
139         }
140 fi