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.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Please note that the GPL allows you to use the driver, NOT the radio.
23 * In order to use the radio, you need a license from the communications
24 * authority of your country.
28 /*****************************************************************************/
34 #include <sys/types.h>
43 /* ---------------------------------------------------------------------- */
45 LIST_HEAD(usbbuslist);
47 /* ---------------------------------------------------------------------- */
49 static void freedev(struct usbdevnode *dev)
54 static void freebus(struct usbbusnode *bus)
59 /* ---------------------------------------------------------------------- */
61 static void markdel(struct list_head *list)
63 struct usbdevnode *dev;
64 struct list_head *list2;
66 for (list2 = list->next; list2 != list; list2 = list2->next) {
67 dev = list_entry(list2, struct usbdevnode, list);
68 dev->flags |= USBFLG_DELETED;
69 markdel(&dev->childlist);
73 void devtree_markdeleted(void)
75 struct usbbusnode *bus;
76 struct list_head *list;
78 for(list = usbbuslist.next; list != &usbbuslist; list = list->next) {
79 bus = list_entry(list, struct usbbusnode, list);
80 markdel(&bus->childlist);
84 struct usbbusnode *devtree_findbus(unsigned int busn)
86 struct usbbusnode *bus;
87 struct list_head *list;
89 for(list = usbbuslist.next; list != &usbbuslist; list = list->next) {
90 bus = list_entry(list, struct usbbusnode, list);
91 if (bus->busnum == busn)
97 static struct usbdevnode *findsubdevice(struct list_head *list, unsigned int devn)
99 struct usbdevnode *dev, *dev2;
100 struct list_head *list2;
102 for (list2 = list->next; list2 != list; list2 = list2->next) {
103 dev = list_entry(list2, struct usbdevnode, list);
104 if (dev->devnum == devn)
106 dev2 = findsubdevice(&dev->childlist, devn);
113 struct usbdevnode *devtree_finddevice(struct usbbusnode *bus, unsigned int devn)
115 return findsubdevice(&bus->childlist, devn);
118 /* ---------------------------------------------------------------------- */
120 void devtree_parsedevfile(int fd)
123 char *start, *end, *lineend, *cp;
125 unsigned int devnum = 0, busnum = 0, parentdevnum = 0, level = 0;
126 unsigned int class = 0xff, vendor = 0xffff, prodid = 0xffff, speed = 0;
127 struct usbbusnode *bus;
128 struct usbdevnode *dev, *dev2;
130 devtree_markdeleted();
131 if (lseek(fd, 0, SEEK_SET) == (off_t)-1)
132 lprintf(0, "lseek: %s (%d)\n", strerror(errno), errno);
133 ret = read(fd, buf, sizeof(buf)-1);
135 lprintf(0, "read: %s (%d)\n", strerror(errno), errno);
139 while (start < end) {
140 lineend = strchr(start, '\n');
145 case 'T': /* topology line */
146 if ((cp = strstr(start, "Dev#="))) {
147 devnum = strtoul(cp + 5, NULL, 0);
150 if ((cp = strstr(start, "Bus="))) {
151 busnum = strtoul(cp + 4, NULL, 10);
154 if ((cp = strstr(start, "Prnt="))) {
155 parentdevnum = strtoul(cp + 5, NULL, 10);
158 if ((cp = strstr(start, "Lev="))) {
159 level = strtoul(cp + 4, NULL, 10);
162 if (strstr(start, "Spd=1.5"))
164 else if (strstr(start, "Spd=12"))
171 if ((cp = strstr(start, "Cls="))) {
172 class = strtoul(cp + 4, NULL, 16);
178 if ((cp = strstr(start, "Vendor="))) {
179 vendor = strtoul(cp + 7, NULL, 16);
182 if ((cp = strstr(start, "ProdID="))) {
183 prodid = strtoul(cp + 7, NULL, 16);
188 printf("Device %3d Vendor %04x Product ID %04x Class %02x Speed %s\n",
189 devnum, vendor, prodid, class, speed == 2 ? "12 MBPS" : speed == 1 ? "1.5 MBPS" : "unknown");
191 if (!(bus = devtree_findbus(busnum))) {
192 if (!(bus = malloc(sizeof(struct usbbusnode))))
193 lprintf(0, "Out of memory\n");
194 bus->busnum = busnum;
195 bus->flags = USBFLG_NEW;
196 INIT_LIST_HEAD(&bus->childlist);
197 list_add_tail(&bus->list, &usbbuslist);
199 bus->flags &= ~USBFLG_DELETED;
201 if (!(dev = devtree_finddevice(bus, devnum)) || dev->vendorid != vendor || dev->productid != prodid) {
202 if (!(dev = malloc(sizeof(struct usbdevnode))))
203 lprintf(0, "Out of memory\n");
204 dev->devnum = devnum;
205 dev->flags = USBFLG_NEW;
207 dev->vendorid = vendor;
208 dev->productid = prodid;
209 INIT_LIST_HEAD(&dev->childlist);
210 if (level == 0 && parentdevnum == 0) {
211 list_add_tail(&dev->list, &bus->childlist);
214 if (!(dev2 = devtree_finddevice(bus, parentdevnum)))
215 lprintf(0, "Bus %d Device %d Parent Device %d not found\n", busnum, devnum, parentdevnum);
217 list_add_tail(&dev->list, &dev2->childlist);
220 dev->flags &= ~USBFLG_DELETED;
228 printf("line: %s\n", start);
234 /* ---------------------------------------------------------------------- */
236 static void deletetree(struct list_head *list, unsigned int force)
238 struct usbdevnode *dev;
239 struct list_head *list2;
241 for (list2 = list->next; list2 != list;) {
242 dev = list_entry(list2, struct usbdevnode, list);
244 deletetree(&dev->childlist, force || dev->flags & USBFLG_DELETED);
245 if (!force && !(dev->flags & USBFLG_DELETED))
247 list_del(&dev->list);
248 INIT_LIST_HEAD(&dev->list);
249 devtree_devdisconnect(dev);
254 static void newtree(struct list_head *list)
256 struct usbdevnode *dev;
257 struct list_head *list2;
259 for (list2 = list->next; list2 != list; list2 = list2->next) {
260 dev = list_entry(list2, struct usbdevnode, list);
261 if (dev->flags & USBFLG_NEW)
262 devtree_devconnect(dev);
263 dev->flags &= ~USBFLG_NEW;
264 newtree(&dev->childlist);
268 void devtree_processchanges(void)
270 struct list_head *list;
271 struct usbbusnode *bus;
273 for (list = usbbuslist.next; list != &usbbuslist;) {
274 bus = list_entry(list, struct usbbusnode, list);
276 deletetree(&bus->childlist, bus->flags & USBFLG_DELETED);
277 if (!(bus->flags & USBFLG_DELETED))
279 list_del(&bus->list);
280 INIT_LIST_HEAD(&bus->list);
281 devtree_busdisconnect(bus);
284 for (list = usbbuslist.next; list != &usbbuslist; list = list->next) {
285 bus = list_entry(list, struct usbbusnode, list);
286 if (bus->flags & USBFLG_NEW)
287 devtree_busconnect(bus);
288 bus->flags &= ~USBFLG_NEW;
289 newtree(&bus->childlist);
293 /* ---------------------------------------------------------------------- */
295 static void dumpdevlist(struct list_head *list, unsigned int level, unsigned int mask)
297 struct usbdevnode *dev;
298 struct list_head *list2;
303 for (list2 = list->next; list2 != list; ) {
304 dev = list_entry(list2, struct usbdevnode, list);
306 for (cp = buf, i = 0; i < level; i++) {
307 *cp++ = (mask & (1 << i)) ? '|' : ' ';
311 mask |= (1 << level);
314 mask &= ~(1 << level);
318 snprintf(cp, buf + sizeof(buf) - cp, "Dev# %3d Vendor 0x%04x Product 0x%04x",
319 dev->devnum, dev->vendorid, dev->productid);
320 lprintf(1, "%s\n", buf);
321 dumpdevlist(&dev->childlist, level+1, mask);
325 void devtree_dump(void)
327 struct list_head *list;
328 struct usbbusnode *bus;
330 for (list = usbbuslist.next; list != &usbbuslist; list = list->next) {
331 bus = list_entry(list, struct usbbusnode, list);
332 lprintf(1, "Bus# %2d\n", bus->busnum);
333 dumpdevlist(&bus->childlist, 0, 0);