Annotation of embedaddon/pciutils/ls-tree.c, revision 1.1
1.1 ! misho 1: /*
! 2: * The PCI Utilities -- Show Bus Tree
! 3: *
! 4: * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
! 5: *
! 6: * Can be freely distributed and used under the terms of the GNU GPL.
! 7: */
! 8:
! 9: #include <stdio.h>
! 10: #include <string.h>
! 11:
! 12: #include "lspci.h"
! 13:
! 14: struct bridge {
! 15: struct bridge *chain; /* Single-linked list of bridges */
! 16: struct bridge *next, *child; /* Tree of bridges */
! 17: struct bus *first_bus; /* List of buses connected to this bridge */
! 18: unsigned int domain;
! 19: unsigned int primary, secondary, subordinate; /* Bus numbers */
! 20: struct device *br_dev;
! 21: };
! 22:
! 23: struct bus {
! 24: unsigned int domain;
! 25: unsigned int number;
! 26: struct bus *sibling;
! 27: struct device *first_dev, **last_dev;
! 28: };
! 29:
! 30: static struct bridge host_bridge = { NULL, NULL, NULL, NULL, 0, ~0, 0, ~0, NULL };
! 31:
! 32: static struct bus *
! 33: find_bus(struct bridge *b, unsigned int domain, unsigned int n)
! 34: {
! 35: struct bus *bus;
! 36:
! 37: for (bus=b->first_bus; bus; bus=bus->sibling)
! 38: if (bus->domain == domain && bus->number == n)
! 39: break;
! 40: return bus;
! 41: }
! 42:
! 43: static struct bus *
! 44: new_bus(struct bridge *b, unsigned int domain, unsigned int n)
! 45: {
! 46: struct bus *bus = xmalloc(sizeof(struct bus));
! 47: bus->domain = domain;
! 48: bus->number = n;
! 49: bus->sibling = b->first_bus;
! 50: bus->first_dev = NULL;
! 51: bus->last_dev = &bus->first_dev;
! 52: b->first_bus = bus;
! 53: return bus;
! 54: }
! 55:
! 56: static void
! 57: insert_dev(struct device *d, struct bridge *b)
! 58: {
! 59: struct pci_dev *p = d->dev;
! 60: struct bus *bus;
! 61:
! 62: if (! (bus = find_bus(b, p->domain, p->bus)))
! 63: {
! 64: struct bridge *c;
! 65: for (c=b->child; c; c=c->next)
! 66: if (c->domain == p->domain && c->secondary <= p->bus && p->bus <= c->subordinate)
! 67: {
! 68: insert_dev(d, c);
! 69: return;
! 70: }
! 71: bus = new_bus(b, p->domain, p->bus);
! 72: }
! 73: /* Simple insertion at the end _does_ guarantee the correct order as the
! 74: * original device list was sorted by (domain, bus, devfn) lexicographically
! 75: * and all devices on the new list have the same bus number.
! 76: */
! 77: *bus->last_dev = d;
! 78: bus->last_dev = &d->next;
! 79: d->next = NULL;
! 80: }
! 81:
! 82: static void
! 83: grow_tree(void)
! 84: {
! 85: struct device *d, *d2;
! 86: struct bridge **last_br, *b;
! 87:
! 88: /* Build list of bridges */
! 89:
! 90: last_br = &host_bridge.chain;
! 91: for (d=first_dev; d; d=d->next)
! 92: {
! 93: word class = d->dev->device_class;
! 94: byte ht = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
! 95: if (class == PCI_CLASS_BRIDGE_PCI &&
! 96: (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS))
! 97: {
! 98: b = xmalloc(sizeof(struct bridge));
! 99: b->domain = d->dev->domain;
! 100: if (ht == PCI_HEADER_TYPE_BRIDGE)
! 101: {
! 102: b->primary = get_conf_byte(d, PCI_PRIMARY_BUS);
! 103: b->secondary = get_conf_byte(d, PCI_SECONDARY_BUS);
! 104: b->subordinate = get_conf_byte(d, PCI_SUBORDINATE_BUS);
! 105: }
! 106: else
! 107: {
! 108: b->primary = get_conf_byte(d, PCI_CB_PRIMARY_BUS);
! 109: b->secondary = get_conf_byte(d, PCI_CB_CARD_BUS);
! 110: b->subordinate = get_conf_byte(d, PCI_CB_SUBORDINATE_BUS);
! 111: }
! 112: *last_br = b;
! 113: last_br = &b->chain;
! 114: b->next = b->child = NULL;
! 115: b->first_bus = NULL;
! 116: b->br_dev = d;
! 117: }
! 118: }
! 119: *last_br = NULL;
! 120:
! 121: /* Create a bridge tree */
! 122:
! 123: for (b=&host_bridge; b; b=b->chain)
! 124: {
! 125: struct bridge *c, *best;
! 126: best = NULL;
! 127: for (c=&host_bridge; c; c=c->chain)
! 128: if (c != b && (c == &host_bridge || b->domain == c->domain) &&
! 129: b->primary >= c->secondary && b->primary <= c->subordinate &&
! 130: (!best || best->subordinate - best->primary > c->subordinate - c->primary))
! 131: best = c;
! 132: if (best)
! 133: {
! 134: b->next = best->child;
! 135: best->child = b;
! 136: }
! 137: }
! 138:
! 139: /* Insert secondary bus for each bridge */
! 140:
! 141: for (b=&host_bridge; b; b=b->chain)
! 142: if (!find_bus(b, b->domain, b->secondary))
! 143: new_bus(b, b->domain, b->secondary);
! 144:
! 145: /* Create bus structs and link devices */
! 146:
! 147: for (d=first_dev; d;)
! 148: {
! 149: d2 = d->next;
! 150: insert_dev(d, &host_bridge);
! 151: d = d2;
! 152: }
! 153: }
! 154:
! 155: static void
! 156: print_it(char *line, char *p)
! 157: {
! 158: *p++ = '\n';
! 159: *p = 0;
! 160: fputs(line, stdout);
! 161: for (p=line; *p; p++)
! 162: if (*p == '+' || *p == '|')
! 163: *p = '|';
! 164: else
! 165: *p = ' ';
! 166: }
! 167:
! 168: static void show_tree_bridge(struct bridge *, char *, char *);
! 169:
! 170: static void
! 171: show_tree_dev(struct device *d, char *line, char *p)
! 172: {
! 173: struct pci_dev *q = d->dev;
! 174: struct bridge *b;
! 175: char namebuf[256];
! 176:
! 177: p += sprintf(p, "%02x.%x", q->dev, q->func);
! 178: for (b=&host_bridge; b; b=b->chain)
! 179: if (b->br_dev == d)
! 180: {
! 181: if (b->secondary == b->subordinate)
! 182: p += sprintf(p, "-[%02x]-", b->secondary);
! 183: else
! 184: p += sprintf(p, "-[%02x-%02x]-", b->secondary, b->subordinate);
! 185: show_tree_bridge(b, line, p);
! 186: return;
! 187: }
! 188: if (verbose)
! 189: p += sprintf(p, " %s",
! 190: pci_lookup_name(pacc, namebuf, sizeof(namebuf),
! 191: PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
! 192: q->vendor_id, q->device_id));
! 193: print_it(line, p);
! 194: }
! 195:
! 196: static void
! 197: show_tree_bus(struct bus *b, char *line, char *p)
! 198: {
! 199: if (!b->first_dev)
! 200: print_it(line, p);
! 201: else if (!b->first_dev->next)
! 202: {
! 203: *p++ = '-';
! 204: *p++ = '-';
! 205: show_tree_dev(b->first_dev, line, p);
! 206: }
! 207: else
! 208: {
! 209: struct device *d = b->first_dev;
! 210: while (d->next)
! 211: {
! 212: p[0] = '+';
! 213: p[1] = '-';
! 214: show_tree_dev(d, line, p+2);
! 215: d = d->next;
! 216: }
! 217: p[0] = '\\';
! 218: p[1] = '-';
! 219: show_tree_dev(d, line, p+2);
! 220: }
! 221: }
! 222:
! 223: static void
! 224: show_tree_bridge(struct bridge *b, char *line, char *p)
! 225: {
! 226: *p++ = '-';
! 227: if (!b->first_bus->sibling)
! 228: {
! 229: if (b == &host_bridge)
! 230: p += sprintf(p, "[%04x:%02x]-", b->domain, b->first_bus->number);
! 231: show_tree_bus(b->first_bus, line, p);
! 232: }
! 233: else
! 234: {
! 235: struct bus *u = b->first_bus;
! 236: char *k;
! 237:
! 238: while (u->sibling)
! 239: {
! 240: k = p + sprintf(p, "+-[%04x:%02x]-", u->domain, u->number);
! 241: show_tree_bus(u, line, k);
! 242: u = u->sibling;
! 243: }
! 244: k = p + sprintf(p, "\\-[%04x:%02x]-", u->domain, u->number);
! 245: show_tree_bus(u, line, k);
! 246: }
! 247: }
! 248:
! 249: void
! 250: show_forest(void)
! 251: {
! 252: char line[256];
! 253:
! 254: grow_tree();
! 255: show_tree_bridge(&host_bridge, line, line);
! 256: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>