¿Cómo restablece un dispositivo USB desde la línea de comandos?

142

¿Es posible restablecer la conexión de un dispositivo USB sin desconectar / conectar físicamente desde la PC?

Específicamente, mi dispositivo es una cámara digital. Estoy usando gphoto2 , pero últimamente recibo "errores de lectura del dispositivo", así que me gustaría intentar restablecer la conexión mediante un software.

Por lo que puedo decir, no hay módulos de kernel que se carguen para la cámara. El único que parece estar relacionado es usbhid .

    
pregunta cmcginty 01.08.2010 - 21:46

16 respuestas

106

Guarda lo siguiente como 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;
}

Ejecuta los siguientes comandos en la terminal:

  1. Compila el programa:

    $ cc usbreset.c -o usbreset
    
  2. Obtenga la ID de dispositivo y bus del dispositivo USB que desea restablecer:

    $ lsusb  
    Bus 002 Device 003: ID 0fe9:9010 DVICO  
    
  3. Haga que nuestro programa compilado sea ejecutable:

    $ chmod +x usbreset
    
  4. Ejecuta el programa con privilegio sudo; haga la sustitución necesaria para <Bus> y <Device> ids como se encuentra ejecutando el comando lsusb :

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

Fuente del programa anterior: enlace

    
respondido por el Li Lo 02.08.2010 - 04:27
48

No me he encontrado en sus circunstancias específicas antes, por lo que no estoy seguro de si será suficiente, pero la forma más sencilla que he encontrado de reiniciar un dispositivo USB es este comando: (No se necesitan aplicaciones externas )

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"

Ese es el real que utilizo para restablecer mi Kinect ya que parece que libfreenect no tiene API para volver a ponerlo en suspensión. Está en mi caja de Gentoo, pero el kernel debería ser lo suficientemente nuevo como para usar la misma estructura de ruta para sysfs.

La suya, obviamente, no sería 1-4.6 , pero puede extraer la ruta del dispositivo desde el registro del kernel ( dmesg ) o puede usar algo como lsusb para obtener las ID del proveedor y del producto y luego usar una Comando de esta manera para enumerar cómo se relacionan las rutas con diferentes pares de ID de proveedor / producto:

