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


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

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

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


141
2017-08-01 19:46


происхождения


Какую версию Ubuntu вы используете? - User
Я пробовал оба решения Li Lo и ssokolow, все, что я получаю, разрешено, нотератор, если я использую код usbreset или командную строку «echo 0> ...» Я использую sudo, также мои устройства usb принадлежат root, но i могут использовать их без прав администратора (камеры ..)
Если вы получаете ошибки чтения, у вас может быть некоторая поврежденность данных. Если ваша камера использует внешнюю карту памяти (например, MicroSD), может быть разумно подключить ее к компьютеру и запустить fsck. - TSJNachos117


ответы:


Сохраните следующее: 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&m=121459435621262&w=2


104
2017-08-02 02:27



Я получил такие ошибки: ./usbreset: команда не найден Dan 11.04 Natty
Спасибо огромное! Это поможет мне получить намного больше жизни от моего умирающего Intellimouse. - Randall Ma
Это работает с ubuntu 13.10. Идентификатор устройства может отличаться. Чтобы получить его для мыши, я обернул код выше в нескольких командах оболочки 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
Если кто-то читает это, у него (wb) мышь замерзает после входа в Ubuntu 16.04 (с dmesg, заполненным «input irq status -75»), я могу подтвердить, что это единственное решение, которое сработало для меня. спасибо - Agustin Baez
@ Водолей, я также получаю ту же ошибку «Ошибка в ioctl: есть каталог». Это разрешено? - ransh


Я не обнаружил себя в ваших конкретных обстоятельствах раньше, поэтому я не уверен, что он будет делать достаточно, но самым простым способом, который я нашел для сброса 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
    echo
done

47
2017-09-13 06:56



sh: 1: невозможно создать /sys/bus/usb/devices/1-3.1:1.0/authorized: Directory nonexistent - Nicolas Marchildon
Похоже, они изменили компоновку файловой системы usbfs. Я попытаюсь понять, что новый способ делать вещи на Ubuntu, когда я не так сонлив. - ssokolow
Спасибо, ты отлично поработал! Возможно, вам стоит упомянуть echo 1 > /sys/bus/usb/devices/whatever/authorized внутри сценария для повторного включения устройства, как только он был отключен. Я сделал это как на моей мыши, так и на клавиатуре usb, и я закончил с полностью глухой системой :) - Avio
В прошлый раз, когда я использовал его, что-то в системе сбросило бы его до 1 секунды или двух позже, без необходимости делать это вручную. - ssokolow
Примечание для всех, кто пытается переключиться на | sudo tee ... подход к привилегированным /sys пишет: Это сильно ломается, если у вас еще нет учетных данных sudo. sudo sh -c "..." работает, как ожидается, когда sudo нужно запросить пароль. - ssokolow


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


37
2018-05-04 11:02



вы считаете, что это может пробуждение хранилища usb? - Aquarius Power
Хотя я получил следующее сообщение: ls: cannot access /sys/bus/pci/drivers/ehci_hcd/: No such file or directory это решило проблему, мышь начала работать немедленно. +1 - Attila Fulop
можно ли добавить проверку, чтобы пропустить установленные USB-накопители? - eadmaster
@Otheus OHCI и UHCI - это стандарты хоста USB 1.1, EHCI - это стандарт USB 2.0, а XHCI - стандарт хоста USB 3.0. - ssokolow
Это прекрасное решение. Однако в некоторых более поздних ядрах и других дистрибутивах * nix вы обнаружите, что вам нужно заменить *hci_hcdс *hci-pci, так как драйвер hci_hcd уже скомпилирован в ядро. - not2qubit


Мне нужно было автоматизировать это в сценарии 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

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


9
2018-03-02 20:38



работал на меня на малине - webo80
Еще несколько слов о вашем решении, пожалуйста. Например, что-то о константе USBDEVFS_RESET, Всегда ли это одинаково для всех систем? - not2qubit
@ not2qubit USBDEVFS_RESET одинаково для всех систем. Для MIPS это 536892692. - yegorich
Новые версии lsusb, похоже, нуждаются в -t аргумент (режим дерева), чтобы показать информацию о драйвере, которую ожидает этот сценарий, но сценарий затем нуждается в некоторых обновлениях для анализа различных выходных строк, которые это генерирует - Cheetah
См. Мой ответ здесь askubuntu.com/a/988297/558070 для значительно улучшенной версии этого скрипта. - mcarans


Я использую кувалду, перезаряжая модули. Это мой скрипт 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, который запускает usb_reset.sh после запуска моего диспетчера diplay:

[Unit]
Description=usbreset Service
After=gdm.service
Wants=gdm.service

[Service]
Type=oneshot
ExecStart=/path/to/usb_reset.sh

4
2018-01-09 10:18



Использование опции listpci моего скрипта здесь: askubuntu.com/a/988297/558070 поможет определить, какой USB-модуль перезагружается (например, xhci_pci, ehci_pci). - mcarans
К сожалению, в моей системе эти модули ядра не являются отдельной формой ядра, поэтому это не сработает: rmmod: ERROR: Module xhci_pci is builtin. - unfa


Самый быстрый способ сброса - сброс самого контроллера 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

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


3
2017-11-24 19:34



Вам нужно запустить эти команды как root / sudo, и он не будет работать на всех системах (на некоторых вам нужно будет заменить ehci_hcdс ehci-pci, Больше информации об этом решении (возможно, откуда оно взялось?): davidjb.com/blog/2012/06/... - Lambart


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

gphoto2 --reset

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


3
2017-08-31 13:19





Я создал скрипт 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 <device_number> \nThe device    number can be obtained from lsusb command result')
            return

    reset_device(args.devnum)

if __name__=='__main__':
    main()

2
2017-09-07 11:42





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

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

2
2018-04-30 03:50



Я нашел ваш скрипт полезным. Но что мне делать, если $DIR исчезает, и устройство не видно? - Eugen Konkov