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

dea*_*sin 10 mouse command-line usb wireless

多年来,我一直在处理这个 Ubuntu 错误,我的鼠标在启动后很快冻结,然后定期冻结。要修复它,我必须物理拔下鼠标的 USB 收发器并重新插入。根据我的研究,当双启动 Linux 和 Windows 时,USB 无线 Windows 鼠标会发生此错误。

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

我正在使用 Ubuntu 16.04

编辑:我解决了我的问题,但它与我的问题并没有真正的关系。

在文件..

/etc/laptop-mode/conf.d/runtime-pm.conf
Run Code Online (Sandbox Code Playgroud)

我不得不做

CONTROL_RUNTIME_AUTOSUSPEND=0
Run Code Online (Sandbox Code Playgroud)

这修复了我多年来遇到的鼠标错误。

des*_*ert 9

I wrote a script to show how I’d do that:

#!/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"
Run Code Online (Sandbox Code Playgroud)

First you need to get the bus and port number of the usb port in question. You can do that with lsusb and any device you recognize in lsusb’s output, I use a Sandisk pendrive here:

$ 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
Run Code Online (Sandbox Code Playgroud)

From the output of lsusb you get the bus and device number of the device, then search this device in the output of lsusb -t to get the bus and port number (sometimes with subports). The syntax is:

1-2.3 # for Bus 1 Port 2 Subport 3 – strip leading zeroes!
Run Code Online (Sandbox Code Playgroud)

Use this as port in the script. Now you just need to make it executable with chmod +x /path/to/script and run it with root permissions:

sudo /path/to/script
Run Code Online (Sandbox Code Playgroud)

I didn’t need one for my pendrive, but it may be necessary for you to add a delay between unbinding and binding again, that’s what the commented out sleep 1 line is for – you can experiment with the values, e.g. sleep 0.5 for half a second.

Note that this approach shows how to disable and enable again a certain USB port, if you want a specific device to be unbound and rebound again you’ll have to use the same USB port for this to work. One could think of a way to parse lsusb’s output to dynamically get the bus and port number of a specific device every time the script is called, this would allow you to use any USB port, but I feel that would be an overkill here.

Suggestions taken from this linux.com blog article.


小智 5

#!/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"
Run Code Online (Sandbox Code Playgroud)

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

  • 此方法的工作原理类似于物理拔出并重新插入 USB 设备。 (2认同)