258

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.

cmcginty
  • 5,888
  • Which version of Ubuntu are you using? – User Aug 01 '10 at 20:15
  • i tried both solutions by Li Lo and ssokolow, all i get is permission denied, nomatter if i use the usbreset code or the command line "echo 0 > ..." i use sudo, also my usb devices are owned by root but i can use them without admin rights(cameras..) –  Jun 08 '14 at 16:40
  • 1
    If you are getting read errors, you might have some data corruption. If your camera uses an external memory card (such as MicroSD), it might be wise to connect it to the computer and run fsck. – TSJNachos117 Jun 08 '14 at 18:47

20 Answers20

174

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

Aditya
  • 13,416
Li Lo
  • 15,894
  • Thank you so much! This will help me get a lot more life out of my dying Intellimouse. – Randall Ma Dec 15 '13 at 00:55
  • 3
    This works with ubuntu 13.10. The device ID can vary. TO get it for the mouse I have wrapped above code in few shell commands echo $(lsusb | grep Mouse) mouse=$( lsusb | grep Mouse | perl -nE "/\D+(\d+)\D+(\d+).+/; print qq(\$1/\$2)") sudo /path/to/c-program/usbreset /dev/bus/usb/$mouse – knb Dec 22 '13 at 11:04
  • 1
    my external drive seems to become undetectable (I have to hard reconnect the usb cable); it is a usb2.0 connected on a usb3.0 desktop PC port; when I run usbreset /dev/bus/usb/011/001 that is one of the 2 usb 3.0 root hubs at lsusb, it errors: "Error in ioctl: Is a directory", any ideia? I tried on both usb 3.0 hubs – Aquarius Power Oct 30 '14 at 03:34
  • 1
    If anyone reading this have a (usb) mouse freeze after logging in on Ubuntu 16.04 (with dmesg filled by "input irq status -75") , i can confirm that this is the only solution that worked for me. Thank you – Agustin Baez May 02 '16 at 12:31
  • 2
    @ Aquarius, I also get the same error "Error in ioctl: Is a directory". Is it resolved ? – ransh Feb 12 '17 at 13:21
  • 1
    See my answer here https://askubuntu.com/a/988297/558070 that uses the same method of reset as this answer but also allows simplified listing of and searching for devices. – mcarans Dec 21 '17 at 10:32
  • I tried this on a hanging USB HDD, but the usbreset process also hangs in D state. I guess the "write() can't fail" unix-ism is still screwing me over. – Navin Mar 17 '19 at 02:36
  • Is it correct that there should be no attempt to close fd on ioctl error? – Gnudiff Nov 12 '19 at 10:59
  • This works nicely with generic file descriptors like "/dev/bus/usb/001/010" but is there anyway we could instead use file descriptors from /dev/serial/by-id/? – Potion Sep 21 '20 at 19:15
  • 17
    At least in Debian 10 and Ubuntu 20.04 there is no need to self-compile - /usr/bin/usbreset is part of the package usbutils. Note that this one uses device ID's instead Bus/Dev-number - simply call 'usbreset 0fe9:9010' in the above case. – spawn Nov 26 '20 at 21:35
  • For the record, I've compiled usbreset from the source in this answer, on Debian 9, and it does work for me, with a custom CDC ACM device. Using an oscilloscope I can see the DATA+/- signals going both low for a few milliseconds, and the device indicates a reset. – frr Mar 03 '22 at 21:49
  • On Arch and lazy? Luckily, there's an AUR: https://aur.archlinux.org/packages/usbreset :) – dvdgsng Mar 14 '22 at 08:56
99

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
muru
  • 197,895
  • 55
  • 485
  • 740
