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.

3

18 Answers

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:

  1. Compile the program:

    $ cc usbreset.c -o usbreset
  2. Get the Bus and Device ID of the USB device you want to reset:

    $ lsusb
    Bus 002 Device 003: ID 0fe9:9010 DVICO 
  3. Make our compiled program executable:

    $ chmod +x usbreset
  4. Execute the program with sudo privilege; make necessary substitution for <Bus> and <Device> ids as found by running the lsusb command:

    $ sudo ./usbreset /dev/bus/usb/002/003 

Source of above program:

12

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
15

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 (USB,_Firewire))

13

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)
1

I needed to automate this in a python script, so I adapted LiLo's extremely helpful answer to the following:

#!/usr/bin/env python
import os
import sys
from subprocess import Popen, PIPE
import fcntl
driver = sys.argv[-1]
print "resetting driver:", driver
USBDEVFS_RESET= 21780
try: lsusb_out = Popen("lsusb | grep -i %s"%driver, shell=True, bufsize=64, stdin=PIPE, stdout=PIPE, close_fds=True).stdout.read().strip().split() bus = lsusb_out[1] device = lsusb_out[3][:-1] f = open("/dev/bus/usb/%s/%s"%(bus, device), 'w', os.O_WRONLY) fcntl.ioctl(f, USBDEVFS_RESET, 0)
except Exception, msg: print "failed to reset device:", msg

In my case it was the cp210x driver (which I could tell from lsmod | grep usbserial), so you could save the above snippet as reset_usb.py and then do this:

sudo python reset_usb.py cp210x

This might also be helpful if you don't already have a c compiler setup on your system, but you do have python.

5

Quickest way to reset will be to reset the USB controller itself. Doing so will enforce udev to unregister the device on disconnection, and register is back once you enable it.

echo -n "0000:00:1a.0" | tee /sys/bus/pci/drivers/ehci_hcd/unbind
echo -n "0000:00:1d.0" | tee /sys/bus/pci/drivers/ehci_hcd/unbind
echo -n "0000:00:1a.0" | tee /sys/bus/pci/drivers/ehci_hcd/bind
echo -n "0000:00:1d.0" | tee /sys/bus/pci/drivers/ehci_hcd/bind

This should work for most PC environment. However, if you are using some custom hardware you can simply iterate through the device names. With this method you don't need to find out the device name by lsusb. You can incorporate in a automated script as well.

1

I'm using kind of sledgehammer by reloading the modules. This is my usb_reset.sh script:

#!/bin/bash
# USB drivers
rmmod xhci_pci
rmmod ehci_pci
# uncomment if you have firewire
#rmmod ohci_pci
modprobe xhci_pci
modprobe ehci_pci
# uncomment if you have firewire
#modprobe ohci_pci

And this is my systemd service file /usr/lib/systemd/system/usbreset.service which runs usb_reset.sh after my diplay manager has started:

[Unit]
Description=usbreset Service
After=gdm.service
Wants=gdm.service
[Service]
Type=oneshot
ExecStart=/path/to/usb_reset.sh
2

As the special case of the question is a communication problem of gphoto2 with a camera on USB, there is an option in gphoto2 to reset its USB connection:

gphoto2 --reset

Maybe this option didn't exist in 2010 when the question was asked.

Here is script that will only reset a matching product/vendor ID.

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
VENDOR="045e"
PRODUCT="0719"
for DIR in $(find /sys/bus/usb/devices/ -maxdepth 1 -type l); do if [[ -f $DIR/idVendor && -f $DIR/idProduct && $(cat $DIR/idVendor) == $VENDOR && $(cat $DIR/idProduct) == $PRODUCT ]]; then echo 0 > $DIR/authorized sleep 0.5 echo 1 > $DIR/authorized fi
done
1

Since the APT package usbutils provides the usbreset binary you can just reset the USB device by:

usbreset ${USB_ID}
e.g.
usbreset 0d8c:0102
2

