Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 342 lines (303 sloc) 9.022 kb
cd35e0d Initial revision
Thomas Sailer authored
1 /*****************************************************************************/
2
3 /*
4 * devtree.c -- USB device tree.
5 *
6 * Copyright (C) 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20 /*****************************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <sys/types.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <unistd.h>
32
9e0cd05 David T. Crosby Fix compiler warning
dafyddcrosby authored
33 #include "names.h"
cd35e0d Initial revision
Thomas Sailer authored
34 #include "devtree.h"
35
36 /* ---------------------------------------------------------------------- */
37
38 LIST_HEAD(usbbuslist);
39
40 /* ---------------------------------------------------------------------- */
41
42 static void freedev(struct usbdevnode *dev)
43 {
44 free(dev);
45 }
46
47 static void freebus(struct usbbusnode *bus)
48 {
49 free(bus);
50 }
51
52 /* ---------------------------------------------------------------------- */
53
54 static void markdel(struct list_head *list)
55 {
56 struct usbdevnode *dev;
57 struct list_head *list2;
58
59 for (list2 = list->next; list2 != list; list2 = list2->next) {
60 dev = list_entry(list2, struct usbdevnode, list);
61 dev->flags |= USBFLG_DELETED;
62 markdel(&dev->childlist);
63 }
64 }
65
66 void devtree_markdeleted(void)
67 {
68 struct usbbusnode *bus;
69 struct list_head *list;
f74441f Greg Kroah-Hartman lots of trailing whitespace removed.
authored
70
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
71 for (list = usbbuslist.next; list != &usbbuslist; list = list->next) {
cd35e0d Initial revision
Thomas Sailer authored
72 bus = list_entry(list, struct usbbusnode, list);
73 markdel(&bus->childlist);
74 }
75 }
76
77 struct usbbusnode *devtree_findbus(unsigned int busn)
78 {
79 struct usbbusnode *bus;
80 struct list_head *list;
f74441f Greg Kroah-Hartman lots of trailing whitespace removed.
authored
81
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
82 for (list = usbbuslist.next; list != &usbbuslist; list = list->next) {
cd35e0d Initial revision
Thomas Sailer authored
83 bus = list_entry(list, struct usbbusnode, list);
84 if (bus->busnum == busn)
85 return bus;
86 }
87 return NULL;
88 }
89
90 static struct usbdevnode *findsubdevice(struct list_head *list, unsigned int devn)
91 {
92 struct usbdevnode *dev, *dev2;
93 struct list_head *list2;
94
95 for (list2 = list->next; list2 != list; list2 = list2->next) {
96 dev = list_entry(list2, struct usbdevnode, list);
97 if (dev->devnum == devn)
98 return dev;
99 dev2 = findsubdevice(&dev->childlist, devn);
100 if (dev2)
101 return dev2;
102 }
103 return NULL;
104 }
105
106 struct usbdevnode *devtree_finddevice(struct usbbusnode *bus, unsigned int devn)
107 {
108 return findsubdevice(&bus->childlist, devn);
109 }
110
111 /* ---------------------------------------------------------------------- */
112
113 void devtree_parsedevfile(int fd)
114 {
115 char buf[16384];
116 char *start, *end, *lineend, *cp;
117 int ret;
118 unsigned int devnum = 0, busnum = 0, parentdevnum = 0, level = 0;
119 unsigned int class = 0xff, vendor = 0xffff, prodid = 0xffff, speed = 0;
120 struct usbbusnode *bus;
121 struct usbdevnode *dev, *dev2;
122
123 devtree_markdeleted();
124 if (lseek(fd, 0, SEEK_SET) == (off_t)-1)
125 lprintf(0, "lseek: %s (%d)\n", strerror(errno), errno);
126 ret = read(fd, buf, sizeof(buf)-1);
127 if (ret == -1)
128 lprintf(0, "read: %s (%d)\n", strerror(errno), errno);
129 end = buf + ret;
130 *end = 0;
131 start = buf;
132 while (start < end) {
133 lineend = strchr(start, '\n');
134 if (!lineend)
135 break;
136 *lineend = 0;
137 switch (start[0]) {
138 case 'T': /* topology line */
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
139 if ((cp = strstr(start, "Dev#=")))
cd35e0d Initial revision
Thomas Sailer authored
140 devnum = strtoul(cp + 5, NULL, 0);
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
141 else
cd35e0d Initial revision
Thomas Sailer authored
142 devnum = 0;
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
143 if ((cp = strstr(start, "Bus=")))
1728e08 aurel32 lsusb: fix parsing of /proc/bus/usb/devices
aurel32 authored
144 busnum = strtoul(cp + 4, NULL, 10);
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
145 else
cd35e0d Initial revision
Thomas Sailer authored
146 busnum = 0;
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
147 if ((cp = strstr(start, "Prnt=")))
1728e08 aurel32 lsusb: fix parsing of /proc/bus/usb/devices
aurel32 authored
148 parentdevnum = strtoul(cp + 5, NULL, 10);
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
149 else
cd35e0d Initial revision
Thomas Sailer authored
150 parentdevnum = 0;
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
151 if ((cp = strstr(start, "Lev=")))
1728e08 aurel32 lsusb: fix parsing of /proc/bus/usb/devices
aurel32 authored
152 level = strtoul(cp + 4, NULL, 10);
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
153 else
cd35e0d Initial revision
Thomas Sailer authored
154 level = 0;
155 if (strstr(start, "Spd=1.5"))
156 speed = 1;
157 else if (strstr(start, "Spd=12"))
158 speed = 2;
f74441f Greg Kroah-Hartman lots of trailing whitespace removed.
authored
159 else
cd35e0d Initial revision
Thomas Sailer authored
160 speed = 0;
161 break;
162
163 case 'D':
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
164 if ((cp = strstr(start, "Cls=")))
cd35e0d Initial revision
Thomas Sailer authored
165 class = strtoul(cp + 4, NULL, 16);
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
166 else
cd35e0d Initial revision
Thomas Sailer authored
167 class = 0xff;
168 break;
169
170 case 'P':
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
171 if ((cp = strstr(start, "Vendor=")))
cd35e0d Initial revision
Thomas Sailer authored
172 vendor = strtoul(cp + 7, NULL, 16);
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
173 else
cd35e0d Initial revision
Thomas Sailer authored
174 vendor = 0xffff;
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
175 if ((cp = strstr(start, "ProdID=")))
cd35e0d Initial revision
Thomas Sailer authored
176 prodid = strtoul(cp + 7, NULL, 16);
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
177 else
cd35e0d Initial revision
Thomas Sailer authored
178 prodid = 0xffff;
179 /* print device */
180 #if 0
181 printf("Device %3d Vendor %04x Product ID %04x Class %02x Speed %s\n",
182 devnum, vendor, prodid, class, speed == 2 ? "12 MBPS" : speed == 1 ? "1.5 MBPS" : "unknown");
183 #endif
184 if (!(bus = devtree_findbus(busnum))) {
185 if (!(bus = malloc(sizeof(struct usbbusnode))))
186 lprintf(0, "Out of memory\n");
187 bus->busnum = busnum;
188 bus->flags = USBFLG_NEW;
189 INIT_LIST_HEAD(&bus->childlist);
190 list_add_tail(&bus->list, &usbbuslist);
191 } else {
192 bus->flags &= ~USBFLG_DELETED;
193 }
194 if (!(dev = devtree_finddevice(bus, devnum)) || dev->vendorid != vendor || dev->productid != prodid) {
195 if (!(dev = malloc(sizeof(struct usbdevnode))))
196 lprintf(0, "Out of memory\n");
197 dev->devnum = devnum;
198 dev->flags = USBFLG_NEW;
199 dev->bus = bus;
200 dev->vendorid = vendor;
201 dev->productid = prodid;
202 INIT_LIST_HEAD(&dev->childlist);
203 if (level == 0 && parentdevnum == 0) {
204 list_add_tail(&dev->list, &bus->childlist);
205 dev->parent = NULL;
206 } else {
207 if (!(dev2 = devtree_finddevice(bus, parentdevnum)))
208 lprintf(0, "Bus %d Device %d Parent Device %d not found\n", busnum, devnum, parentdevnum);
209 dev->parent = dev2;
210 list_add_tail(&dev->list, &dev2->childlist);
211 }
212 } else {
213 dev->flags &= ~USBFLG_DELETED;
214 }
215 break;
216
217 default:
218 break;
219 }
220 #if 0
221 printf("line: %s\n", start);
222 #endif
223 start = lineend + 1;
224 }
225 }
226
227 /* ---------------------------------------------------------------------- */
228
229 static void deletetree(struct list_head *list, unsigned int force)
230 {
231 struct usbdevnode *dev;
232 struct list_head *list2;
233
234 for (list2 = list->next; list2 != list;) {
235 dev = list_entry(list2, struct usbdevnode, list);
236 list2 = list2->next;
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
237 deletetree(&dev->childlist,
238 force || dev->flags & USBFLG_DELETED);
cd35e0d Initial revision
Thomas Sailer authored
239 if (!force && !(dev->flags & USBFLG_DELETED))
240 continue;
241 list_del(&dev->list);
242 INIT_LIST_HEAD(&dev->list);
243 devtree_devdisconnect(dev);
244 freedev(dev);
245 }
246 }
247
248 static void newtree(struct list_head *list)
249 {
250 struct usbdevnode *dev;
251 struct list_head *list2;
252
253 for (list2 = list->next; list2 != list; list2 = list2->next) {
254 dev = list_entry(list2, struct usbdevnode, list);
255 if (dev->flags & USBFLG_NEW)
256 devtree_devconnect(dev);
257 dev->flags &= ~USBFLG_NEW;
258 newtree(&dev->childlist);
259 }
260 }
261
262 void devtree_processchanges(void)
263 {
264 struct list_head *list;
265 struct usbbusnode *bus;
266
267 for (list = usbbuslist.next; list != &usbbuslist;) {
268 bus = list_entry(list, struct usbbusnode, list);
269 list = list->next;
270 deletetree(&bus->childlist, bus->flags & USBFLG_DELETED);
271 if (!(bus->flags & USBFLG_DELETED))
272 continue;
273 list_del(&bus->list);
274 INIT_LIST_HEAD(&bus->list);
275 devtree_busdisconnect(bus);
276 freebus(bus);
277 }
278 for (list = usbbuslist.next; list != &usbbuslist; list = list->next) {
279 bus = list_entry(list, struct usbbusnode, list);
280 if (bus->flags & USBFLG_NEW)
281 devtree_busconnect(bus);
282 bus->flags &= ~USBFLG_NEW;
283 newtree(&bus->childlist);
284 }
285 }
286
287 /* ---------------------------------------------------------------------- */
288
09bf37e Greg Kroah-Hartman devtree.c: coding style cleanups
authored
289 static void dumpdevlist(struct list_head *list, unsigned int level,
71413e7 David T. Crosby Verbose flag in tree mode shows vendor and product name.
dafyddcrosby authored
290 unsigned int mask, unsigned int verblevel)
cd35e0d Initial revision
Thomas Sailer authored
291 {
292 struct usbdevnode *dev;
293 struct list_head *list2;
71413e7 David T. Crosby Verbose flag in tree mode shows vendor and product name.
dafyddcrosby authored
294 char vendor[128];
295 char product[128];
cd35e0d Initial revision
Thomas Sailer authored
296 char buf[512];
297 char *cp;
298 unsigned int i;
299
300 for (list2 = list->next; list2 != list; ) {
301 dev = list_entry(list2, struct usbdevnode, list);
302 list2 = list2->next;
303 for (cp = buf, i = 0; i < level; i++) {
304 *cp++ = (mask & (1 << i)) ? '|' : ' ';
305 *cp++ = ' ';
306 }
307 if (list2 != list) {
308 mask |= (1 << level);
309 *cp++ = '|';
310 } else {
311 mask &= ~(1 << level);
312 *cp++ = '`';
313 }
314 *cp++ = '-';
71413e7 David T. Crosby Verbose flag in tree mode shows vendor and product name.
dafyddcrosby authored
315 if (verblevel > 1) {
316 get_vendor_string(vendor, sizeof(vendor), dev->vendorid);
317 get_product_string(product, sizeof(product), dev->vendorid, dev->productid);
318 snprintf(cp, buf + sizeof(buf) - cp,
319 "Dev# %3d Vendor 0x%04x Product 0x%04x %s %s",
320 dev->devnum, dev->vendorid, dev->productid, vendor, product);
321 } else {
322 snprintf(cp, buf + sizeof(buf) - cp,
323 "Dev# %3d Vendor 0x%04x Product 0x%04x",
324 dev->devnum, dev->vendorid, dev->productid);
325 }
cd35e0d Initial revision
Thomas Sailer authored
326 lprintf(1, "%s\n", buf);
71413e7 David T. Crosby Verbose flag in tree mode shows vendor and product name.
dafyddcrosby authored
327 dumpdevlist(&dev->childlist, level+1, mask, verblevel);
cd35e0d Initial revision
Thomas Sailer authored
328 }
329 }
330
71413e7 David T. Crosby Verbose flag in tree mode shows vendor and product name.
dafyddcrosby authored
331 void devtree_dump(unsigned int verblevel)
cd35e0d Initial revision
Thomas Sailer authored
332 {
333 struct list_head *list;
334 struct usbbusnode *bus;
335
336 for (list = usbbuslist.next; list != &usbbuslist; list = list->next) {
337 bus = list_entry(list, struct usbbusnode, list);
338 lprintf(1, "Bus# %2d\n", bus->busnum);
71413e7 David T. Crosby Verbose flag in tree mode shows vendor and product name.
dafyddcrosby authored
339 dumpdevlist(&bus->childlist, 0, 0, verblevel);
cd35e0d Initial revision
Thomas Sailer authored
340 }
341 }
Something went wrong with that request. Please try again.