Domanda Come si ripristina un dispositivo USB dalla riga di comando?


È possibile ripristinare la connessione di un dispositivo USB, senza disconnettersi / connettersi fisicamente dal PC?

Nello specifico, il mio dispositivo è una fotocamera digitale. sto usando gphoto2, ma ultimamente ricevo "errori di lettura del dispositivo", quindi mi piacerebbe provare a eseguire un ripristino software della connessione.

Da quello che posso dire, non ci sono moduli del kernel caricati per la fotocamera. L'unico che sembra correlato è usbhid.


141
2017-08-01 19:46


origine


Quale versione di Ubuntu stai usando? - User
Ho provato entrambe le soluzioni di Li Lo e ssokolow, tutto quello che ottengo è il permesso negato, nomatter se uso il codice usbreset o la riga di comando "echo 0> ..." io uso sudo, anche i miei dispositivi USB sono di proprietà di root ma io può usarli senza diritti di amministratore (telecamere ..)
Se ricevi degli errori di lettura, potresti avere alcuni problemi di corruzione dei dati. Se la tua fotocamera utilizza una scheda di memoria esterna (come MicroSD), potrebbe essere saggio collegarlo al computer ed eseguire fsck. - TSJNachos117


risposte:


Salva quanto segue 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;
}

Esegui i seguenti comandi nel terminale:

  1. Compila il programma:

    $ cc usbreset.c -o usbreset
    
  2. Ottieni il bus e l'ID dispositivo del dispositivo USB che desideri ripristinare:

    $ lsusb  
    Bus 002 Device 003: ID 0fe9:9010 DVICO  
    
  3. Rendi eseguibile il nostro programma compilato:

    $ chmod +x usbreset
    
  4. Esegui il programma con privilegio sudo; rendere necessaria la sostituzione per <Bus> e <Device> id come trovato eseguendo il lsusb comando:

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

Fonte del programma di cui sopra: http://marc.info/?l=linux-usb&m=121459435621262&w=2


104
2017-08-02 02:27



Ho errori come questo: ./usbreset: comando non trovato Dan 11.04 Natty
Grazie mille! Questo mi aiuterà a ottenere molta più vita dalla mia Intellimouse morente. - Randall Ma
Funziona con Ubuntu 13.10. L'ID del dispositivo può variare. Per ottenerlo per il mouse ho spostato sopra il codice in pochi comandi di shell 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
Se qualcuno che legge questo ha un blocco del mouse (usb) dopo l'accesso su Ubuntu 16.04 (con dmesg riempito da "input irq status -75"), posso confermare che questa è l'unica soluzione che ha funzionato per me. Grazie - Agustin Baez
@ Acquario, ho anche lo stesso errore "Errore in ioctl: è una directory". È risolto? - ransh


Non mi sono mai trovato nelle tue specifiche circostanze prima, quindi non sono sicuro che farà abbastanza, ma il modo più semplice per reimpostare un dispositivo USB è questo comando: (non sono necessarie app esterne)

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"

Questo è quello che uso per resettare il mio Kinect dal momento che libfreenect sembra non avere API per rimetterlo in stato di stop. È nella mia scatola di Gentoo, ma il kernel dovrebbe essere abbastanza nuovo da usare la stessa struttura di percorso per sysfs.

Il tuo ovviamente non lo sarebbe 1-4.6 ma puoi estrarre il percorso del dispositivo dal registro del kernel (dmesg) oppure puoi usare qualcosa di simile lsusb per ottenere l'ID del produttore e del prodotto e quindi utilizzare un comando rapido come questo per elencare in che modo i percorsi si riferiscono a coppie di fornitori / prodotti diversi:

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: impossibile creare /sys/bus/usb/devices/1-3.1:1.0/authorized: directory inesistente - Nicolas Marchildon
Sembra che abbiano cambiato il layout del filesystem usbfs. Cercherò di capire quale sia il nuovo modo di fare le cose su Ubuntu una volta che non sono così assonnato. - ssokolow
Grazie ha funzionato alla grande! Forse dovresti menzionare anche per eseguire un echo 1 > /sys/bus/usb/devices/whatever/authorizedall'interno di uno script per riattivare il dispositivo non appena è stato disabilitato. L'ho fatto sia con il mouse sia con la tastiera usb e ho finito con un sistema completamente sordo :) - Avio
L'ultima volta che l'ho usato, qualcosa nel sistema l'avrebbe resettato a 1 secondo o due dopo senza che dovessi farlo manualmente. - ssokolow
Una nota per chiunque tenti di passare a | sudo tee ... approccio ai privilegiati /sys scrive: che si rompe male se non hai già le tue credenziali sudo memorizzate nella cache. sudo sh -c "..." funziona come previsto quando sudo richiede la richiesta di una password. - ssokolow


Ciò ripristinerà tutte le porte collegate 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

Credo che questo risolva il tuo problema. Se non si desidera ripristinare tutti gli endpoint USB, è possibile utilizzare l'ID dispositivo appropriato da /sys/bus/pci/drivers/ehci_hcd


