Como você redefine um dispositivo USB a partir da linha de comando?

155

É possível redefinir a conexão de um dispositivo USB sem desconectar / conectar fisicamente o PC?

Especificamente, meu dispositivo é uma câmera digital. Estou usando gphoto2 , mas ultimamente recebo "erros de leitura de dispositivo", portanto, gostaria de tentar fazer uma redefinição de software da conexão.

Pelo que eu posso dizer, não há módulos do kernel sendo carregados para a câmera. O único que parece relacionado é usbhid .

    
por cmcginty 01.08.2010 / 21:46

16 respostas

112

Salve o seguinte 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;
}

Execute os seguintes comandos no terminal:

  1. Compile o programa:

    $ cc usbreset.c -o usbreset
    
  2. Obtenha o ID do barramento e do dispositivo do dispositivo USB que você deseja redefinir:

    $ lsusb  
    Bus 002 Device 003: ID 0fe9:9010 DVICO  
    
  3. Faça o nosso executável do programa compilado:

    $ chmod +x usbreset
    
  4. Execute o programa com privilégio sudo; faça a substituição necessária para <Bus> e <Device> ids conforme encontrado executando o comando lsusb :

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

Origem do programa acima: link

    
por Li Lo 02.08.2010 / 04:27
54

Eu não me encontrei em suas circunstâncias específicas antes, então não tenho certeza se isso será suficiente, mas a maneira mais simples que encontrei para redefinir um dispositivo USB é este comando: (Nenhum aplicativo externo é necessário )

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"

Esse é o que eu uso para redefinir meu Kinect, já que o libfreenect parece não ter API para colocá-lo de volta ao modo de suspensão. Está na minha caixa Gentoo, mas o kernel deve ser novo o suficiente para usar a mesma estrutura de caminho para o sysfs.

Seu obviamente não seria 1-4.6 , mas você pode extrair o caminho do dispositivo do seu log do kernel ( dmesg ) ou usar algo como lsusb para obter as IDs do fornecedor e do produto e usar uma rápida comando como este para listar como os caminhos se relacionam com diferentes pares de ID de fornecedor / produto:

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

Isso redefinirá todas as portas conectadas com 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

Eu acredito que isso resolverá seu problema. Se você não quiser redefinir todos os pontos de extremidade USB, poderá usar o ID de dispositivo apropriado em /sys/bus/pci/drivers/ehci_hcd

Notas: [1]: os drivers do kernel *hci_hcd normalmente controlam as portas USB. ohci_hcd e uhci_hcd são para portas USB1.1, ehci_hcd é para portas USB2 e xhci_hcd para portas USB3. (veja link )

    
por Tamás Tapsonyi 04.05.2013 / 13:02
9

Eu precisava automatizar isso em um script python, então adaptei a resposta extremamente útil do LiLo para o seguinte:

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

No meu caso, foi o driver cp210x (que eu poderia dizer de lsmod | grep usbserial ), então você pode salvar o trecho acima como reset_usb.py e fazer isso:

sudo python reset_usb.py cp210x

Isso também pode ser útil se você ainda não tiver uma configuração do compilador c em seu sistema, mas você tiver python.

    
por Peter 02.03.2015 / 21:38
4

Eu estou usando o tipo de marreta recarregando os módulos. Este é o meu 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 este é o meu arquivo de serviço systemd /usr/lib/systemd/system/usbreset.service que executa o usb_reset.sh após o início do meu gerenciador de eventos:

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

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

Como o caso especial da pergunta é um problema de comunicação do gphoto2 com uma câmera na porta USB, há uma opção no gphoto2 para redefinir sua conexão USB:

gphoto2 --reset

Talvez essa opção não existisse em 2010 quando a pergunta foi feita.

    
por mviereck 31.08.2016 / 15:19
3

A maneira mais rápida de redefinir será redefinir o próprio controlador USB. Fazer isso aplicará o udev para cancelar o registro do dispositivo na desconexão, e o registro estará de volta quando você o ativar.

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

Isso deve funcionar para a maioria dos ambientes de PC. No entanto, se você estiver usando algum hardware personalizado, basta simplesmente iterar pelos nomes dos dispositivos. Com este método você não precisa descobrir o nome do dispositivo por LSUSB. Você pode incorporar em um script automatizado também.

    
por chandank 24.11.2014 / 20:34
3

