Как сбросить настройки USB-устройства из командной строки?

Можно ли сбросить подключение USB-устройства без физического отключения / подключения к ПК?

В частности, мое устройство представляет собой цифровую камеру. Я использую gphoto2, но в последнее время я получаю "ошибки чтения устройства", поэтому я хотел бы попытаться выполнить программный сброс соединения.

Из того, что я могу сказать, для камеры не загружаются модули ядра. Единственный, который выглядит связанным, - это usbhid.

Сохраните следующее как 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;}

Выполните следующие команды в терминале:

  1. Скомпилируйте программу:

    $ cc usbreset.c -o usbreset
  2. Получите идентификатор шины и устройства USB-устройства, которое вы хотите сбросить:

    $ lsusb  Bus 002 Device 003: ID 0fe9:9010 DVICO  
  3. Сделайте нашу скомпилированную программу исполняемой:

    $ chmod +x usbreset
  4. Запустите программу с привилегией sudo; произведите необходимую замену для <Bus> и <Device> идентификаторы, найденные при запуске lsusb команда:

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

Источник вышеупомянутой программы: http://marc.info/?l=linux-usb&amp ;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 чтобы получить идентификаторы поставщика и продукта, а затем использовать быструю команду, подобную этой, чтобы указать, как пути связаны с различными парами идентификаторов поставщика и продукта:

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

Это приведет к сбросу всех подключенных портов 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


Примечания:[1]: the *hci_hcd драйверы ядра обычно управляют USB-портами. ohci_hcd и uhci_hcd предназначены для портов USB1.1, ehci_hcd предназначен для портов USB2 и xhci_hcd предназначен для портов USB3. (см. https://en.wikipedia.org/wiki/Host_controller_interface_ (USB,_Firewire))

Я создал скрипт на Python, который упрощает весь процесс на основе ответов здесь.

Сохраните приведенный ниже сценарий как reset_usb.py или клонировать это репо.

Использование:

python reset_usb.py help  # Show this helpsudo python reset_usb.py list  # List all USB devicessudo python reset_usb.py path /dev/bus/usb/XXX/YYY  # Reset USB device using path /dev/bus/usb/XXX/YYYsudo 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 devicesudo python reset_usb.py listpci  # List all PCI USB devicessudo 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.Xsudo 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

Скрипт:

#!/usr/bin/env pythonimport osimport sysfrom subprocess import Popen, PIPEimport fcntlinstructions = '''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_listdef 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_listif '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/binddef 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)

Мне нужно было автоматизировать это в скрипте python, поэтому я адаптировал чрезвычайно полезный ответ LiLo к следующему:

#!/usr/bin/env pythonimport osimport sysfrom subprocess import Popen, PIPEimport fcntldriver = sys.argv[-1]print "resetting driver:", driverUSBDEVFS_RESET= 21780try:    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

Это также может быть полезно, если в вашей системе еще не установлен компилятор c, но у вас есть python.

Самым быстрым способом сброса будет сброс самого USB-контроллера. Это заставит udev отменить регистрацию устройства при отключении, и регистрация вернется, как только вы ее включите.

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

Это должно работать для большинства сред ПК. Однако, если вы используете какое-то пользовательское оборудование, вы можете просто перебирать имена устройств. С помощью этого метода вам не нужно узнавать имя устройства по lsusb. Вы также можете включить его в автоматизированный сценарий.

Я использую что-то вроде кувалды, перезагружая модули.Это мой usb_reset.sh сценарий:

#!/bin/bash# USB driversrmmod xhci_pcirmmod ehci_pci# uncomment if you have firewire#rmmod ohci_pcimodprobe xhci_pcimodprobe ehci_pci# uncomment if you have firewire#modprobe ohci_pci

И это мой служебный файл systemd /usr/lib/systemd/system/usbreset.service, который запускается usb_reset.sh после того, как мой менеджер diplay начал:

[Unit]Description=usbreset ServiceAfter=gdm.serviceWants=gdm.service[Service]Type=oneshotExecStart=/path/to/usb_reset.sh

Поскольку частным случаем вопроса является проблема связи gphoto2 с камерой на USB, в gphoto2 есть возможность сбросить его USB-соединение:

gphoto2 --reset

Возможно, этой опции не существовало в 2010 году, когда был задан этот вопрос.

Вот сценарий, который сбросит только соответствующий идентификатор продукта / поставщика.

#!/bin/bashset -euo pipefailIFS=$'\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  fidone

Я создал скрипт на python, который сбросит конкретное USB-устройство на основе номера устройства. Вы можете узнать номер устройства из команды lsusb.

например:

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

В этой строке 004 - это номер устройства

import osimport argparseimport subprocesspath='/sys/bus/usb/devices/'def runbash(cmd):    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)    out = p.stdout.read().strip()    return outdef 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()

Если вы получаете ошибки чтения, возможно, у вас есть некоторые повреждения данных. Если ваша камера использует внешнюю карту памяти (например, microSD), возможно, было бы разумно подключить ее к компьютеру и запустить fsck.

Какую версию Ubuntu вы используете?

я попробовал оба решения Li Lo и ssokolow, все, что я получаю, - это отказ в разрешении, неважно, использую ли я код usbreset или командную строку “echo 0 > …” я использую sudo, также мои usb-устройства принадлежат root, но я могу использовать их без прав администратора (камеры …)