ssokolow
  • 2,238
  • sh: 1: cannot create /sys/bus/usb/devices/1-3.1:1.0/authorized: Directory nonexistent – Nicolas May 31 '12 at 03:22
  • It looks like they've changed the layout of the usbfs filesystem. I'll try to figure out what the new way of doing things is on Ubuntu once I'm not so sleepy. – ssokolow Jun 02 '12 at 15:46
  • 16
    Thank you worked great! Maybe you should also mention to perform a echo 1 > /sys/bus/usb/devices/whatever/authorized inside a script to re-enable the device as soon as it has been disabled. I did it on both my mouse and usb keyboard and I ended up with a completely deaf system :) – Avio Apr 28 '13 at 08:43
  • Last time I used it, something in the system would reset it to 1 a second or two later without me having to do it manually. – ssokolow Apr 29 '13 at 20:33
  • 1
    It's extremely strange if it automatically re-set the value to 1 as setting it to 0 is telling the system you don't want the device to be "authorized" and therefore inaccessible. – Tim Tisdall Oct 18 '13 at 19:45
  • 6
    A note for anyone who tries to switch to the | sudo tee ... approach to privileged /sys writes: That breaks badly if you don't already have your sudo credentials cached. sudo sh -c "..." works as expected when sudo needs to prompt for a password. – ssokolow Jun 05 '16 at 10:40
  • There are several authorized in that tree. Which one is the correct one? The deepest? – not2qubit Mar 01 '17 at 17:09
  • @TimTisdall Perhaps that device have avoid_reset_quirk or persist is set? See here. Are you sure you're using the right authorized file? – not2qubit Mar 01 '17 at 21:36
  • 5
    find /sys/bus/usb/devices/*/authorized -exec sh -c 'echo 0 > ${0}; echo 1 > ${0}' {} \; worked like charm for me. ty for pointing at the authorized files. – Marc Bredt Mar 05 '18 at 10:46
  • 1
    This doesn't power-cycle a stuck device – MarcH Jul 10 '18 at 01:22
  • @NicolasMarchildon DIR exists on Linux 5.4.1 – user1133275 Dec 03 '19 at 00:40
  • it's possible to work out the [bus]-[port].[port] using lsusb -t. Also, the sudo tee version actually works and prompts for password, might be new, dunno... – pevinkinel Nov 19 '20 at 02:04
  • 1
    FANTASTIC! this should be the answer. Works perfect on Ubuntu 20.04.2 (April 2021) – Polymerase Apr 20 '21 at 22:06
  • 2
    @MarcH no this certainly doesn't power-cycle a USB device. Even the USBDEVFS_RESET ioctl() does not have that power. I have yet to see some hardware (a motherboard) that supports power-cycling a USB port. But moreover, this /sys/bus/usb/devices/*/authorized thing does not even seem to bring the port into the "reset requested" state (data+/- both low for a fraction of a second). But, it does make my custom CDC ACM device show all signs of an actual reset... is this possibly a mere reload of the SW stack, on the host PC and on the slave, for the USB port indicated? – frr Mar 03 '22 at 21:57
  • @frr I don't have a source for it, but I think I remember reading that some laptop motherboards allow that degree of control over USB power supply rather than just wiring it into the 5V rail like desktop ones tend to. – ssokolow May 25 '22 at 19:35
  • Great. On 22.04 I did cd /sys/bus/usb/devices/;echo 0 >usb2/authorized;echo 1 >usb2/authorized to re-initialize this specific device, in my case an arduino connected to a server where I was too lazy to walk down to the basement :-) – Harald Jan 15 '23 at 14:42
86

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

