modeswitch.hotplug 3.0 KB

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