web-dev-qa-db-fra.com

Comment réinitialiser un périphérique USB à partir de la ligne de commande?

Est-il possible de réinitialiser la connexion d'un périphérique USB sans se déconnecter/se connecter physiquement du PC?

Plus précisément, mon appareil est un appareil photo numérique. J'utilise gphoto2, mais dernièrement, des "erreurs de lecture de périphérique" se produisent, j'aimerais donc essayer de réinitialiser le logiciel de la connexion.

D'après ce que je peux dire, aucun module de noyau n'est chargé pour la caméra. Le seul qui semble lié est usbhid.

156
cmcginty

Enregistrez les éléments suivants sous 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;
}

Le exécuter les commandes suivantes dans le terminal:

  1. Compiler le programme:

    $ cc usbreset.c -o usbreset
    
  2. Obtenez les identifiants de bus et de périphérique du périphérique USB que vous souhaitez réinitialiser:

    $ lsusb  
    Bus 002 Device 003: ID 0fe9:9010 DVICO  
    
  3. Rendre notre programme compilé exécutable:

    $ chmod +x usbreset
    
  4. Exécutez le programme avec le privilège Sudo. effectuez la substitution nécessaire pour les ids <Bus> et <Device> tels qu'ils ont été trouvés en exécutant la commande lsusb:

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

Source du programme ci-dessus: http://marc.info/?l=linux-usb&m=121459435621262&w=2

112
Li Lo

Je ne me suis jamais trouvé dans votre situation particulière auparavant, alors je ne sais pas si cela suffira, mais la façon la plus simple que j'ai trouvée de réinitialiser un périphérique USB est cette commande: (Aucune application externe nécessaire)

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"

C’est celui que j’utilise pour réinitialiser mon Kinect car libfreenect ne semble pas avoir d’API pour le remettre en veille. C'est sur ma boîte Gentoo, mais le noyau devrait être suffisamment nouveau pour utiliser la même structure de chemin pour sysfs.

Votre nom ne serait évidemment pas 1-4.6 mais vous pouvez extraire ce chemin du périphérique de votre journal du noyau (dmesg) ou vous pouvez utiliser quelque chose comme lsusb pour obtenir les ID fournisseur et produit, puis utiliser une commande rapide comme celle-ci pour répertorier le lien entre les chemins. à différentes paires ID fournisseur/produit:

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

Ceci réinitialisera tous les ports USB1/2/3 connectés [1]:

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

Je crois que cela résoudra votre problème. Si vous ne souhaitez pas réinitialiser tous les points de terminaison USB, vous pouvez utiliser l'ID de périphérique approprié à partir de /sys/bus/pci/drivers/ehci_hcd


Remarques: [1]: les pilotes du noyau *hci_hcd contrôlent généralement les ports USB. ohci_hcd et uhci_hcd correspondent aux ports USB 1.1, ehci_hcd aux ports USB2 et xhci_hcd aux ports USB3. (voir https://en.wikipedia.org/wiki/Host_controller_interface_ (USB, _Firewire) )

46
Tamás Tapsonyi

J'avais besoin d'automatiser cela dans un script python, alors j'ai adapté la réponse extrêmement utile de LiLo aux éléments suivants:

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

Dans mon cas, il s’agissait du pilote cp210x (que je pourrais lire à partir de lsmod | grep usbserial), de sorte que vous puissiez enregistrer le fragment de code ci-dessus sous le nom reset_usb.py, puis procédez comme suit:

Sudo python reset_usb.py cp210x

Cela pourrait également être utile si vous n'avez pas déjà configuré le compilateur c sur votre système, mais que vous avez le python.

9
Peter

J'ai créé un script Python qui simplifie l'ensemble du processus en fonction des réponses fournies.

Enregistrez le script ci-dessous sous le nom reset_usb.py ou clone this repo .

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

Scénario:

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

J'utilise une sorte de sledgehammer en rechargeant les modules. Voici mon 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

Et voici mon fichier de service systemd /usr/lib/systemd/system/usbreset.service qui exécute usb_reset.sh après le démarrage de mon gestionnaire de diplay:

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

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

Comme le cas particulier de la question est un problème de communication de gphoto2 avec un appareil photo sur USB, il existe une option dans gphoto2 pour réinitialiser sa connexion USB:

gphoto2 --reset

Peut-être que cette option n'existait pas en 2010 lorsque la question a été posée.

4
mviereck

J'ai créé un script python qui réinitialisera un périphérique USB particulier en fonction du numéro de périphérique. Vous pouvez trouver le numéro de périphérique à l'aide de la commande lsusb.

par exemple:

$ lsusb

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

Dans cette chaîne 004 est le numéro de périphérique

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

Le moyen le plus rapide de réinitialiser consiste à réinitialiser le contrôleur USB lui-même. Cela obligera udev à annuler l’enregistrement du périphérique lors de la déconnexion, et l’enregistrement est de retour une fois que vous l’activez.

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

Cela devrait fonctionner pour la plupart des environnements PC. Toutefois, si vous utilisez du matériel personnalisé, vous pouvez simplement parcourir les noms de périphériques. Avec cette méthode, vous n'avez pas besoin de connaître le nom du périphérique à l'aide de lsusb. Vous pouvez également intégrer un script automatisé.

3
chandank

Voici un script qui réinitialisera uniquement un ID de produit/fournisseur correspondant.

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

Parfois, je souhaite effectuer cette opération sur un périphérique particulier, identifié par VID (identifiant du fournisseur) et PID (identifiant du produit). C'est un script que j'ai trouvé utile à cette fin, qui utilise la bibliothèque nifty libusb.

Première exécution:

Sudo apt-get install libusb-dev

Ensuite, resetDeviceConnection de ce fichier c ++ doit exécuter cette tâche, en réinitialisant une connexion de périphérique identifiée par vid et 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;
}

