拔下并重新插入终端中的 USB 设备

拔下并重新插入终端中的 USB 设备

多年来,我一直在处理这个 Ubuntu 错误,我的鼠标在启动后不久就会冻结,然后会定期冻结。为了解决这个问题,我必须物理拔下鼠标的 USB 收发器,然后重新插入。根据我的研究,当双启动 Linux 和 Windows 时,USB 无线 Windows 鼠标会发生此错误。

有没有办法可以以编程方式(从终端)拔下 USB 收发器,而不是以物理方式拔下?我想在启动 bash 脚本中实现这一点。

我正在使用 Ubuntu 16.04

编辑:我解决了我的问题,但它与我的问题没有太大关系。

在文件中..

/etc/laptop-mode/conf.d/runtime-pm.conf

我必须

CONTROL_RUNTIME_AUTOSUSPEND=0

这解决了我多年来遇到的鼠标错误。

答案1

我编写了一个脚本来演示如何做到这一点:

#!/bin/bash

port="1-1.1" # as shown by lsusb -t: {bus}-{port}(.{subport})

bind_usb() {
  echo "$1" >/sys/bus/usb/drivers/usb/bind
}

unbind_usb() {
  echo "$1" >/sys/bus/usb/drivers/usb/unbind
}

unbind_usb "$port"
# sleep 1 # enable delay here
bind_usb "$port"

首先,您需要获取相关 USB 端口的总线和端口号。您可以使用lsusb以及您在 的输出中识别的任何设备来执行此操作lsusb,我使用闪迪此处为 pendrive:

$ lsusb
Bus 001 Device 005: ID 04f2:b39a Chicony Electronics Co., Ltd 
Bus 001 Device 112: ID 8087:07dc Intel Corp. 
Bus 001 Device 019: ID 04d9:1603 Holtek Semiconductor, Inc. Keyboard
Bus 001 Device 018: ID 0424:2504 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 022: ID 0781:5567 SanDisk Corp. Cruzer Blade
Bus 001 Device 002: ID 8087:8000 Intel Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M
        |__ Port 1: Dev 22, If 0, Class=Mass Storage, Driver=usb-storage, 480M
        |__ Port 2: Dev 18, If 0, Class=Hub, Driver=hub/4p, 480M
            |__ Port 1: Dev 19, If 1, Class=Human Interface Device, Driver=usbhid, 1.5M
            |__ Port 1: Dev 19, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
        |__ Port 7: Dev 112, If 0, Class=Wireless, Driver=btusb, 12M
        |__ Port 7: Dev 112, If 1, Class=Wireless, Driver=btusb, 12M
        |__ Port 8: Dev 5, If 1, Class=Video, Driver=uvcvideo, 480M
        |__ Port 8: Dev 5, If 0, Class=Video, Driver=uvcvideo, 480M

从 的输出中,lsusb您可以获得设备的总线和设备号,然后在 的输出中搜索此设备以lsusb -t获取总线和端口号(有时带有子端口)。语法为:

1-2.3 # for Bus 1 Port 2 Subport 3 – strip leading zeroes!

按照脚本的方式使用它port。现在你只需要让它可执行chmod +x /path/to/script并运行它具有 root 权限

sudo /path/to/script

我的 pendrive 不需要这个,但您可能需要在解除绑定和再次绑定之间添加延迟,这就是注释掉的sleep 1行的作用——您可以试验这些值,例如sleep 0.5半秒钟。

请注意,此方法显示了如何禁用并再次启用某个USB端口,如果你想要一个特定的设备要解除绑定并再次绑定,您必须使用相同的 USB 端口才能正常工作。可以想办法解析 的lsusb输出,以便在每次调用脚本时动态获取特定设备的总线和端口号,这将允许您使用任何 USB 端口,但我觉得这样有点过头了。

建议来自这篇 linux.com 博客文章

答案2

#!/bin/bash

port="usb1" # replace '1' with actual bus number as shown by lsusb -t: {bus}-{port}(.{subport})

bind_usb() {
  echo "$1" >/sys/bus/usb/drivers/usb/bind
}

unbind_usb() {
  echo "$1" >/sys/bus/usb/drivers/usb/unbind
}

unbind_usb "$port"
# sleep 1 # enable delay here
bind_usb "$port"

与之前的答案类似,这将重置集线器。如果您在诸如 wireshark 之类的程序中观察 USB 流量,您会发现之前的答案不会导致设备重新枚举,而只是重新启动设备驱动程序。重新启动集线器会在内核的 USB 树中更深入一点,并强制设备完全重新枚举。

答案3

您还可以使用 ioctl 向相关设备发送重置 - 假设它仍然有响应

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

你可以这样称呼

sudo ./usbreset /dev/bus/usb/002/004

不是我的代码,但我不知道该归功于谁

答案4

我创建了一个 Python 脚本来简化整个过程。

将以下脚本保存为 reset_usb.py 或者克隆这个仓库

用法:

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

脚本:

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

相关内容