it-swarm-pt.tech

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

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

Especificamente, meu dispositivo é uma câmera digital. Eu estou usando gphoto2, mas ultimamente eu recebo "erros de leitura de dispositivo", então eu gostaria de tentar fazer um reset de software da conexão.

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

156
cmcginty

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 nosso executável do programa compilado:

    $ chmod +x usbreset
    
  4. Execute o programa com o 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  
    

Fonte do programa acima: http://marc.info/?l=linux-usb&m=121459435621262&w=2

112
Li Lo

Eu não me encontrei em suas circunstâncias específicas antes, então eu não tenho certeza se isso vai fazer o 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 no 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 puxar o caminho do dispositivo do seu log do kernel (dmesg) ou usar algo como lsusb para obter o fornecedor e os IDs do produto e usar um comando rápido para listar como os caminhos se relacionam para 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
55
ssokolow

Isso redefinirá todas as portas conectadas a 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 vai resolver o seu problema. Se você não quiser redefinir todos os pontos de extremidade USB, poderá usar o ID de dispositivo apropriado de /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 https://en.wikipedia.org/wiki/Host_controller_interface_ (USB, _Firewire) )

46
Tamás Tapsonyi

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 snippet 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 de compilador c em seu sistema, mas você tiver python.

9
Peter

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 this repo .

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

Roteiro:

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

Eu estou usando 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
4
Ulrich-Lorenz Schlüter

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

gphoto2 --reset

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

4
mviereck

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 cadeia de caracteres 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()
3
Raghu

A maneira mais rápida de redefinir será redefinir o próprio controlador USB. Ao fazer isso, você 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, pode 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.

3
chandank

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
2
cmcginty

Às vezes, quero executar 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 essa finalidade, que usa a biblioteca nifty do libusb.

Primeira corrida:

Sudo apt-get install libusb-dev

Então, o 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: https://github.com/Marviel/TIL/blob/master/unix_tools/Reset_specific_USB_Device.md )

1
Marviel

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

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

Tente isto, é um software desconecte (ejete).

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

Exemplo:

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

Então eu primeiro Verifiquei o 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 checar este porque o meu Bus é 002, e um a 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 aparelho!

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

Conecte novamente o dispositivo USB e ele funcionará novamente!

0
user242078

eu fiz um script bash simples para redefinir determinado dispositivo 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
0
Thoht

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

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

Após reviveu um HDD USB 3.0 em um 3.4.42 (kernel.org) Linux do meu lado. dmesg disse, que estava 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 única 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 o kernel 2.6.32-5-686, 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 reinicialização real para um dispositivo.

0
Tino