Question 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 déconnecter / se connecter physiquement depuis le PC?

Plus précisément, mon appareil est un appareil photo numérique. j'utilise gphoto2, mais dernièrement, je reçois des "erreurs de lecture de périphérique", donc je voudrais essayer de faire une réinitialisation logicielle de la connexion.

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


141
2017-08-01 19:46


origine


Quelle version d'Ubuntu utilisez-vous? - User
J'ai essayé les deux solutions par Li Lo et ssokolow, tout ce que j'obtiens est la permission refusée, nomatter si j'utilise le code usbreset ou la ligne de commande "echo 0> ..." j'utilise sudo, mes périphériques usb appartiennent peut les utiliser sans droits d’administrateur (caméras ..)
Si vous obtenez des erreurs de lecture, il se peut que vous ayez une corruption de données. Si votre appareil photo utilise une carte mémoire externe (telle que MicroSD), il peut être judicieux de le connecter à l'ordinateur et d'exécuter fsck. - TSJNachos117


Réponses:


Enregistrer le suivant comme 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. Compilez le programme:

    $ cc usbreset.c -o usbreset
    
  2. Obtenez l'identifiant 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. Rendez notre programme exécutable exécutable:

    $ chmod +x usbreset
    
  4. Exécutez le programme avec le privilège sudo; faire la substitution nécessaire pour <Bus> et <Device> identifiants tels que trouvés en exécutant le lsusb commander:

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

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


104
2017-08-02 02:27



J'ai des erreurs comme ceci: ./usbreset: commande introuvable Dan 11.04 Natty
Merci beaucoup! Cela m'aidera à améliorer ma vie avec mon Intellimouse en train de mourir. - Randall Ma
Cela fonctionne avec Ubuntu 13.10. L'identifiant de l'appareil peut varier. POUR l'obtenir pour la souris, j'ai enveloppé le code dans quelques commandes de shell echo $(lsusb | grep Mouse) mouse=$( lsusb | grep Mouse | perl -nE "/\D+(\d+)\D+(\d+).+/; print qq(\$1/\$2)") sudo /path/to/c-program/usbreset /dev/bus/usb/$mouse - knb
Si quelqu'un qui lit ceci a un blocage de souris (USB) après s'être connecté sur Ubuntu 16.04 (avec dmesg rempli par "input irq status -75"), je peux confirmer que c'est la seule solution qui a fonctionné pour moi. Je vous remercie - Agustin Baez
@ Aquarius, j'ai aussi la même erreur "Erreur dans ioctl: est un répertoire". Est-ce résolu? - ransh


Je ne me suis pas trouvé dans vos circonstances spécifiques, donc je ne suis pas sûr que cela suffira, mais la façon la plus simple de réinitialiser un périphérique USB est la 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 le réel que j'utilise pour réinitialiser mon Kinect puisque libfreenect semble ne pas avoir d'API pour le remettre en sommeil. C'est sur ma boîte Gentoo, mais le noyau devrait être assez récent pour utiliser la même structure de chemin pour sysfs.

Le vôtre ne serait évidemment pas 1-4.6 mais vous pouvez soit extraire ce chemin de périphérique de votre journal du noyau (dmesg) ou vous pouvez utiliser quelque chose comme lsusb Pour obtenir les ID de fournisseur et de produit, puis utiliser une commande rapide comme celle-ci pour répertorier les liens entre les chemins d'accès et les différentes paires d'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

47
2017-09-13 06:56



sh: 1: impossible de créer /sys/bus/usb/devices/1-3.1:1.0/authorized: répertoire inexistant - Nicolas Marchildon
On dirait qu'ils ont changé la disposition du système de fichiers usbfs. Je vais essayer de comprendre quelle est la nouvelle façon de faire les choses sur Ubuntu une fois que je ne suis pas trop endormi. - ssokolow
Merci beaucoup travaillé! Peut-être que vous devriez également mentionner pour effectuer un echo 1 > /sys/bus/usb/devices/whatever/authorized dans un script pour réactiver le périphérique dès qu'il a été désactivé. Je l'ai fait sur mon clavier souris et USB et j'ai fini avec un système complètement sourd :) - Avio
La dernière fois que je l'ai utilisé, quelque chose dans le système le réinitialiserait à une seconde ou deux plus tard, sans que je doive le faire manuellement. - ssokolow
Une note pour quiconque tente de passer à la | sudo tee ... approche privilégiée /sys écrit: Cela se casse mal si vous n'avez pas déjà vos informations d'identification sudo en cache. sudo sh -c "..." fonctionne comme prévu lorsque sudo doit demander un mot de passe. - ssokolow


