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>