5

I have a USB GSM modem that does not always work property (Huawei E367u-2) Sometimes it gets reset (USB device disconnect/reconnect in logs) and when it comes back up, it has different ttyUSB numbers. Sometimes on boot, usb_modeswitch seems to just not get fired. The computer is a Raspberry Pi running Raspbian.

I have a simple solution to this: every minute cron runs the following script (pseudo-code):

If WVDIAL is not running:
    Run WVDIAL

I want to change the script to be this:

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

Obviously this is pseudo-code, but I have the following lines that I need to string together but I can't figure out how:

This loads wvdial if it is not running:

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

This lets me find the /sys path to a certain device:

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

And this resets a USB device if you know the correct /sys path:

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

So, I need to string together those last 2 sections and a test to /dev/ttyUSB0 into a section that goes under the "If you want a command to always run, put it here" comment.

  • How can I do that?
  • Is there a better way to do this?

2 Answers 2

1

I think you're basically there:

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

This loops over all devices (as you were doing) and each time it finds a match for the vendor:product ids, it applies the reset which works for you.


As an aside, you might want to look into the watchdog program as an alternative to your cron job.

1

If you are thinking to use a command line and then reset it.

Save the following as 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;
}

The run the following commands in terminal:

Compile the program:

$ 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

Else

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

In my case it was the cp210x driver (which I could tell from lsmod | grep usbserial), so you could save the above snippet as reset_usb.py and then do this:

sudo python reset_usb.py cp210x

This might also be helpful if you don't already have a c compiler setup on your system, but you do have python.

Useful answer raspberry pi official

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .