it-swarm.it

Come si reimposta un dispositivo USB dalla riga di comando?

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

In particolare, il mio dispositivo è una fotocamera digitale. Sto usando gphoto2, ma ultimamente ricevo "errori di lettura del dispositivo", quindi vorrei provare a ripristinare il software della connessione.

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

161
cmcginty

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

Eseguono i seguenti comandi nel terminale:

  1. Compila il programma:

    $ cc usbreset.c -o usbreset
    
  2. Ottieni l'ID bus e 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. Eseguire il programma con privilegio Sudo; effettuare la sostituzione necessaria per <Bus> e <Device> ids come trovato eseguendo il comando lsusb:

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

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

114
Li Lo

Non mi sono mai trovato nelle tue circostanze specifiche prima, quindi non sono sicuro che farà abbastanza, ma il modo più semplice che ho trovato per ripristinare 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"

È quello vero che uso per ripristinare il mio Kinect poiché libfreenect sembra non avere API per rimetterlo in sospensione. È sulla mia scatola di Gentoo, ma il kernel dovrebbe essere abbastanza nuovo da usare la stessa struttura di percorso per sysfs.

Ovviamente il tuo non sarebbe 1-4.6 ma puoi estrarre quel percorso del dispositivo dal log del kernel (dmesg) oppure puoi usare qualcosa come lsusb per ottenere gli ID del fornitore e del prodotto e quindi utilizzare un comando rapido come questo per elencare il modo in cui i percorsi si collegano alle diverse coppie ID fornitore/prodotto:

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

Ciò ripristinerà tutte le porte USB1/2/3 collegate [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 risolverà 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


Note: [1]: i driver del kernel *hci_hcd generalmente controllano le porte USB. ohci_hcd e uhci_hcd sono per le porte USB 1.1, ehci_hcd è per le porte USB2 e xhci_hcd è per le porte USB3. (vedi https://en.wikipedia.org/wiki/Host_controller_interface_ (USB, _Firewire) )

49
Tamás Tapsonyi

Avevo bisogno di automatizzare questo 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 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.

10
Peter

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

Salvare lo script seguente come reset_usb.py o clonare questo repository .

Uso:

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

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

gphoto2 --reset

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

4
mviereck

Ho creato uno script python che ripristinerà un determinato dispositivo USB in base al numero del dispositivo. Puoi 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()
3
Raghu

Il modo più rapido per ripristinare sarà ripristinare il controller USB stesso. In questo modo imponerai a udev di annullare la registrazione del dispositivo al momento della disconnessione e il registro tornerà dopo averlo abilitato.

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 stai utilizzando hardware personalizzato, puoi semplicemente scorrere i nomi dei dispositivi. Con questo metodo non è necessario scoprire il nome del dispositivo tramite lsusb. Puoi anche incorporare in uno script automatizzato.

3
chandank

Sto usando una specie 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 l'avvio del mio gestore di visualizzazione:

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

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

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
cmcginty

ho realizzato un semplice script bash per ripristinare particolari dispositivi USB.

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

A volte voglio eseguire questa operazione su un particolare dispositivo, come identificato da VID (ID fornitore) e PID (ID prodotto). Questo è uno script che ho trovato utile a questo scopo, che utilizza la libreria nifty libusb.

Prima corsa:

Sudo apt-get install libusb-dev

Quindi, resetDeviceConnection di questo file c ++ dovrebbe eseguire questa attività, di reimpostare una connessione del dispositivo identificata da vid e 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;
}

(rubato dal mio catalogo TIL personale: https://github.com/Marviel/TIL/blob/master/unix_tools/Reset_specific_USB_Device.md )

1
Marviel

Qualcuno ha ordinato un martello? Questo è messo insieme da varie altre risposte qui.

#!/bin/bash

# Root required
if (( UID )); then
        exec Sudo "$0" "[email protected]"
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
1
Mark K Cowan

Prova questo, è un software unplug (Espelli).

A volte non funziona semplicemente sbloccare il dispositivo per alcuni dispositivi.

Esempio:

Voglio rimuovere o espellere il mio "Genius NetScroll 120".

Quindi prima controllo il mio dispositivo USB collegato

$ 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, ho trovato il mio mouse, ha un bus 002, dispositivo 009, idVendor 0458 e idProduct 003a, quindi queste sono le informazioni di un dispositivo di riferimento sul mouse.

Questo è importante, il numero del bus è il percorso del nome iniziale per il dispositivo e controllerò l'ID del prodotto e il fornitore per garantire che il dispositivo corretto da rimuovere.

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

Prestare attenzione alle cartelle, controllare all'inizio con la cartella numero 2, verificherò questa perché il mio bus è 002 e uno per uno ho controllato ogni cartella contenente l'idVendor e l'idProduct corretti sulle informazioni del mio mouse.

In questo caso, recupererò le informazioni con questo comando:

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

Ok, il percorso /sys/bus/usb/drivers/usb/2-1.3/ corrisponde al mio mouse informativo! XDDD.

È tempo di rimuovere il dispositivo!

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

Ricollega il dispositivo USB ed è di nuovo funzionante!

0
user242078

Se conosci il nome del tuo dispositivo, questo script python funzionerà:

#!/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 __== '__main__':
    main()
0
Clay

Forse funziona anche per una macchina fotografica:

In seguito ho rianimato un HDD USB 3.0 affamato su un 3.4.42 (kernel.org) Linux dalla mia parte. dmesg ha detto che stava scadendo i comandi dopo 360 secondi (mi dispiace, non riesco a copiare il syslog qui, non le reti connesse) e l'unità si è bloccata completamente. I processi di accesso al dispositivo sono stati bloccati nel kernel, non verificabili. NFS appeso, ZFS appeso, dd appeso.

Dopo aver fatto questo, tutto ha funzionato di nuovo. dmesg ha riferito a una sola riga del dispositivo USB trovato.

Non ho davvero idea di cosa segue in dettaglio. Ma ha funzionato.

Il seguente esempio di output proviene da Debian Squeeze con il kernel 2.6.32-5-686, quindi penso che funzioni per 2.6 e versioni successive:

$ 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

Se questo non funziona, forse qualcun altro può capire come inviare un ripristino reale a un dispositivo.

0
Tino