8

I use motion on a Raspberry Pi, and sometimes the camera feed hangs. The camera is physically mounted, and it is kind of awkward to remove the cable and insert it again, so I was wondering:

Is there a way of achieving the same effect programmatically?

1
  • Hi - Could you accept an answer please :D seems like some answers here have helped many people in your situation.. wondering if it helped you too?
    – Piotr Kula
    Commented Jan 5, 2017 at 12:31

4 Answers 4

8

Good question and good idea. Shuckle suggests some code that resets the USB bus for the device, which may clear up some problems. See official forum:

http://www.raspberrypi.org/phpBB3/viewtopic.php?p=219980#p219980

I quote his c code, which I have not tested yet:

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>

void main(int argc, char **argv)
{
    const char *filename;
    int fd;

    if (argc < 2) {
        printf("Give USB device name as parameter\n");
        exit(1);
    }
    filename = argv[1];
    fd = open(filename, O_WRONLY);
    if (fd == -1) {
        perror("USB device open failed");
        exit(2);
    }
    if (ioctl(fd, USBDEVFS_RESET, 0) == -1) {
        perror("USBDEVFS_RESET device ioctl failed");
        exit(3);
    }
    close(fd);
}

You then use this code by saying, basically:

usbreset /dev/bus/usb/001/004

You could get the bus numbers from lsusb:

$ lsusb
...
Bus 001 Device 004: ID 046d:092f Logitech, Inc. QuickCam Express Plus
Bus 001 Device 006: ID 046d:0825 Logitech, Inc. Webcam C270

Now you've got me curious about whether that would fix a problem with the old Express Plus, I'll try that soon!

2
  • Thank you for a great answer, I shall surely test it! Do let us know if it fixes your Express Plus-related problem. :-) Commented Apr 4, 2013 at 14:53
  • It didn't fix my problem, but the code given above does seem to reset the bus and prevent the camera from getting stuck in a broken state. Also, firmware updates continue to improve the USB performance for these questionable cameras. ** Linux psychic 3.6.11+ #414 PREEMPT Thu Apr 18 02:00:59 BST 2013 armv6l GNU/Linux ** Commented Apr 20, 2013 at 1:47
7

You can make USB devices disappear using sysfs. I have tested this with a Logitech Unifying USB receiver. Although lsusb listed the device, key presses weren't processed when the device was removed using this method.

  1. Determine the ID associated with your USB device using dmesg. For instance, after plugging the USB receiver in, I get 1-1.2 as ID:

    usb 1-1.2: new full-speed USB device number 4 using dwc_otg
    usb 1-1.2: New USB device found, idVendor=046d, idProduct=c52b
    usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
    usb 1-1.2: Product: USB Receiver
    usb 1-1.2: Manufacturer: Logitech
    
  2. Remove and re-insert the device:

    sudo sh -c 'echo 1-1.2 > /sys/bus/usb/drivers/usb/unbind'
    sudo sh -c 'echo 1-1.2 > /sys/bus/usb/drivers/usb/bind'
    
  3. Profit!

You may also have success by writing unbind and bind on the driver for your camera driver. Use ls -l /dev/bus/[DRIVER]/devices to determine the driver.

(Inspired by an answer on Unix.SE)

4

In the spirit of sharing, I modified the usbreset code provided, in Tai's answer above, to accept parameters like you get from lsusb (in addition). That way it can be invoked conveniently by

DEVNUMS=`lsusb | grep -i webcam | tr -d : | awk '{print $2, $4;}'`
/home/xyz/cam/usbreset $DEVNUMS

which turns, for example, into

/home/xyz/cam/usbreset 001 018

The code is at the end.

I found the Pi USB webcam driver crashed often, but this is a way to recover it. It was easiest to make the executable be su root.

void main(int argc, char **argv)
{
    char devicename[1024];
    const char *filename = devicename;
    int fd;

    if ( 2 > argc || 3 < argc ) {
        printf("Give USB device name as parameter\n");
        exit(1);
    }

    if ( 2 == argc ) 
        filename = argv[1];
    else
        sprintf( devicename, "/dev/bus/usb/%s/%s", argv[1], argv[2] );

    printf( "Resetting USB device '%s'\n", filename );

    fd = open(filename, O_WRONLY);
    if (fd == -1) {
        perror("USB device open failed");
        exit(2);
    }
    if (ioctl(fd, USBDEVFS_RESET, 0) == -1) {
        // Don't care!  It usually does, when we need to reset it.
        //perror("USBDEVFS_RESET device ioctl failed");
        //exit(3);
    }
    close(fd);
}
0

You could try un-mounting and mounting the USB drive?

$ sudo mount /dev/sda1 /path/to/usb
$ sudo umount /path/to/usb

The first line is making /path/to/usb the mount point of the usb port at /dev/sda1 (you'll have to check to see which port it is connected to each time you plug it in).

The second line is unmounting the port through the alias

2
  • 1
    I think the OP means physically mounted, and it's hard to unplug as a result. :) Commented Apr 4, 2013 at 14:35
  • Yes, physically mounted. (And it's not a USB drive, by the way, it's a camera.) Commented Apr 4, 2013 at 14:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.