|
|
|
@ -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]; |
|
|
|
|
|
|
|
|
|
if (argc != 2) { |
|
|
|
|
fprintf(stderr, "Usage: usbreset device-filename\n"); |
|
|
|
|
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 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; |
|
|
|
|
} |
|
|
|
|