Cela réinitialisera tous les ports connectés 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

Je crois que cela va résoudre 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é /sys/bus/pci/drivers/ehci_hcd


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


37
2018-05-04 11:02



Croyez-vous que cela peut marcher pour réveiller un stockage USB? - Aquarius Power
Bien que j'ai reçu le message suivant: ls: cannot access /sys/bus/pci/drivers/ehci_hcd/: No such file or directory Cela a résolu le problème, la souris a commencé à travailler immédiatement. +1 - Attila Fulop
est-il possible d'ajouter une vérification pour ignorer les périphériques de stockage de masse USB montés? - eadmaster
@Otheus OHCI et UHCI sont les normes hôtes USB 1.1, EHCI est la norme hôte USB 2.0 et XHCI est la norme hôte USB 3.0. - ssokolow
Ceci est une belle solution. Cependant, sur certains noyaux plus récents et d’autres distributions * nix, vous constaterez que vous devez remplacer *hci_hcd avec *hci-pci, car le pilote hci_hcd est déjà compilé dans le noyau. - not2qubit


J'avais besoin d'automatiser cela dans un script Python, alors j'ai adapté la réponse extrêmement utile de LiLo à ce qui suit:

#!/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, c’est le pilote cp210x lsmod | grep usbserial), vous pouvez donc enregistrer l'extrait ci-dessus en tant que reset_usb.py, puis procédez comme suit:

sudo python reset_usb.py cp210x

Cela pourrait également être utile si vous n'avez pas encore de configuration du compilateur c sur votre système, mais vous avez python.


9
2018-03-02 20:38



travaillé pour moi sur une framboise - webo80
Quelques mots sur votre solution s'il vous plaît. Par exemple, quelque chose sur la constante USBDEVFS_RESET. Est-ce toujours la même chose pour tous les systèmes? - not2qubit
@ not2qubit USBDEVFS_RESET est le même pour tous les systèmes. Pour MIPS, il s'agit de 536892692. - yegorich
Les nouvelles versions de lsusb semblent avoir besoin de la -t argument (mode arbre) pour afficher les informations de pilote attendues par ce script, mais le script a besoin de quelques mises à jour pour analyser les différentes lignes de sortie générées - Cheetah
Voir ma réponse ici askubuntu.com/a/988297/558070 pour une version beaucoup améliorée de ce script. - mcarans


J'utilise une sorte de marteau en rechargeant les modules. Ceci est 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

4
2018-01-09 10:18



En utilisant l'option listpci de mon script ici: askubuntu.com/a/988297/558070 aidera à identifier le module USB à recharger (par exemple, xhci_pci, ehci_pci). - mcarans
Malheureusement, sur mon système, ces modules du noyau ne sont pas séparés du noyau, donc cela ne fonctionnera pas: rmmod: ERROR: Module xhci_pci is builtin. - unfa


Le moyen le plus rapide de réinitialiser consiste à réinitialiser le contrôleur USB lui-même. En faisant cela, vous forcerez udev à annuler l’enregistrement de l’appareil lors de la déconnexion et l’enregistrement sera rétabli 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. Cependant, 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 trouver le nom de périphérique par lsusb. Vous pouvez également intégrer un script automatisé.


3
2017-11-24 19:34



Vous devez exécuter ces commandes en tant que root / sudo, et cela ne fonctionnera pas sur tous les systèmes (sur certains, vous devrez remplacer ehci_hcd avec ehci-pci. Plus d'infos sur cette solution (peut-être d'où elle vient?): davidjb.com/blog/2012/06/… - Lambart


Comme le cas particulier de la question est un problème de communication de gphoto2 avec une caméra 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.


3
2017-08-31 13:19