I made a python script which will reset a particular USB device based on the device number. You can find out the device number from command lsusb.

for example:

$ lsusb
Bus 002 Device 004: ID 046d:c312 Logitech, Inc. DeLuxe 250 Keyboard

In this string 004 is the device number

import os
import argparse
import subprocess
path='/sys/bus/usb/devices/'
def runbash(cmd): p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) out = p.stdout.read().strip() return out
def reset_device(dev_num): sub_dirs = [] for root, dirs, files in os.walk(path): for name in dirs: sub_dirs.append(os.path.join(root, name)) dev_found = 0 for sub_dir in sub_dirs: if True == os.path.isfile(sub_dir+'/devnum'): fd = open(sub_dir+'/devnum','r') line = fd.readline() if int(dev_num) == int(line): print ('Your device is at: '+sub_dir) dev_found = 1 break fd.close() if dev_found == 1: reset_file = sub_dir+'/authorized' runbash('echo 0 > '+reset_file) runbash('echo 1 > '+reset_file) print ('Device reset successful') else: print ("No such device")
def main(): parser = argparse.ArgumentParser() parser.add_argument('-d', '--devnum', dest='devnum') args = parser.parse_args() if args.devnum is None: print('Usage:usb_reset.py -d <device_number> \nThe device number can be obtained from lsusb command result') return reset_device(args.devnum)
if __name__=='__main__': main()
1

Try this, it's a software unplug (Eject).

Sometimes doesn't work simply unbind device for some devices.

Example:

I want to remove or eject my "Genius NetScroll 120".

Then i first Check my attached usb device

$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub
Bus 002 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub
Bus 001 Device 003: ID 03f0:231d Hewlett-Packard
Bus 001 Device 004: ID 138a:0007 Validity Sensors, Inc. VFS451 Fingerprint Reader
Bus 001 Device 005: ID 04f2:b163 Chicony Electronics Co., Ltd
Bus 002 Device 009: ID 0458:003a KYE Systems Corp. (Mouse Systems) NetScroll+ Mini Traveler / Genius NetScroll 120 **<----This my Mouse! XDDD**

Ok, i found my mouse, it's has a Bus 002, Device 009, idVendor 0458 and idProduct 003a, so this is a reference device info about the mouse.

This is important, the Bus number is the begin name path to device and i will check the product Id and Vendor to ensure the correct device to remove.

$ ls /sys/bus/usb/drivers/usb/
1-1/ 1-1.1/ 1-1.3/ 1-1.5/ 2-1/ 2-1.3/ bind uevent unbind usb1/ usb2/

Pay atention on the folders, check the begining with folder number 2, i will check this one because my Bus is 002, and one by one i have check each folder containing the correct idVendor and idProduct about my mouse info.

In this case, i will retrieve the info with this command:

cat /sys/bus/usb/drivers/usb/2-1.3/idVendor
0458
cat /sys/bus/usb/drivers/usb/2-1.3/idProduct
003a

Ok, the path /sys/bus/usb/drivers/usb/2-1.3/ match with my info mouse! XDDD.

It's time to remove the device!

su -c "echo 1 > /sys/bus/usb/drivers/usb/2-1.3/remove"

Plug again the usb device and it's work again!

1

Did somebody order a sledgehammer? This is pieced together from various other answers here.

#!/bin/bash
# Root required
if (( UID )); then exec sudo "$0" "$@"
fi
cd /sys/bus/pci/drivers
function reinit {( local d="$1" test -e "$d" || return rmmod "$d" cd "$d" for i in $(ls | grep :); do echo "$i" > unbind done sleep 1 for i in $(ls | grep :); do echo "$i" > bind done modprobe "$d"
)}
for d in ?hci_???; do echo " - $d" reinit "$d"
done
7

Sometimes I want to perform this operation on a particular device, as identified by VID (vendor id) and PID (product id). This is a script I've found useful for this purpose, that uses the nifty libusb library.

First run:

sudo apt-get install libusb-dev

