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
owl
Jo-Philipp Wich 2012-07-16 00:39:39 +00:00
parent ec770abd0d
commit b29239d9f0
2 changed files with 201 additions and 24 deletions

View File

@ -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

View File

@ -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, 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 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>
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)
{
int fd;
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");
close(fd);
}
else
{
printf("can't open [%s]\n", strerror(errno));
}
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
const char *filename; int id1, id2;
int fd; struct usbentry *dev;
int rc;
if (argc != 2) { if (!find_usbfs())
fprintf(stderr, "Usage: usbreset device-filename\n"); {
return 1; fprintf(stderr, "Unable to find usbfs, is it mounted?\n");
}
filename = argv[1];
fd = open(filename, O_WRONLY);
if (fd < 0) {
perror("Error opening output file");
return 1; return 1;
} }
printf("Resetting USB device %s\n", filename); if ((argc == 2) && (sscanf(argv[1], "%3d/%3d", &id1, &id2) == 2))
rc = ioctl(fd, USBDEVFS_RESET, 0); {
if (rc < 0) { dev = find_device(&id1, &id2, NULL, NULL, NULL);
perror("Error in ioctl"); }
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("Reset successful\n");
close(fd); if (!dev)
{
fprintf(stderr, "No such device found\n");
return 1;
}
reset_device(dev);
return 0; return 0;
} }