Gli appunti: [1]: il *hci_hcd i driver del kernel in genere controllano le porte USB. ohci_hcd e uhci_hcd sono per porte USB1.1, ehci_hcd è per porte USB2 e xhci_hcd è per porte USB3. (vedere https://en.wikipedia.org/wiki/Host_controller_interface_(USB,_Firewire))


37
2018-05-04 11:02



credi che possa funzionare sveglia una memoria USB? - Aquarius Power
Sebbene abbia ricevuto il seguente messaggio: ls: cannot access /sys/bus/pci/drivers/ehci_hcd/: No such file or directory questo ha risolto il problema, il mouse ha iniziato a funzionare immediatamente. +1 - Attila Fulop
è possibile aggiungere un assegno per saltare i dispositivi di archiviazione di massa USB montati? - eadmaster
@Otheus OHCI e UHCI sono gli standard host USB 1.1, EHCI è lo standard host USB 2.0 e XHCI è lo standard host USB 3.0. - ssokolow
Questa è una bellissima soluzione. Tuttavia, in alcuni Kernels successivi e in altre distribuzioni * nix, troverai che devi sostituirlo *hci_hcd con *hci-pci, poiché il driver hci_hcd è già compilato nel kernel. - not2qubit


Avevo bisogno di automatizzarlo in uno script python, quindi ho adattato la risposta estremamente utile di LiLo a quanto segue:

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

Nel mio caso era il driver cp210x (che potrei dire da lsmod | grep usbserial), in modo da poter salvare lo snippet sopra riportato come reset_usb.py e quindi fare questo:

sudo python reset_usb.py cp210x

Questo potrebbe anche essere utile se non hai già una configurazione del compilatore c sul tuo sistema, ma hai python.


9
2018-03-02 20:38



ha funzionato per me su un Raspberry - webo80
Qualche altra parola sulla tua soluzione per favore. Ad esempio, qualcosa sulla costante USBDEVFS_RESET. È sempre lo stesso per tutti i sistemi? - not2qubit
@ not2qubit USBDEVFS_RESET è uguale per tutti i sistemi. Per MIPS è 536892692. - yegorich
Le versioni più recenti di lsusb sembrano aver bisogno del -t argomento (modalità albero) per mostrare le informazioni sul driver che questo script è in attesa, ma lo script necessita di alcuni aggiornamenti per analizzare le diverse linee di output che questo genera - Cheetah
Vedi la mia risposta qui askubuntu.com/a/988297/558070 per una versione molto migliorata di questo script. - mcarans


Sto usando un po 'di mazza ricaricando i moduli. Questo è il mio script 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

E questo è il mio file di servizio systemd /usr/lib/systemd/system/usbreset.service che esegue usb_reset.sh dopo che il mio manager di diplay è stato avviato:

[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



Usando l'opzione listpci del mio script qui: askubuntu.com/a/988297/558070 ti aiuterà a identificare quale modulo USB ricaricare (ad esempio xhci_pci, ehci_pci). - mcarans
Sfortunatamente sul mio sistema questi moduli del kernel non sono separati dal kernel, quindi questo non funzionerà: rmmod: ERROR: Module xhci_pci is builtin. - unfa


Il modo più rapido per resettare sarà quello di ripristinare il controller USB stesso. Così facendo si imposterà udev per annullare la registrazione del dispositivo in caso di disconnessione, e la registrazione verrà ripristinata una volta abilitata.

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

Questo dovrebbe funzionare per la maggior parte dell'ambiente PC. Tuttavia, se si utilizza un hardware personalizzato, è possibile semplicemente scorrere i nomi dei dispositivi. Con questo metodo non è necessario trovare il nome del dispositivo da lsusb. Puoi incorporare anche in uno script automatico.


3
2017-11-24 19:34



È necessario eseguire questi comandi come root / sudo e non funzionerà su tutti i sistemi (su alcuni, sarà necessario sostituirli ehci_hcd con ehci-pci. Maggiori informazioni su questa soluzione (forse da dove proviene?): davidjb.com/blog/2012/06/... - Lambart


Poiché il caso specifico della domanda è un problema di comunicazione di gphoto2 con una fotocamera su USB, c'è un'opzione in gphoto2 per ripristinare la sua connessione USB:

gphoto2 --reset

Forse questa opzione non esisteva nel 2010 quando la domanda è stata posta.


3
2017-08-31 13:19





Ho creato uno script python che resetterà un particolare dispositivo USB in base al numero del dispositivo. È possibile trovare il numero del dispositivo dal comando lsusb.

per esempio:

$ lsusb

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

In questa stringa 004 è il numero del dispositivo

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





Ecco uno script che reimposterà solo un ID prodotto / fornitore corrispondente.

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



Ho trovato che il tuo script è utile. Ma cosa dovrei fare se il $DIR scompare e il dispositivo non è visibile? - Eugen Konkov


Ho creato uno script Python che semplifica l'intero processo in base alle risposte qui.

Salva lo script di seguito come reset_usb.py o clona questo repository: https://github.com/mcarans/resetusb/.

Uso:

python reset_usb.py help: Mostra questo aiuto

sudo python elenco reset_usb.py: elenca tutti i dispositivi USB

sudo python reset_usb.py percorso / dev / bus / usb / XXX / YYY: resetta il dispositivo USB usando il percorso / dev / bus / usb / XXX / YYY

sudo python reset_usb.py cerca "termini di ricerca": cerca il dispositivo USB utilizzando i termini di ricerca all'interno della stringa di ricerca restituita dall'elenco e ripristina il dispositivo corrispondente

sudo python reset_usb.py listpci: elenca tutti i dispositivi PCI USB

sudo python reset_usb.py pathpci /sys/bus/pci/drivers/.../XXXX:XX:XX.X: Ripristina dispositivo USB PCI utilizzando il percorso /sys/bus/pci/drivers/.../XXXX:XX: XX.X

sudo python reset_usb.py searchpci "termini di ricerca": cerca il dispositivo PCI USB utilizzando i termini di ricerca all'interno della stringa di ricerca restituita da listpci e ripristina il dispositivo corrispondente

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

2
2017-12-21 10:15