X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ls-tree.c;h=ba7873b7764924e4e94a686730ffefe8ba840f5d;hb=41e49114068eb53a7a46d2ecd46f755962c41f1a;hp=dbb65eb3f633b96ae9801b0c1367df2cdb457f26;hpb=6b056c8ec7ae4b2d49b80d701409eff9f14ce7cc;p=pciutils.git diff --git a/ls-tree.c b/ls-tree.c index dbb65eb..ba7873b 100644 --- a/ls-tree.c +++ b/ls-tree.c @@ -1,17 +1,18 @@ /* * The PCI Utilities -- Show Bus Tree * - * Copyright (c) 1997--2018 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 host_bridge = { NULL, NULL, NULL, NULL, 0, ~0, 0, ~0, NULL }; +struct bridge host_bridge = { NULL, NULL, NULL, NULL, NULL, 0, ~0, 0, ~0, NULL }; static struct bus * find_bus(struct bridge *b, unsigned int domain, unsigned int n) @@ -30,11 +31,15 @@ new_bus(struct bridge *b, unsigned int domain, unsigned int n) struct bus *bus = xmalloc(sizeof(struct bus)); bus->domain = domain; bus->number = n; - bus->sibling = b->first_bus; + bus->sibling = NULL; bus->first_dev = NULL; bus->last_dev = &bus->first_dev; bus->parent_bridge = b; - b->first_bus = bus; + if (b->last_bus) + b->last_bus->sibling = bus; + b->last_bus = bus; + if (!b->first_bus) + b->first_bus = bus; return bus; } @@ -76,13 +81,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); @@ -99,8 +105,12 @@ grow_tree(void) last_br = &b->chain; b->next = b->child = NULL; b->first_bus = NULL; + b->last_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; @@ -150,6 +160,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) { @@ -157,22 +192,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); } @@ -183,8 +218,7 @@ show_tree_bus(struct bus *b, char *line, char *p) print_it(line, p); else if (!b->first_dev->bus_next) { - *p++ = '-'; - *p++ = '-'; + p = tree_printf(line, p, "--"); show_tree_dev(b->first_dev, line, p); } else @@ -192,14 +226,12 @@ show_tree_bus(struct bus *b, char *line, char *p) struct device *d = b->first_dev; while (d->bus_next) { - p[0] = '+'; - p[1] = '-'; - show_tree_dev(d, line, p+2); + 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); } } @@ -210,7 +242,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 @@ -220,20 +252,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); + } + } + } }