usbutils: add from /packages, clean up, add myself as maintainer
[openwrt.git] / package / 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 <stdbool.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <string.h>
45 #include <sys/ioctl.h>
46
47 #include <linux/usbdevice_fs.h>
48
49
50 static char *usbfs = NULL;
51
52 struct usbentry {
53         int bus_num;
54         int dev_num;
55         int vendor_id;
56         int product_id;
57         char vendor_name[128];
58         char product_name[128];
59 };
60
61
62 static bool find_usbfs(void)
63 {
64         FILE *mtab;
65
66         char buf[1024], type[32];
67         static char path[1024];
68
69         if ((mtab = fopen("/proc/mounts", "r")) != NULL)
70         {
71                 while (fgets(buf, sizeof(buf), mtab))
72                 {
73                         if (sscanf(buf, "%*s %1023s %31s ", path, type) == 2 &&
74                                 !strncmp(type, "usbfs", 5))
75                         {
76                                 usbfs = path;
77                                 break;
78                         }
79                 }
80
81                 fclose(mtab);
82         }
83
84         return !!usbfs;
85 }
86
87 static FILE * open_devlist(void)
88 {
89         char buf[1024];
90         snprintf(buf, sizeof(buf), "%s/devices", usbfs);
91         return fopen(buf, "r");
92 }
93
94 static void close_devlist(FILE *devs)
95 {
96         fclose(devs);
97 }
98
99 static struct usbentry * parse_devlist(FILE *devs)
100 {
101         char buf[1024];
102         static struct usbentry dev;
103
104         memset(&dev, 0, sizeof(dev));
105
106         while (fgets(buf, sizeof(buf), devs))
107         {
108                 buf[strlen(buf)-1] = 0;
109
110                 switch (buf[0])
111                 {
112                 case 'T':
113                         sscanf(buf, "T: Bus=%d Lev=%*d Prnt=%*d Port=%*d Cnt=%*d Dev#=%d",
114                                    &dev.bus_num, &dev.dev_num);
115                         break;
116
117                 case 'P':
118                         sscanf(buf, "P: Vendor=%x ProdID=%x",
119                                    &dev.vendor_id, &dev.product_id);
120                         break;
121
122                 case 'S':
123                         if (!strncmp(buf, "S:  Manufacturer=", 17))
124                                 snprintf(dev.vendor_name, sizeof(dev.vendor_name),
125                                          "%s", buf+17);
126                         else if (!strncmp(buf, "S:  Product=", 12))
127                                 snprintf(dev.product_name, sizeof(dev.product_name),
128                                          "%s", buf+12);
129                         break;
130                 }
131
132                 if (dev.product_name[0])
133                         return &dev;
134         }
135
136         return NULL;
137 }
138
139 static void list_devices(void)
140 {
141         FILE *devs = open_devlist();
142         struct usbentry *dev;
143
144         if (!devs)
145                 return;
146
147         while ((dev = parse_devlist(devs)) != NULL)
148         {
149                 printf("  Number %03d/%03d  ID %04x:%04x  %s\n",
150                            dev->bus_num, dev->dev_num,
151                            dev->vendor_id, dev->product_id,
152                            dev->product_name);
153         }
154
155         close_devlist(devs);
156 }
157
158 struct usbentry * find_device(int *bus, int *dev,
159                               int *vid, int *pid,
160                               const char *product)
161 {
162         FILE *devs = open_devlist();
163
164         struct usbentry *e, *match = NULL;
165
166         if (!devs)
167                 return NULL;
168
169         while ((e = parse_devlist(devs)) != NULL)
170         {
171                 if ((bus && (e->bus_num == *bus) && (e->dev_num == *dev)) ||
172                         (vid && (e->vendor_id == *vid) && (e->product_id == *pid)) ||
173                         (product && !strcasecmp(e->product_name, product)))
174                 {
175                         match = e;
176                         break;
177                 }
178         }
179
180         close_devlist(devs);
181
182         return match;
183 }
184
185 static void reset_device(struct usbentry *dev)
186 {
187         int fd;
188         char path[1024];
189
190         snprintf(path, sizeof(path), "%s/%03d/%03d",
191                          usbfs, dev->bus_num, dev->dev_num);
192
193         printf("Resetting %s ... ", dev->product_name);
194
195         if ((fd = open(path, O_WRONLY)) > -1)
196         {
197                 if (ioctl(fd, USBDEVFS_RESET, 0) < 0)
198                         printf("failed [%s]\n", strerror(errno));
199                 else
200                         printf("ok\n");
201
202                 close(fd);
203         }
204         else
205         {
206                 printf("can't open [%s]\n", strerror(errno));
207         }
208 }
209
210
211 int main(int argc, char **argv)
212 {
213         int id1, id2;
214         struct usbentry *dev;
215
216         if (!find_usbfs())
217         {
218                 fprintf(stderr, "Unable to find usbfs, is it mounted?\n");
219                 return 1;
220         }
221
222         if ((argc == 2) && (sscanf(argv[1], "%3d/%3d", &id1, &id2) == 2))
223         {
224                 dev = find_device(&id1, &id2, NULL, NULL, NULL);
225         }
226         else if ((argc == 2) && (sscanf(argv[1], "%4x:%4x", &id1, &id2) == 2))
227         {
228                 dev = find_device(NULL, NULL, &id1, &id2, NULL);
229         }
230         else if ((argc == 2) && strlen(argv[1]) < 128)
231         {
232                 dev = find_device(NULL, NULL, NULL, NULL, argv[1]);
233         }
234         else
235         {
236                 printf("Usage:\n"
237                        "  usbreset PPPP:VVVV - reset by product and vendor id\n"
238                        "  usbreset BBB/DDD   - reset by bus and device number\n"
239                        "  usbreset \"Product\" - reset by product name\n\n"
240                        "Devices:\n");
241                 list_devices();
242                 return 1;
243         }
244
245         if (!dev)
246         {
247                 fprintf(stderr, "No such device found\n");
248                 return 1;
249         }
250
251         reset_device(dev);
252         return 0;
253 }