summaryrefslogtreecommitdiffstats
path: root/package
diff options
context:
space:
mode:
Diffstat (limited to 'package')
-rw-r--r--package/usbreset/Makefile4
-rw-r--r--package/usbreset/src/usbreset.c215
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;
}