Browse Source

usbreset: improve usability - add device list in usage screen - support resetting by bus/device number, by produc:vendor id or by device name

SVN-Revision: 32741
Jo-Philipp Wich 13 years ago
parent
commit
b29239d9f0
2 changed files with 198 additions and 21 deletions
  1. 2 2
      package/usbreset/Makefile
  2. 196 19
      package/usbreset/src/usbreset.c

+ 2 - 2
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.
 # This is free software, licensed under the GNU General Public License v2.
 # See /LICENSE for more information.
 # See /LICENSE for more information.
@@ -8,7 +8,7 @@
 include $(TOPDIR)/rules.mk
 include $(TOPDIR)/rules.mk
 
 
 PKG_NAME:=usbreset
 PKG_NAME:=usbreset
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 
 include $(INCLUDE_DIR)/package.mk
 include $(INCLUDE_DIR)/package.mk
 
 

+ 196 - 19
package/usbreset/src/usbreset.c

@@ -8,16 +8,16 @@ and needs mounted usbfs filesystem
 
 
 	sudo mount -t usbfs none /proc/bus/usb
 	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):
 suspend a device, do (as root):
 
 
 	echo -n 2 >/sys/bus/usb/devices/.../power/state
 	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.
 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.
 the next year.  Hopefully some other mechanism will take its place.
 
 
 > To reset a
 > To reset a
@@ -37,40 +37,217 @@ Alan Stern
 */
 */
 
 
 #include <stdio.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <errno.h>
+#include <string.h>
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
 
 
 #include <linux/usbdevice_fs.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 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;
 		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;
 		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;
 		return 1;
 	}
 	}
-	printf("Reset successful\n");
 
 
-	close(fd);
+	reset_device(dev);
 	return 0;
 	return 0;
 }
 }