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

143

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 .

    
posée cmcginty 01.08.2010 - 21:46
la source

16 réponses

107

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

Lancez les commandes suivantes dans le terminal:

  1. Compilez 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 les substitutions nécessaires pour <Bus> et <Device> ids en exécutant la commande lsusb :

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

Source du programme ci-dessus: lien

    
réponse donnée Li Lo 02.08.2010 - 04:27
la source
49

Je ne me suis jamais trouvé dans votre situation particulière, je ne sais donc pas si cela suffira, mais la méthode la plus simple que j'ai trouvée pour réinitialiser un périphérique USB est la commande suivante: (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.

Évidemment, vous ne seriez pas 1-4.6 , mais vous pouvez extraire ce chemin du périphérique à partir du journal de votre noyau ( dmesg ) ou utiliser quelque chose comme lsusb pour obtenir les ID fournisseur et produit, puis utiliser comme ceci pour répertorier le lien entre les chemins d’accès et différentes paires d’identificateurs produit / fournisseur:

for X in /sys/bus/usb/devices/*; do 
    echo "$X"
    cat "$X/idVendor" 2>/dev/null 
    cat "$X/idProduct" 2>/dev/null
    echo
done
    
réponse donnée ssokolow 13.09.2011 - 08:56
la source
40

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

.

Notes: [1]: les pilotes du noyau *hci_hcd contrôlent généralement les ports USB. ohci_hcd et uhci_hcd sont destinés aux ports USB1.1, ehci_hcd à des ports USB2 et xhci_hcd à des ports USB3. (voir lien )

    
réponse donnée Tamás Tapsonyi 04.05.2013 - 13:02
la source
9

J'avais besoin d'automatiser cela dans un script python. J'ai donc 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 (ce que je pouvais dire à partir de lsmod | grep usbserial ), afin que vous puissiez enregistrer l’extrait ci-dessus sous le nom reset_usb.py, puis procédez ainsi:

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 si vous avez le python.

    
réponse donnée Peter 02.03.2015 - 21:38
la source
4

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
    
réponse donnée Ulrich-Lorenz Schlüter 09.01.2016 - 11:18
la source
4

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.

    
réponse donnée mviereck 31.08.2016 - 15:19
la source
3

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 à ce que l’enregistrement revienne 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 dans 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é.

    
réponse donnée chandank 24.11.2014 - 20:34
la source
2

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 correspond au 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()
    
réponse donnée Raghu 07.09.2016 - 13:42
la source
2

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
    
réponse donnée cmcginty 30.04.2017 - 05:50
la source
2

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

Enregistrez le script ci-dessous sous le nom reset_usb.py ou clonez ce référentiel: lien .

Utilisation:

python reset_usb.py help: Afficher cette aide

Liste sudo python reset_usb.py: répertorie tous les périphériques USB

sudo python reset_usb.py chemin / dev / bus / usb / XXX / YYY: réinitialisez le périphérique USB à l'aide du chemin / dev / bus / usb / XXX / YYY

sudo python reset_usb.py recherche "termes de recherche": recherchez un périphérique USB à l'aide des termes de recherche figurant dans la chaîne de recherche renvoyée par liste et réinitialisez le périphérique correspondant

sudo python reset_usb.py listpci: Répertorie tous les périphériques USB PCI

sudo python reset_usb.py pathpci /sys/bus/pci/drivers/.../XXXX:XX:XX.X: réinitialisez le périphérique USB PCI à l'aide du chemin /sys/bus/pci/drivers/.../XXXX : XX: XX.X

sudo python reset_usb.py searchpci "search search": recherchez un périphérique USB PCI à l'aide des termes de recherche figurant dans la chaîne de recherche renvoyée par listpci et réinitialisez le périphérique correspondant

.
#!/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)
    
réponse donnée mcarans 21.12.2017 - 11:15
la source
1

Quelqu'un a-t-il commandé une masse? 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
    
réponse donnée Mark K Cowan 28.06.2016 - 16:08
la source
1

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 et 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: lien )

    
réponse donnée Marviel 29.12.2016 - 14:53
la source
0

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

Après avoir relancé un USB 3.0 disque dur sous-alimenté sous un Linux 3.4.42 (kernel.org) de mon côté. dmesg a 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 s'est bloqué complètement. Les processus accédant à l'appareil étaient bloqués dans le noyau, impossible à tuer. NFS accroché, ZFS accroché, dd accroché.

Après cela, tout a fonctionné à nouveau. dmesg n'a indiqué qu'une seule ligne concernant le périphérique USB trouvé.

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 2.6.32-5-686 kernel. 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.

    
réponse donnée Tino 06.06.2013 - 02:08
la source
0

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

Parfois, cela ne fonctionne pas simplement en annulant la connexion de périphériques 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**

D'accord, 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 afin de nous assurer que le périphérique à supprimer est correct.

$ 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 vérifierai celui-ci car mon bus est 002, et un par un, j’ai vérifié chaque dossier contenant les identifiants idVendor et idProduct corrects.

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 le périphérique!

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

Rebranchez le périphérique USB et ça fonctionnera à nouveau!

    
réponse donnée user242078 31.01.2014 - 12:15
la source
0

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 __name__ == '__main__':
    main()
    
réponse donnée Clay 04.08.2017 - 16:35
la source
-3

Peut-être que ce guide peut vous aider:

Si vous êtes harcelé par le bogue qui ne vous permet pas de monter des périphériques USB dans Ubuntu Lucid Lynx, le problème est causé par le module de disquette. Désactivez-le avec:

sudo modprobe -r floppy

Après un redémarrage, le module sera probablement rechargé.

    
réponse donnée User 01.08.2010 - 22:16
la source

Lire d'autres questions sur les étiquettes