"Fossies" - the Fresh Open Source Software Archive

Member "usbutils-014/lsusb-t.c" (4 Aug 2021, 18412 Bytes) of package /linux/misc/usbutils-014.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "lsusb-t.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 013_vs_014.

    1 // SPDX-License-Identifier: GPL-2.0-only
    2 /* Copyright (c) 2009 Greg Kroah-Hartman <gregkh@suse.de> */
    3 #include <stdint.h>
    4 #include <sys/stat.h>
    5 #include <fcntl.h>
    6 #include <dirent.h>
    7 #include <string.h>
    8 #include <ctype.h>
    9 #include <stdlib.h>
   10 #include <stdio.h>
   11 #include <unistd.h>
   12 #include <stddef.h>
   13 
   14 #include "list.h"
   15 #include "lsusb.h"
   16 #include "names.h"
   17 
   18 #define MY_SYSFS_FILENAME_LEN 255
   19 #define MY_PATH_MAX 4096
   20 #define MY_PARAM_MAX 64
   21 
   22 struct usbinterface {
   23     struct list_head list;
   24     struct usbinterface *next;
   25     struct usbdevice *parent;
   26     unsigned int configuration;
   27     unsigned int ifnum;
   28 
   29     unsigned int bAlternateSetting;
   30     unsigned int bInterfaceClass;
   31     unsigned int bInterfaceNumber;
   32     unsigned int bInterfaceProtocol;
   33     unsigned int bInterfaceSubClass;
   34     unsigned int bNumEndpoints;
   35 
   36     char name[MY_SYSFS_FILENAME_LEN];
   37     char driver[MY_SYSFS_FILENAME_LEN];
   38 };
   39 
   40 struct usbdevice {
   41     struct list_head list;  /* connect devices independent of the bus */
   42     struct usbdevice *next; /* next port on this hub */
   43     struct usbinterface *first_interface;   /* list of interfaces */
   44     struct usbdevice *first_child;  /* connect devices on this port */
   45     struct usbdevice *parent;   /* hub this device is connected to */
   46     unsigned int busnum;
   47     unsigned int parent_portnum;
   48     unsigned int portnum;
   49 
   50     unsigned int bConfigurationValue;
   51     unsigned int bDeviceClass;
   52     unsigned int bDeviceProtocol;
   53     unsigned int bDeviceSubClass;
   54     unsigned int bMaxPacketSize0;
   55     char bMaxPower[MY_PARAM_MAX];
   56     unsigned int bNumConfigurations;
   57     unsigned int bNumInterfaces;
   58     unsigned int bcdDevice;
   59     unsigned int bmAttributes;
   60     unsigned int configuration;
   61     unsigned int devnum;
   62     unsigned int idProduct;
   63     unsigned int idVendor;
   64     unsigned int maxchild;
   65     char manufacturer[MY_PARAM_MAX];
   66     char product[MY_PARAM_MAX];
   67     char serial[MY_PARAM_MAX];
   68     char version[MY_PARAM_MAX];
   69     char speed[MY_PARAM_MAX];   /* '1.5','12','480','5000' + '\n' */
   70     unsigned int rx_lanes;
   71     unsigned int tx_lanes;
   72 
   73     char name[MY_SYSFS_FILENAME_LEN];
   74     char driver[MY_SYSFS_FILENAME_LEN];
   75 };
   76 
   77 struct usbbusnode {
   78     struct usbbusnode *next;
   79     struct usbinterface *first_interface;   /* list of interfaces */
   80     struct usbdevice *first_child;  /* connect children belonging to this bus */
   81     unsigned int busnum;
   82 
   83     unsigned int bDeviceClass;
   84     unsigned int devnum;
   85     unsigned int idProduct;
   86     unsigned int idVendor;
   87     unsigned int maxchild;
   88     char speed[5 + 1];  /* '1.5','12','480','5000' + '\n' */
   89     unsigned int rx_lanes;
   90     unsigned int tx_lanes;
   91 
   92     char name[MY_SYSFS_FILENAME_LEN];
   93     char driver[MY_SYSFS_FILENAME_LEN];
   94 };
   95 
   96 #define SYSFS_INTu(de,tgt, name) do { tgt->name = read_sysfs_file_int(de,#name,10); } while(0)
   97 #define SYSFS_INTx(de,tgt, name) do { tgt->name = read_sysfs_file_int(de,#name,16); } while(0)
   98 #define SYSFS_STR(de,tgt, name) do { read_sysfs_file_string(de, #name, tgt->name, MY_PARAM_MAX); } while(0)
   99 
  100 LIST_HEAD(interfacelist);
  101 LIST_HEAD(usbdevlist);
  102 static struct usbbusnode *usbbuslist;
  103 
  104 static const char sys_bus_usb_devices[] = "/sys/bus/usb/devices";
  105 static int indent;
  106 
  107 #if 0
  108 static void dump_usbbusnode(struct usbbusnode *b)
  109 {
  110     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);
  111 }
  112 
  113 static void dump_usbdevice(struct usbdevice *d)
  114 {
  115     printf
  116         (" 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",
  117          d, d->name, d->next, d->first_interface, d->first_child, d->busnum, d->parent_portnum, d->portnum, d->parent, d->bConfigurationValue, d->bDeviceClass,
  118          d->bDeviceProtocol, d->bDeviceSubClass, d->bMaxPacketSize0, d->bMaxPower, d->bNumConfigurations, d->bNumInterfaces, d->bcdDevice, d->bmAttributes,
  119          d->configuration, d->devnum, d->idProduct, d->idVendor, d->maxchild, d->manufacturer, d->product, d->serial, d->version, d->speed, d->driver);
  120 }
  121 
  122 static void dump_usbinterface(struct usbinterface *i)
  123 {
  124     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,
  125            i->bAlternateSetting, i->bInterfaceClass, i->bInterfaceNumber, i->bInterfaceProtocol, i->bInterfaceSubClass, i->bNumEndpoints, i->driver);
  126 }
  127 #endif
  128 
  129 static char tmp_str[128];
  130 static const char *bDeviceClass_to_str(unsigned int dc)
  131 {
  132     const char *s;
  133     switch (dc) {
  134     case 9:
  135         s = "root_hub";
  136         break;
  137     default:
  138         snprintf(tmp_str, 128, "'bDeviceClass 0x%02x not yet handled'", dc);;
  139         s = tmp_str;
  140     }
  141     return s;
  142 }
  143 
  144 static void lanes_to_str(char *lanes, unsigned int tx, unsigned int rx) {
  145     if (tx == rx) {
  146         if (tx < 2) {
  147             *lanes = '\0';
  148             return;
  149         }
  150         sprintf(lanes, "/x%u", tx);
  151     } else {
  152         sprintf(lanes, "/Tx%u+Rx%u", tx, rx);
  153     }
  154 }
  155 
  156 static void print_usbbusnode(struct usbbusnode *b)
  157 {
  158     char vendor[128], product[128];
  159     char lanes[32];
  160 
  161     lanes_to_str(lanes, b->tx_lanes, b->rx_lanes);
  162 
  163     printf("/:  Bus %02u.Port %u: Dev %u, Class=%s, Driver=%s/%up, %sM%s\n", b->busnum, 1,
  164            b->devnum, bDeviceClass_to_str(b->bDeviceClass), b->driver, b->maxchild, b->speed, lanes);
  165     if (verblevel >= 1) {
  166         get_vendor_string(vendor, sizeof(vendor), b->idVendor);
  167         get_product_string(product, sizeof(product), b->idVendor, b->idProduct);
  168         printf("    ID %04x:%04x %s %s\n", b->idVendor, b->idProduct, vendor, product);
  169     }
  170     if (verblevel >= 2) {
  171         printf("    %s/%s  /dev/bus/usb/%03d/%03d\n", sys_bus_usb_devices, b->name, b->busnum, b->devnum);
  172     }
  173 }
  174 
  175 static void print_usbdevice(struct usbdevice *d, struct usbinterface *i)
  176 {
  177     char subcls[128];
  178     char vendor[128], product[128];
  179     char lanes[32];
  180 
  181     lanes_to_str(lanes, d->tx_lanes, d->rx_lanes);
  182     get_class_string(subcls, sizeof(subcls), i->bInterfaceClass);
  183 
  184     if (i->bInterfaceClass == 9)
  185         printf("Port %u: Dev %u, If %u, Class=%s, Driver=%s/%up, %sM%s\n", d->portnum, d->devnum, i->ifnum, subcls,
  186                i->driver, d->maxchild, d->speed, lanes);
  187     else
  188         printf("Port %u: Dev %u, If %u, Class=%s, Driver=%s, %sM%s\n", d->portnum, d->devnum, i->ifnum, subcls, i->driver,
  189                d->speed, lanes);
  190     if (verblevel >= 1) {
  191         printf(" %*s", indent, "    ");
  192         get_vendor_string(vendor, sizeof(vendor), d->idVendor);
  193         get_product_string(product, sizeof(product), d->idVendor, d->idProduct);
  194         printf("ID %04x:%04x %s %s\n", d->idVendor, d->idProduct, vendor, product);
  195     }
  196     if (verblevel >= 2) {
  197         printf(" %*s", indent, "    ");
  198         printf("%s/%s  /dev/bus/usb/%03d/%03d\n", sys_bus_usb_devices, d->name, d->busnum, d->devnum);
  199     }
  200 }
  201 
  202 static unsigned int read_sysfs_file_int(const char *d_name, const char *file, int base)
  203 {
  204     char buf[12], path[MY_PATH_MAX];
  205     int fd;
  206     ssize_t r;
  207     unsigned long ret;
  208     snprintf(path, MY_PATH_MAX, "%s/%s/%s", sys_bus_usb_devices, d_name, file);
  209     path[MY_PATH_MAX - 1] = '\0';
  210     fd = open(path, O_RDONLY);
  211     if (fd < 0)
  212         goto error;
  213     memset(buf, 0, sizeof(buf));
  214     r = read(fd, buf, sizeof(buf) - 1);
  215     close(fd);
  216     if (r < 0)
  217         goto error;
  218     buf[sizeof(buf) - 1] = '\0';
  219     ret = strtoul(buf, NULL, base);
  220     return (unsigned int)ret;
  221 
  222       error:
  223     perror(path);
  224     return 0;
  225 }
  226 
  227 static void read_sysfs_file_string(const char *d_name, const char *file, char *buf, int len)
  228 {
  229     char path[MY_PATH_MAX];
  230     int fd;
  231     ssize_t r;
  232     fd = snprintf(path, MY_PATH_MAX, "%s/%s/%s", sys_bus_usb_devices, d_name, file);
  233     if (fd < 0 || fd >= MY_PATH_MAX)
  234         goto error;
  235     path[fd] = '\0';
  236     fd = open(path, O_RDONLY);
  237     if (fd < 0)
  238         goto error;
  239     r = read(fd, buf, len);
  240     close(fd);
  241     if (r > 0 && r < len) {
  242         buf[r] = '\0';
  243         r--;
  244         while (r >= 0 && buf[r] == '\n') {
  245             buf[r] = '\0';
  246             r--;
  247         }
  248         while (r >= 0) {
  249             if (buf[r] == '\n')
  250                 buf[r] = ' ';
  251             r--;
  252         }
  253         return;
  254     }
  255       error:
  256     buf[0] = '\0';
  257 }
  258 
  259 static void append_dev_interface(struct usbinterface *i, struct usbinterface *new)
  260 {
  261     while (i->next) {
  262         if (i == new)
  263             return;
  264         i = i->next;
  265     }
  266         if (i == new)
  267             return;
  268     i->next = new;
  269 }
  270 
  271 static void append_dev_sibling(struct usbdevice *d, struct usbdevice *new)
  272 {
  273     while (d->next)
  274         d = d->next;
  275     d->next = new;
  276 }
  277 
  278 static void append_businterface(unsigned int busnum, struct usbinterface *new)
  279 {
  280     struct usbbusnode *b = usbbuslist;
  281     struct usbinterface *i;
  282     while (b) {
  283         if (b->busnum == busnum) {
  284             i = b->first_interface;
  285             if (i) {
  286                 while (i->next) {
  287                     if (i == new)
  288                         return;
  289                     i = i->next;
  290                 }
  291                 if (i == new)
  292                     return;
  293                 i->next = new;
  294             } else
  295                 b->first_interface = new;
  296             break;
  297         }
  298         b = b->next;
  299     }
  300 }
  301 
  302 static void append_busnode(struct usbbusnode *new)
  303 {
  304     struct usbbusnode *b = usbbuslist;
  305     if (b) {
  306         while (b->next)
  307             b = b->next;
  308         b->next = new;
  309     } else
  310         usbbuslist = new;
  311 }
  312 
  313 static void add_usb_interface(const char *d_name)
  314 {
  315     struct usbinterface *e;
  316     const char *p;
  317     char *pn, driver[MY_PATH_MAX], link[MY_PATH_MAX];
  318     unsigned long i;
  319     int l;
  320     p = strchr(d_name, ':');
  321     p++;
  322     i = strtoul(p, &pn, 10);
  323     if (!pn || p == pn)
  324         return;
  325     e = malloc(sizeof(struct usbinterface));
  326     if (!e)
  327         return;
  328     memset(e, 0, sizeof(struct usbinterface));
  329     e->configuration = i;
  330     p = pn + 1;
  331     i = strtoul(p, &pn, 10);
  332     if (!pn || p == pn)
  333     {
  334         free(e);
  335         return;
  336     }
  337     e->ifnum = i;
  338     if (snprintf(e->name, MY_SYSFS_FILENAME_LEN, "%s", d_name) >= MY_SYSFS_FILENAME_LEN)
  339         printf("warning: '%s' truncated to '%s'\n", d_name, e->name);
  340     SYSFS_INTu(d_name, e, bAlternateSetting);
  341     SYSFS_INTx(d_name, e, bInterfaceClass);
  342     SYSFS_INTx(d_name, e, bInterfaceNumber);
  343     SYSFS_INTx(d_name, e, bInterfaceProtocol);
  344     SYSFS_INTx(d_name, e, bInterfaceSubClass);
  345     SYSFS_INTx(d_name, e, bNumEndpoints);
  346     l = snprintf(link, MY_PATH_MAX, "%s/%s/driver", sys_bus_usb_devices, d_name);
  347     if (l > 0 && l < MY_PATH_MAX) {
  348         l = readlink(link, driver, MY_PATH_MAX);
  349         if (l >= 0) {
  350             if (l < MY_PATH_MAX - 1)
  351                 driver[l] = '\0';
  352             else
  353                 driver[0] = '\0';
  354             p = strrchr(driver, '/');
  355             if (p)
  356                 snprintf(e->driver, sizeof(e->driver), "%s", p + 1);
  357         }
  358     } else
  359         printf("Can not read driver link for '%s': %d\n", d_name, l);
  360     list_add_tail(&e->list, &interfacelist);
  361 }
  362 
  363 static void add_usb_device(const char *d_name)
  364 {
  365     struct usbdevice *d;
  366     const char *p;
  367     char *pn, driver[MY_PATH_MAX], link[MY_PATH_MAX];
  368     unsigned long i;
  369     int l;
  370     p = d_name;
  371     i = strtoul(p, &pn, 10);
  372     if (!pn || p == pn)
  373         return;
  374     d = malloc(sizeof(struct usbdevice));
  375     if (!d)
  376         return;
  377     memset(d, 0, sizeof(struct usbdevice));
  378     d->busnum = i;
  379     while (*pn) {
  380         p = pn + 1;
  381         i = strtoul(p, &pn, 10);
  382         if (p == pn)
  383             break;
  384         d->parent_portnum = d->portnum;
  385         d->portnum = i;
  386     }
  387     if (snprintf(d->name, MY_SYSFS_FILENAME_LEN, "%s", d_name) >= MY_SYSFS_FILENAME_LEN)
  388         printf("warning: '%s' truncated to '%s'\n", d_name, d->name);
  389     SYSFS_INTu(d_name, d, bConfigurationValue);
  390     SYSFS_INTx(d_name, d, bDeviceClass);
  391     SYSFS_INTx(d_name, d, bDeviceProtocol);
  392     SYSFS_INTx(d_name, d, bDeviceSubClass);
  393     SYSFS_INTx(d_name, d, bMaxPacketSize0);
  394     SYSFS_STR(d_name, d, bMaxPower);
  395     SYSFS_INTu(d_name, d, bNumConfigurations);
  396     SYSFS_INTx(d_name, d, bNumInterfaces);
  397     SYSFS_INTx(d_name, d, bcdDevice);
  398     SYSFS_INTx(d_name, d, bmAttributes);
  399     SYSFS_INTu(d_name, d, configuration);
  400     SYSFS_INTu(d_name, d, devnum);
  401     SYSFS_INTx(d_name, d, idProduct);
  402     SYSFS_INTx(d_name, d, idVendor);
  403     SYSFS_INTu(d_name, d, maxchild);
  404     SYSFS_STR(d_name, d, manufacturer);
  405     SYSFS_STR(d_name, d, product);
  406     SYSFS_STR(d_name, d, serial);
  407     SYSFS_STR(d_name, d, version);
  408     SYSFS_STR(d_name, d, speed);
  409     SYSFS_INTu(d_name, d, rx_lanes);
  410     SYSFS_INTu(d_name, d, tx_lanes);
  411     l = snprintf(link, MY_PATH_MAX, "%s/%s/driver", sys_bus_usb_devices, d_name);
  412     if (l > 0 && l < MY_PATH_MAX) {
  413         l = readlink(link, driver, MY_PATH_MAX);
  414         if (l >= 0) {
  415             if (l < MY_PATH_MAX - 1)
  416                 driver[l] = '\0';
  417             else
  418                 driver[0] = '\0';
  419             p = strrchr(driver, '/');
  420             if (p)
  421                 snprintf(d->driver, sizeof(d->driver), "%s", p + 1);
  422         }
  423     } else
  424         printf("Can not read driver link for '%s': %d\n", d_name, l);
  425     list_add_tail(&d->list, &usbdevlist);
  426 }
  427 
  428 static void get_roothub_driver(struct usbbusnode *b, const char *d_name)
  429 {
  430     char *p, path[MY_PATH_MAX], link[MY_PATH_MAX];
  431     int l;
  432     l = snprintf(link, MY_PATH_MAX, "%s/%s/../driver", sys_bus_usb_devices, d_name);
  433     if (l > 0 && l < MY_PATH_MAX) {
  434         l = readlink(link, path, MY_PATH_MAX);
  435         if (l >= 0) {
  436             if (l < MY_PATH_MAX - 1)
  437                 path[l] = '\0';
  438             else
  439                 path[0] = '\0';
  440             p = strrchr(path, '/');
  441             if (p)
  442                 snprintf(b->driver, sizeof(b->driver), "%s", p + 1);
  443         }
  444     } else
  445         printf("Can not read driver link for '%s': %d\n", d_name, l);
  446 }
  447 
  448 static void add_usb_bus(const char *d_name)
  449 {
  450     struct usbbusnode *bus;
  451     bus = malloc(sizeof(struct usbbusnode));
  452     if (bus) {
  453         memset(bus, 0, sizeof(struct usbbusnode));
  454         bus->busnum = strtoul(d_name + 3, NULL, 10);
  455         if (snprintf(bus->name, MY_SYSFS_FILENAME_LEN, "%s", d_name) >= MY_SYSFS_FILENAME_LEN)
  456             printf("warning: '%s' truncated to '%s'\n", d_name, bus->name);
  457         SYSFS_INTu(d_name, bus, devnum);
  458         SYSFS_INTx(d_name, bus, bDeviceClass);
  459         SYSFS_INTx(d_name, bus, idProduct);
  460         SYSFS_INTx(d_name, bus, idVendor);
  461         SYSFS_INTu(d_name, bus, maxchild);
  462         SYSFS_STR(d_name, bus, speed);
  463         SYSFS_INTu(d_name, bus, rx_lanes);
  464         SYSFS_INTu(d_name, bus, tx_lanes);
  465         append_busnode(bus);
  466         get_roothub_driver(bus, d_name);
  467     }
  468 }
  469 
  470 static void inspect_bus_entry(const char *d_name)
  471 {
  472     if (d_name[0] == '.' && (!d_name[1] || (d_name[1] == '.' && !d_name[2])))
  473         return;
  474     if (d_name[0] == 'u' && d_name[1] == 's' && d_name[2] == 'b' && isdigit(d_name[3])) {
  475         add_usb_bus(d_name);
  476     } else if (isdigit(d_name[0])) {
  477         if (strchr(d_name, ':'))
  478             add_usb_interface(d_name);
  479         else
  480             add_usb_device(d_name);
  481     } else
  482         fprintf(stderr, "ignoring '%s'\n", d_name);
  483 }
  484 
  485 static void walk_usb_devices(DIR * sbud)
  486 {
  487     struct dirent *de;
  488     while ((de = readdir(sbud)))
  489         inspect_bus_entry(de->d_name);
  490 }
  491 
  492 static void assign_dev_to_bus(struct usbdevice *d)
  493 {
  494     struct usbbusnode *b = usbbuslist;
  495     while (b) {
  496         if (b->busnum == d->busnum) {
  497             if (b->first_child)
  498                 append_dev_sibling(b->first_child, d);
  499             else
  500                 b->first_child = d;
  501         }
  502         b = b->next;
  503     }
  504 }
  505 
  506 static void assign_dev_to_parent(struct usbdevice *d)
  507 {
  508     struct list_head *l;
  509     struct usbdevice *pd;
  510     char n[MY_SYSFS_FILENAME_LEN], *p;
  511     for (l = usbdevlist.next; l != &usbdevlist; l = l->next) {
  512         pd = list_entry(l, struct usbdevice, list);
  513         if (pd == d)
  514             continue;
  515         if (pd->busnum == d->busnum && pd->portnum == d->parent_portnum) {
  516             strcpy(n, d->name);
  517             p = strrchr(n, '.');
  518             if (p) {
  519                 *p = '\0';
  520                 if (strcmp(n, pd->name)) {
  521                     continue;
  522                 }
  523                 d->parent = pd;
  524                 if (pd->first_child)
  525                     append_dev_sibling(pd->first_child, d);
  526                 else
  527                     pd->first_child = d;
  528                 break;
  529             }
  530         }
  531     }
  532 }
  533 
  534 static void assign_interface_to_parent(struct usbdevice *d, struct usbinterface *i)
  535 {
  536     const char *p;
  537     char *pn, name[MY_SYSFS_FILENAME_LEN];
  538     ptrdiff_t l;
  539     unsigned int busnum;
  540 
  541     p = strchr(i->name, ':');
  542     if (p) {
  543         l = p - i->name;
  544         if (l < MY_SYSFS_FILENAME_LEN) {
  545             memcpy(name, i->name, l);
  546             name[l] = '\0';
  547         } else
  548             name[0] = '\0';
  549         if (strcmp(d->name, name) == 0) {
  550             i->parent = d;
  551             if (d->first_interface)
  552                 append_dev_interface(d->first_interface, i);
  553             else
  554                 d->first_interface = i;
  555         } else {
  556             busnum = strtoul(name, &pn, 10);
  557             if (pn && pn != name) {
  558                 if (p[1] == '0')
  559                     append_businterface(busnum, i);
  560             }
  561         }
  562     }
  563 }
  564 
  565 static void connect_devices(void)
  566 {
  567     struct list_head *ld, *li;
  568     struct usbdevice *d;
  569     struct usbinterface *e;
  570     for (ld = usbdevlist.next; ld != &usbdevlist; ld = ld->next) {
  571         d = list_entry(ld, struct usbdevice, list);
  572         if (d->parent_portnum)
  573             assign_dev_to_parent(d);
  574         else
  575             assign_dev_to_bus(d);
  576         for (li = interfacelist.next; li != &interfacelist; li = li->next) {
  577             e = list_entry(li, struct usbinterface, list);
  578             if (!e->parent)
  579                 assign_interface_to_parent(d, e);
  580         }
  581     }
  582     for (li = interfacelist.next; li != &interfacelist; li = li->next) {
  583         e = list_entry(li, struct usbinterface, list);
  584     }
  585 }
  586 
  587 static void sort_dev_interfaces(struct usbinterface **i)
  588 {
  589     struct usbinterface *t, *p, **pp;
  590     int swapped;
  591     p = *i;
  592     pp = i;
  593     do {
  594         p = *i;
  595         pp = i;
  596         swapped = 0;
  597         while (p->next) {
  598             if (p->configuration > p->next->configuration) {
  599                 t = p->next;
  600                 p->next = t->next;
  601                 t->next = p;
  602                 *pp = t;
  603                 swapped = 1;
  604                 p = t;
  605             }
  606             if (p->ifnum > p->next->ifnum) {
  607                 t = p->next;
  608                 p->next = t->next;
  609                 t->next = p;
  610                 *pp = t;
  611                 swapped = 1;
  612                 p = t;
  613             }
  614             pp = &p->next;
  615             p = p->next;
  616         }
  617     } while (swapped);
  618 }
  619 
  620 static void sort_dev_siblings(struct usbdevice **d)
  621 {
  622     struct usbdevice *t, *p, **pp;
  623     int swapped;
  624     p = *d;
  625     pp = d;
  626     if (p->first_child)
  627         sort_dev_siblings(&p->first_child);
  628     if (p->first_interface)
  629         sort_dev_interfaces(&p->first_interface);
  630     do {
  631         p = *d;
  632         pp = d;
  633         swapped = 0;
  634         while (p->next) {
  635             if (p->portnum > p->next->portnum) {
  636                 t = p->next;
  637                 p->next = t->next;
  638                 t->next = p;
  639                 *pp = t;
  640                 swapped = 1;
  641                 p = t;
  642             }
  643             pp = &p->next;
  644             p = p->next;
  645         }
  646     } while (swapped);
  647 }
  648 
  649 static void sort_devices(void)
  650 {
  651     struct usbbusnode *b = usbbuslist;
  652     while (b) {
  653         if (b->first_child)
  654             sort_dev_siblings(&b->first_child);
  655         b = b->next;
  656     }
  657 }
  658 
  659 static void sort_busses(void)
  660 {
  661     /* need to reverse sort bus numbers */
  662     struct usbbusnode *t, *p, **pp;
  663     int swapped;
  664     do {
  665         p = usbbuslist;
  666         if (p == NULL)
  667             return;
  668         pp = &usbbuslist;
  669         swapped = 0;
  670         while (p && p->next) {
  671             if (p->busnum < p->next->busnum) {
  672                 t = p->next;
  673                 p->next = t->next;
  674                 t->next = p;
  675                 *pp = t;
  676                 swapped = 1;
  677                 p = t;
  678             }
  679             pp = &p->next;
  680             p = p->next;
  681         }
  682     } while (swapped);
  683 }
  684 
  685 static void print_tree_dev_interface(struct usbdevice *d, struct usbinterface *i)
  686 {
  687     indent += 3;
  688     while (i) {
  689         printf(" %*s", indent, "|__ ");
  690         print_usbdevice(d, i);
  691         i = i->next;
  692     }
  693     indent -= 3;
  694 }
  695 static void print_tree_dev_children(struct usbdevice *d)
  696 {
  697     indent += 4;
  698     while (d) {
  699         print_tree_dev_interface(d, d->first_interface);
  700         print_tree_dev_children(d->first_child);
  701         d = d->next;
  702     }
  703     indent -= 4;
  704 }
  705 
  706 static void print_tree(void)
  707 {
  708     struct usbbusnode *b = usbbuslist;
  709     while (b) {
  710         print_usbbusnode(b);
  711         if (b->first_child)
  712             print_tree_dev_children(b->first_child);
  713         b = b->next;
  714     }
  715 }
  716 
  717 int lsusb_t(void)
  718 {
  719     DIR *sbud = opendir(sys_bus_usb_devices);
  720     if (sbud) {
  721         walk_usb_devices(sbud);
  722         closedir(sbud);
  723         connect_devices();
  724         sort_devices();
  725         sort_busses();
  726         print_tree();
  727     } else
  728         perror(sys_bus_usb_devices);
  729     return sbud == NULL;
  730 }