Vraag Hoe reset je een USB-apparaat vanaf de opdrachtregel?


Is het mogelijk om de verbinding van een USB-apparaat te resetten, zonder fysiek los te koppelen van de pc?

In het bijzonder is mijn apparaat een digitale camera. ik gebruik gphoto2, maar de laatste tijd krijg ik "apparaat leesfouten", dus ik zou graag een software-reset van de verbinding proberen te doen.

Van wat ik kan vertellen, zijn er geen kernelmodules geladen voor de camera. De enige die er verwant uitziet, is usbhid.


141
2017-08-01 19:46


oorsprong


Welke versie van Ubuntu gebruikt u? - User
ik heb beide oplossingen geprobeerd door Li Lo en ssokolow, alles wat ik krijg is toestemming geweigerd, nomatter als ik de usbreset-code gebruik of de commandoregel "echo 0> ..." ik gebruik sudo, ook mijn usb-apparaten zijn eigendom van root maar ik kan ze gebruiken zonder beheerdersrechten (camera's ..)
Als u leesfouten krijgt, is er mogelijk sprake van datacorruptie. Als uw camera een externe geheugenkaart (zoals MicroSD) gebruikt, is het misschien verstandig om deze op de computer aan te sluiten en fsck uit te voeren. - TSJNachos117


antwoorden:


Sla het volgende op als 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;
}

Voer de volgende opdrachten uit in terminal:

  1. Compileer het programma:

    $ cc usbreset.c -o usbreset
    
  2. Haal de bus- en apparaat-ID op van het USB-apparaat dat u wilt resetten:

    $ lsusb  
    Bus 002 Device 003: ID 0fe9:9010 DVICO  
    
  3. Maak ons ​​gecompileerde programma uitvoerbaar:

    $ chmod +x usbreset
    
  4. Voer het programma uit met sudo privilege; maak de noodzakelijke vervanging voor <Bus> en <Device> id's zoals gevonden door het uitvoeren van de lsusb opdracht:

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

Bron van bovenstaand programma: http://marc.info/?l=linux-usb&m=121459435621262&w=2


104
2017-08-02 02:27



Ik heb fouten als deze: ./usbreset: commando niet gevonden Dan 11.04 Natty
Heel erg bedankt! Dit zal me helpen om meer leven te krijgen van mijn stervende Intellimouse. - Randall Ma
Dit werkt met ubuntu 13.10. Het apparaat-ID kan variëren. Om het voor de muis te krijgen, heb ik bovenstaande code ingepakt in enkele shell-commando's 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
Als iemand die dit leest een (usb) muis bevriest na het inloggen op Ubuntu 16.04 (met dmesg gevuld met "input irq status -75"), kan ik bevestigen dat dit de enige oplossing is die voor mij werkte. Dank je - Agustin Baez
@ Aquarius, ik krijg ook dezelfde foutmelding "Fout in ioctl: is een map". Is het opgelost? - ransh


Ik ben niet eerder in uw specifieke omstandigheden geweest, dus ik weet niet zeker of het genoeg zal doen, maar de eenvoudigste manier om een ​​USB-apparaat te resetten is deze opdracht: (geen externe apps nodig)

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"

Dat is de daadwerkelijke die ik gebruik om mijn Kinect opnieuw in te stellen, omdat libfreenect geen API lijkt te hebben om het weer in slaap te brengen. Het staat in mijn Gentoo-box, maar de kernel moet nieuw genoeg zijn om dezelfde padstructuur voor sysf's te gebruiken.