Eu fiz um script python que irá redefinir um determinado dispositivo USB com base no número do dispositivo. Você pode descobrir o número do dispositivo no comando lsusb.

por exemplo:

$ lsusb

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

Nesta string, 004 é o número do 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()
    
por Raghu 07.09.2016 / 13:42
3

Eu criei um script Python que simplifica todo o processo com base nas respostas aqui.

Salve o script abaixo como reset_usb.py ou clone este repositório .

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)
    
por mcarans 21.12.2017 / 11:15
2

Aqui está o script que redefinirá apenas um ID de produto / fornecedor correspondente.

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

Alguém pediu uma marreta? Isto é reunido a partir de várias outras respostas aqui.

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

Às vezes, quero realizar essa operação em um determinado dispositivo, conforme identificado pelo VID (ID do fornecedor) e pelo PID (ID do produto). Este é um script que eu achei útil para esse propósito, que usa a biblioteca nifty do libusb.

Primeira execução:

sudo apt-get install libusb-dev

Em seguida, resetDeviceConnection deste arquivo c ++ deve executar esta tarefa, de redefinir uma conexão de dispositivo conforme identificado por 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;
}

(roubado do meu catálogo TIL pessoal: link )

    
por Marviel 29.12.2016 / 14:53
0

Talvez isso funcione também para uma câmera:

Após reviver um HDD USB 3.0 faminto em um Linux 3.4.42 (kernel.org) do meu lado. dmesg disse que estavam expirando os comandos após 360s (desculpe, não consigo copiar o syslog aqui, não as redes conectadas) e a unidade ficou completamente desligada. Os processos que acessam o dispositivo foram bloqueados no kernel, impossíveis de matar. NFS pendurado, ZFS pendurado, dd pendurado.

Depois de fazer isso, tudo funcionou novamente. dmesg disse apenas uma linha sobre o dispositivo USB encontrado.

Eu realmente não tenho ideia do que fazer em detalhes. Mas funcionou.

A saída do exemplo a seguir é do Debian Squeeze com 2.6.32-5-686 kernel, então eu acho que funciona para o 2.6 e acima:

$ 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 isso não funcionar, talvez outra pessoa possa descobrir como enviar uma redefinição real para um dispositivo.

    
por Tino 06.06.2013 / 02:08
0

Tente isso, é um software desconectar (Ejetar).

Às vezes, não funciona simplesmente para desvincular o dispositivo de alguns dispositivos.

Exemplo:

Eu quero remover ou ejetar meu "Genius NetScroll 120".

Então eu primeiro verifico meu 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, eu encontrei meu mouse, ele tem um Bus 002, o Device 009, o idVendor 0458 e o idProduct 003a, então esta é uma informação de dispositivo de referência sobre o mouse.

Isso é importante, o número do barramento é o caminho do nome inicial para o dispositivo e eu verificarei o ID do produto e o fornecedor para garantir que o dispositivo correto seja removido.

$ 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 atenção nas pastas, verifique o início com o número da pasta 2, vou marcar esta porque meu Bus é 002, e um por um eu verifico cada pasta contendo o idVendor correto e idProduct sobre as informações do meu mouse.

Nesse caso, recuperarei as informações com 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, o caminho /sys/bus/usb/drivers/usb/2-1.3/ combina com meu mouse de informações! XDDD.

Está na hora de remover o dispositivo!

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

Conecte novamente o dispositivo USB e volte a funcionar!

    
por user242078 31.01.2014 / 12:15
0

Se você souber o nome do seu dispositivo, este script 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()
    
por Clay 04.08.2017 / 16:35
0

Eu fiz um script bash simples para redefinir um dispositivo USB específico.

#!/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
    
por 21.01.2019 / 12:58
-2

Talvez este guia possa ajudar você:

Se você for importunado pelo bug que não permite montar dispositivos USB no Ubuntu Lucid Lynx, o problema é causado pelo módulo de disquete. Desativar com:

sudo modprobe -r floppy

Após a reinicialização, o módulo provavelmente será recarregado.

    
por User 01.08.2010 / 22:16