upload tizen2.0 source
[framework/system/usbutils.git] / devtree.c
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  *      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.
21  *
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.
25  *
26  */
27
28 /*****************************************************************************/
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <sys/types.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "devtree.h"
42
43 /* ---------------------------------------------------------------------- */
44
45 LIST_HEAD(usbbuslist);
46
47 /* ---------------------------------------------------------------------- */
48
49 static void freedev(struct usbdevnode *dev)
50 {
51         free(dev);
52 }
53
54 static void freebus(struct usbbusnode *bus)
55 {
56         free(bus);
57 }
58
59 /* ---------------------------------------------------------------------- */
60
61 static void markdel(struct list_head *list)
62 {
63         struct usbdevnode *dev;
64         struct list_head *list2;
65
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);
70         }
71 }
72
73 void devtree_markdeleted(void)
74 {
75         struct usbbusnode *bus;
76         struct list_head *list;
77         
78         for(list = usbbuslist.next; list != &usbbuslist; list = list->next) {
79                 bus = list_entry(list, struct usbbusnode, list);
80                 markdel(&bus->childlist);
81         }
82 }
83
84 struct usbbusnode *devtree_findbus(unsigned int busn)
85 {
86         struct usbbusnode *bus;
87         struct list_head *list;
88         
89         for(list = usbbuslist.next; list != &usbbuslist; list = list->next) {
90                 bus = list_entry(list, struct usbbusnode, list);
91                 if (bus->busnum == busn)
92                         return bus;
93         }
94         return NULL;
95 }
96
97 static struct usbdevnode *findsubdevice(struct list_head *list, unsigned int devn)
98 {
99         struct usbdevnode *dev, *dev2;
100         struct list_head *list2;
101
102         for (list2 = list->next; list2 != list; list2 = list2->next) {
103                 dev = list_entry(list2, struct usbdevnode, list);
104                 if (dev->devnum == devn)
105                         return dev;
106                 dev2 = findsubdevice(&dev->childlist, devn);
107                 if (dev2)
108                         return dev2;
109         }
110         return NULL;
111 }
112
113 struct usbdevnode *devtree_finddevice(struct usbbusnode *bus, unsigned int devn)
114 {
115         return findsubdevice(&bus->childlist, devn);
116 }
117
118 /* ---------------------------------------------------------------------- */
119
120 void devtree_parsedevfile(int fd)
121 {
122         char buf[16384];
123         char *start, *end, *lineend, *cp;
124         int ret;
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;
129
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);
134         if (ret == -1)
135                 lprintf(0, "read: %s (%d)\n", strerror(errno), errno);
136         end = buf + ret;
137         *end = 0;
138         start = buf;
139         while (start < end) {
140                 lineend = strchr(start, '\n');
141                 if (!lineend)
142                         break;
143                 *lineend = 0;
144                 switch (start[0]) {
145                 case 'T':  /* topology line */
146                         if ((cp = strstr(start, "Dev#="))) {
147                                 devnum = strtoul(cp + 5, NULL, 0);
148                         } else
149                                 devnum = 0;
150                         if ((cp = strstr(start, "Bus="))) {
151                                 busnum = strtoul(cp + 4, NULL, 10);
152                         } else
153                                 busnum = 0;
154                         if ((cp = strstr(start, "Prnt="))) {
155                                 parentdevnum = strtoul(cp + 5, NULL, 10);
156                         } else
157                                 parentdevnum = 0;
158                         if ((cp = strstr(start, "Lev="))) {
159                                 level = strtoul(cp + 4, NULL, 10);
160                         } else
161                                 level = 0;
162                         if (strstr(start, "Spd=1.5"))
163                                 speed = 1;
164                         else if (strstr(start, "Spd=12"))
165                                 speed = 2;
166                         else 
167                                 speed = 0;
168                         break;
169
170                 case 'D':
171                         if ((cp = strstr(start, "Cls="))) {
172                                 class = strtoul(cp + 4, NULL, 16);
173                         } else
174                                 class = 0xff;
175                         break;
176
177                 case 'P':
178                         if ((cp = strstr(start, "Vendor="))) {
179                                 vendor = strtoul(cp + 7, NULL, 16);
180                         } else
181                                 vendor = 0xffff;
182                         if ((cp = strstr(start, "ProdID="))) {
183                                 prodid = strtoul(cp + 7, NULL, 16);
184                         } else
185                                 prodid = 0xffff;
186                         /* print device */
187 #if 0
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");
190 #endif
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);
198                         } else {
199                                 bus->flags &= ~USBFLG_DELETED;
200                         }
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;
206                                 dev->bus = bus;
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);
212                                         dev->parent = NULL;
213                                 } else {
214                                         if (!(dev2 = devtree_finddevice(bus, parentdevnum)))
215                                                 lprintf(0, "Bus %d Device %d Parent Device %d not found\n", busnum, devnum, parentdevnum);
216                                         dev->parent = dev2;
217                                         list_add_tail(&dev->list, &dev2->childlist);
218                                 }
219                         } else {
220                                 dev->flags &= ~USBFLG_DELETED;
221                         }
222                         break;
223
224                 default:
225                         break;
226                 }
227 #if 0
228                 printf("line: %s\n", start);
229 #endif
230                 start = lineend + 1;
231         }
232 }
233
234 /* ---------------------------------------------------------------------- */
235
236 static void deletetree(struct list_head *list, unsigned int force)
237 {
238         struct usbdevnode *dev;
239         struct list_head *list2;
240
241         for (list2 = list->next; list2 != list;) {
242                 dev = list_entry(list2, struct usbdevnode, list);
243                 list2 = list2->next;
244                 deletetree(&dev->childlist, force || dev->flags & USBFLG_DELETED);
245                 if (!force && !(dev->flags & USBFLG_DELETED))
246                         continue;
247                 list_del(&dev->list);
248                 INIT_LIST_HEAD(&dev->list);
249                 devtree_devdisconnect(dev);
250                 freedev(dev);
251         }
252 }
253
254 static void newtree(struct list_head *list)
255 {
256         struct usbdevnode *dev;
257         struct list_head *list2;
258
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);
265         }
266 }
267
268 void devtree_processchanges(void)
269 {
270         struct list_head *list;
271         struct usbbusnode *bus;
272
273         for (list = usbbuslist.next; list != &usbbuslist;) {
274                 bus = list_entry(list, struct usbbusnode, list);
275                 list = list->next;
276                 deletetree(&bus->childlist, bus->flags & USBFLG_DELETED);
277                 if (!(bus->flags & USBFLG_DELETED))
278                         continue;
279                 list_del(&bus->list);
280                 INIT_LIST_HEAD(&bus->list);
281                 devtree_busdisconnect(bus);
282                 freebus(bus);
283         }
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);
290         }
291 }
292
293 /* ---------------------------------------------------------------------- */
294
295 static void dumpdevlist(struct list_head *list, unsigned int level, unsigned int mask)
296 {
297         struct usbdevnode *dev;
298         struct list_head *list2;
299         char buf[512];
300         char *cp;
301         unsigned int i;
302
303         for (list2 = list->next; list2 != list; ) {
304                 dev = list_entry(list2, struct usbdevnode, list);
305                 list2 = list2->next;
306                 for (cp = buf, i = 0; i < level; i++) {
307                         *cp++ = (mask & (1 << i)) ? '|' : ' ';
308                         *cp++ = ' ';
309                 }
310                 if (list2 != list) {
311                         mask |= (1 << level);
312                         *cp++ = '|';
313                 } else {
314                         mask &= ~(1 << level);
315                         *cp++ = '`';
316                 }
317                 *cp++ = '-';
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);
322         }
323 }
324
325 void devtree_dump(void)
326 {
327         struct list_head *list;
328         struct usbbusnode *bus;
329
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);
334         }
335 }