(volé de mon catalogue TIL personnel: https://github.com/Marviel/TIL/blob/master/unix_tools/Reset_specific_USB_Device.md )

1
Marviel

Est-ce que quelqu'un a commandé un sledgehammer? Ceci est reconstitué à partir de diverses autres réponses ici.

#!/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
1
Mark K Cowan

Essayez ceci, il s’agit d’un débranchement de logiciel (Eject).

Parfois, cela ne fonctionne pas simplement en déconnectant un périphérique pour certains périphériques.

Exemple:

Je souhaite retirer ou éjecter mon "Genius NetScroll 120".

Ensuite, je vérifie d'abord mon périphérique USB connecté

$ 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, j'ai trouvé ma souris, elle a les bus 002, 009, idVendor 0458 et idProduct 003a. Il s'agit donc d'une information de référence sur la souris.

Ceci est important, le numéro de bus est le chemin du nom de début du périphérique et je vérifierai l'ID du produit et le fournisseur pour s'assurer que le périphérique correct à supprimer.

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

Faites attention aux dossiers, vérifiez le début avec le dossier numéro 2, je vais vérifier celui-ci car mon bus est 002, et un par un, j'ai vérifié chaque dossier contenant le bon idVendor et idProduct à propos de mes informations de souris.

Dans ce cas, je vais récupérer les informations avec cette commande:

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

Ok, le chemin /sys/bus/usb/drivers/usb/2-1.3/ correspond à ma souris d’information! XDDD.

Il est temps de retirer l'appareil!

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

Rebranchez le périphérique USB et ça marche encore!

0
user242078

j'ai fait un script bash simple pour réinitialiser un périphérique USB particulier.

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

Si vous connaissez le nom de votre appareil, ce script python fonctionnera:

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

Peut-être que cela fonctionne aussi pour une caméra:

Après avoir relancé un disque dur USB 3.0 affamé sur un 3.4.42 (kernel.org) Linux de mon côté. dmesga dit que les commandes expiraient au bout de 360 ​​secondes (désolé, je ne peux pas copier le journal système ici, pas de réseaux connectés) et que le lecteur est complètement bloqué. Les processus accédant à l'appareil étaient bloqués dans le noyau, impossible à tuer. NFSHung, ZFS Name__ Hung, ddHung.

Après cela, tout a encore fonctionné. dmesga indiqué une seule ligne à propos du USBtrouvé.

Je n'ai vraiment aucune idée de ce qui suit fait en détail. Mais cela a fonctionné.

L'exemple de sortie suivant provient de Debian Squeeze avec le noyau 2.6.32-5-686. Je pense donc que cela fonctionne pour les versions 2.6 et supérieures:

$ 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 cela ne fonctionne pas, quelqu'un d'autre peut peut-être comprendre comment envoyer une réinitialisation réelle à un périphérique.

0
Tino