it-swarm-es.com

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

¿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 el software de la conexión.

Por lo que puedo decir, no se están cargando módulos del núcleo para la cámara. El único que parece relacionado es usbhid.

156
cmcginty

Guarde 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;
}

El ejecutar los siguientes comandos en la terminal:

  1. Compila el programa:

    $ cc usbreset.c -o usbreset
    
  2. Obtenga la identificación de bus y dispositivo 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. Ejecute el programa con privilegio Sudo; realice la sustitución necesaria de <Bus> y <Device> ids como se encuentra al ejecutar el comando lsusb:

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

Fuente del programa anterior: http://marc.info/?l=linux-usb&m=121459435621262&w=2

114
Li Lo

No me he encontrado en sus circunstancias específicas antes, por lo que no estoy seguro de si hará lo suficiente, pero la forma más simple que he encontrado para restablecer 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 que uso para restablecer mi Kinect ya que libfreenect parece no tener API para volverlo a dormir. Está en mi cuadro Gentoo, pero el núcleo debería ser lo suficientemente nuevo como para usar la misma estructura de ruta para sysfs.

Obviamente, el suyo no sería 1-4.6 pero puede extraer esa ruta del dispositivo del registro del kernel (dmesg) o puede usar algo como lsusb para obtener las ID del proveedor y del producto y luego use un comando rápido como este para enumerar cómo se relacionan las rutas con los diferentes pares de proveedor/ID de 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
57
ssokolow

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 apropiada desde /sys/bus/pci/drivers/ehci_hcd


Notas: [1]: los controladores de kernel *hci_hcd suelen controlar los puertos USB. ohci_hcd y uhci_hcd son para puertos USB1.1, ehci_hcd es para puertos USB2 y xhci_hcd es para puertos USB3. (ver https://en.wikipedia.org/wiki/Host_controller_interface_ (USB, _Firewire) )

49
Tamás Tapsonyi

Necesitaba automatizar esto en una secuencia de comandos 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, era el controlador cp210x (que pude ver por lsmod | grep usbserial), por lo que podría guardar el fragmento 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 del compilador de c en su sistema, pero sí tiene python.

10
Peter

Creé un script 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 .

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

Guión:

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

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

Quizás esta opción no existía en 2010 cuando se hizo la pregunta.

4
mviereck

Hice una secuencia de comandos python que restablecerá un dispositivo USB en particular en función del número de dispositivo. Puede encontrar 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 de 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

La forma más rápida de restablecer será restablecer el controlador USB en sí. Hacerlo obligará a udev a cancelar el registro del dispositivo en la desconexión, y el registro volverá 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 un hardware personalizado, simplemente puede recorrer los nombres de los dispositivos. Con este método no necesita encontrar el nombre del dispositivo por lsusb. También puede incorporar en un script automatizado.

3
chandank

Estoy usando una especie de mazo 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 mi administrador de diplay ha comenzado:

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

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

Aquí hay un script que solo restablecerá una identificación de producto/proveedor coincidente.

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

hice un script bash simple para restablecer un dispositivo USB en particular.

#!/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 veces quiero realizar esta operación en un dispositivo en particular, según lo identificado por VID (identificación del proveedor) y PID (identificación del producto). Este es un script que he encontrado útil para este propósito, que utiliza la ingeniosa biblioteca libusb.

Primer intento:

Sudo apt-get install libusb-dev

Luego, resetDeviceConnection de este archivo c ++ debe realizar esta tarea, de restablecer una conexión de dispositivo como se identifica por 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: https://github.com/Marviel/TIL/blob/master/unix_tools/Reset_specific_USB_Device.md )

1
Marviel

¿Alguien ordenó un mazo? Esto se reconstruye a partir de varias otras respuestas aquí.

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

Intente esto, es un desenchufe de software (Expulsar).

A veces no funciona simplemente desconectar el dispositivo para algunos dispositivos.

Ejemplo:

Quiero eliminar o expulsar mi "Genius NetScroll 120".

Entonces primero verifico mi dispositivo usb conectado

$ 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, encontré mi mouse, tiene un Bus 002, Dispositivo 009, idVendor 0458 e idProduct 003a, así que esta es una información del dispositivo de referencia sobre el mouse.

Esto es importante, el número de Bus es la ruta de inicio del nombre del dispositivo y comprobaré el Id. Del producto y el Proveedor para asegurarme de 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 comienzo con la carpeta número 2, comprobaré esta porque mi Bus es 002, y una por una compruebo cada carpeta que contiene el idVendor y idProduct correctos sobre 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 quitar el dispositivo!

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

¡Vuelva a enchufar el dispositivo usb y vuelve a funcionar!

0
user242078

Si conoce el nombre de su dispositivo, este python script 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 __== '__main__':
    main()
0
Clay

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

Después revivió un USB 3.0 HDD hambriento en un 3.4.42 (kernel.org) Linux de mi lado. dmesg dijo, que estaba agotando los comandos después de 360 ​​segundos (lo siento, no puedo copiar el registro del sistema aquí, no las redes conectadas) y la unidad se bloqueó por completo. Los procesos que acceden al dispositivo fueron bloqueados en el núcleo, imposibles de matar. NFS colgado, ZFS colgado, dd colgado.

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

Realmente no tengo idea de lo que sigue en detalle. Pero funcionó.

El siguiente resultado de ejemplo 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 descubrir cómo enviar un reinicio real a un dispositivo.

0
Tino