for X in /sys/bus/usb/devices/*; do 
    echo "$X"
    cat "$X/idVendor" 2>/dev/null 
    cat "$X/idProduct" 2>/dev/null
    echo
done
    
respondido por el ssokolow 13.09.2011 - 08:56
40

Esto restablecerá todos los puertos USB1 / 2/3 conectados [1]:

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

Creo que esto resolverá tu problema. Si no desea restablecer todos los puntos finales USB, puede usar la ID de dispositivo adecuada de /sys/bus/pci/drivers/ehci_hcd

Notas: [1]: los controladores del núcleo *hci_hcd típicamente controlan los puertos USB. ohci_hcd y uhci_hcd son para puertos USB1.1, ehci_hcd son para puertos USB2 y xhci_hcd son para puertos USB3. (consulte enlace )

    
respondido por el Tamás Tapsonyi 04.05.2013 - 13:02
9

Necesitaba automatizar esto en un script de Python, así que adapté la respuesta extremadamente útil de LiLo a lo siguiente:

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

En mi caso, fue el controlador cp210x (que pude ver en lsmod | grep usbserial ), así que puedes guardar el fragmento de código anterior como reset_usb.py y luego hacer esto:

sudo python reset_usb.py cp210x

Esto también podría ser útil si aún no tiene una configuración de compilador de c en su sistema, pero sí tiene python.

    
respondido por el Peter 02.03.2015 - 21:38
4

Estoy usando una especie de martillo al recargar los módulos. Este es mi 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

Y este es mi archivo de servicio systemd /usr/lib/systemd/system/usbreset.service que ejecuta usb_reset.sh después de que se haya iniciado mi administrador de diplay:

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

[Service]
Type=oneshot
ExecStart=/path/to/usb_reset.sh
    
respondido por el Ulrich-Lorenz Schlüter 09.01.2016 - 11:18
4

Como el caso especial de la pregunta es un problema de comunicación de gphoto2 con una cámara en USB, hay una opción en gphoto2 para restablecer su conexión USB:

gphoto2 --reset

Tal vez esta opción no existía en 2010 cuando se hizo la pregunta.

    
respondido por el mviereck 31.08.2016 - 15:19
3

La forma más rápida de restablecer será restablecer el controlador USB. Si lo hace, forzará a udev a cancelar el registro del dispositivo cuando se desconecte, y el registro vuelve una vez que lo habilite.

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

Esto debería funcionar para la mayoría de los entornos de PC. Sin embargo, si está utilizando algún hardware personalizado, simplemente puede iterar a través de los nombres de los dispositivos. Con este método no necesita averiguar el nombre del dispositivo por lsusb. También puede incorporar en un script automatizado.

    
respondido por el chandank 24.11.2014 - 20:34
2

Hice una secuencia de comandos de python que restablecerá un dispositivo USB en particular según el número de dispositivo. Puede averiguar el número de dispositivo desde el comando lsusb.

por ejemplo:

$ lsusb

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

En esta cadena, 004 es el número 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()
    
respondido por el Raghu 07.09.2016 - 13:42
2

Aquí hay una secuencia de comandos que solo restablecerá la identificación del producto / proveedor correspondiente.

#!/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
    
respondido por el cmcginty 30.04.2017 - 05:50
2

He creado un script en Python que simplifica todo el proceso basado en las respuestas aquí.

Guarde el script a continuación como reset_usb.py o clone este repositorio: enlace .

Uso:

python reset_usb.py help: muestra esta ayuda

sudo python reset_usb.py list: enumerar todos los dispositivos USB

sudo python reset_usb.py ruta / dev / bus / usb / XXX / YYY: restablece el dispositivo USB usando la ruta / dev / bus / usb / XXX / YYY

sudo python reset_usb.py buscar "términos de búsqueda": busque un dispositivo USB utilizando los términos de búsqueda dentro de la cadena de búsqueda devuelta por lista y reinicie el dispositivo correspondiente

sudo python reset_usb.py listpci: enumerar todos los dispositivos PCI USB

sudo python reset_usb.py pathpci /sys/bus/pci/drivers/.../XXXX:XX:XX.X: Restablecer el dispositivo USB PCI usando la ruta /sys/bus/pci/drivers/.../XXXX : XX: XX.X

sudo python reset_usb.py searchpci "términos de búsqueda": busque un dispositivo USB PCI utilizando los términos de búsqueda dentro de la cadena de búsqueda devuelta por listpci y reinicie el dispositivo correspondiente

#!/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)
    
respondido por el mcarans 21.12.2017 - 11:15
1

¿Alguien ordenó un martillo? Esto se juntó de varias otras respuestas aquí.

#!/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
    
respondido por el Mark K Cowan 28.06.2016 - 16:08
1

Algunas veces quiero realizar esta operación en un dispositivo en particular, como se identifica mediante VID (Id. de proveedor) y PID (Id. de producto). Este es un script que he encontrado útil para este propósito, que utiliza la biblioteca libusb ingeniosa.

Primera ejecución:

sudo apt-get install libusb-dev

Luego, resetDeviceConnection de este archivo c ++ debe realizar esta tarea, de restablecer la conexión de un dispositivo como se identifica mediante vid y 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;
}

(robado de mi catálogo personal de TIL: enlace )

    
respondido por el Marviel 29.12.2016 - 14:53
0

Quizás esto también funcione para una cámara:

A continuación reviví un USB 3.0 HDD hambriento en un 3.4.42 (kernel.org) Linux de mi lado. dmesg dijo que se estaban agotando los comandos después de 360s (lo siento, no puedo copiar el syslog aquí, no las redes conectadas) y la unidad se colgó por completo. Los procesos que accedieron al dispositivo fueron bloqueados en el kernel, no pueden ser procesados. NFS colgado, ZFS colgado, dd colgado.

Después de hacer esto, todo volvió a funcionar. dmesg dijo solo una línea sobre el dispositivo USB encontrado.

Realmente no tengo idea de lo que hace el siguiente detalle. Pero funcionó.

El siguiente ejemplo de salida es de Debian Squeeze con 2.6.32-5-686 kernel, así que creo que funciona para 2.6 y superior:

$ 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

Si esto no funciona, quizás alguien más pueda averiguar cómo enviar un reinicio real a un dispositivo.

    
respondido por el Tino 06.06.2013 - 02:08
0

Intente esto, es un software desenchufado (Expulsar).

A veces no funciona, simplemente desvincula el dispositivo para algunos dispositivos.

Ejemplo:

Quiero eliminar o expulsar mi "Genius NetScroll 120".

Luego primero reviso mi dispositivo usb adjunto

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

Bien, encontré mi mouse, tiene un Bus 002, Device 009, idVendor 0458 e idProduct 003a, así que esta es una información de referencia del dispositivo sobre el mouse.

Esto es importante, el número de Bus es la ruta de inicio del nombre al dispositivo y verificaré la Id. del producto y el Proveedor para asegurar que se elimine el dispositivo correcto.

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

Preste atención a las carpetas, verifique el principio con la carpeta número 2, revisaré esta porque mi Bus es 002, y una por una he revisado cada carpeta que contiene el idVendor correcto y el producto id acerca de la información de mi mouse.

En este caso, recuperaré la información con este comando:

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

Ok, la ruta /sys/bus/usb/drivers/usb/2-1.3/ coincide con mi mouse de información! XDDD.

¡Es hora de eliminar el dispositivo!

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

Vuelve a enchufar el dispositivo USB y vuelve a funcionar!

    
respondido por el user242078 31.01.2014 - 12:15
0

Si conoce el nombre de su dispositivo, esta secuencia de comandos de Python funcionará:

#!/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 __name__ == '__main__':
    main()
    
respondido por el Clay 04.08.2017 - 16:35
-3

Tal vez esta guía pueda ayudarte:

Si está molesto por el error que no le permite montar dispositivos USB en Ubuntu Lucid Lynx, el problema se debe al módulo de disquete. Deshabilítelo con:

sudo modprobe -r floppy

Después de reiniciar, es probable que el módulo se vuelva a cargar.

    
respondido por el User 01.08.2010 - 22:16

Lea otras preguntas en las etiquetas