用一台PC做的服务器,USB上插了个串口工具,每次重启系统,这个设备都无法自动打开,必须手动插拔一下,所以需要一个能重新上电USB设备的脚本。
注意:并非所有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来上电或者断电。
新建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秒后再打开串口。