File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pciutils / ls-tree.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:18:43 2012 UTC (12 years, 3 months ago) by misho
Branches: pciutils, MAIN
CVS tags: v3_1_9, HEAD
pciutils

    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>