diff options
Diffstat (limited to 'package')
-rw-r--r-- | package/usbreset/Makefile | 4 | ||||
-rw-r--r-- | package/usbreset/src/usbreset.c | 215 |
2 files changed, 198 insertions, 21 deletions
diff --git a/package/usbreset/Makefile b/package/usbreset/Makefile index 32e073faa..75bfd8513 100644 --- a/package/usbreset/Makefile +++ b/package/usbreset/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011 OpenWrt.org +# Copyright (C) 2011-2012 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=usbreset -PKG_RELEASE:=1 +PKG_RELEASE:=2 include $(INCLUDE_DIR)/package.mk diff --git a/package/usbreset/src/usbreset.c b/package/usbreset/src/usbreset.c index 03d178753..087a14cfa 100644 --- a/package/usbreset/src/usbreset.c +++ b/package/usbreset/src/usbreset.c @@ -8,16 +8,16 @@ and needs mounted usbfs filesystem sudo mount -t usbfs none /proc/bus/usb -There is a way to suspend a USB device. In order to use it, -you must have a kernel with CONFIG_PM_SYSFS_DEPRECATED turned on. To +There is a way to suspend a USB device. In order to use it, +you must have a kernel with CONFIG_PM_SYSFS_DEPRECATED turned on. To suspend a device, do (as root): echo -n 2 >/sys/bus/usb/devices/.../power/state -where the "..." is the ID for your device. To unsuspend, do the same +where the "..." is the ID for your device. To unsuspend, do the same thing but with a "0" instead of the "2" above. -Note that this mechanism is slated to be removed from the kernel within +Note that this mechanism is slated to be removed from the kernel within the next year. Hopefully some other mechanism will take its place. > To reset a @@ -37,40 +37,217 @@ Alan Stern */ #include <stdio.h> +#include <stdbool.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> +#include <string.h> #include <sys/ioctl.h> #include <linux/usbdevice_fs.h> -int main(int argc, char **argv) +static char *usbfs = NULL; + +struct usbentry { + int bus_num; + int dev_num; + int vendor_id; + int product_id; + char vendor_name[128]; + char product_name[128]; +}; + + +static bool find_usbfs(void) +{ + FILE *mtab; + + char buf[1024], type[32]; + static char path[1024]; + + if ((mtab = fopen("/proc/mounts", "r")) != NULL) + { + while (fgets(buf, sizeof(buf), mtab)) + { + if (sscanf(buf, "%*s %1023s %31s ", path, type) == 2 && + !strncmp(type, "usbfs", 5)) + { + usbfs = path; + break; + } + } + + fclose(mtab); + } + + return !!usbfs; +} + +static FILE * open_devlist(void) +{ + char buf[1024]; + snprintf(buf, sizeof(buf), "%s/devices", usbfs); + return fopen(buf, "r"); +} + +static void close_devlist(FILE *devs) +{ + fclose(devs); +} + +static struct usbentry * parse_devlist(FILE *devs) +{ + char buf[1024]; + static struct usbentry dev; + + memset(&dev, 0, sizeof(dev)); + + while (fgets(buf, sizeof(buf), devs)) + { + buf[strlen(buf)-1] = 0; + + switch (buf[0]) + { + case 'T': + sscanf(buf, "T: Bus=%d Lev=%*d Prnt=%*d Port=%*d Cnt=%*d Dev#=%d", + &dev.bus_num, &dev.dev_num); + break; + + case 'P': + sscanf(buf, "P: Vendor=%x ProdID=%x", + &dev.vendor_id, &dev.product_id); + break; + + case 'S': + if (!strncmp(buf, "S: Manufacturer=", 17)) + snprintf(dev.vendor_name, sizeof(dev.vendor_name), + "%s", buf+17); + else if (!strncmp(buf, "S: Product=", 12)) + snprintf(dev.product_name, sizeof(dev.product_name), + "%s", buf+12); + break; + } + + if (dev.product_name[0]) + return &dev; + } + + return NULL; +} + +static void list_devices(void) +{ + FILE *devs = open_devlist(); + struct usbentry *dev; + + if (!devs) + return; + + while ((dev = parse_devlist(devs)) != NULL) + { + printf(" Number %03d/%03d ID %04x:%04x %s\n", + dev->bus_num, dev->dev_num, + dev->vendor_id, dev->product_id, + dev->product_name); + } + + close_devlist(devs); +} + +struct usbentry * find_device(int *bus, int *dev, + int *vid, int *pid, + const char *product) +{ + FILE *devs = open_devlist(); + + struct usbentry *e, *match = NULL; + + if (!devs) + return NULL; + + while ((e = parse_devlist(devs)) != NULL) + { + if ((bus && (e->bus_num == *bus) && (e->dev_num == *dev)) || + (vid && (e->vendor_id == *vid) && (e->product_id == *pid)) || + (product && !strcasecmp(e->product_name, product))) + { + match = e; + break; + } + } + + close_devlist(devs); + + return match; +} + +static void reset_device(struct usbentry *dev) { - const char *filename; int fd; - int rc; + char path[1024]; + + snprintf(path, sizeof(path), "%s/%03d/%03d", + usbfs, dev->bus_num, dev->dev_num); + + printf("Resetting %s ... ", dev->product_name); + + if ((fd = open(path, O_WRONLY)) > -1) + { + if (ioctl(fd, USBDEVFS_RESET, 0) < 0) + printf("failed [%s]\n", strerror(errno)); + else + printf("ok\n"); - if (argc != 2) { - fprintf(stderr, "Usage: usbreset device-filename\n"); + close(fd); + } + else + { + printf("can't open [%s]\n", strerror(errno)); + } +} + + +int main(int argc, char **argv) +{ + int id1, id2; + struct usbentry *dev; + + if (!find_usbfs()) + { + fprintf(stderr, "Unable to find usbfs, is it mounted?\n"); return 1; } - filename = argv[1]; - fd = open(filename, O_WRONLY); - if (fd < 0) { - perror("Error opening output file"); + if ((argc == 2) && (sscanf(argv[1], "%3d/%3d", &id1, &id2) == 2)) + { + dev = find_device(&id1, &id2, NULL, NULL, NULL); + } + else if ((argc == 2) && (sscanf(argv[1], "%4x:%4x", &id1, &id2) == 2)) + { + dev = find_device(NULL, NULL, &id1, &id2, NULL); + } + else if ((argc == 2) && strlen(argv[1]) < 128) + { + dev = find_device(NULL, NULL, NULL, NULL, argv[1]); + } + else + { + printf("Usage:\n" + " usbreset PPPP:VVVV - reset by product and vendor id\n" + " usbreset BBB/DDD - reset by bus and device number\n" + " usbreset \"Product\" - reset by product name\n\n" + "Devices:\n"); + list_devices(); return 1; } - printf("Resetting USB device %s\n", filename); - rc = ioctl(fd, USBDEVFS_RESET, 0); - if (rc < 0) { - perror("Error in ioctl"); + if (!dev) + { + fprintf(stderr, "No such device found\n"); return 1; } - printf("Reset successful\n"); - close(fd); + reset_device(dev); return 0; } |