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
This commit is contained in:
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.
# 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

View File

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