John Fremlin's blog: USB replug script in bash

Posted 2020-09-08 22:00:00 GMT

USB devices especially webcams frequently get wedged, and stop responding to the host computer. On Linux, you can reset them with software directing the unplug or replug event by calling bind and unbind.

This script maps from the USB port path, which can be complex, to the USB vendor id and product id. Unfortunately, lsusb does not report the port path.

Without a device to reset, it prints something like this

1-10 -> 8087:0029 unknown_product
1-8 -> 06cb:00c4 unknown_product
1-9 -> 30c9:0002 HP HD Camera
9-1 -> feed:1307 Ergodox EZ
9-2 -> 046d:085e Logitech BRIO
And with a device,
$ sudo bash usbreplug.sh 046d:085e
replugging 9-2 -> 046d:085e Logitech BRIO

For a given /dev/video device you can find the product and vendor IDs from the udevadm info -x -q all --name /dev/video0 output - assuming it is connected by USB.

And now - the script

#! /bin/bash
set -o errexit -o pipefail -o nounset
shopt -s extglob
targetVendorProduct="${1:-}"
sleepDelay=0.5
cd /sys/bus/usb/devices/
for portPath in +([0-9])-+([0-9\.]); do
    function portInfo() {
	cat $portPath/$1 2>/dev/null || echo "unknown_$1"
    }
    idProduct=$(portInfo idProduct)
    idVendor=$(portInfo idVendor)
    product="$(portInfo product)"
    if [ -z "$targetVendorProduct" ]; then
	echo "$portPath -> $idVendor:$idProduct $product"
    elif [ "$targetVendorProduct" == "$idVendor:$idProduct" ]; then
	echo "replugging $portPath -> $idVendor:$idProduct $product"
	echo $portPath > /sys/bus/usb/drivers/usb/unbind || echo "unbind $portPath failed" >&2
	sleep ${sleepDelay}
	echo $portPath > /sys/bus/usb/drivers/usb/bind
    fi
done

Post a comment