Ubuntu: How do you reset a USB device from the command line?



Question:

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:

  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: 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    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 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.


Solution:5

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  


Solution:6

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.


Solution:7

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.


Solution:8

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


Solution:9

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: https://github.com/Marviel/TIL/blob/master/unix_tools/Reset_specific_USB_Device.md)


Solution:10

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  


Solution:11

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.


Solution:12

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!


Solution:13

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  


Solution:14

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


Solution:15

Maybe this guide can help you:

If you are pestered by the bug that doesn;t let you mount USB devices in Ubuntu Lucid Lynx, the issue is caused by the floppy module. Disable it with:

sudo modprobe -r floppy  

After a reboot the module will likely reload.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »