Debian Linux 通过命令行脚本实现重新插拔USB设备重新上电的效果

用一台PC做的服务器,USB上插了个串口工具,每次重启系统,这个设备都无法自动打开,必须手动插拔一下,所以需要一个能重新上电USB设备的脚本。

注意:并非所有USB设备都支持电源管理,建议先尝试方案三。

查看 Linux kenel USB电源管理文档

方案一:使用udev规则来控制usb设备的重新上电

前置条件,需要设备先处于idle状态。 驱动必须支持。 如果无法处于idle状态,则下面的命令无效。

# for kernels around 2.6.38 and above:
echo "0" > "/sys/bus/usb/devices/usbX/power/autosuspend_delay_ms"  # 休眠延迟设为0
echo "auto" > "/sys/bus/usb/devices/usbX/power/control"   # 或者echo "on" > ....

使用udev规则断电、上电USB设备,实现命令行重新插拔USB的效果,我使用的脚本如下,仅供参考:

#!/bin/bash

# USB设备的ID,通过lsusb 查看, 一定要改为自己的
usb_id="1111:2222"

# USB设备的供电状态文件路径,这里的usbX根据实际情况改为usb0或usb1..... 等
power_file="/sys/bus/usb/devices/【usbX】/power/control"

# 检查USB设备是否已连接
if lsusb | grep -q "$usb_id"; then
    echo "0" > "/sys/bus/usb/devices/usb2/power/autosuspend_delay_ms"
    echo  "关闭USB口的供电"
    sleep 3
    echo "on" > "/sys/bus/usb/devices/usb2/power/control"
    echo  "打开USB口的供电"
else
    echo "USB设备未连接"
fi

通过lsusb命令USB设备的ID:

qgbf@rangotec.com# lsusb
Bus 003 Device 002: ID 8087:8001 Intel Corp. Integrated Hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 8087:8009 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 002 Device 002: ID c251:f001 Keil Software, Inc. CMSIS-DAP
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

我的STM32下载调试器的ID是 【c251:f001】,把脚本里的的ID替换为这个ID。

把脚本里的usbX 替换为实际的 usb2。 然后运行即可实现重新插拔的效果。

如果不确定usbX到底是哪个,可以进入到对应的目录,如usb3目录,目录下有个power/control文件,这个文件就是用来控制电源的,通过写入on或者0来上电或者断电。

方案二:使用ioctl 重置下usb设备

新建usb-reset.c 文件,粘贴以下内容:

/*重启usb硬件端口*/
#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];//表示usb的ID

    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);//ioctl是设备驱动中,对I/O设备进行管理的函数
    if (rc < 0) {
        perror("Error in ioctl");
        return 1;
    }
    printf("Reset successful\n");

    close(fd);
    return 0;
}

然后gcc编译一下:

qgbf@rangotec.com$ gcc usb-reset.c -o usb-reset

赋予执行权限:

qgbf@rangotec.com$ chmod +x usb-reset

然后执行程序:

./usb-reset /dev/bus/usb/002/002

完事。

 

方案三:

使用 hub_ctrl

首先下载 hub_ctrl 源码及编译工具

$ git clone https://github.com/yy502/hub-ctrl
$ sudo apt-get install libusb-dev gcc

进入 hub-ctrl目录,用gcc编译源码

$ cd hub-ctrl
$ gcc -o hub-ctrl hub-ctrl.c -lusb -std=c99
列表当前的USB设备,以HUB的方式:
rangotec@rangotec.com:$ sudo ./hub-ctrl/hub-ctrl
Hub 0 (Bus 3, Dev 2) - individual power switching
 ├─ Port  1: power
 ├─ Port  2: power
 ├─ Port  3: power
 ├─ Port  4: power
 ├─ Port  5: power
 ├─ Port  6: power
 ├─ Port  7: power
 └─ Port  8: power
Hub 1 (Bus 3, Dev 1) - no power switching
 ├─ Port  1: power high-speed connect enable suspend
 └─ Port  2: power
Hub 2 (Bus 4, Dev 1) - no power switching
 ├─ Port  1: low-speed
 └─ Port  2: low-speed
Hub 3 (Bus 2, Dev 1) - no power switching
 ├─ Port  1: power
 ├─ Port  2: power
 ├─ Port  3: power connect enable
 ├─ Port  4: power
 ├─ Port  5: power
 ├─ Port  6: power
 ├─ Port  7: power
 ├─ Port  8: power
 ├─ Port  9: power
 ├─ Port 10: power
 ├─ Port 11: power
 ├─ Port 12: power
 ├─ Port 13: power
 └─ Port 14: power
Hub 4 (Bus 1, Dev 2) - individual power switching
 ├─ Port  1: power
 ├─ Port  2: power
 ├─ Port  3: power
 ├─ Port  4: power
 ├─ Port  5: power
 └─ Port  6: power
Hub 5 (Bus 1, Dev 1) - no power switching
 ├─ Port  1: power high-speed connect enable suspend
 └─ Port  2: power

可以看到我的HUB3的PORT3上有个设备,通过以下命令打开电源和关闭电源:

rangotec@rangotec.com: $ sudo ./hub-ctrl/hub-ctrl -H 3 -P 3 -p 0     // -H 3 代表Hub3 , -P 3 : Port3,  -p 0 : 关闭电源
rangotec@rangotec.com: $ sudo ./hub-ctrl/hub-ctrl -H 3 -P 3 -p 1    // -p 1 开启电源

我用hub-ctrl 的时候断电之后需要等待几秒,然后再执行上电命令,才管用。 

 

注意事项:

重新上电后还是无法读usb串口设备,执行完重置命令后等待1~2秒后再打开串口。

评论列表: