f6f2ba288ae4926ae59eeb03d9a727889f72b02e
[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 <stdbool.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include <limits.h>
47 #include <dirent.h>
48 #include <sys/ioctl.h>
49 #include <sys/types.h>
50
51 #include <linux/usbdevice_fs.h>
52
53
54 static char *usbfs = NULL;
55
56 struct usbentry {
57         int bus_num;
58         int dev_num;
59         int vendor_id;
60         int product_id;
61         char vendor_name[128];
62         char product_name[128];
63 };
64
65
66 static char *sysfs_attr(const char *dev, const char *attr)
67 {
68         int fd, len;
69         char path[PATH_MAX];
70         static char buf[129];
71
72         memset(buf, 0, sizeof(buf));
73         snprintf(path, sizeof(path) - 1, "/sys/bus/usb/devices/%s/%s", dev, attr);
74
75         if ((fd = open(path, O_RDONLY)) >= 0)
76         {
77                 len = read(fd, buf, sizeof(buf) - 1);
78                 close(fd);
79         }
80
81         while (--len > 0 && isspace(buf[len]))
82                 buf[len] = 0;
83
84         return (len >= 0) ? buf : NULL;
85 }
86
87 static struct usbentry * parse_devlist(DIR *d)
88 {
89         char *attr;
90         struct dirent *e;
91         static struct usbentry dev;
92
93         do {
94                 e = readdir(d);
95
96                 if (!e)
97                         return NULL;
98         }
99         while(!isdigit(e->d_name[0]) || strchr(e->d_name, ':'));
100
101         memset(&dev, 0, sizeof(dev));
102
103         if ((attr = sysfs_attr(e->d_name, "busnum")) != NULL)
104                 dev.bus_num = strtoul(attr, NULL, 10);
105
106         if ((attr = sysfs_attr(e->d_name, "devnum")) != NULL)
107                 dev.dev_num = strtoul(attr, NULL, 10);
108
109         if ((attr = sysfs_attr(e->d_name, "idVendor")) != NULL)
110                 dev.vendor_id = strtoul(attr, NULL, 16);
111
112         if ((attr = sysfs_attr(e->d_name, "idProduct")) != NULL)
113                 dev.product_id = strtoul(attr, NULL, 16);
114
115         if ((attr = sysfs_attr(e->d_name, "manufacturer")) != NULL)
116                 strcpy(dev.vendor_name, attr);
117
118         if ((attr = sysfs_attr(e->d_name, "product")) != NULL)
119                 strcpy(dev.product_name, attr);
120
121         if (dev.bus_num && dev.dev_num && dev.vendor_id && dev.product_id)
122                 return &dev;
123
124         return NULL;
125 }
126
127 static void list_devices(void)
128 {
129         DIR *devs = opendir("/sys/bus/usb/devices");
130         struct usbentry *dev;
131
132         if (!devs)
133                 return;
134
135         while ((dev = parse_devlist(devs)) != NULL)
136         {
137                 printf("  Number %03d/%03d  ID %04x:%04x  %s\n",
138                            dev->bus_num, dev->dev_num,
139                            dev->vendor_id, dev->product_id,
140                            dev->product_name);
141         }
142
143         closedir(devs);
144 }
145
146 struct usbentry * find_device(int *bus, int *dev,
147                               int *vid, int *pid,
148                               const char *product)
149 {
150         DIR *devs = opendir("/sys/bus/usb/devices");
151
152         struct usbentry *e, *match = NULL;
153
154         if (!devs)
155                 return NULL;
156
157         while ((e = parse_devlist(devs)) != NULL)
158         {
159                 if ((bus && (e->bus_num == *bus) && (e->dev_num == *dev)) ||
160                         (vid && (e->vendor_id == *vid) && (e->product_id == *pid)) ||
161                         (product && !strcasecmp(e->product_name, product)))
162                 {
163                         match = e;
164                         break;
165                 }
166         }
167
168         closedir(devs);
169
170         return match;
171 }
172
173 static void reset_device(struct usbentry *dev)
174 {
175         int fd;
176         char path[PATH_MAX];
177
178         snprintf(path, sizeof(path) - 1, "/dev/bus/usb/%03d/%03d",
179                  dev->bus_num, dev->dev_num);
180
181         printf("Resetting %s ... ", dev->product_name);
182
183         if ((fd = open(path, O_WRONLY)) > -1)
184         {
185                 if (ioctl(fd, USBDEVFS_RESET, 0) < 0)
186                         printf("failed [%s]\n", strerror(errno));
187                 else
188                         printf("ok\n");
189
190                 close(fd);
191         }
192         else
193         {
194                 printf("can't open [%s]\n", strerror(errno));
195         }
196 }
197
198
199 int main(int argc, char **argv)
200 {
201         int id1, id2;
202         struct usbentry *dev;
203
204         if ((argc == 2) && (sscanf(argv[1], "%3d/%3d", &id1, &id2) == 2))
205         {
206                 dev = find_device(&id1, &id2, NULL, NULL, NULL);
207         }
208         else if ((argc == 2) && (sscanf(argv[1], "%4x:%4x", &id1, &id2) == 2))
209         {
210                 dev = find_device(NULL, NULL, &id1, &id2, NULL);
211         }
212         else if ((argc == 2) && strlen(argv[1]) < 128)
213         {
214                 dev = find_device(NULL, NULL, NULL, NULL, argv[1]);
215         }
216         else
217         {
218                 printf("Usage:\n"
219                        "  usbreset PPPP:VVVV - reset by product and vendor id\n"
220                        "  usbreset BBB/DDD   - reset by bus and device number\n"
221                        "  usbreset \"Product\" - reset by product name\n\n"
222                        "Devices:\n");
223                 list_devices();
224                 return 1;
225         }
226
227         if (!dev)
228         {
229                 fprintf(stderr, "No such device found\n");
230                 return 1;
231         }
232
233         reset_device(dev);
234         return 0;
235 }