Hi GNUser
Hi Rich. Why not unbind+bind using the generic /sys/bus/usb/drivers/usb/unbind and /sys/bus/usb/drivers/usb/bind? ...
There are a bunch of directories under /sys/bus/usb/drivers/usb/.
I don't want to guess and reset something too high in the chain of
devices, like a hub, and resetting everything connected to it.
I changed my tactics and rewrote the script:
1. I'm using udevadm to find device path(s) for VID and PID.
2. Then use udevadm to find the driver name.
3. Find the driver name in /sys/.
That provides BINDPATH (plus BINDFILE and UNBINDFILE).
4. Sort the links in BINDPATH from longest to shortest.
5. Check the links to see which one points back to our device.
6. Strip the leading path information from the link (USBPORT).
7. Use USBPORT , BINDFILE , and UNBINDFILE to reset the port.
#!/bin/sh
Debug="test"
# Uncomment the next line to turn on debugging messages.
Debug="echo"
# Vendor ID and product ID (8644:8003).
VID="8644"
PID="8003"
# Notes
# This is the driver property we are looking for.
# ID_USB_DRIVER=usb-storage
#
# This won't work because it searches for "ID_VENDOR_ID=0644 OR ID_MODEL_ID=0200"
# udevadm trigger -v -n -t devices -p ID_VENDOR_ID=0644 -p ID_MODEL_ID=0200
#
# Returns properties for the device listed in the path.
# udevadm info -q property -p /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-7
udevadm trigger -v -n -t devices -p ID_VENDOR_ID="$VID" | sort > VIDs.txt
udevadm trigger -v -n -t devices -p ID_MODEL_ID="$PID" | sort > PIDs.txt
# Since we had to search for VID and PID separately, we check which
# results are common to both lists for an exact match.
DEVICES="$(comm -12 VIDs.txt PIDs.txt)"
[ -z "$DEVICES" ] && echo "No DEVICES found" && exit 1
for DEVICE in $DEVICES
do
ID_USB_DRIVER="$(udevadm info -q property -p "$DEVICE" | grep "ID_USB_DRIVER=" | cut -d = -f2)"
"$Debug" "DEVICE=$DEVICE ID_USB_DRIVER=$ID_USB_DRIVER"
[ -n "$ID_USB_DRIVER" ] && break
done
[ -z "$ID_USB_DRIVER" ] && echo "No ID_USB_DRIVER found" && exit 1
BINDPATH="$(find /sys/bus/usb/drivers/ -type d -name "$ID_USB_DRIVER")"
[ -z "$BINDPATH" ] && echo "No BINDPATH found" && exit 1
# That directory should contain the unbind and bind files.
BINDFILE="$BINDPATH""/bind"
UNBINDFILE="$BINDPATH""/unbind"
"$Debug" "BINDPATH=$BINDPATH"
"$Debug" "BINDFILE=$BINDFILE"
"$Debug" "UNBINDFILE=$UNBINDFILE"
# Needed for embedding a newline character in "for ITEM in ..." loop.
# Without it, sort and cut won't be applied to all ITEMs in LIST.
NL="
"
# BINDPATH directory contains links to devices using that driver.
# ${#ITEM} returns string length for sorting later on.
# "/sys/${ITEM##*../}" converts ../../../../devices/... to /sys/devices/...
for ITEM in $(readlink "$BINDPATH"/*)
do
LIST=$LIST$(printf "%04d %s\n" ${#ITEM} "/sys/${ITEM##*../}")$NL
done
"$Debug" "LIST=$LIST"
# We want to sort longest to shortest and remove the string lengths.
CHOICES="$(echo "$LIST" | sort -r | cut -c 6-)"
"$Debug" "CHOICES=$CHOICES"
# Yhis tries to find and remove needle (CHOICE) from haystack (DEVICE).
# If it succeeds, we found the link to our device.
for CHOICE in $CHOICES
do
if [ "$DEVICE" != "${DEVICE/$CHOICE/}" ]
then
# Remove leading path information.
USBPORT="${CHOICE##*/}"
"$Debug" "USBPORT=$USBPORT"
break
fi
done
if [ -e "$UNBINDFILE" ]
then
# Remove device.
echo "$USBPORT" | sudo tee "$UNBINDFILE" 1> /dev/null
fi
"$Debug" "Sleep ..."
sleep 3
"$Debug" "... Wake up"
if [ -e "$BINDFILE" ]
then
# Add device back.
echo "$USBPORT" | sudo tee "$BINDFILE" 1> /dev/null
fi
# Clean up.
rm -rf VIDs.txt
rm -rf PIDs.txt
Hopefully, third times the charm.