usbreset: Add missing header
[openwrt/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 }