1 /*****************************************************************************/
4 * devtree.c -- USB device tree.
6 * Copyright (C) 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
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.
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.
20 /*****************************************************************************/
26 #include <sys/types.h>
36 /* ---------------------------------------------------------------------- */
38 LIST_HEAD(usbbuslist);
40 /* ---------------------------------------------------------------------- */
42 static void freedev(struct usbdevnode *dev)
47 static void freebus(struct usbbusnode *bus)
52 /* ---------------------------------------------------------------------- */
54 static void markdel(struct list_head *list)
56 struct usbdevnode *dev;
57 struct list_head *list2;
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);
66 void devtree_markdeleted(void)
68 struct usbbusnode *bus;
69 struct list_head *list;
71 for (list = usbbuslist.next; list != &usbbuslist; list = list->next) {
72 bus = list_entry(list, struct usbbusnode, list);
73 markdel(&bus->childlist);
77 struct usbbusnode *devtree_findbus(unsigned int busn)
79 struct usbbusnode *bus;
80 struct list_head *list;
82 for (list = usbbuslist.next; list != &usbbuslist; list = list->next) {
83 bus = list_entry(list, struct usbbusnode, list);
84 if (bus->busnum == busn)
90 static struct usbdevnode *findsubdevice(struct list_head *list, unsigned int devn)
92 struct usbdevnode *dev, *dev2;
93 struct list_head *list2;
95 for (list2 = list->next; list2 != list; list2 = list2->next) {
96 dev = list_entry(list2, struct usbdevnode, list);
97 if (dev->devnum == devn)
99 dev2 = findsubdevice(&dev->childlist, devn);
106 struct usbdevnode *devtree_finddevice(struct usbbusnode *bus, unsigned int devn)
108 return findsubdevice(&bus->childlist, devn);
111 /* ---------------------------------------------------------------------- */
113 void devtree_parsedevfile(int fd)
116 char *start, *end, *lineend, *cp;
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;
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);
128 lprintf(0, "read: %s (%d)\n", strerror(errno), errno);
132 while (start < end) {
133 lineend = strchr(start, '\n');
138 case 'T': /* topology line */
139 if ((cp = strstr(start, "Dev#=")))
140 devnum = strtoul(cp + 5, NULL, 0);
143 if ((cp = strstr(start, "Bus=")))
144 busnum = strtoul(cp + 4, NULL, 10);
147 if ((cp = strstr(start, "Prnt=")))
148 parentdevnum = strtoul(cp + 5, NULL, 10);
151 if ((cp = strstr(start, "Lev=")))
152 level = strtoul(cp + 4, NULL, 10);
155 if (strstr(start, "Spd=1.5"))
157 else if (strstr(start, "Spd=12"))
164 if ((cp = strstr(start, "Cls=")))
165 class = strtoul(cp + 4, NULL, 16);
171 if ((cp = strstr(start, "Vendor=")))
172 vendor = strtoul(cp + 7, NULL, 16);
175 if ((cp = strstr(start, "ProdID=")))
176 prodid = strtoul(cp + 7, NULL, 16);
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");
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);
192 bus->flags &= ~USBFLG_DELETED;
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;
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);
207 if (!(dev2 = devtree_finddevice(bus, parentdevnum)))
208 lprintf(0, "Bus %d Device %d Parent Device %d not found\n", busnum, devnum, parentdevnum);
210 list_add_tail(&dev->list, &dev2->childlist);
213 dev->flags &= ~USBFLG_DELETED;
221 printf("line: %s\n", start);
227 /* ---------------------------------------------------------------------- */
229 static void deletetree(struct list_head *list, unsigned int force)
231 struct usbdevnode *dev;
232 struct list_head *list2;
234 for (list2 = list->next; list2 != list;) {
235 dev = list_entry(list2, struct usbdevnode, list);
237 deletetree(&dev->childlist,
238 force || dev->flags & USBFLG_DELETED);
239 if (!force && !(dev->flags & USBFLG_DELETED))
241 list_del(&dev->list);
242 INIT_LIST_HEAD(&dev->list);
243 devtree_devdisconnect(dev);
248 static void newtree(struct list_head *list)
250 struct usbdevnode *dev;
251 struct list_head *list2;
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);
262 void devtree_processchanges(void)
264 struct list_head *list;
265 struct usbbusnode *bus;
267 for (list = usbbuslist.next; list != &usbbuslist;) {
268 bus = list_entry(list, struct usbbusnode, list);
270 deletetree(&bus->childlist, bus->flags & USBFLG_DELETED);
271 if (!(bus->flags & USBFLG_DELETED))
273 list_del(&bus->list);
274 INIT_LIST_HEAD(&bus->list);
275 devtree_busdisconnect(bus);
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);
287 /* ---------------------------------------------------------------------- */
289 static void dumpdevlist(struct list_head *list, unsigned int level,
290 unsigned int mask, unsigned int verblevel)
292 struct usbdevnode *dev;
293 struct list_head *list2;
300 for (list2 = list->next; list2 != list; ) {
301 dev = list_entry(list2, struct usbdevnode, list);
303 for (cp = buf, i = 0; i < level; i++) {
304 *cp++ = (mask & (1 << i)) ? '|' : ' ';
308 mask |= (1 << level);
311 mask &= ~(1 << level);
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);
322 snprintf(cp, buf + sizeof(buf) - cp,
323 "Dev# %3d Vendor 0x%04x Product 0x%04x",
324 dev->devnum, dev->vendorid, dev->productid);
326 lprintf(1, "%s\n", buf);
327 dumpdevlist(&dev->childlist, level+1, mask, verblevel);
331 void devtree_dump(unsigned int verblevel)
333 struct list_head *list;
334 struct usbbusnode *bus;
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);
339 dumpdevlist(&bus->childlist, 0, 0, verblevel);