X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ls-tree.c;h=aeb40870865e42afe410ee48cbae5dd67391b359;hb=ae833de28e16a9ec0144befa36affa2f4239a7c1;hp=add5b7ec63ea5921716f3a38c7111c265446627b;hpb=8442ab4bc6a775a5fea8132c133e49f9b9bf71d5;p=pciutils.git diff --git a/ls-tree.c b/ls-tree.c index add5b7e..aeb4087 100644 --- a/ls-tree.c +++ b/ls-tree.c @@ -1,33 +1,18 @@ /* * The PCI Utilities -- Show Bus Tree * - * Copyright (c) 1997--2008 Martin Mares + * Copyright (c) 1997--2020 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ +#include #include #include #include "lspci.h" -struct bridge { - struct bridge *chain; /* Single-linked list of bridges */ - struct bridge *next, *child; /* Tree of bridges */ - struct bus *first_bus; /* List of buses connected to this bridge */ - unsigned int domain; - unsigned int primary, secondary, subordinate; /* Bus numbers */ - struct device *br_dev; -}; - -struct bus { - unsigned int domain; - unsigned int number; - struct bus *sibling; - struct device *first_dev, **last_dev; -}; - -static struct bridge host_bridge = { NULL, NULL, NULL, NULL, 0, ~0, 0, ~0, NULL }; +struct bridge host_bridge = { NULL, NULL, NULL, NULL, 0, ~0, 0, ~0, NULL }; static struct bus * find_bus(struct bridge *b, unsigned int domain, unsigned int n) @@ -49,6 +34,7 @@ new_bus(struct bridge *b, unsigned int domain, unsigned int n) bus->sibling = b->first_bus; bus->first_dev = NULL; bus->last_dev = &bus->first_dev; + bus->parent_bridge = b; b->first_bus = bus; return bus; } @@ -75,14 +61,15 @@ insert_dev(struct device *d, struct bridge *b) * and all devices on the new list have the same bus number. */ *bus->last_dev = d; - bus->last_dev = &d->next; - d->next = NULL; + bus->last_dev = &d->bus_next; + d->bus_next = NULL; + d->parent_bus = bus; } -static void +void grow_tree(void) { - struct device *d, *d2; + struct device *d; struct bridge **last_br, *b; /* Build list of bridges */ @@ -90,13 +77,14 @@ grow_tree(void) last_br = &host_bridge.chain; for (d=first_dev; d; d=d->next) { - word class = d->dev->device_class; + struct pci_dev *dd = d->dev; + word class = dd->device_class; byte ht = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f; - if (class == PCI_CLASS_BRIDGE_PCI && + if ((class >> 8) == PCI_BASE_CLASS_BRIDGE && (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS)) { b = xmalloc(sizeof(struct bridge)); - b->domain = d->dev->domain; + b->domain = dd->domain; if (ht == PCI_HEADER_TYPE_BRIDGE) { b->primary = get_conf_byte(d, PCI_PRIMARY_BUS); @@ -114,6 +102,10 @@ grow_tree(void) b->next = b->child = NULL; b->first_bus = NULL; b->br_dev = d; + d->bridge = b; + pacc->debug("Tree: bridge %04x:%02x:%02x.%d: %02x -> %02x-%02x\n", + dd->domain, dd->bus, dd->dev, dd->func, + b->primary, b->secondary, b->subordinate); } } *last_br = NULL; @@ -144,12 +136,8 @@ grow_tree(void) /* Create bus structs and link devices */ - for (d=first_dev; d;) - { - d2 = d->next; - insert_dev(d, &host_bridge); - d = d2; - } + for (d=first_dev; d; d=d->next) + insert_dev(d, &host_bridge); } static void @@ -167,6 +155,31 @@ print_it(char *line, char *p) static void show_tree_bridge(struct bridge *, char *, char *); +#define LINE_BUF_SIZE 1024 + +static char * FORMAT_CHECK(printf, 3, 4) +tree_printf(char *line, char *p, char *fmt, ...) +{ + va_list args; + char *end = line + LINE_BUF_SIZE - 2; + + if (p >= end) + return p; + + va_start(args, fmt); + int res = vsnprintf(p, end - p, fmt, args); + if (res < 0) + { + /* Ancient C libraries return -1 on overflow */ + p += strlen(p); + } + else + p += res; + + va_end(args); + return p; +} + static void show_tree_dev(struct device *d, char *line, char *p) { @@ -174,22 +187,22 @@ show_tree_dev(struct device *d, char *line, char *p) struct bridge *b; char namebuf[256]; - p += sprintf(p, "%02x.%x", q->dev, q->func); + p = tree_printf(line, p, "%02x.%x", q->dev, q->func); for (b=&host_bridge; b; b=b->chain) if (b->br_dev == d) { if (b->secondary == b->subordinate) - p += sprintf(p, "-[%02x]-", b->secondary); + p = tree_printf(line, p, "-[%02x]-", b->secondary); else - p += sprintf(p, "-[%02x-%02x]-", b->secondary, b->subordinate); + p = tree_printf(line, p, "-[%02x-%02x]-", b->secondary, b->subordinate); show_tree_bridge(b, line, p); return; } if (verbose) - p += sprintf(p, " %s", - pci_lookup_name(pacc, namebuf, sizeof(namebuf), - PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, - q->vendor_id, q->device_id)); + p = tree_printf(line, p, " %s", + pci_lookup_name(pacc, namebuf, sizeof(namebuf), + PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, + q->vendor_id, q->device_id)); print_it(line, p); } @@ -198,25 +211,22 @@ show_tree_bus(struct bus *b, char *line, char *p) { if (!b->first_dev) print_it(line, p); - else if (!b->first_dev->next) + else if (!b->first_dev->bus_next) { - *p++ = '-'; - *p++ = '-'; + p = tree_printf(line, p, "--"); show_tree_dev(b->first_dev, line, p); } else { struct device *d = b->first_dev; - while (d->next) + while (d->bus_next) { - p[0] = '+'; - p[1] = '-'; - show_tree_dev(d, line, p+2); - d = d->next; + char *p2 = tree_printf(line, p, "+-"); + show_tree_dev(d, line, p2); + d = d->bus_next; } - p[0] = '\\'; - p[1] = '-'; - show_tree_dev(d, line, p+2); + p = tree_printf(line, p, "\\-"); + show_tree_dev(d, line, p); } } @@ -227,7 +237,7 @@ show_tree_bridge(struct bridge *b, char *line, char *p) if (!b->first_bus->sibling) { if (b == &host_bridge) - p += sprintf(p, "[%04x:%02x]-", b->domain, b->first_bus->number); + p = tree_printf(line, p, "[%04x:%02x]-", b->domain, b->first_bus->number); show_tree_bus(b->first_bus, line, p); } else @@ -237,20 +247,33 @@ show_tree_bridge(struct bridge *b, char *line, char *p) while (u->sibling) { - k = p + sprintf(p, "+-[%04x:%02x]-", u->domain, u->number); + k = tree_printf(line, p, "+-[%04x:%02x]-", u->domain, u->number); show_tree_bus(u, line, k); u = u->sibling; } - k = p + sprintf(p, "\\-[%04x:%02x]-", u->domain, u->number); + k = tree_printf(line, p, "\\-[%04x:%02x]-", u->domain, u->number); show_tree_bus(u, line, k); } } void -show_forest(void) +show_forest(struct pci_filter *filter) { - char line[256]; - - grow_tree(); - show_tree_bridge(&host_bridge, line, line); + char line[LINE_BUF_SIZE]; + if (filter == NULL) + show_tree_bridge(&host_bridge, line, line); + else + { + struct bridge *b; + for (b=&host_bridge; b; b=b->chain) + { + if (b->br_dev && pci_filter_match(filter, b->br_dev->dev)) + { + struct pci_dev *d = b->br_dev->dev; + char *p = line; + p = tree_printf(line, p, "%04x:%02x:", d->domain_16, d->bus); + show_tree_dev(b->br_dev, line, p); + } + } + } }