ath79: do not build TP-Link tiny images by default
[oweals/openwrt.git] / package / utils / usbreset / src / usbreset.c
1 /* usbreset -- send a USB port reset to a USB device */
2
3 /*
4
5 http://marc.info/?l=linux-usb-users&m=116827193506484&w=2
6
7 and needs mounted usbfs filesystem
8
9         sudo mount -t usbfs none /proc/bus/usb
10
11 There is a way to suspend a USB device.  In order to use it,
12 you must have a kernel with CONFIG_PM_SYSFS_DEPRECATED turned on.  To
13 suspend a device, do (as root):
14
15         echo -n 2 >/sys/bus/usb/devices/.../power/state
16
17 where the "..." is the ID for your device.  To unsuspend, do the same
18 thing but with a "0" instead of the "2" above.
19
20 Note that this mechanism is slated to be removed from the kernel within
21 the next year.  Hopefully some other mechanism will take its place.
22
23 > To reset a
24 > device?
25
26 Here's a program to do it.  You invoke it as either
27
28         usbreset /proc/bus/usb/BBB/DDD
29 or
30         usbreset /dev/usbB.D
31
32 depending on how your system is set up, where BBB and DDD are the bus and
33 device address numbers.
34
35 Alan Stern
36
37 */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdbool.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <limits.h>
48 #include <dirent.h>
49 #include <sys/ioctl.h>
50 #include <sys/types.h>
51
52 #include <linux/usbdevice_fs.h>
53
54
55 static char *usbfs = NULL;
56
57 struct usbentry {
58         int bus_num;
59         int dev_num;
60         int vendor_id;
61         int product_id;
62         char vendor_name[128];
63         char product_name[128];
64 };
65
66
67 static char *sysfs_attr(const char *dev, const char *attr)
68 {
69         int fd, len = 0;
70         char path[PATH_MAX];
71         static char buf[129];
72
73         memset(buf, 0, sizeof(buf));
74         snprintf(path, sizeof(path) - 1, "/sys/bus/usb/devices/%s/%s", dev, attr);
75
76         if ((fd = open(path, O_RDONLY)) >= 0)
77         {
78                 len = read(fd, buf, sizeof(buf) - 1);
79                 close(fd);
80         }
81
82         while (--len > 0 && isspace(buf[len]))
83                 buf[len] = 0;
84
85         return (len >= 0) ? buf : NULL;
86 }
87
88 static struct usbentry * parse_devlist(DIR *d)
89 {
90         char *attr;
91         struct dirent *e;
92         static struct usbentry dev;
93
94         do {
95                 e = readdir(d);
96
97                 if (!e)
98                         return NULL;
99         }
100         while(!isdigit(e->d_name[0]) || strchr(e->d_name, ':'));
101
102         memset(&dev, 0, sizeof(dev));
103
104         if ((attr = sysfs_attr(e->d_name, "busnum")) != NULL)
105                 dev.bus_num = strtoul(attr, NULL, 10);
106
107         if ((attr = sysfs_attr(e->d_name, "devnum")) != NULL)
108                 dev.dev_num = strtoul(attr, NULL, 10);
109
110         if ((attr = sysfs_attr(e->d_name, "idVendor")) != NULL)
111                 dev.vendor_id = strtoul(attr, NULL, 16);
112
113         if ((attr = sysfs_attr(e->d_name, "idProduct")) != NULL)
114                 dev.product_id = strtoul(attr, NULL, 16);
115
116         if ((attr = sysfs_attr(e->d_name, "manufacturer")) != NULL)
117                 strcpy(dev.vendor_name, attr);
118
119         if ((attr = sysfs_attr(e->d_name, "product")) != NULL)
120                 strcpy(dev.product_name, attr);
121
122         if (dev.bus_num && dev.dev_num && dev.vendor_id && dev.product_id)
123                 return &dev;
124
125         return NULL;
126 }
127
128 static void list_devices(void)
129 {
130         DIR *devs = opendir("/sys/bus/usb/devices");
131         struct usbentry *dev;
132
133         if (!devs)
134                 return;
135
136         while ((dev = parse_devlist(devs)) != NULL)
137         {
138                 printf("  Number %03d/%03d  ID %04x:%04x  %s\n",
139                            dev->bus_num, dev->dev_num,
140                            dev->vendor_id, dev->product_id,
141                            dev->product_name);
142         }
143
144         closedir(devs);
145 }
146
147 struct usbentry * find_device(int *bus, int *dev,
148                               int *vid, int *pid,
149                               const char *product)
150 {
151         DIR *devs = opendir("/sys/bus/usb/devices");
152
153         struct usbentry *e, *match = NULL;
154
155         if (!devs)
156                 return NULL;
157
158         while ((e = parse_devlist(devs)) != NULL)
159         {
160                 if ((bus && (e->bus_num == *bus) && (e->dev_num == *dev)) ||
161                         (vid && (e->vendor_id == *vid) && (e->product_id == *pid)) ||
162                         (product && !strcasecmp(e->product_name, product)))
163                 {
164                         match = e;
165                         break;
166                 }
167         }
168
169         closedir(devs);
170
171         return match;
172 }
173
174 static void reset_device(struct usbentry *dev)
175 {
176         int fd;
177         char path[PATH_MAX];
178
179         snprintf(path, sizeof(path) - 1, "/dev/bus/usb/%03d/%03d",
180                  dev->bus_num, dev->dev_num);
181
182         printf("Resetting %s ... ", dev->product_name);
183
184         if ((fd = open(path, O_WRONLY)) > -1)
185         {
186                 if (ioctl(fd, USBDEVFS_RESET, 0) < 0)
187                         printf("failed [%s]\n", strerror(errno));
188                 else
189                         printf("ok\n");
190
191                 close(fd);
192         }
193         else
194         {
195                 printf("can't open [%s]\n", strerror(errno));
196         }
197 }
198
199
200 int main(int argc, char **argv)
201 {
202         int id1, id2;
203         struct usbentry *dev;
204
205         if ((argc == 2) && (sscanf(argv[1], "%3d/%3d", &id1, &id2) == 2))
206         {
207                 dev = find_device(&id1, &id2, NULL, NULL, NULL);
208         }
209         else if ((argc == 2) && (sscanf(argv[1], "%4x:%4x", &id1, &id2) == 2))
210         {
211                 dev = find_device(NULL, NULL, &id1, &id2, NULL);
212         }
213         else if ((argc == 2) && strlen(argv[1]) < 128)
214         {
215                 dev = find_device(NULL, NULL, NULL, NULL, argv[1]);
216         }
217         else
218         {
219                 printf("Usage:\n"
220                        "  usbreset PPPP:VVVV - reset by product and vendor id\n"
221                        "  usbreset BBB/DDD   - reset by bus and device number\n"
222                        "  usbreset \"Product\" - reset by product name\n\n"
223                        "Devices:\n");
224                 list_devices();
225                 return 1;
226         }
227
228         if (!dev)
229         {
230                 fprintf(stderr, "No such device found\n");
231                 return 1;
232         }
233
234         reset_device(dev);
235         return 0;
236 }