Die van jou zou dat natuurlijk niet zijn 1-4.6 maar je kunt dat apparaatpad uit je kernellog halen (dmesg) of je kunt zoiets gebruiken lsusb om de leveranciers- en product-ID's te krijgen en gebruik vervolgens een snelle opdracht als deze om een ​​lijst weer te geven met hoe de paden betrekking hebben op verschillende leveranciers / product-ID-paren:

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: can not create /sys/bus/usb/devices/1-3.1:1.0/authorized: map niet aanwezig - Nicolas Marchildon
Het lijkt erop dat ze de layout van het usbfs-bestandssysteem hebben veranderd. Ik zal proberen uit te vinden wat de nieuwe manier van doen is op Ubuntu als ik niet zo slaperig ben. - ssokolow
Dankjewel werkte geweldig! Misschien moet je ook vermelden om een echo 1 > /sys/bus/usb/devices/whatever/authorizedin een script om het apparaat opnieuw in te schakelen zodra het is uitgeschakeld. Ik deed het op zowel mijn muis- als usb-toetsenbord en ik eindigde met een volledig doof systeem :) - Avio
De laatste keer dat ik het gebruikte, stelde iets in het systeem het in op 1 seconde of twee later zonder dat ik het handmatig hoefde te doen. - ssokolow
Een notitie voor iedereen die probeert over te schakelen naar de | sudo tee ... benadering van bevoorrechte /sys schrijft: dat breekt slecht als je je sudo-inloggegevens niet in de cache hebt opgeslagen. sudo sh -c "..." werkt zoals verwacht wanneer sudo om een ​​wachtwoord moet vragen. - ssokolow


Hiermee worden alle aangesloten USB1 / 2/3-poorten [1] gereset:

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

Ik geloof dat dit je probleem zal oplossen. Als u niet alle USB-eindpunten opnieuw wilt instellen, kunt u de juiste apparaat-ID gebruiken van /sys/bus/pci/drivers/ehci_hcd


