How do you reset a USB device from the command line?
Is it possible to reset the connection of a USB device, without physically disconnecting/connecting from the PC?
Specifically, my device is a digital camera. I'm using gphoto2
, but lately I get "device read errors", so I'd like to try to do a software-reset of the connection.
From what I can tell, there are no kernel modules being loaded for the camera. The only one that looks related is usbhid
.
Solution 1:
Save the following as usbreset.c
/* usbreset -- send a USB port reset to a USB device */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
int main(int argc, char **argv)
{
const char *filename;
int fd;
int rc;
if (argc != 2) {
fprintf(stderr, "Usage: usbreset device-filename\n");
return 1;
}
filename = argv[1];
fd = open(filename, O_WRONLY);
if (fd < 0) {
perror("Error opening output file");
return 1;
}
printf("Resetting USB device %s\n", filename);
rc = ioctl(fd, USBDEVFS_RESET, 0);
if (rc < 0) {
perror("Error in ioctl");
return 1;
}
printf("Reset successful\n");
close(fd);
return 0;
}
The run the following commands in terminal:
-
Compile the program:
$ cc usbreset.c -o usbreset
-
Get the Bus and Device ID of the USB device you want to reset:
$ lsusb Bus 002 Device 003: ID 0fe9:9010 DVICO
-
Make our compiled program executable:
$ chmod +x usbreset
-
Execute the program with sudo privilege; make necessary substitution for
<Bus>
and<Device>
ids as found by running thelsusb
command:$ sudo ./usbreset /dev/bus/usb/002/003
Source of above program: http://marc.info/?l=linux-usb&m=121459435621262&w=2
Solution 2:
I haven't found myself in your specific circumstances before, so I'm not sure if it'll do enough, but the simplest way I've found to reset a USB device is this command: (No external apps necessary)
sudo sh -c "echo 0 > /sys/bus/usb/devices/1-4.6/authorized"
sudo sh -c "echo 1 > /sys/bus/usb/devices/1-4.6/authorized"
That's the actual one I use to reset my Kinect since libfreenect seems to have no API for putting it back to sleep. It's on my Gentoo box, but the kernel should be new enough to use the same path structure for sysfs.
Yours obviously wouldn't be 1-4.6
but you can either pull that device path from your kernel log (dmesg
) or you can use something like lsusb
to get the vendor and product IDs and then use a quick command like this to list how the paths relate to different vendor/product ID pairs:
for X in /sys/bus/usb/devices/*; do
echo "$X"
cat "$X/idVendor" 2>/dev/null
cat "$X/idProduct" 2>/dev/null
echo
done
Solution 3:
This will reset all of USB1/2/3 attached ports[1]:
for i in /sys/bus/pci/drivers/[uoex]hci_hcd/*:*; do
[ -e "$i" ] || continue
echo "${i##*/}" > "${i%/*}/unbind"
echo "${i##*/}" > "${i%/*}/bind"
done
I believe this will solve your problem. If you do not want to reset all of the USB endpoints, you can use appropriate device ID from /sys/bus/pci/drivers/ehci_hcd
Notes:
[1]: the *hci_hcd
kernel drivers typically control the USB ports. ohci_hcd
and uhci_hcd
are for USB1.1 ports, ehci_hcd
is for USB2 ports and xhci_hcd
is for USB3 ports. (see https://en.wikipedia.org/wiki/Host_controller_interface_(USB,_Firewire))
Solution 4:
I've created a Python script that simplifies the whole process based on answers here.
Save the script below as reset_usb.py or clone this repo.
Usage:
python reset_usb.py help # Show this help
sudo python reset_usb.py list # List all USB devices
sudo python reset_usb.py path /dev/bus/usb/XXX/YYY # Reset USB device using path /dev/bus/usb/XXX/YYY
sudo python reset_usb.py search "search terms" # Search for USB device using the search terms within the search string returned by list and reset matching device
sudo python reset_usb.py listpci # List all PCI USB devices
sudo python reset_usb.py pathpci /sys/bus/pci/drivers/.../XXXX:XX:XX.X # Reset PCI USB device using path /sys/bus/pci/drivers/.../XXXX:XX:XX.X
sudo python reset_usb.py searchpci "search terms" # Search for PCI USB device using the search terms within the search string returned by listpci and reset matching device
Script:
#!/usr/bin/env python
import os
import sys
from subprocess import Popen, PIPE
import fcntl
instructions = '''
Usage: python reset_usb.py help : Show this help
sudo python reset_usb.py list : List all USB devices
sudo python reset_usb.py path /dev/bus/usb/XXX/YYY : Reset USB device using path /dev/bus/usb/XXX/YYY
sudo python reset_usb.py search "search terms" : Search for USB device using the search terms within the search string returned by list and reset matching device
sudo python reset_usb.py listpci : List all PCI USB devices
sudo python reset_usb.py pathpci /sys/bus/pci/drivers/.../XXXX:XX:XX.X : Reset PCI USB device using path
sudo python reset_usb.py searchpci "search terms" : Search for PCI USB device using the search terms within the search string returned by listpci and reset matching device
'''
if len(sys.argv) < 2:
print(instructions)
sys.exit(0)
option = sys.argv[1].lower()
if 'help' in option:
print(instructions)
sys.exit(0)
def create_pci_list():
pci_usb_list = list()
try:
lspci_out = Popen('lspci -Dvmm', shell=True, bufsize=64, stdin=PIPE, stdout=PIPE, close_fds=True).stdout.read().strip().decode('utf-8')
pci_devices = lspci_out.split('%s%s' % (os.linesep, os.linesep))
for pci_device in pci_devices:
device_dict = dict()
categories = pci_device.split(os.linesep)
for category in categories:
key, value = category.split('\t')
device_dict[key[:-1]] = value.strip()
if 'USB' not in device_dict['Class']:
continue
for root, dirs, files in os.walk('/sys/bus/pci/drivers/'):
slot = device_dict['Slot']
if slot in dirs:
device_dict['path'] = os.path.join(root, slot)
break
pci_usb_list.append(device_dict)
except Exception as ex:
print('Failed to list pci devices! Error: %s' % ex)
sys.exit(-1)
return pci_usb_list
def create_usb_list():
device_list = list()
try:
lsusb_out = Popen('lsusb -v', shell=True, bufsize=64, stdin=PIPE, stdout=PIPE, close_fds=True).stdout.read().strip().decode('utf-8')
usb_devices = lsusb_out.split('%s%s' % (os.linesep, os.linesep))
for device_categories in usb_devices:
if not device_categories:
continue
categories = device_categories.split(os.linesep)
device_stuff = categories[0].strip().split()
bus = device_stuff[1]
device = device_stuff[3][:-1]
device_dict = {'bus': bus, 'device': device}
device_info = ' '.join(device_stuff[6:])
device_dict['description'] = device_info
for category in categories:
if not category:
continue
categoryinfo = category.strip().split()
if categoryinfo[0] == 'iManufacturer':
manufacturer_info = ' '.join(categoryinfo[2:])
device_dict['manufacturer'] = manufacturer_info
if categoryinfo[0] == 'iProduct':
device_info = ' '.join(categoryinfo[2:])
device_dict['device'] = device_info
path = '/dev/bus/usb/%s/%s' % (bus, device)
device_dict['path'] = path
device_list.append(device_dict)
except Exception as ex:
print('Failed to list usb devices! Error: %s' % ex)
sys.exit(-1)
return device_list
if 'listpci' in option:
pci_usb_list = create_pci_list()
for device in pci_usb_list:
print('path=%s' % device['path'])
print(' manufacturer=%s' % device['SVendor'])
print(' device=%s' % device['SDevice'])
print(' search string=%s %s' % (device['SVendor'], device['SDevice']))
sys.exit(0)
if 'list' in option:
usb_list = create_usb_list()
for device in usb_list:
print('path=%s' % device['path'])
print(' description=%s' % device['description'])
print(' manufacturer=%s' % device['manufacturer'])
print(' device=%s' % device['device'])
print(' search string=%s %s %s' % (device['description'], device['manufacturer'], device['device']))
sys.exit(0)
if len(sys.argv) < 3:
print(instructions)
sys.exit(0)
option2 = sys.argv[2]
print('Resetting device: %s' % option2)
# echo -n "0000:39:00.0" | tee /sys/bus/pci/drivers/xhci_hcd/unbind;echo -n "0000:39:00.0" | tee /sys/bus/pci/drivers/xhci_hcd/bind
def reset_pci_usb_device(dev_path):
folder, slot = os.path.split(dev_path)
try:
fp = open(os.path.join(folder, 'unbind'), 'wt')
fp.write(slot)
fp.close()
fp = open(os.path.join(folder, 'bind'), 'wt')
fp.write(slot)
fp.close()
print('Successfully reset %s' % dev_path)
sys.exit(0)
except Exception as ex:
print('Failed to reset device! Error: %s' % ex)
sys.exit(-1)
if 'pathpci' in option:
reset_pci_usb_device(option2)
if 'searchpci' in option:
pci_usb_list = create_pci_list()
for device in pci_usb_list:
text = '%s %s' % (device['SVendor'], device['SDevice'])
if option2 in text:
reset_pci_usb_device(device['path'])
print('Failed to find device!')
sys.exit(-1)
def reset_usb_device(dev_path):
USBDEVFS_RESET = 21780
try:
f = open(dev_path, 'w', os.O_WRONLY)
fcntl.ioctl(f, USBDEVFS_RESET, 0)
print('Successfully reset %s' % dev_path)
sys.exit(0)
except Exception as ex:
print('Failed to reset device! Error: %s' % ex)
sys.exit(-1)
if 'path' in option:
reset_usb_device(option2)
if 'search' in option:
usb_list = create_usb_list()
for device in usb_list:
text = '%s %s %s' % (device['description'], device['manufacturer'], device['device'])
if option2 in text:
reset_usb_device(device['path'])
print('Failed to find device!')
sys.exit(-1)