aboutsummaryrefslogtreecommitdiffstats
path: root/package/utils/usbreset/src/usbreset.c
diff options
context:
space:
mode:
Diffstat (limited to 'package/utils/usbreset/src/usbreset.c')
-rw-r--r--package/utils/usbreset/src/usbreset.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/package/utils/usbreset/src/usbreset.c b/package/utils/usbreset/src/usbreset.c
new file mode 100644
index 0000000..ead30b1
--- /dev/null
+++ b/package/utils/usbreset/src/usbreset.c
@@ -0,0 +1,235 @@
+/* usbreset -- send a USB port reset to a USB device */
+
+/*
+
+http://marc.info/?l=linux-usb-users&m=116827193506484&w=2
+
+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
+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
+thing but with a "0" instead of the "2" above.
+
+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
+> device?
+
+Here's a program to do it. You invoke it as either
+
+ usbreset /proc/bus/usb/BBB/DDD
+or
+ usbreset /dev/usbB.D
+
+depending on how your system is set up, where BBB and DDD are the bus and
+device address numbers.
+
+Alan Stern
+
+*/
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <linux/usbdevice_fs.h>
+
+
+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 char *sysfs_attr(const char *dev, const char *attr)
+{
+ int fd, len = 0;
+ char path[PATH_MAX];
+ static char buf[129];
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(path, sizeof(path) - 1, "/sys/bus/usb/devices/%s/%s", dev, attr);
+
+ if ((fd = open(path, O_RDONLY)) >= 0)
+ {
+ len = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ }
+
+ while (--len > 0 && isspace(buf[len]))
+ buf[len] = 0;
+
+ return (len >= 0) ? buf : NULL;
+}
+
+static struct usbentry * parse_devlist(DIR *d)
+{
+ char *attr;
+ struct dirent *e;
+ static struct usbentry dev;
+
+ do {
+ e = readdir(d);
+
+ if (!e)
+ return NULL;
+ }
+ while(!isdigit(e->d_name[0]) || strchr(e->d_name, ':'));
+
+ memset(&dev, 0, sizeof(dev));
+
+ if ((attr = sysfs_attr(e->d_name, "busnum")) != NULL)
+ dev.bus_num = strtoul(attr, NULL, 10);
+
+ if ((attr = sysfs_attr(e->d_name, "devnum")) != NULL)
+ dev.dev_num = strtoul(attr, NULL, 10);
+
+ if ((attr = sysfs_attr(e->d_name, "idVendor")) != NULL)
+ dev.vendor_id = strtoul(attr, NULL, 16);
+
+ if ((attr = sysfs_attr(e->d_name, "idProduct")) != NULL)
+ dev.product_id = strtoul(attr, NULL, 16);
+
+ if ((attr = sysfs_attr(e->d_name, "manufacturer")) != NULL)
+ strcpy(dev.vendor_name, attr);
+
+ if ((attr = sysfs_attr(e->d_name, "product")) != NULL)
+ strcpy(dev.product_name, attr);
+
+ if (dev.bus_num && dev.dev_num && dev.vendor_id && dev.product_id)
+ return &dev;
+
+ return NULL;
+}
+
+static void list_devices(void)
+{
+ DIR *devs = opendir("/sys/bus/usb/devices");
+ 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);
+ }
+
+ closedir(devs);
+}
+
+struct usbentry * find_device(int *bus, int *dev,
+ int *vid, int *pid,
+ const char *product)
+{
+ DIR *devs = opendir("/sys/bus/usb/devices");
+
+ 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;
+ }
+ }
+
+ closedir(devs);
+
+ return match;
+}
+
+static void reset_device(struct usbentry *dev)
+{
+ int fd;
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path) - 1, "/dev/bus/usb/%03d/%03d",
+ 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");
+
+ close(fd);
+ }
+ else
+ {
+ printf("can't open [%s]\n", strerror(errno));
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ int id1, id2;
+ struct usbentry *dev;
+
+ 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;
+ }
+
+ if (!dev)
+ {
+ fprintf(stderr, "No such device found\n");
+ return 1;
+ }
+
+ reset_device(dev);
+ return 0;
+}