如何从命令行重置USB设备?

是否可以重置USB设备的连接,而无需从PC上物理断开/连接?

具体来说,我的设备是数码相机。 我正在使用gphoto2 ,但最近我收到“设备读取错误”,所以我想尝试对连接进行软件重置。

据我所知,没有为相机加载内核模块。 唯一看起来相关的是usbhid

将以下内容保存为usbreset.c

 /* usbreset -- send a USB port reset to a USB device */ #include  #include  #include  #include  #include  #include  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; } 

在终端中运行以下命令:

  1. 编译程序:

     $ cc usbreset.c -o usbreset 
  2. 获取要重置的USB设备的总线和设备ID:

     $ lsusb Bus 002 Device 003: ID 0fe9:9010 DVICO 
  3. 使我们编译的程序可执行:

     $ chmod +x usbreset 
  4. 使用sudo权限执行程序; 通过运行lsusb命令找到 id的必要替换:

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

上述计划的来源: http : //marc.info/?l = linux-usb&m = 121459435621262&w = 2

我之前没有发现自己处于特定情况,所以我不确定它是否足够,但我发现重置USB设备的最简单方法是这个命令:(无需外部应用程序)

 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" 

这是我用来重置我的Kinect的实际的一个,因为libfreenect似乎没有让它重新入睡的API。 它在我的Gentoo盒子上,但内核应该足够新,以便为sysfs使用相同的路径结构。

