Avoiding reboot: Resetting USB on a Linux machine
Every now and then, some USB device misbehaves badly enough to knock out the entire interface, to the extent that the system doesn’t detect any new USB devices. Or work so well with the existing ones, for that matter. The solution for me until now was to reboot the computer. But hey, I don’t like rebooting Linux!
So this script (I call it usbreset) performs a reset to the USB drivers as necessary to bring them back to life. As a side effect, an equivalent to unplugging and replugging all USB devices takes place. If possible, unmount any connected USB storage device (e.g. disk on key) before doing this. Also, if you’re in the middle of printing through a USB device, or some other operation, this will not be graceful.
An interesting thing I noted, was that if there’s a really problematic device on the bus (for example, a device that fails to enumerate), this script doesn’t return. It probably gets stuck on one of the writes to “bind” (hasn’t checked that all the way through).
Use at your own risk. You are root, you should know what you’re doing (or gamble like myself). Script follows.
If it doesn’t work for you, check the comments below. The names of the /sys files vary slightly among different distributions.
A word about how this script works, so it goes like this: The USB controllers are PCI / PCIe / fake PCI devices. So the script goes to the /sys directory that is related to the PCI devices’ driver, and unbinds them from the device, and then bind them back. So it’s like saying, nah, this device doesn’t belong to the driver, and then say, well, it is. And in the latter stage, the driver initializes the device, which does the job. On a good day.
Those file names like 0000:00:14.0 that appear in /sys/bus/pci/drivers/xhci_hcd/ are the PCI bus addresses of the USB controllers that are handled by the xhci_hcd driver. These will vanish from the directory after writing to “unbind” and return after writing to “bind”. The names can be found in /sys/bus/pci/devices/. Use “lspci” to tell which device is which.
#!/bin/bash if [[ $EUID != 0 ]] ; then echo This must be run as root! exit 1 fi for xhci in /sys/bus/pci/drivers/?hci_hcd ; do if ! cd $xhci ; then echo Weird error. Failed to change directory to $xhci exit 1 fi echo Resetting devices from $xhci... for i in ????:??:??.? ; do echo -n "$i" > unbind echo -n "$i" > bind done done
The script above is in fact a newer version of the script, which I updated to in June 2014, after upgrading my kernel to 3.12. The older one, to which some of the comments relate, is this one:
#!/bin/bash
SYSEHCI=/sys/bus/pci/drivers/ehci_hcd
SYSUHCI=/sys/bus/pci/drivers/uhci_hcd
if [[ $EUID != 0 ]] ; then
echo This must be run as root!
exit 1
fi
if ! cd $SYSUHCI ; then
echo Weird error. Failed to change directory to $SYSUHCI
exit 1
fi
for i in ????:??:??.? ; do
echo -n "$i" > unbind
echo -n "$i" > bind
done
if ! cd $SYSEHCI ; then
echo Weird error. Failed to change directory to $SYSEHCI
exit 1
fi
for i in ????:??:??.? ; do
echo -n "$i" > unbind
echo -n "$i" > bind
done
The problem with the old script is that the EHCI subdirectory doesn’t appear on my system, because xHCI is a catch-all for all USB versions, hence when a USB port is 3.0 capable, it’s driven by the xhci_hcd driver only. The new script catches all possibilities. Hopefully.
Reader Comments
Hi I tried your script yesterday, and it worked perfectly. Then I updated to Ubuntu 13.04, and now I get the ehci_hcd error, do you have any idea why?
No idea. I’ll be glad if you found out and posted another comment saying how you solved this…
Thanks for the info Eli, the problem that Jesper might be having is that the bus names might be slightly different. I put an updated script at https://enc.com.au/2014/02/14/resetting-usb-devices/ with a link back here because its largely your script with that change and some minor cleanups.
sudo ./reset_usb
./reset_usb: line 17: echo: write error: No such device
./reset_usb: line 18: echo: write error: No such device
./reset_usb: line 21: cd: /sys/bus/pci/drivers/ehci_hcd: No such file or directory
Weird error. Failed to change directory to /sys/bus/pci/drivers/ehci_hcd
For what it’s worth. VMware loves to kill my USB for some reason.
Hmmm… Why did you use the old version?
But yes, VMware has a thing about stealing USB devices under my nose, but I didn’t know that it eliminated them too. :)
+1
Thanks for sharing, mate! You helped me out there. (y)
Eli,
I have a wonky USB port on my Linux laptop, and it sometimes just locks up and the mouse stops working.
I tried your script above and it works like a charm. No more rebooting to fix the USB port! Thanks so much!
Cheers,
Steve
Works great, one of my USB drives likes to go offline during file copies on occasion, this allowed me to get it back online so I could continue where I left off.
Thanks a ton!
Great script thanks.
I have a USB UPS that goes mental randomly.
Ran the script on debian wheezy without issues.
Now I can make it part of my nut-server ups script to auto reset the usb bus once it looses communication.
added to my Linux 14.04, it works really fine; many thanks!!!
Awesome, thank you! Saved me lots of time.
Problem: The script will choke on an empty ?hci_hcd directory, because bash for loop will use the literal string “????:??:??.?” instead of null.
Solution: in the first line of the script use:
shopt -s nullglob
Thanks again!
I am getting errors on Ubuntu Server 14.04.
And the other dudes comment that had made his own fixes also didn’t work for my system. And the dudes comment of the other dudes comment had posted some github and also that didn’t work…
tzz@upuffle:~$ sudo ./resetusbs.sh
Resetting devices from /sys/bus/pci/drivers/uhci_hcd…
./resetusbs.sh: line 18: echo: write error: No such device
./resetusbs.sh: line 19: echo: write error: No such device
Resetting devices from /sys/bus/pci/drivers/xhci_hcd…
Haha ok I forgot what script I am using. I should have made multiple files for the different scripts… For your June 2014 script, I get:
tzz@upuffle:~$ sudo ./resetusbs.sh
Reseting: xhci_hcd
Not present: ehci_hcd
Reseting: uhci_hcd
sh: printf: I/O error
sh: printf: I/O error
My mouse often becomes erratic after a hibernate, and this script fixes the issue! Kubuntu 14.10
Thanks!
I probably have this issue once a day. Thanks for posting your script, worked perfectly for me.
worked perfect!! =D
Tried several other bash solutions, and 2 C scripts – neither worked on Ubuntu 14.04 running 3.13.0-48-generic.
This one did. Thanks!
Nice work!
Thank you so much, I have spent many hours looking for something like this, and now I finally found this working solution!
I have been rebooting my system for last one or two months. But not anymore!
Thanks. :D
Another fully satisfied customer (so to speak). No more reboots for this reason thanks to you.
Works on Fedora 22 & Lenovo T450s. Thanks!
I do not believe. Impressive, I had already tried everything. He stopped there.
=> usb 2-1.5: new low-speed USB device number 4 using ehci-pci
I would generally scaling device namber 5,6,7 … 16. then froze the xwindows.
I changed the script to ehci-pci and it seems that work … Thank you! you saved my day.
Thanks, this fixed my problem of hanging usb3 controller.
I just updated it to avoid printing errors in cases where the ?hci folder is not having any busses.
#!/bin/bash
if [[ $EUID != 0 ]] ; then
echo This must be run as root!
exit 1
fi
for xhci in /sys/bus/pci/drivers/?hci_hcd ; do
if ! cd $xhci ; then
echo Weird error. Failed to change directory to $xhci
exit 1
fi
echo Resetting devices from $xhci…
for i in ????:??:??.? ; do
if [ $i == "????:??:??.?" ]; then
echo “ignoring”
continue
fi
echo “Device $xhci:$i”
echo -n “$i” > unbind
echo -n “$i” > bind
done
done
this script gives an error in fedora 23:
Resetting devices from /sys/bus/pci/drivers/uhci_hcd…
Resetting devices from /sys/bus/pci/drivers/xhci_hcd…
./unplug: line 18: echo: write error: No such device
./unplug: line 19: echo: write error: No such device
Works like a charm, thank you !
It does reset the device.
Most likely this will fix when my USB-sound system does not work.
(Until now when it doesn’t, I unplug and replug the device).
Thanks!
you forgot “cd ..” before last “done” in forst script!
That would have been quite peculiar, given all the comments saying it worked for them, wouldn’t it?
So no, the loop runs on absolute paths (/sys/bus/…), so it doesn’t matter what the current directory is at the end of the loop.
Works perfectly for me, on Linux Mint 17.1, kernel 3.13
On lenovo Laptop… thanks for the post
I had to change ?hci_hcd to ?hci-pci on my system to get it to find the devices, but once I did that it works great on my desktop system.
Strangely enough, I don’t have *-hcd folders there. I do have a bunch of -pci folders (ehci-pci, uhci-pci and ohci-pci), which seem to contain the information you use later in the script.
This is Slackware 14.1, always a bit different from other distros, but I thought you might be interested.
Minor error in my previous message. Your script expects *_hcd folders, Slackware uses *-pci names. Note the underscore/normal dash.
After changing the script to ?hci-pci, the script worked fine.
Thanks!
worked perfect!! =D
add Reset ohci.
Thanks! I’m on a Lenovo laptop that I’m dual-booting. Every time it went to sleep in Linux, on wake my mouse would fail. I thought for a while, it was the unifying receiver for Logitech(M570 trackball), but realized it was actually not loading at the USB level, even with unplug/plug. I rebooted constantly, but it apparently isn’t a clean/full reboot, so often times it’d just fail even after a reboot. Much thanks!
Thank you!! :)
This helped me greatly.
Hey all, works for me on Linux Mint 17. Only had to change “?hci_hcd” to “?hci-pci” :)
I had to modify your script slightly, and it worked like a charm for me. However, in June 2016, it stopped working. The script would just hang, and then I’d have to reboot. lsusb also just hangs once the mouse stops responding, so I can’t use that to check for problems.
I’m using Ubuntu 14.04 LTS with uname -r returning 3.13.0-88-generic
Thank you! Great job! Worked perfectly on CentOS 7.
Worked perfectly, thanks.
However I would replace the line warning to run as root with:
exec sudo bash “$0″
I can’t use this meethod as one of my USB devices is the memory stick the OS itself is running on (as a live CD).
Is there a means of resetting ONLY other USB devices?
Worked perfect! Thought the USB backup drive had died, replaced it, but still that “hub_port_status failed” in /var/log/messages. Ran the usb_reset script on CentOS 6.5, then the drive appeared again – and both the old and new drive worked.
USB speaker and microphone wasn’t available anymore in the sound manager. Ran the script and everything worked again. Great! One small issue: The script seemed to hang, so I did CTRL C, provided the password and USB was fixed.
On VirtualBox I had USB 2.0 controller selected, so my driver directory was /sys/bus/pci/drivers/ehci-pci/.
To find correct directory use
lspci
to find id of USB controller, then search for the ID.
For example (the Id was 0c in my case):
cd /sys/bus
find . -name “*00:0c.0″
to see where your device is located. Modified script works as expected. Thanks!
Almost 2018 and still working. Thank you!
> for xhci in /sys/bus/pci/drivers/?hci_hcd ; do
I had change “?hci_hcd” to “?hci-pci” to make it run.
Worked perfectly! Thought the USB backup drive had died, replaced it, but still that “hub_port_status failed” in /var/log/messages. Ran the usb_reset script on CentOS 6.5, then the drive appeared again – and both the old and new drive worked.
IF anyone is using MINT Cinnamon, This is how i had to configure the script including a pause inbetween unbind and bind…
#!/bin/bash
shopt -s nullglob
if [[ $EUID != 0 ]] ; then
echo This must be run as root!
exit 1
fi
for ehci in /sys/bus/pci/drivers/?hci-pci ; do
if ! cd $ehci ; then
echo Weird error. Failed to change directory to $ehci
exit 1
fi
echo Resetting devices from $ehci…
for i in ????:??:??.? ; do
echo -n “$i” > unbind
echo -n “$i” > bind
read -t5
done
done
Thanks to the auther for this very useful script!!!!
Just another happy user! Many thanks!
cool!
it’s working perfectly for me on FC26!
Most of the time, by unplugging and them again plugging is helpful. Because USB reset can simulate the unplug and replug operation.
Thanks! I learned quite a bit from the script but eventually ended up using a Python script because I didn’t want to operate at such a low level (that’s not a judgment but a technical term :))
So here’s a high level approach…
First get some details about the particular USB device you want to reset.
>lsusb
or
>usb-devices
What we need are the vendor ID and product ID
the output of lsusb will have this info in this format:
ID 1234:5678
usb-devices spells it out more clearly:
Vendor=1234 ProdID=5678 Rev=01.00
Now install the Python package that provides USB support (pyusb)
sudo pip3 install pyusb
Create a python script with the following in it and you’re good to go:
#!/usr/bin/python3
from usb.core import find as finddev
dev = finddev(idVendor=0x1234, idProduct=0x5678)
dev.reset()
That’s it!
Man, it worked for me too (on a Debian Cinnamon Mint derivative, kernel 4.19.20), thank you!
Eli, is there a way to subscribe to your blog?
thank you again for publishing,
-vb
Hi,
Unfortunately, there is no subscription. It’s a pile of random posts anyhow.
Eli
Works on ubuntu 16.04. Thanks! This save me from countless reboot when switching between two computers with a USB switch and the logitech keyboard/mouse combo.
Great, thank you! Works perfectly with Manjaro KDE.
Hi, i’ve been finding ways to reset USB without rebooting/physical reconnect and managed to stumble upon yours. It works wonder on uBuntu 16.04!!!
However, when i tried on a Nano Jetson, which is a arm64 architecture, the directory /sys/bus/pci/drivers/?hci_hcd do not work as the USB file was not in it BUT i do found out the directory of the USB itself.
By changing:
‘/sys/bus/pci/drivers/?hci_hcd’ to ‘/sys/bus/usb/drivers/usb’
and
‘for i in ????:??:??.? ; do’ to ‘for i in usb? ; do’
it works on both amd64 and arm64 now.
Many thanks for your script! It saved me immense grief when all of my USB devices went dark on my Ubuntu 16.04 system with lots of unsaved work. Unplugging and replugging everything hadn’t had any effect, and the system put up a dialog advising me I had files open and how did I want to restart that I couldn’t dispatch because the mouse didn’t work! I ssh’d in from a laptop, and your script brought my desktop back to life – WHEW!!
Again, many thanks!!
Happy New Year – 2020, “the year of perfect vision”
Many thanks, all ports are working again. It fixes my most frequent reason to reboot!
Working on Linux MX19 dual boot with Windows 10 and I can finally just do a reboot without the need to power off to get USB-Ethernet-adapter to work.
THANK YOU!
Amazing! Thanks!
None of these work on raspberry pi, I have both directories on Raspberry Pi, also tried python script, but I guess it detects four times the same vid,pid combination and that is why it fails to reset anything, at least for stlink v2 programmers. I use 4 of them, vid 0x0483,pid 0x3748, the same on each of them. I can distinguisg them by commandline stm8flash -S serial number option. The only solution I think there is to power cycle each one separetly . Power cycling on usb hub doesn’t work neither. Newest firmware loaded in to stlinks.
The reason it doesn’t work on Raspberry Pi is that this script relies on that the USB host controllers are PCI (or PCIe) devices, and hence their drivers can be bound and unbound to these devices in /sys/bus/pci/drivers/.
I suggest looking for the relevant /sys/bus/ location on your device. The path should be quite similar.
Many thanks for the usbreset script! I have been looking for a solution for a once and then hanging built-in usb-hub for a very long time now and have finally found it here.
I’ve been having USB issues for months, and this one script works to fix them all! Amazing, thankyou so much!
Thanks for usbreset; works as expected on Ubuntu Mate 21.04. My networking / wifi connection drops occasionally (but not w/ other home computers) and the standard service start/restart instructions to network manager do not revive the connection. Would the same logic in usbreset work to bring back my wireless adapter? Here is a line from lspci:
03:00.0 Network controller: Qualcomm Atheros QCA9565 / AR9565 Wireless Network Adapter (rev 01)
and here is the contents of the driver ath9k:
0000:03:00.0 bind module new_id remove_id uevent unbind
Thanks in advance…
Well, why don’t you give it a try and tell us all?
Works on MX21.1. Thanks.
Saved my ass. Thanks. (Fedora 37)
All good thanks !
I also don’t like to reboot a linux… It is so much not the spirit…
thanks it works. i had problem on my debian12.