Pārlūkot izejas kodu

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 gadi atpakaļ
vecāks
revīzija
b29239d9f0
2 mainītis faili ar 198 papildinājumiem un 21 dzēšanām
  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.
 # 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
 

+ 196 - 19
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;
 }