您的显然不会是1-4.6但您可以从内核日志( dmesg )中提取该设备路径,或者您可以使用类似lsusb来获取供应商和产品ID,然后使用这样的快速命令列出如何路径与不同的供应商/产品ID对相关:

 for X in /sys/bus/usb/devices/*; do echo "$X" cat "$X/idVendor" 2>/dev/null cat "$X/idProduct" 2>/dev/null echo done 

这将重置所有USB1 / 2/3连接端口[1]:

 for i in /sys/bus/pci/drivers/[uoex]hci_hcd/*:*; do [ -e "$i" ] || continue echo "${i##*/}" > "${i%/*}/unbind" echo "${i##*/}" > "${i%/*}/bind" done 

我相信这会解决你的问题。 如果您不想重置所有USB端点,可以使用/sys/bus/pci/drivers/ehci_hcd相应设备ID


注意:[1]: *hci_hcd内核驱动程序通常控制USB端口。 ohci_hcduhci_hcd用于USB1.1端口, ehci_hcd用于USB2端口, xhci_hcd用于USB3端口。 (见https://en.wikipedia.org/wiki/Host_controller_interface_(USB,_Firewire) )

我需要在python脚本中自动执行此操作,因此我对LiLo的以下内容进行了非常有用的回答:

 #!/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 

在我的情况下,它是cp210x驱动程序(我可以从lsmod | grep usbserial告诉),因此您可以将上面的代码段保存为reset_usb.py,然后执行以下操作:

 sudo python reset_usb.py cp210x 

如果你的系统上还没有安装ac编译器,但是你确实有python,这也可能会有所帮助。

我正在通过重新加载模块来使用大锤。 这是我的usb_reset.sh脚本:

 #!/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 

这是我的系统服务文件/usr/lib/systemd/system/usbreset.service,它在我的diplay管理器启动后运行usb_reset.sh:

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

由于问题的特殊情况是gphoto2与USB相机的通信问题,gphoto2中有一个选项可以重置其USB连接:

 gphoto2 --reset 

也许这个选项在2010年问题时并不存在。

最快的重置方法是重置USB控制器本身。 这样做会强制udev在断开连接时取消注册设备,并在启用后重新注册。

 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 

这适用于大多数PC环境。 但是,如果您使用的是某些自定义硬件,则可以简单地遍历设备名称。 使用此方法,您无需通过lsusb查找设备名称。 您也可以合并到自动脚本中。

我制作了一个python脚本,它将根据设备号重置特定的USB设备。 您可以从命令lsusb中找到设备编号。

例如:

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

在此字符串中,004是设备编号

 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  \nThe device number can be obtained from lsusb command result') return reset_device(args.devnum) if __name__=='__main__': main() 

以下是仅重置匹配产品/供应商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 

我已经创建了一个Python脚本,可以根据这里的答案简化整个过程。

将以下脚本保存为reset_usb.py或克隆此repo: https : //github.com/mcarans/resetusb/ 。

用法:

python reset_usb.py help:显示此帮助

sudo python reset_usb.py list:列出所有USB设备

sudo python reset_usb.py path / dev / bus / usb / XXX / YYY:使用路径/ dev / bus / usb / XXX / YYY重置USB设备

sudo python reset_usb.py搜索“搜索词”:使用列表返回的搜索字符串中的搜索词搜索USB设备并重置匹配设备

sudo python reset_usb.py listpci:列出所有PCI USB设备

sudo python reset_usb.py pathpci /sys/bus/pci/drivers/…/XXXX:XX:XX.X:使用路径/sys/bus/pci/drivers/…/XXXX:XX重置PCI USB设备: XX.X

sudo python reset_usb.py searchpci“搜索术语”:使用listpci返回的搜索字符串中的搜索词搜索PCI USB设备并重置匹配设备

 #!/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) 

有人订了一把大锤吗? 这是从其他各种答案拼凑而成的。

 #!/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 

有时我想在特定设备上执行此操作,由VID(供应商ID)和PID(产品ID)标识。 这是我发现用于此目的的脚本,它使用了漂亮的libusb库。

第一次运行:

 sudo apt-get install libusb-dev 

然后,这个c ++文件的resetDeviceConnection应该执行此任务,重置由vid和pid标识的设备连接。

 #include  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; } 

(从我个人的TIL目录中窃取: https : //github.com/Marviel/TIL/blob/master/unix_tools/Reset_specific_USB_Device.md )

也许这适用于相机:

继我在3.4.42 (kernel.org)Linux上恢复了一个饥饿的USB 3.0硬盘。 dmesg告诉我,它是在360s之后超时命令(对不起,我不能在这里复制系统日志,没有连接的网络)并且驱动器完全挂起。 访问设备的进程在内核中被阻止,不可杀死。 NFS挂了, ZFS挂了, dd挂了。

这样做之后,一切都恢复了。 dmesg只发了一行关于USB设备的信息。

我真的不知道以下详细介绍了什么。 但它奏效了。

以下示例输出来自Debian Squeeze和2.6.32-5-686内核,因此我认为它适用于2.6及以上版本:

 $ 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 

如果这不起作用,也许其他人可以弄清楚如何向设备发送真正的重置。

试试这个,它是一个软件拔出(弹出)。

有时不起作用只是为某些设备取消绑定设备。

例:

我想删除或弹出我的“Genius NetScroll 120”。

然后我首先检查我附加的USB设备

 $ 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** 

好的,我找到了我的鼠标,它有一个总线002,设备009,idVendor 0458和idProduct 003a,所以这是一个关于鼠标的参考设备信息。

这很重要,总线编号是设备的开始名称路径,我将检查产品ID和供应商,以确保删除正确的设备。

 $ 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/ 

关注文件夹,检查开头的文件夹编号2,我将检查这一个,因为我的总线是002,并逐一检查每个文件夹包含正确的idVendor和idProduct关于我的鼠标信息。

在这种情况下,我将使用此命令检索信息:

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

好的,路径/sys/bus/usb/drivers/usb/2-1.3/与我的信息鼠标匹配! XDDD。

是时候删除设备了!

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

再次插入USB设备,它再次工作!

如果你知道你的设备名称,这个python脚本将工作:

 #!/usr/bin/python """ USB Reset Call as "usbreset.py " 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() 

也许本指南可以帮助您:

如果你被那个没有的错误所困扰,你可以在Ubuntu Lucid Lynx中安装USB设备,这个问题是由软盘模块引起的。 禁用它:

 sudo modprobe -r floppy 

重启后,模块可能会重新加载。