Opmerkingen: [1]: de *hci_hcd kerneldrivers besturen meestal de USB-poorten. ohci_hcd en uhci_hcd zijn voor USB1.1-poorten, ehci_hcd is voor USB2-poorten en xhci_hcd is voor USB3-poorten. (zien https://en.wikipedia.org/wiki/Host_controller_interface_(USB,_Firewire))


37
2018-05-04 11:02



geloof je dat het kan werken ontwaken een usb-opslag? - Aquarius Power
Hoewel ik het volgende bericht heb ontvangen: ls: cannot access /sys/bus/pci/drivers/ehci_hcd/: No such file or directory dit heeft het probleem opgelost, de muis is meteen aan het werk gegaan. 1 - Attila Fulop
is het mogelijk om een ​​controle toe te voegen om gemonteerde USB-apparaten voor massaopslag over te slaan? - eadmaster
@Otheus OHCI en UHCI zijn de USB 1.1-hoststandaarden, EHCI is de USB 2.0-hoststandaard en XHCI is de USB 3.0-hoststandaard. - ssokolow
Dit is een mooie oplossing. Op sommige latere kernels en andere * nix-distributies vindt u echter dat u deze moet vervangen *hci_hcd met *hci-pci, omdat de driver hci_hcd al in de kernel is gecompileerd. - not2qubit


Ik moest dit in een python-script automatiseren, dus paste ik het uiterst behulpzame antwoord van LiLo op het volgende aan:

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

In mijn geval was het de cp210x-driver (die ik kon zien lsmod | grep usbserial), dus u kunt het bovenstaande fragment opslaan als reset_usb.py en dit doen:

sudo python reset_usb.py cp210x

Dit kan ook handig zijn als je nog geen c-compilerconfiguratie hebt op je systeem, maar je hebt wel python.


9
2018-03-02 20:38



werkte voor me op een Raspberry - webo80
Nog een paar woorden over uw oplossing alstublieft. Bijvoorbeeld iets over de constante USBDEVFS_RESET. Is het altijd hetzelfde voor alle systemen? - not2qubit
@ not2qubit USBDEVFS_RESET is hetzelfde voor alle systemen. Voor MIPS is dit 536892692. - yegorich
Nieuwere versies van lsusb lijken de -t argument (boomstammodus) om de driverinformatie te tonen die dit script verwacht, maar het script heeft dan enkele updates nodig om de verschillende uitvoerregels die dit genereert te analyseren - Cheetah
Zie mijn antwoord hier askubuntu.com/a/988297/558070 voor een sterk verbeterde versie van dit script. - mcarans


Ik gebruik een soort voorhamer door de modules opnieuw te laden. Dit is mijn usb_reset.sh script:

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

En dit is mijn systemd service bestand /usr/lib/systemd/system/usbreset.service dat usb_reset.sh draait nadat mijn diplay manager is gestart:

[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



Gebruik de listpci optie van mijn script hier: askubuntu.com/a/988297/558070 zal helpen identificeren welke USB-module moet worden herladen (bijv. xhci_pci, ehci_pci). - mcarans
Helaas op mijn systeem zijn deze kernel-modules niet gescheiden van de kernel, dus dit zal niet werken: rmmod: ERROR: Module xhci_pci is builtin. - unfa


De snelste manier om te resetten is om de USB-controller zelf te resetten. Als u dit doet, wordt udev verplicht om het apparaat af te melden bij het verbreken van de verbinding, en het register is terug zodra u het hebt ingeschakeld.

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

Dit zou voor de meeste pc-omgevingen moeten werken. Als u echter bepaalde aangepaste hardware gebruikt, kunt u eenvoudig de apparaatnamen doorlopen. Met deze methode hoeft u de apparaatnaam niet te achterhalen door lsusb. U kunt ook opnemen in een geautomatiseerd script.


3
2017-11-24 19:34



Je moet deze commando's uitvoeren als root / sudo en het zal niet werken op alle systemen (in sommige gevallen moet je het vervangen ehci_hcd met ehci-pci. Meer informatie over deze oplossing (misschien waar het vandaan kwam?): davidjb.com/blog/2012/06/... - Lambart


Omdat het speciale geval van de vraag een communicatieprobleem is van gphoto2 met een camera op USB, is er een optie in gphoto2 om de USB-verbinding te resetten:

gphoto2 --reset

Misschien bestond deze optie in 2010 niet toen de vraag werd gesteld.


3
2017-08-31 13:19





Ik heb een python-script gemaakt waarmee een bepaald USB-apparaat kan worden gereset op basis van het apparaatnummer. U kunt het apparaatnummer achter het commando lsusb vinden.

bijvoorbeeld:

$ lsusb

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

In deze string 004 staat het apparaatnummer

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()

2
2017-09-07 11:42





Hier is een script dat alleen een overeenkomende product / leverancier-ID reset.

#!/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
2018-04-30 03:50



Ik vond dat je script nuttig is. Maar wat moet ik doen als de $DIR verdwijnt en apparaat is niet zichtbaar? - Eugen Konkov


Ik heb een Python-script gemaakt dat het hele proces vereenvoudigt op basis van de antwoorden hier.

Sla het onderstaande script op als reset_usb.py of clone this repo: https://github.com/mcarans/resetusb/.

Gebruik:

python reset_usb.py help: toon deze hulp

sudo python reset_usb.py lijst: lijst met alle USB-apparaten

sudo python reset_usb.py pad / dev / bus / usb / XXX / YYY: USB-apparaat opnieuw instellen met pad / dev / bus / usb / XXX / YYY

sudo python reset_usb.py zoeken "zoektermen": zoeken naar USB-apparaat met behulp van de zoektermen in de zoekreeks geretourneerd door lijst en het bijbehorende apparaat opnieuw instellen

sudo python reset_usb.py listpci: lijst met alle PCI USB-apparaten

sudo python reset_usb.py pathpci /sys/bus/pci/drivers/.../XXXX:XX:XX.X: Reset PCI USB-apparaat met pad /sys/bus/pci/drivers/.../XXXX:XX: XX.X

sudo python reset_usb.py searchpci "zoektermen": zoeken naar een PCI USB-apparaat met behulp van de zoektermen in de zoekreeks geretourneerd door listpci en het bijbehorende apparaat opnieuw instellen

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

2
2017-12-21 10:15