Then, this c++ file's resetDeviceConnection should perform this task, of resetting a device connection as identified by vid and pid.

#include <libusb-1.0/libusb.h>
int resetDeviceConnection(UINT_16 vid, UINT_16 pid){ /*Open libusb*/ int resetStatus = 0; libusb_context * context; libusb_init(&context); libusb_device_handle * dev_handle = libusb_open_device_with_vid_pid(context,vid,pid); if (dev_handle == NULL){ printf("usb resetting unsuccessful! No matching device found, or error encountered!\n"); resetStatus = 1; } else{ /*reset the device, if one was found*/ resetStatus = libusb_reset_device(dev_handle); } /*exit libusb*/ libusb_exit(context); return resetStatus;
}

(stolen from my personal TIL catalog: )

4

i made a simple bash script for reset particular USB device.

#!/bin/bash
#type lsusb to find "vendor" and "product" ID in terminal
set -euo pipefail
IFS=$'\n\t'
#edit the below two lines of vendor and product values using lsusb result
dev=$(lsusb -t | grep usbdevicename | grep 'If 1' | cut -d' ' -f13|cut -d"," -f1)
#VENDOR=05a3
#PRODUCT=9230
VENDOR=$(lsusb -s $dev | cut -d' ' -f6 | cut -d: -f1)
PRODUCT=$(lsusb -s $dev | cut -d' ' -f6 | cut -d: -f2)
for DIR in $(find /sys/bus/usb/devices/ -maxdepth 1 -type l); do if [[ -f $DIR/idVendor && -f $DIR/idProduct && $(cat $DIR/idVendor) == $VENDOR && $(cat $DIR/idProduct) == $PRODUCT ]]; then echo 0 > $DIR/authorized sleep 0.5 echo 1 > $DIR/authorized fi
done

This is a very elegant and yet ugly way of doing it. I ran a shell line in cpp which uses python to reset the usb.

  1. install the python usb library:sudo pip3 install pyusb

  2. get the ID of the vendor and product so you can use it in the code: lsusb -v

  3. copy-paste the follwing code but remember to replace <vendor_id> and <product_id> with the vendor ID and product ID that you found in the previous step:

#include <iostream>
int main()
{ int res = system("echo \"from usb.core import find as finddev; dev=finddev(idVendor=<vendor_id>,idProduct=<product_id>); dev.reset()\" | python3"); return res;
}

If you know your device name, this python script will work:

#!/usr/bin/python
"""
USB Reset
Call as "usbreset.py <device_file_path>"
With device_file_path like "/dev/bus/usb/bus_number/device_number"
"""
import fcntl, sys, os
USBDEVFS_RESET = ord('U') << (4*2) | 20
def main(): fd = os.open(sys.argv[1], os.O_WRONLY) if fd < 0: sys.exit(1) fcntl.ioctl(fd, USBDEVFS_RESET, 0) os.close(fd) sys.exit(0)
# end main
if __name__ == '__main__': main()

Perhaps this works for a camera, too:

Following revived a starved USB 3.0 HDD on a 3.4.42 (kernel.org) Linux on my side. dmesg told, that it was timing out commands after 360s (sorry, I cannot copy the syslog here, not connected networks) and the drive hung completely. Processes accessing the device were blocked in the kernel, unkillable. NFS hung, ZFS hung, dd hung.

After doing this, everything worked again. dmesg told just a single line about the USB device found.

I really have no idea what following does in detail. But it worked.

The following example output is from Debian Squeeze with 2.6.32-5-686 kernel, so I think it works for 2.6 and above:

$ ls -al /dev/sdb
brw-rw---T 1 root floppy 8, 16 Jun 3 20:24 /dev/sdb
$ ls -al /sys/dev/block/8:16/device/rescan
--w------- 1 root root 4096 Jun 6 01:46 /sys/dev/block/8:16/device/rescan
$ echo 1 > /sys/dev/block/8:16/device/rescan

If this does not work, perhaps somebody else can figure out how to send a real reset to a device.

1

You Might Also Like