fresskoma
  • 105
  • do you believe it may work to wakeup an usb storage? – Aquarius Power Jun 30 '14 at 05:53
  • 2
    Although I've received the following message: ls: cannot access /sys/bus/pci/drivers/ehci_hcd/: No such file or directory this has resolved the issue, the mouse has started working immediately. +1 – Attila Fulop Oct 10 '14 at 06:16
  • is it possible to add a check to skip mounted USB mass storage devices? – eadmaster Nov 01 '15 at 10:32
  • uhci_hcd on rhel7 QEMU environment – Otheus Apr 19 '16 at 10:19
  • 2
    @Otheus OHCI and UHCI are the USB 1.1 host standards, EHCI is the USB 2.0 host standard, and XHCI is the USB 3.0 host standard. – ssokolow Jul 20 '16 at 19:02
  • Uh! That was some experience I didn't have for years: black screen and system frozen. Might be a one-time thing or related to 12.04 – but sorry, I won't retry. No bad feelings, reboot was due anyway (pending updates ;) – Izzy Jul 25 '16 at 21:51
  • It solved my problems on a Dell XPS13 notebook were the USB controller (especially the USB3 one) was locking up every few days or weeks. In case it helps someone else lspci on my ubuntu 12.04 reports these USB controllers: - Fresco Logic FL1009 USB 3.0 Host Controller (rev 02) - Intel Corporation 6 Series/C200 Series Chipset Family USB Enhanced Host Controller #1 (rev 05) – ndemou Nov 10 '16 at 14:12
  • 6
    This is a beautiful solution. However, on some later Kernels and other nix distributions, you will find that you need to substitute `hci_hcdwith*hci-pci`, as the hci_hcd driver is already compiled into the Kernel. – not2qubit Mar 01 '17 at 17:14
  • 2
    On a Banana Pi, there apparently is no PCI bus, I had to use the following: for i in /sys/bus/usb/drivers/*/*:*; do – Martin Hansen Jun 29 '17 at 09:14
  • I've incorporated this method of resetting as a second one in my script here: https://askubuntu.com/a/988297/558070 – mcarans Jan 24 '18 at 14:11
  • This worked even on a Raspberry Pi4 with a Volumio distribution on it ! Sometimes Volumio behaves badly and a USB reset appears to solve the problem. Thanks ! you saved my day ! – Alfonso Tesauro Oct 05 '19 at 15:43
  • This worked perfectly for me, running Ubuntu Core 18 on NUC. Thanks a lot, u saved me a lot of trouble! – Ismar Slomic Aug 16 '21 at 20:17
  • This worked flawlessly on Ubuntu 20.04 LTS, after wake from failed systemd-hybrid-sleep.service left USB dead... with usbhid still insisting it was running and connected to devices and therefore refusing to respond to modprobe. Thanks! – Criminally Inane Feb 17 '22 at 20:44
  • Worked great as ExecStartPre condition for NUT driver which wouldn't work unless USB ports got reset. I modified the service file to include ExecStartPre=/usr/bin/bash -c for i in /sys/bus/pci/drivers/[uoex]hci_hcd/*:*; do [ -e "$i" ] || continue; echo "${i##*/}" > "${i%/*}/unbind"; echo "${i##*/}" > "${i%/*}/bind"; done. Thanks. – Orsiris de Jong Sep 27 '22 at 10:06
  • On Debian 11 (Bullseye)/Linux v5.10, ehci_hcd has become ehci-pci so the original filename expansion pattern (/sys/bus/pci/drivers/[uoex]hci_hcd/*:*) misses these controllers. Instead, use /sys/bus/pci/drivers/[uoex]hci[-_]?c*/*:* so that the first line becomes for i in /sys/bus/pci/drivers/[uoex]hci[-_]?c*/*:*; do – jaimet Jul 28 '23 at 21:53
32

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

panticz
  • 1,718
21

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)

mcarans
  • 1,175
11

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.

David Foerster
  • 36,264
  • 56
  • 94
  • 147
Peter
  • 381
  • worked for me on a Raspberry – webo80 Jun 23 '16 at 14:36
  • 1
    A few more words on your solution please. For example, something about the constant USBDEVFS_RESET. Is it always the same for all systems? – not2qubit Feb 28 '17 at 07:25
  • @not2qubit USBDEVFS_RESET is the same for all systems. For MIPS it is 536892692. – yegorich Apr 21 '17 at 09:09
  • 1
    Newer versions of lsusb seem to need the -t argument (tree mode) to show the driver info that this script is expecting, but the script then needs some updates to parse the different output lines this generates – Cheetah Oct 19 '17 at 18:56
  • See my answer here https://askubuntu.com/a/988297/558070 for a much improved version of this script. – mcarans Dec 21 '17 at 10:30
8

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.

chandank
  • 319
  • 1
    You need to run these commands as root/sudo, and it will not work on all systems (on some, you'll need to replace ehci_hcd with ehci-pci. More info on this solution (perhaps where it came from?): http://davidjb.com/blog/2012/06/restartreset-usb-in-ubuntu-12-04-without-rebooting/ – Lambart Nov 05 '15 at 17:43
6

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
  • Using the listpci option of my script here: https://askubuntu.com/a/988297/558070 will help identify which USB module to reload (eg. xhci_pci, ehci_pci). – mcarans Jan 24 '18 at 15:14
  • 7
    Unfortunately on my system these kernel modules are not separate form the kernel, so this won't work: rmmod: ERROR: Module xhci_pci is builtin. – unfa Jun 28 '18 at 13:00
6

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.

mviereck
  • 219
5

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()
Raghu
  • 51
  • 1
    I like this solution! I've made a few tweaks to the script for my own tastes: https://gist.github.com/willstott101/7a455817ec6f4b8d89571ce72bdfd34a – Will S May 09 '19 at 09:58
5

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
derHugo
  • 3,356
  • 5
  • 31
  • 51
cmcginty
  • 5,888
1

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
Olorin
  • 3,488
Thoht
  • 131
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!

user242078
  • 11
  • 1
  • 10
    What if you can't plug it in again? (for example it's an internal sdcard reader) – aleb Jun 29 '14 at 20:57
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
derHugo
  • 3,356
  • 5
  • 31
  • 51
  • Mark, have you found that the unbinding is really necessary or is it here just to be on the safe side? – ndemou Nov 10 '16 at 14:27
  • 1
    This is a sledgehammer, it probably does a lot of unnecessary things – Mark K Cowan Nov 10 '16 at 14:37
  • @MarkKCowan , How do you use it? What are the command arguments needed/expected? – not2qubit Feb 28 '17 at 07:15
  • 1
    @not2qubit: No command-line arguments required. The $@ in the sudo proxy is just a force of habbit, having it prevents bugs if I later decide to add arguments (and forget to update the sudo proxy). – Mark K Cowan Nov 21 '17 at 14:54
  • @not2qubit Looks to me like it's a function parameter. I suggest RTFM. – Mark K Cowan Nov 21 '17 at 16:01
  • 1
    @MarkKCowan Doh! Sorry mate! Oh yes of curse! I should not be commenting on this site while sleepy. Upvoted! – not2qubit Nov 21 '17 at 16:29
  • FWIW, executing this script on my system (Ubuntu 17) disabled my USB hub but didn't re-enable it (which was a problem because it was connected to my keyboard and mouse). – logidelic Jan 15 '18 at 14:15
1

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)

derHugo
  • 3,356
  • 5
  • 31
  • 51
Marviel
  • 11
0

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 &quot;from usb.core import find as finddev; dev=finddev(idVendor=<vendor_id>,idProduct=<product_id>); dev.reset()&quot; | python3");

return res;

}

  • 1
    Why do you wrap Python code with C++? Very ugly and serves no purpose. Downvoted. – snap Jul 26 '22 at 18:28
0

So far I came to the conclusion that you cannot control the power of a USB port. The 5V USB is always provided, and it's up to the device to use it or not. You can check this with a 5V fan or light.

So there's no perfect way to make a USB reset. Nevertheless,

I've tried various methods found on stackoverflow, stackexchange etc, (disconnect/reconnect/bind/unbind/reset signal). Best so far are bind/unbind as it forces a cold restart of the device (but no power cycle).

I came up with a solution to reset USB devices, ports and controllers in a python script, which supports all of the above methods. You can find the script at my Github page

Install with pip install usb_resetter

Usage:

usb_resetter --help

#Example: usb_resetter -d 8086:1001 --reset-hub

The script uses among others the following solution to reset USB hubs/controllers:

Unbindind a USB port / controller works best via:

echo "myhub" > "/sys/bus/usb/drivers/usb/unbind"
echo "myhub" > "/sys/bus/usb/drivers/usb/bind"

Where myhub is found in /sys/bus/usb/devices/*

Or litteral controllers:

echo "mycontroller" > "/sys/bus/pci/drivers/unbind"
echo "mycontroller" > "/sys/bus/pci/drivers/bind"

Where mycontroller is found in /sys/bus/pci/drivers/[uoex]hci_hcd/*:*

0

Pure bash script for finding which USB device and driver provide a given network interface, and then resetting the device by unbinding and rebinding that driver:

#!/usr/bin/env bash
DEV=${1-eth1}

DRIVER=$(readlink -f /sys/class/net/$DEV/device/driver) # E.g. /sys/bus/usb/drivers/ax88179_178a DEVICE=$(find $DRIVER -name ':' -printf %f) # E.g. 4-2:1.0

echo $DEVICE > $DRIVER/unbind echo $DEVICE > $DRIVER/bind

RobM
  • 320
0

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()
derHugo
  • 3,356
  • 5
  • 31
  • 51
Clay
  • 101
-1

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.

Tino
  • 720
  • 1
  • 7
  • 16
  • To the downvoter: Why? If you are unhappy with some wording, you can always suggest an edit. Also: Please check, which answers were here at the time this was posted. Please do not compare with the versions of the others as seen today, compare with the versions of the others as seen back then! Thank you very much. – Tino Feb 02 '20 at 16:30