15 #define MY_SYSFS_FILENAME_LEN 255
16 #define MY_PATH_MAX 4096
17 #define MY_PARAM_MAX 64
20 struct list_head list;
21 struct usbinterface *next;
22 struct usbdevice *parent;
23 unsigned int configuration;
26 unsigned int bAlternateSetting;
27 unsigned int bInterfaceClass;
28 unsigned int bInterfaceNumber;
29 unsigned int bInterfaceProtocol;
30 unsigned int bInterfaceSubClass;
31 unsigned int bNumEndpoints;
33 char name[MY_SYSFS_FILENAME_LEN];
34 char driver[MY_SYSFS_FILENAME_LEN];
38 struct list_head list; /* connect devices independant of the bus */
39 struct usbdevice *next; /* next port on this hub */
40 struct usbinterface *first_interface; /* list of interfaces */
41 struct usbdevice *first_child; /* connect devices on this port */
42 struct usbdevice *parent; /* hub this device is connected to */
44 unsigned int parent_portnum;
47 unsigned int bConfigurationValue;
48 unsigned int bDeviceClass;
49 unsigned int bDeviceProtocol;
50 unsigned int bDeviceSubClass;
51 unsigned int bMaxPacketSize0;
52 char bMaxPower[MY_PARAM_MAX];
53 unsigned int bNumConfigurations;
54 unsigned int bNumInterfaces;
55 unsigned int bcdDevice;
56 unsigned int bmAttributes;
57 unsigned int configuration;
59 unsigned int idProduct;
60 unsigned int idVendor;
61 unsigned int maxchild;
62 char manufacturer[MY_PARAM_MAX];
63 char product[MY_PARAM_MAX];
64 char serial[MY_PARAM_MAX];
65 char version[MY_PARAM_MAX];
66 char speed[MY_PARAM_MAX]; /* '1.5','12','480','5000' + '\n' */
68 char name[MY_SYSFS_FILENAME_LEN];
69 char driver[MY_SYSFS_FILENAME_LEN];
73 struct usbbusnode *next;
74 struct usbinterface *first_interface; /* list of interfaces */
75 struct usbdevice *first_child; /* connect childs belonging to this bus */
78 unsigned int bDeviceClass;
80 unsigned int maxchild;
81 char speed[5 + 1]; /* '1.5','12','480','5000' + '\n' */
83 char driver[MY_SYSFS_FILENAME_LEN];
86 #define SYSFS_INTu(de,tgt, name) do { tgt->name = read_sysfs_file_int(de,#name,10); } while(0)
87 #define SYSFS_INTx(de,tgt, name) do { tgt->name = read_sysfs_file_int(de,#name,16); } while(0)
88 #define SYSFS_STR(de,tgt, name) do { read_sysfs_file_string(de, #name, tgt->name, MY_PARAM_MAX); } while(0)
90 LIST_HEAD(interfacelist);
91 LIST_HEAD(usbdevlist);
92 static struct usbbusnode *usbbuslist;
94 static const char sys_bus_usb_devices[] = "/sys/bus/usb/devices";
98 static void dump_usbbusnode(struct usbbusnode *b)
100 printf(" B %p:'%u': n %p fi %p fc %p driver '%s'\n", b, b->busnum, b->next, b->first_interface, b->first_child, b->driver);
103 static void dump_usbdevice(struct usbdevice *d)
106 (" D %p:'%s': n %p fi %p fc %p bn %u ppn %u pn %u p %p bCV %u bDC %02x bDP %02x bDSC %02x bMPS %02x bMP '%s' bNC %u bNI %u bcdD %02x bmA %02x c %u dn %u idP %04x idV %04x mc %u m '%s' p '%s' s '%s' v '%s' sp '%s' driver '%s'\n",
107 d, d->name, d->next, d->first_interface, d->first_child, d->busnum, d->parent_portnum, d->portnum, d->parent, d->bConfigurationValue, d->bDeviceClass,
108 d->bDeviceProtocol, d->bDeviceSubClass, d->bMaxPacketSize0, d->bMaxPower, d->bNumConfigurations, d->bNumInterfaces, d->bcdDevice, d->bmAttributes,
109 d->configuration, d->devnum, d->idProduct, d->idVendor, d->maxchild, d->manufacturer, d->product, d->serial, d->version, d->speed, d->driver);
112 static void dump_usbinterface(struct usbinterface *i)
114 printf(" I %p:'%s': n %p c %u if %u bAS %u bIC %02x bIN %02x bIP %02x bISC %02x bNE %u d '%s'\n", i, i->name, i->next, i->configuration, i->ifnum,
115 i->bAlternateSetting, i->bInterfaceClass, i->bInterfaceNumber, i->bInterfaceProtocol, i->bInterfaceSubClass, i->bNumEndpoints, i->driver);
119 static char tmp_str[128];
120 static const char *bInterfaceClass_to_str(unsigned int dc)
167 snprintf(tmp_str, 128, "'bInterfaceClass 0x%02x not yet handled'", dc);;
172 static const char *bDeviceClass_to_str(unsigned int dc)
180 snprintf(tmp_str, 128, "'bDeviceClass 0x%02x not yet handled'", dc);;
185 static void print_usbbusnode(struct usbbusnode *b)
187 printf("/: Bus %02u.Port %u: Dev %u, Class=%s, Driver=%s/%up, %sM\n", b->busnum, 1,
188 b->devnum, bDeviceClass_to_str(b->bDeviceClass), b->driver, b->maxchild, b->speed);
191 static void print_usbdevice(struct usbdevice *d, struct usbinterface *i)
193 if (i->bInterfaceClass == 9)
194 printf("Port %u: Dev %u, If %u, Class=%s, Driver=%s/%up, %sM\n", d->portnum, d->devnum, i->ifnum, bInterfaceClass_to_str(i->bInterfaceClass),
195 i->driver, d->maxchild, d->speed);
197 printf("Port %u: Dev %u, If %u, Class=%s, Driver=%s, %sM\n", d->portnum, d->devnum, i->ifnum, bInterfaceClass_to_str(i->bInterfaceClass), i->driver,
201 static unsigned int read_sysfs_file_int(const char *d_name, const char *file, int base)
203 char buf[12], path[MY_PATH_MAX];
207 snprintf(path, MY_PATH_MAX, "%s/%s/%s", sys_bus_usb_devices, d_name, file);
208 path[MY_PATH_MAX - 1] = '\0';
209 fd = open(path, O_RDONLY);
212 memset(buf, 0, sizeof(buf));
213 r = read(fd, buf, sizeof(buf) - 1);
217 buf[sizeof(buf) - 1] = '\0';
218 ret = strtoul(buf, NULL, base);
219 return (unsigned int)ret;
226 static void read_sysfs_file_string(const char *d_name, const char *file, char *buf, int len)
228 char path[MY_PATH_MAX];
231 fd = snprintf(path, MY_PATH_MAX, "%s/%s/%s", sys_bus_usb_devices, d_name, file);
232 if (fd < 0 || fd >= MY_PATH_MAX)
235 fd = open(path, O_RDONLY);
238 r = read(fd, buf, len);
240 if (r > 0 && r < len) {
243 while (buf[r] == '\n') {
258 static void append_dev_interface(struct usbinterface *i, struct usbinterface *new)
265 static void append_dev_sibling(struct usbdevice *d, struct usbdevice *new)
272 static void append_businterface(unsigned int busnum, struct usbinterface *new)
274 struct usbbusnode *b = usbbuslist;
275 struct usbinterface *i;
277 if (b->busnum == busnum) {
278 i = b->first_interface;
284 b->first_interface = new;
291 static void append_busnode(struct usbbusnode *new)
293 struct usbbusnode *b = usbbuslist;
302 static void add_usb_interface(const char *d_name)
304 struct usbinterface *e;
306 char *pn, driver[MY_PATH_MAX];
309 p = strchr(d_name, ':');
311 i = strtoul(p, &pn, 10);
314 e = malloc(sizeof(struct usbinterface));
317 memset(e, 0, sizeof(struct usbinterface));
318 e->configuration = i;
320 i = strtoul(p, &pn, 10);
327 if (snprintf(e->name, MY_SYSFS_FILENAME_LEN, "%s", d_name) >= MY_SYSFS_FILENAME_LEN)
328 printf("warning: '%s' truncated to '%s'\n", e->name, d_name);
329 SYSFS_INTu(d_name, e, bAlternateSetting);
330 SYSFS_INTx(d_name, e, bInterfaceClass);
331 SYSFS_INTx(d_name, e, bInterfaceNumber);
332 SYSFS_INTx(d_name, e, bInterfaceProtocol);
333 SYSFS_INTx(d_name, e, bInterfaceSubClass);
334 SYSFS_INTx(d_name, e, bNumEndpoints);
335 l = snprintf(driver, MY_PATH_MAX, "%s/%s/driver", sys_bus_usb_devices, d_name);
336 if (l > 0 && l < MY_PATH_MAX) {
337 l = readlink(driver, driver, MY_PATH_MAX);
341 if (l < MY_PATH_MAX - 1)
345 p = strrchr(driver, '/');
347 snprintf(e->driver, sizeof(e->driver), "%s", p + 1);
350 printf("Can not read driver link for '%s': %d\n", d_name, l);
351 list_add_tail(&e->list, &interfacelist);
354 static void add_usb_device(const char *d_name)
358 char *pn, driver[MY_PATH_MAX];
362 i = strtoul(p, &pn, 10);
365 d = malloc(sizeof(struct usbdevice));
368 memset(d, 0, sizeof(struct usbdevice));
372 i = strtoul(p, &pn, 10);
375 d->parent_portnum = d->portnum;
378 if (snprintf(d->name, MY_SYSFS_FILENAME_LEN, "%s", d_name) >= MY_SYSFS_FILENAME_LEN)
379 printf("warning: '%s' truncated to '%s'\n", d->name, d_name);
380 SYSFS_INTu(d_name, d, bConfigurationValue);
381 SYSFS_INTx(d_name, d, bDeviceClass);
382 SYSFS_INTx(d_name, d, bDeviceProtocol);
383 SYSFS_INTx(d_name, d, bDeviceSubClass);
384 SYSFS_INTx(d_name, d, bMaxPacketSize0);
385 SYSFS_STR(d_name, d, bMaxPower);
386 SYSFS_INTu(d_name, d, bNumConfigurations);
387 SYSFS_INTx(d_name, d, bNumInterfaces);
388 SYSFS_INTx(d_name, d, bcdDevice);
389 SYSFS_INTx(d_name, d, bmAttributes);
390 SYSFS_INTu(d_name, d, configuration);
391 SYSFS_INTu(d_name, d, devnum);
392 SYSFS_INTx(d_name, d, idProduct);
393 SYSFS_INTx(d_name, d, idVendor);
394 SYSFS_INTu(d_name, d, maxchild);
395 SYSFS_STR(d_name, d, manufacturer);
396 SYSFS_STR(d_name, d, product);
397 SYSFS_STR(d_name, d, serial);
398 SYSFS_STR(d_name, d, version);
399 SYSFS_STR(d_name, d, speed);
400 l = snprintf(driver, MY_PATH_MAX, "%s/%s/driver", sys_bus_usb_devices, d_name);
401 if (l > 0 && l < MY_PATH_MAX) {
402 l = readlink(driver, driver, MY_PATH_MAX);
406 if (l < MY_PATH_MAX - 1)
410 p = strrchr(driver, '/');
412 snprintf(d->driver, sizeof(d->driver), "%s", p + 1);
415 printf("Can not read driver link for '%s': %d\n", d_name, l);
416 list_add_tail(&d->list, &usbdevlist);
419 static void get_roothub_driver(struct usbbusnode *b, const char *d_name)
421 char *p, path[MY_PATH_MAX];
423 l = snprintf(path, MY_PATH_MAX, "%s/%s/../driver", sys_bus_usb_devices, d_name);
424 if (l > 0 && l < MY_PATH_MAX) {
425 l = readlink(path, path, MY_PATH_MAX);
429 if (l < MY_PATH_MAX - 1)
433 p = strrchr(path, '/');
435 snprintf(b->driver, sizeof(b->driver), "%s", p + 1);
438 printf("Can not read driver link for '%s': %d\n", d_name, l);
441 static void add_usb_bus(const char *d_name)
443 struct usbbusnode *bus;
444 bus = malloc(sizeof(struct usbbusnode));
446 memset(bus, 0, sizeof(struct usbbusnode));
447 bus->busnum = strtoul(d_name + 3, NULL, 10);
448 SYSFS_INTu(d_name, bus, devnum);
449 SYSFS_INTx(d_name, bus, bDeviceClass);
450 SYSFS_INTu(d_name, bus, maxchild);
451 SYSFS_STR(d_name, bus, speed);
453 get_roothub_driver(bus, d_name);
457 static void inspect_bus_entry(const char *d_name)
459 if (d_name[0] == '.' && (!d_name[1] || (d_name[1] == '.' && !d_name[2])))
461 if (d_name[0] == 'u' && d_name[1] == 's' && d_name[2] == 'b' && isdigit(d_name[3])) {
463 } else if (isdigit(d_name[0])) {
464 if (strchr(d_name, ':'))
465 add_usb_interface(d_name);
467 add_usb_device(d_name);
469 fprintf(stderr, "ignoring '%s'\n", d_name);
472 static void walk_usb_devices(DIR * sbud)
475 while ((de = readdir(sbud)))
476 inspect_bus_entry(de->d_name);
479 static void assign_dev_to_bus(struct usbdevice *d)
481 struct usbbusnode *b = usbbuslist;
483 if (b->busnum == d->busnum) {
485 append_dev_sibling(b->first_child, d);
493 static void assign_dev_to_parent(struct usbdevice *d)
496 struct usbdevice *pd;
497 char n[MY_SYSFS_FILENAME_LEN], *p;
498 for (l = usbdevlist.next; l != &usbdevlist; l = l->next) {
499 pd = list_entry(l, struct usbdevice, list);
502 if (pd->busnum == d->busnum && pd->portnum == d->parent_portnum) {
507 if (strcmp(n, pd->name)) {
512 append_dev_sibling(pd->first_child, d);
521 static void assign_interface_to_parent(struct usbdevice *d, struct usbinterface *i)
524 char *pn, name[MY_SYSFS_FILENAME_LEN];
528 p = strchr(i->name, ':');
531 if (l < MY_SYSFS_FILENAME_LEN) {
532 memcpy(name, i->name, l);
536 if (strcmp(d->name, name) == 0) {
538 if (d->first_interface)
539 append_dev_interface(d->first_interface, i);
541 d->first_interface = i;
543 busnum = strtoul(name, &pn, 10);
544 if (pn && pn != name) {
546 append_businterface(busnum, i);
552 static void connect_devices(void)
554 struct list_head *ld, *li;
556 struct usbinterface *e;
557 for (ld = usbdevlist.next; ld != &usbdevlist; ld = ld->next) {
558 d = list_entry(ld, struct usbdevice, list);
559 if (d->parent_portnum)
560 assign_dev_to_parent(d);
562 assign_dev_to_bus(d);
563 for (li = interfacelist.next; li != &interfacelist; li = li->next) {
564 e = list_entry(li, struct usbinterface, list);
566 assign_interface_to_parent(d, e);
569 for (li = interfacelist.next; li != &interfacelist; li = li->next) {
570 e = list_entry(li, struct usbinterface, list);
574 static void sort_dev_interfaces(struct usbinterface **i)
576 struct usbinterface *t, *p, **pp;
585 if (p->configuration > p->next->configuration) {
593 if (p->ifnum > p->next->ifnum) {
607 static void sort_dev_siblings(struct usbdevice **d)
609 struct usbdevice *t, *p, **pp;
614 sort_dev_siblings(&p->first_child);
615 if (p->first_interface)
616 sort_dev_interfaces(&p->first_interface);
622 if (p->portnum > p->next->portnum) {
636 static void sort_devices(void)
638 struct usbbusnode *b = usbbuslist;
641 sort_dev_siblings(&b->first_child);
646 static void sort_busses(void)
648 /* need to reverse sort bus numbers */
649 struct usbbusnode *t, *p, **pp;
656 if (p->busnum < p->next->busnum) {
670 static void print_tree_dev_interface(struct usbdevice *d, struct usbinterface *i)
674 printf(" %*s", indent, "|__ ");
675 print_usbdevice(d, i);
680 static void print_tree_dev_children(struct usbdevice *d)
684 print_tree_dev_interface(d, d->first_interface);
685 print_tree_dev_children(d->first_child);
691 static void print_tree(void)
693 struct usbbusnode *b = usbbuslist;
697 print_tree_dev_children(b->first_child);
704 DIR *sbud = opendir(sys_bus_usb_devices);
706 walk_usb_devices(sbud);
713 perror(sys_bus_usb_devices);