Skip to content

Instantly share code, notes, and snippets.

@jettero
Last active September 30, 2020 22:09
Show Gist options
  • Save jettero/15919217ff4137a40ff73ed9cc51e723 to your computer and use it in GitHub Desktop.
Save jettero/15919217ff4137a40ff73ed9cc51e723 to your computer and use it in GitHub Desktop.
Every now and again my xhci_hcd goes wonky and I can't get USB devices to pop up on it. I hate rebooting for usb problems, so I came up with this.
#!/usr/bin/env bash
# old http://billauer.co.il/blog/2013/02/usb-reset-ehci-uhci-linux/
# old http://enc.com.au/2014/02/14/resetting-usb-devices/
#
# http://www.linux.org/threads/resetting-the-usb-subsystem.6256/
# (page was dead, used google cache)
#
# XXX This definitely worked (2016-08-21), the trouble is finding the serial
# number and the bind/unbind kernel interfaces
#
# echo 0000:00:14.0 | sudo tee /sys/bus/pci/drivers/xhci_hcd/unbind
# echo 0000:00:14.0 | sudo tee /sys/bus/pci/drivers/xhci_hcd/bind
#
# XXX This program produces the right output, but will it work in 6 months or
# whenver the hell I need this reset again??
#
## dmesg notes
# [5809402.670110] usb 3-4: new full-speed USB device number 35 using xhci_hcd
# [5809407.786315] usb 3-4: device descriptor read/8, error -110
# [5809412.999259] usb 3-4: device descriptor read/8, error -110
# [5809413.212180] usb 3-4: new full-speed USB device number 36 using xhci_hcd
# [5809418.324116] usb 3-4: device descriptor read/8, error -110
# [5809423.537067] usb 3-4: device descriptor read/8, error -110
## serial notes
# the article uses lsusb, which is slow and meant for human parsing, not
# machine parsing. this file seems to have the serial I need though, and
# matches the bus number that was malfunctioning (3)
#
# echo $(< /sys/bus/usb/devices/usb3/serial)
# 0000:00:14.0
#
## find notes
# it's not always going to be xhci_hcd (there's also uhci and ehci, etc)
# this usually produces exactly one match.
# application of s/$serial/unbind/ aught to do the trick
#
# find /sys/bus/pci/drivers -name 0000:00:14.0
# /sys/bus/pci/drivers/xhci_hcd/0000:00:14.0
BUSNUMBER="$1"; shift
function perform-the-reset() {
SERIAL="$1"; shift
DRV="$(sed -e "s,/$SERIAL\$,," <<< "$1")"; shift
echo "sending unbind: echo $SERIAL | sudo tee $DRV/unbind"
[ -z "$DRY_RUN" ] && (echo "$SERIAL" | sudo tee "$DRV/unbind")
[ -z "$DRY_RUN" ] && sleep 2 # doubt this is ever necessary … meh
echo "sending bind: echo $SERIAL | sudo tee $DRV/bind"
[ -z "$DRY_RUN" ] && (echo "$SERIAL" | sudo tee "$DRV/bind")
}
if [ -z "$BUSNUMBER" ]; then
echo
echo BUSNUMBER unspecified, trying to guess
dmesg | grep 'usb [0-9]-[0-9].*error' | tail -n 10 | sed -e 's/^/ /'
lasterr="$(dmesg | grep 'usb [0-9]-[0-9].*error' | tail -n 1)"
if [[ "$lasterr" =~ ([0-9])-([0-9]): ]]; then
GUESS="${BASH_REMATCH[1]}"
echo "guessing bus=$GUESS hit enter if this is right"
else
echo
fi
read -ep "usb bus number: " -i "$GUESS" BUSNUMBER
fi
if [ -d "/sys/bus/usb/devices/usb$BUSNUMBER" ]; then
echo "found the bus device in sysfs /sys/bus/usb/devices/usb$BUSNUMBER"
SERIAL="$(< /sys/bus/usb/devices/usb$BUSNUMBER/serial)"
if [ -n "$SERIAL" ]; then
echo "found the serial number: $SERIAL"
echo "trying to find the driver bind/unbind files"
drvsno=( $(find /sys/bus/pci/drivers -name "$SERIAL") )
drvsnoc=${#drvsno[*]}
if [ $drvsnoc == 1 ]; then
echo "found this serial in exactly one driver $drvsno"
perform-the-reset $SERIAL $drvsno
elif [ $drvsnoc == 0 ]; then
echo "unable to find any drivers with this serial, strange"
echo "this tool was only ever tested on xhci_hcd … patches welcome"
else
echo "found more than one driver, please specify which you wish to try"
for d in "${drvsno[@]}"; do
echo $d
done
read -ep which: -i "${drvsno[0]}" driver
perform-the-reset $SERIAL $driver
fi
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment