如何使用脚本重置 USB 设备?

如何使用脚本重置 USB 设备?

我有一个 USB GSM 调制解调器,它并不总是工作属性(华为 E367u-2),有时它会被重置(USB 设备在日志中断开/重新连接),并且当它恢复时,它具有不同的 ttyUSB 编号。有时在启动时,usb_modeswitch似乎只是没有被解雇。计算机是运行 Raspbian 的 Raspberry Pi。

我对此有一个简单的解决方案:每分钟cron运行以下脚本(伪代码):

If WVDIAL is not running:
    Run WVDIAL

我想将脚本更改为:

If /dev/ttyUSB0 is not present:
    If DevicePresent(12d1:1446):
        ResetDevice(12d1:1446)
    ElseIf DevicePresent(12d1:1506)
        ResetUSB(12d1:1506)
If WVDIAL is not running:
    Run WVDIAL

显然这是伪代码,但我需要将以下几行串在一起,但我不知道如何串起来:

如果 wvdial 未运行,则会加载它:

#! /bin/sh 
# /etc/init.d/wvdial

### BEGIN INIT INFO
# Provides:          TheInternet
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Simple script to start a program at boot
# Description:       A simple script from www.stuffaboutcode.com which will start / stop a program a boot / shutdown.
### END INIT INFO

# If you want a command to always run, put it here

# Carry out specific functions when asked to by the system
case "$1" in
  start)
    echo "Starting GPRS Internet"
    # run application you want to start
    /sbin/start-stop-daemon --start --background --quiet --exec /usr/bin/wvdial internet
    ;;
  stop)
    echo "Stopping GPRS Internet"
    # kill application you want to stop
    /sbin/start-stop-daemon --stop --exec /usr/bin/wvdial 
    ;;
  *)
    echo "Usage: /etc/init.d/noip {start|stop}"
    exit 1
    ;;
esac

exit 0

这让我可以找到/sys特定设备的路径:

for X in /sys/bus/usb/devices/*; do
    echo "$X"
    cat "$X/idVendor" 2>/dev/null
    cat "$X/idProduct" 2>/dev/null
    echo
done

如果您知道正确的 /sys 路径,这将重置 USB 设备:

echo 0 > /sys/bus/usb/devices/1-1.2.1.1/authorized
echo 1 > /sys/bus/usb/devices/1-1.2.1.1/authorized

因此,我需要将最后两个部分和一个测试串在一起,/dev/ttyUSB0放入“如果您希望命令始终运行,请将其放在此处”注释下的部分。

  • 我怎样才能做到这一点?
  • 有一个更好的方法吗?

答案1

我想你基本上就在那里:

#!/bin/sh

for X in /sys/bus/usb/devices/*
do
    if [ -e "$X/idVendor" ] && [ -e "$X/idProduct" ] \
           && [ 12d1 = $(cat "$X/idVendor") ] && [ 1446 = $(cat "$X/idProduct") ]
    then
        echo 0 >"$X/authorized"
        # might need a small sleep here
        echo 1 >"$X/authorized"
    fi
done

这会在所有设备上循环(正如您所做的那样),每次找到供应商:产品 ID 的匹配项时,它都会应用适合您的重置。


顺便说一句,您可能想将该watchdog计划作为您工作的替代方案cron

答案2

如果您想使用命令行然后重置它。

将以下内容另存为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;
}

在终端中运行以下命令:

编译程序:

$ cc usbreset.c -o usbreset Get the Bus and Device ID of the USB device you want to reset:

$ lsusb
Bus 002 Device 003: ID 0fe9:9010 DVICO
Make our compiled program executable:

$ chmod +x usbreset Execute the program with sudo privilege; make necessary substitution for <Bus> and <Device> ids as found by running the lsusb command:

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

别的

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

就我而言,它是 cp210x 驱动程序(我可以从 lsmod | grep usbserial 得知),因此您可以将上面的代码片段保存为 reset_usb.py,然后执行以下操作:

sudo python reset_usb.py cp210x

如果您的系统上尚未安装 ac 编译器,但您有 python,这也可能会有所帮助。

有用的答案树莓派官方

相关内容