Back to index

lshw  02.16
pci.cc
Go to the documentation of this file.
00001 #include "version.h"
00002 #include "config.h"
00003 #include "pci.h"
00004 #include "osutils.h"
00005 #include "options.h"
00006 #include <sys/types.h>
00007 #include <sys/stat.h>
00008 #include <fcntl.h>
00009 #include <stdint.h>
00010 #include <unistd.h>
00011 #include <stdio.h>
00012 #include <string.h>
00013 #include <stdlib.h>
00014 #include <dirent.h>
00015 
00016 __ID("@(#) $Id: pci.cc 2433 2012-01-10 22:01:30Z lyonel $");
00017 
00018 #define PROC_BUS_PCI "/proc/bus/pci"
00019 #define SYS_BUS_PCI "/sys/bus/pci"
00020 #define PCIID_PATH DATADIR"/pci.ids:/usr/share/lshw/pci.ids:/usr/local/share/pci.ids:/usr/share/pci.ids:/etc/pci.ids:/usr/share/hwdata/pci.ids:/usr/share/misc/pci.ids"
00021 
00022 #define PCI_CLASS_REVISION      0x08              /* High 24 bits are class, low 8 revision */
00023 #define PCI_VENDOR_ID           0x00    /* 16 bits */
00024 #define PCI_DEVICE_ID           0x02    /* 16 bits */
00025 #define PCI_COMMAND             0x04              /* 16 bits */
00026 #define PCI_REVISION_ID         0x08              /* Revision ID */
00027 #define PCI_CLASS_PROG          0x09              /* Reg. Level Programming Interface */
00028 #define PCI_CLASS_DEVICE        0x0a              /* Device class */
00029 #define PCI_HEADER_TYPE         0x0e              /* 8 bits */
00030 #define  PCI_HEADER_TYPE_NORMAL 0
00031 #define  PCI_HEADER_TYPE_BRIDGE 1
00032 #define  PCI_HEADER_TYPE_CARDBUS 2
00033 #define PCI_PRIMARY_BUS         0x18              /* Primary bus number */
00034 #define PCI_SECONDARY_BUS       0x19              /* Secondary bus number */
00035 #define PCI_STATUS              0x06              /* 16 bits */
00036 #define PCI_LATENCY_TIMER 0x0d                    /* 8 bits */
00037 #define PCI_SEC_LATENCY_TIMER 0x1b                /* Latency timer for secondary interface */
00038 #define PCI_CB_LATENCY_TIMER  0x1b                /* CardBus latency timer */
00039 #define PCI_STATUS_66MHZ       0x20               /* Support 66 Mhz PCI 2.1 bus */
00040 #define PCI_STATUS_CAP_LIST    0x10               /* Support Capability List */
00041 #define PCI_COMMAND_IO         0x1                /* Enable response in I/O space */
00042 #define PCI_COMMAND_MEMORY     0x2                /* Enable response in Memory space */
00043 #define PCI_COMMAND_MASTER     0x4                /* Enable bus mastering */
00044 #define PCI_COMMAND_SPECIAL    0x8                /* Enable response to special cycles */
00045 #define PCI_COMMAND_INVALIDATE 0x10               /* Use memory write and invalidate */
00046 #define PCI_COMMAND_VGA_PALETTE 0x20              /* Enable palette snooping */
00047 #define PCI_COMMAND_PARITY     0x40               /* Enable parity checking */
00048 #define PCI_COMMAND_WAIT       0x80               /* Enable address/data stepping */
00049 #define PCI_COMMAND_SERR       0x100              /* Enable SERR */
00050 #define PCI_COMMAND_FAST_BACK  0x200              /* Enable back-to-back writes */
00051 
00052 #define PCI_MIN_GNT   0x3e                        /* 8 bits */
00053 #define PCI_MAX_LAT   0x3f                        /* 8 bits */
00054 
00055 #define PCI_CAPABILITY_LIST     0x34    /* Offset of first capability list entry */
00056 #define PCI_CAP_LIST_ID         0       /* Capability ID */
00057 #define  PCI_CAP_ID_PM          0x01    /* Power Management */
00058 #define  PCI_CAP_ID_AGP         0x02    /* Accelerated Graphics Port */
00059 #define  PCI_CAP_ID_VPD         0x03    /* Vital Product Data */
00060 #define  PCI_CAP_ID_SLOTID      0x04    /* Slot Identification */
00061 #define  PCI_CAP_ID_MSI         0x05    /* Message Signalled Interrupts */
00062 #define  PCI_CAP_ID_CHSWP       0x06    /* CompactPCI HotSwap */
00063 #define  PCI_CAP_ID_PCIX        0x07    /* PCI-X */
00064 #define  PCI_CAP_ID_HT          0x08    /* HyperTransport */
00065 #define  PCI_CAP_ID_VNDR        0x09    /* Vendor specific */
00066 #define  PCI_CAP_ID_DBG         0x0A    /* Debug port */
00067 #define  PCI_CAP_ID_CCRC        0x0B    /* CompactPCI Central Resource Control */
00068 #define  PCI_CAP_ID_AGP3        0x0E    /* AGP 8x */
00069 #define  PCI_CAP_ID_EXP         0x10    /* PCI Express */
00070 #define  PCI_CAP_ID_MSIX        0x11    /* MSI-X */
00071 #define PCI_CAP_LIST_NEXT       1       /* Next capability in the list */
00072 #define PCI_CAP_FLAGS           2       /* Capability defined flags (16 bits) */
00073 #define PCI_CAP_SIZEOF          4
00074 #define PCI_FIND_CAP_TTL       48
00075 
00076 #define PCI_SID_ESR             2       /* Expansion Slot Register */
00077 #define  PCI_SID_ESR_NSLOTS     0x1f    /* Number of expansion slots available */
00078 
00079 
00080 /*
00081  * The PCI interface treats multi-function devices as independent
00082  * devices.  The slot/function address of each device is encoded
00083  * in a single byte as follows:
00084  *
00085  *     7:3 = slot
00086  *     2:0 = function
00087  */
00088 #define PCI_DEVFN(slot,func)  ((((slot) & 0x1f) << 3) | ((func) & 0x07))
00089 #define PCI_SLOT(devfn)   (((devfn) >> 3) & 0x1f)
00090 #define PCI_FUNC(devfn)   ((devfn) & 0x07)
00091 
00092 /* Device classes and subclasses */
00093 
00094 #define PCI_CLASS_NOT_DEFINED   0x0000
00095 #define PCI_CLASS_NOT_DEFINED_VGA 0x0001
00096 
00097 #define PCI_BASE_CLASS_STORAGE    0x01
00098 #define PCI_CLASS_STORAGE_SCSI    0x0100
00099 #define PCI_CLASS_STORAGE_IDE   0x0101
00100 #define PCI_CLASS_STORAGE_FLOPPY  0x0102
00101 #define PCI_CLASS_STORAGE_IPI   0x0103
00102 #define PCI_CLASS_STORAGE_RAID    0x0104
00103 #define PCI_CLASS_STORAGE_OTHER   0x0180
00104 
00105 #define PCI_BASE_CLASS_NETWORK    0x02
00106 #define PCI_CLASS_NETWORK_ETHERNET  0x0200
00107 #define PCI_CLASS_NETWORK_TOKEN_RING  0x0201
00108 #define PCI_CLASS_NETWORK_FDDI    0x0202
00109 #define PCI_CLASS_NETWORK_ATM   0x0203
00110 #define PCI_CLASS_NETWORK_OTHER   0x0280
00111 
00112 #define PCI_BASE_CLASS_DISPLAY    0x03
00113 #define PCI_CLASS_DISPLAY_VGA   0x0300
00114 #define PCI_CLASS_DISPLAY_XGA   0x0301
00115 #define PCI_CLASS_DISPLAY_OTHER   0x0380
00116 
00117 #define PCI_BASE_CLASS_MULTIMEDIA 0x04
00118 #define PCI_CLASS_MULTIMEDIA_VIDEO  0x0400
00119 #define PCI_CLASS_MULTIMEDIA_AUDIO  0x0401
00120 #define PCI_CLASS_MULTIMEDIA_OTHER  0x0480
00121 
00122 #define PCI_BASE_CLASS_MEMORY   0x05
00123 #define  PCI_CLASS_MEMORY_RAM   0x0500
00124 #define  PCI_CLASS_MEMORY_FLASH   0x0501
00125 #define  PCI_CLASS_MEMORY_OTHER   0x0580
00126 
00127 #define PCI_BASE_CLASS_BRIDGE   0x06
00128 #define  PCI_CLASS_BRIDGE_HOST    0x0600
00129 #define  PCI_CLASS_BRIDGE_ISA   0x0601
00130 #define  PCI_CLASS_BRIDGE_EISA    0x0602
00131 #define  PCI_CLASS_BRIDGE_MC    0x0603
00132 #define  PCI_CLASS_BRIDGE_PCI   0x0604
00133 #define  PCI_CLASS_BRIDGE_PCMCIA  0x0605
00134 #define  PCI_CLASS_BRIDGE_NUBUS   0x0606
00135 #define  PCI_CLASS_BRIDGE_CARDBUS 0x0607
00136 #define  PCI_CLASS_BRIDGE_OTHER   0x0680
00137 
00138 #define PCI_BASE_CLASS_COMMUNICATION  0x07
00139 #define PCI_CLASS_COMMUNICATION_SERIAL  0x0700
00140 #define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
00141 #define PCI_CLASS_COMMUNICATION_MODEM 0x0703
00142 #define PCI_CLASS_COMMUNICATION_OTHER 0x0780
00143 
00144 #define PCI_BASE_CLASS_SYSTEM   0x08
00145 #define PCI_CLASS_SYSTEM_PIC    0x0800
00146 #define PCI_CLASS_SYSTEM_DMA    0x0801
00147 #define PCI_CLASS_SYSTEM_TIMER    0x0802
00148 #define PCI_CLASS_SYSTEM_RTC    0x0803
00149 #define PCI_CLASS_SYSTEM_OTHER    0x0880
00150 
00151 #define PCI_BASE_CLASS_INPUT    0x09
00152 #define PCI_CLASS_INPUT_KEYBOARD  0x0900
00153 #define PCI_CLASS_INPUT_PEN   0x0901
00154 #define PCI_CLASS_INPUT_MOUSE   0x0902
00155 #define PCI_CLASS_INPUT_OTHER   0x0980
00156 
00157 #define PCI_BASE_CLASS_DOCKING    0x0a
00158 #define PCI_CLASS_DOCKING_GENERIC 0x0a00
00159 #define PCI_CLASS_DOCKING_OTHER   0x0a01
00160 
00161 #define PCI_BASE_CLASS_PROCESSOR  0x0b
00162 #define PCI_CLASS_PROCESSOR_386   0x0b00
00163 #define PCI_CLASS_PROCESSOR_486   0x0b01
00164 #define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02
00165 #define PCI_CLASS_PROCESSOR_ALPHA 0x0b10
00166 #define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
00167 #define PCI_CLASS_PROCESSOR_CO    0x0b40
00168 
00169 #define PCI_BASE_CLASS_SERIAL   0x0c
00170 #define PCI_CLASS_SERIAL_FIREWIRE 0x0c00
00171 #define PCI_CLASS_SERIAL_ACCESS   0x0c01
00172 #define PCI_CLASS_SERIAL_SSA    0x0c02
00173 #define PCI_CLASS_SERIAL_USB    0x0c03
00174 #define PCI_CLASS_SERIAL_FIBER    0x0c04
00175 
00176 #define PCI_CLASS_OTHERS    0xff
00177 
00178 #define PCI_ADDR_MEM_MASK (~(pciaddr_t) 0xf)
00179 #define PCI_BASE_ADDRESS_0 0x10                   /* 32 bits */
00180 #define  PCI_BASE_ADDRESS_SPACE 0x01              /* 0 = memory, 1 = I/O */
00181 #define  PCI_BASE_ADDRESS_SPACE_IO 0x01
00182 #define  PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
00183 #define  PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
00184 #define  PCI_BASE_ADDRESS_MEM_TYPE_32   0x00      /* 32 bit address */
00185 #define  PCI_BASE_ADDRESS_MEM_TYPE_1M   0x02      /* Below 1M [obsolete] */
00186 #define  PCI_BASE_ADDRESS_MEM_TYPE_64   0x04      /* 64 bit address */
00187 #define  PCI_BASE_ADDRESS_MEM_PREFETCH  0x08      /* prefetchable? */
00188 #define  PCI_BASE_ADDRESS_MEM_MASK      (~0x0fUL)
00189 #define  PCI_BASE_ADDRESS_IO_MASK       (~0x03UL)
00190 
00191 #define PCI_SUBSYSTEM_VENDOR_ID 0x2c
00192 #define PCI_SUBSYSTEM_ID        0x2e
00193 
00194 #define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
00195 #define PCI_CB_SUBSYSTEM_ID     0x42
00196 
00197 bool pcidb_loaded = false;
00198 
00199 typedef unsigned long long pciaddr_t;
00200 typedef enum
00201 {
00202   pcidevice,
00203   pcisubdevice,
00204   pcisubsystem,
00205   pciclass,
00206   pcisubclass,
00207   pcivendor,
00208   pcisubvendor,
00209   pciprogif
00210 }
00211 
00212 
00213 catalog;
00214 
00215 struct pci_dev
00216 {
00217   u_int16_t domain;                               /* PCI domain (host bridge) */
00218   u_int16_t bus;                                  /* Higher byte can select host bridges */
00219   u_int8_t dev, func;                             /* Device and function */
00220 
00221   u_int16_t vendor_id, device_id;                 /* Identity of the device */
00222   unsigned int irq;                               /* IRQ number */
00223   pciaddr_t base_addr[6];                         /* Base addresses */
00224   pciaddr_t size[6];                              /* Region sizes */
00225   pciaddr_t rom_base_addr;                        /* Expansion ROM base address */
00226   pciaddr_t rom_size;                             /* Expansion ROM size */
00227 
00228   u_int8_t config[256];                           /* non-root users can only use first 64 bytes */
00229 };
00230 
00231 struct pci_entry
00232 {
00233   long ids[4];
00234   string description;
00235 
00236   pci_entry(const string & description,
00237     long u1 = -1,
00238     long u2 = -1,
00239     long u3 = -1,
00240     long u4 = -1);
00241 
00242   unsigned int matches(long u1 = -1,
00243     long u2 = -1,
00244     long u3 = -1,
00245     long u4 = -1);
00246 };
00247 
00248 static vector < pci_entry > pci_devices;
00249 static vector < pci_entry > pci_classes;
00250 
00251 pci_entry::pci_entry(const string & d,
00252 long u1,
00253 long u2,
00254 long u3,
00255 long u4)
00256 {
00257   description = d;
00258   ids[0] = u1;
00259   ids[1] = u2;
00260   ids[2] = u3;
00261   ids[3] = u4;
00262 }
00263 
00264 
00265 unsigned int pci_entry::matches(long u1,
00266 long u2,
00267 long u3,
00268 long u4)
00269 {
00270   unsigned int result = 0;
00271 
00272   if (ids[0] == u1)
00273   {
00274     result++;
00275     if (ids[1] == u2)
00276     {
00277       result++;
00278       if (ids[2] == u3)
00279       {
00280         result++;
00281         if (ids[3] == u4)
00282           result++;
00283       }
00284     }
00285   }
00286 
00287   return result;
00288 }
00289 
00290 
00291 static bool find_best_match(vector < pci_entry > &list,
00292 pci_entry & result,
00293 long u1 = -1,
00294 long u2 = -1,
00295 long u3 = -1,
00296 long u4 = -1)
00297 {
00298   int lastmatch = -1;
00299   unsigned int lastscore = 0;
00300 
00301   for (unsigned int i = 0; i < list.size(); i++)
00302   {
00303     unsigned int currentscore = list[i].matches(u1, u2, u3, u4);
00304 
00305     if (currentscore > lastscore)
00306     {
00307       lastscore = currentscore;
00308       lastmatch = i;
00309     }
00310   }
00311 
00312   if (lastmatch >= 0)
00313   {
00314     result = list[lastmatch];
00315     return true;
00316   }
00317 
00318   return false;
00319 }
00320 
00321 
00322 static const char *get_class_name(unsigned int c)
00323 {
00324   switch (c)
00325   {
00326     case PCI_CLASS_NOT_DEFINED_VGA:
00327       return "display";
00328     case PCI_CLASS_STORAGE_SCSI:
00329       return "scsi";
00330     case PCI_CLASS_STORAGE_IDE:
00331       return "ide";
00332     case PCI_CLASS_BRIDGE_HOST:
00333       return "host";
00334     case PCI_CLASS_BRIDGE_ISA:
00335       return "isa";
00336     case PCI_CLASS_BRIDGE_EISA:
00337       return "eisa";
00338     case PCI_CLASS_BRIDGE_MC:
00339       return "mc";
00340     case PCI_CLASS_BRIDGE_PCI:
00341       return "pci";
00342     case PCI_CLASS_BRIDGE_PCMCIA:
00343       return "pcmcia";
00344     case PCI_CLASS_BRIDGE_NUBUS:
00345       return "nubus";
00346     case PCI_CLASS_BRIDGE_CARDBUS:
00347       return "pcmcia";
00348     case PCI_CLASS_SERIAL_FIREWIRE:
00349       return "firewire";
00350     case PCI_CLASS_SERIAL_USB:
00351       return "usb";
00352     case PCI_CLASS_SERIAL_FIBER:
00353       return "fiber";
00354   }
00355 
00356   switch (c >> 8)
00357   {
00358     case PCI_BASE_CLASS_STORAGE:
00359       return "storage";
00360     case PCI_BASE_CLASS_NETWORK:
00361       return "network";
00362     case PCI_BASE_CLASS_DISPLAY:
00363       return "display";
00364     case PCI_BASE_CLASS_MULTIMEDIA:
00365       return "multimedia";
00366     case PCI_BASE_CLASS_MEMORY:
00367       return "memory";
00368     case PCI_BASE_CLASS_BRIDGE:
00369       return "bridge";
00370     case PCI_BASE_CLASS_COMMUNICATION:
00371       return "communication";
00372     case PCI_BASE_CLASS_SYSTEM:
00373       return "generic";
00374     case PCI_BASE_CLASS_INPUT:
00375       return "input";
00376     case PCI_BASE_CLASS_DOCKING:
00377       return "docking";
00378     case PCI_BASE_CLASS_PROCESSOR:
00379       return "processor";
00380     case PCI_BASE_CLASS_SERIAL:
00381       return "serial";
00382   }
00383 
00384   return "generic";
00385 }
00386 
00387 
00388 static bool parse_pcidb(vector < string > &list)
00389 {
00390   long u[4];
00391   string line = "";
00392   catalog current_catalog = pcivendor;
00393   unsigned int level = 0;
00394 
00395   memset(u, 0, sizeof(u));
00396 
00397   for (unsigned int i = 0; i < list.size(); i++)
00398   {
00399     line = hw::strip(list[i]);
00400 
00401 // ignore empty or commented-out lines
00402     if (line.length() == 0 || line[0] == '#')
00403       continue;
00404 
00405     level = 0;
00406     while ((level < list[i].length()) && (list[i][level] == '\t'))
00407       level++;
00408 
00409     switch (level)
00410     {
00411       case 0:
00412         if ((line[0] == 'C') && (line.length() > 1) && (line[1] == ' '))
00413         {
00414           current_catalog = pciclass;
00415           line = line.substr(2);                  // get rid of 'C '
00416 
00417           if ((line.length() < 3) || (line[2] != ' '))
00418             return false;
00419           if (sscanf(line.c_str(), "%lx", &u[0]) != 1)
00420             return false;
00421           line = line.substr(3);
00422           line = hw::strip(line);
00423         }
00424         else
00425         {
00426           current_catalog = pcivendor;
00427 
00428           if ((line.length() < 5) || (line[4] != ' '))
00429             return false;
00430           if (sscanf(line.c_str(), "%lx", &u[0]) != 1)
00431             return false;
00432           line = line.substr(5);
00433           line = hw::strip(line);
00434         }
00435         u[1] = u[2] = u[3] = -1;
00436         break;
00437       case 1:
00438         if ((current_catalog == pciclass) || (current_catalog == pcisubclass)
00439           || (current_catalog == pciprogif))
00440         {
00441           current_catalog = pcisubclass;
00442 
00443           if ((line.length() < 3) || (line[2] != ' '))
00444             return false;
00445           if (sscanf(line.c_str(), "%lx", &u[1]) != 1)
00446             return false;
00447           line = line.substr(3);
00448           line = hw::strip(line);
00449         }
00450         else
00451         {
00452           current_catalog = pcidevice;
00453 
00454           if ((line.length() < 5) || (line[4] != ' '))
00455             return false;
00456           if (sscanf(line.c_str(), "%lx", &u[1]) != 1)
00457             return false;
00458           line = line.substr(5);
00459           line = hw::strip(line);
00460         }
00461         u[2] = u[3] = -1;
00462         break;
00463       case 2:
00464         if ((current_catalog != pcidevice) && (current_catalog != pcisubvendor)
00465           && (current_catalog != pcisubclass)
00466           && (current_catalog != pciprogif))
00467           return false;
00468         if ((current_catalog == pcisubclass) || (current_catalog == pciprogif))
00469         {
00470           current_catalog = pciprogif;
00471           if ((line.length() < 3) || (line[2] != ' '))
00472             return false;
00473           if (sscanf(line.c_str(), "%lx", &u[2]) != 1)
00474             return false;
00475           u[3] = -1;
00476           line = line.substr(2);
00477           line = hw::strip(line);
00478         }
00479         else
00480         {
00481           current_catalog = pcisubvendor;
00482           if ((line.length() < 10) || (line[4] != ' ') || (line[9] != ' '))
00483             return false;
00484           if (sscanf(line.c_str(), "%lx%lx", &u[2], &u[3]) != 2)
00485             return false;
00486           line = line.substr(9);
00487           line = hw::strip(line);
00488         }
00489         break;
00490       default:
00491         return false;
00492     }
00493 
00494 //printf("%04x %04x %04x %04x %s\n", u[0], u[1], u[2], u[3], line.c_str());
00495     if ((current_catalog == pciclass) ||
00496       (current_catalog == pcisubclass) || (current_catalog == pciprogif))
00497     {
00498       pci_classes.push_back(pci_entry(line, u[0], u[1], u[2], u[3]));
00499     }
00500     else
00501     {
00502       pci_devices.push_back(pci_entry(line, u[0], u[1], u[2], u[3]));
00503     }
00504   }
00505   return true;
00506 }
00507 
00508 
00509 static bool load_pcidb()
00510 {
00511   vector < string > lines;
00512   vector < string > filenames;
00513 
00514   splitlines(PCIID_PATH, filenames, ':');
00515   for (int i = filenames.size() - 1; i >= 0; i--)
00516   {
00517     lines.clear();
00518     if (loadfile(filenames[i], lines))
00519       parse_pcidb(lines);
00520   }
00521 
00522   if (lines.size() == 0)
00523     return false;
00524 
00525   return true;
00526 }
00527 
00528 
00529 static string get_class_description(long c,
00530 long pi = -1)
00531 {
00532   pci_entry result("");
00533 
00534   if (find_best_match(pci_classes, result, c >> 8, c & 0xff, pi))
00535     return result.description;
00536   else
00537     return "";
00538 }
00539 
00540 
00541 static string get_device_description(long u1,
00542 long u2 = -1,
00543 long u3 = -1,
00544 long u4 = -1)
00545 {
00546   pci_entry result("");
00547 
00548   if (find_best_match(pci_devices, result, u1, u2, u3, u4))
00549     return result.description;
00550   else
00551     return "";
00552 }
00553 
00554 
00555 static u_int32_t get_conf_long(struct pci_dev d,
00556 unsigned int pos)
00557 {
00558   if (pos > sizeof(d.config))
00559     return 0;
00560 
00561   return d.config[pos] | (d.config[pos + 1] << 8) |
00562     (d.config[pos + 2] << 16) | (d.config[pos + 3] << 24);
00563 }
00564 
00565 
00566 static u_int16_t get_conf_word(struct pci_dev d,
00567 unsigned int pos)
00568 {
00569   if (pos > sizeof(d.config))
00570     return 0;
00571 
00572   return d.config[pos] | (d.config[pos + 1] << 8);
00573 }
00574 
00575 
00576 static u_int8_t get_conf_byte(struct pci_dev d,
00577 unsigned int pos)
00578 {
00579   if (pos > sizeof(d.config))
00580     return 0;
00581 
00582   return d.config[pos];
00583 }
00584 
00585 
00586 static string pci_bushandle(u_int8_t bus, u_int16_t domain = 0)
00587 {
00588   char buffer[20];
00589 
00590   if(domain == (u_int16_t)(-1))
00591     snprintf(buffer, sizeof(buffer), "%02x", bus);
00592   else
00593     snprintf(buffer, sizeof(buffer), "%04x:%02x", domain, bus);
00594 
00595   return "PCIBUS:" + string(buffer);
00596 }
00597 
00598 
00599 static string pci_handle(u_int16_t bus,
00600 u_int8_t dev,
00601 u_int8_t fct,
00602 u_int16_t domain = 0)
00603 {
00604   char buffer[30];
00605 
00606   if(domain == (u_int16_t)(-1))
00607     snprintf(buffer, sizeof(buffer), "PCI:%02x:%02x.%x", bus, dev, fct);
00608   else
00609     snprintf(buffer, sizeof(buffer), "PCI:%04x:%02x:%02x.%x", domain, bus, dev, fct);
00610 
00611   return string(buffer);
00612 }
00613 
00614 
00615 static bool scan_resources(hwNode & n,
00616 struct pci_dev &d)
00617 {
00618   u_int16_t cmd = get_conf_word(d, PCI_COMMAND);
00619 
00620   n.setWidth(32);
00621 
00622   for (int i = 0; i < 6; i++)
00623   {
00624     u_int32_t flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4 * i);
00625     u_int32_t pos = d.base_addr[i];
00626     u_int32_t len = d.size[i];
00627 
00628     if (flg == 0xffffffff)
00629       flg = 0;
00630 
00631     if (!pos && !flg && !len)
00632       continue;
00633 
00634     if (pos && !flg)                              /* Reported by the OS, but not by the device */
00635     {
00636 //printf("[virtual] ");
00637       flg = pos;
00638     }
00639     if (flg & PCI_BASE_ADDRESS_SPACE_IO)
00640     {
00641       u_int32_t a = pos & PCI_BASE_ADDRESS_IO_MASK;
00642       if ((a != 0) && (cmd & PCI_COMMAND_IO) != 0)
00643         n.addResource(hw::resource::ioport(a, a + len - 1));
00644     }
00645     else                                          // resource is memory
00646     {
00647       int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
00648       u_int64_t a = pos & PCI_ADDR_MEM_MASK;
00649       u_int64_t z = 0;
00650 
00651       if (t == PCI_BASE_ADDRESS_MEM_TYPE_64)
00652       {
00653         n.setWidth(64);
00654         if (i < 5)
00655         {
00656           i++;
00657           z = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4 * i);
00658           a += z << 4;
00659         }
00660       }
00661       if (a)
00662         n.addResource(hw::resource::iomem(a, a + len - 1));
00663     }
00664   }
00665 
00666   return true;
00667 }
00668 
00669 static bool scan_capabilities(hwNode & n, struct pci_dev &d)
00670 {
00671   unsigned int where = get_conf_byte(d, PCI_CAPABILITY_LIST) & ~3;
00672   string buffer;
00673   unsigned int ttl = PCI_FIND_CAP_TTL;
00674 
00675   while(where && ttl--)
00676   {
00677     unsigned int id, next, cap;
00678 
00679     id = get_conf_byte(d, where + PCI_CAP_LIST_ID);
00680     next = get_conf_byte(d, where + PCI_CAP_LIST_NEXT) & ~3;
00681     cap = get_conf_word(d, where + PCI_CAP_FLAGS);
00682 
00683     if(!id || id == 0xff)
00684       return false;
00685 
00686     switch(id)
00687     {
00688       case PCI_CAP_ID_PM:
00689         n.addCapability("pm", "Power Management");
00690         break;
00691       case PCI_CAP_ID_AGP:
00692         n.addCapability("agp", "AGP");
00693         buffer = hw::asString((cap >> 4) & 0x0f) + "." + hw::asString(cap & 0x0f);
00694         n.addCapability("agp-"+buffer, "AGP "+buffer);
00695         break;
00696       case PCI_CAP_ID_VPD:
00697         n.addCapability("vpd", "Vital Product Data");
00698         break;
00699       case PCI_CAP_ID_SLOTID:
00700         n.addCapability("slotid", "Slot Identification");
00701         n.setSlot(hw::asString(cap & PCI_SID_ESR_NSLOTS)+", chassis "+hw::asString(cap>>8));
00702         break;
00703       case PCI_CAP_ID_MSI:
00704         n.addCapability("msi", "Message Signalled Interrupts");
00705         break;
00706       case PCI_CAP_ID_CHSWP:
00707         n.addCapability("hotswap", "Hot-swap");
00708         break;
00709       case PCI_CAP_ID_PCIX:
00710         n.addCapability("pcix", "PCI-X");
00711         break;
00712       case PCI_CAP_ID_HT:
00713         n.addCapability("ht", "HyperTransport");
00714         break;
00715       case PCI_CAP_ID_DBG:
00716         n.addCapability("debug", "Debug port");
00717         break;
00718       case PCI_CAP_ID_CCRC:
00719         n.addCapability("ccrc", "CompactPCI Central Resource Control");
00720         break;
00721       case PCI_CAP_ID_AGP3:
00722         n.addCapability("agp8x", "AGP 8x");
00723         break;
00724       case PCI_CAP_ID_EXP:
00725         n.addCapability("pciexpress", _("PCI Express"));
00726         break;
00727       case PCI_CAP_ID_MSIX:
00728         n.addCapability("msix", "MSI-X");
00729         break;
00730     }
00731 
00732     where = next;
00733   }
00734 
00735   return true;
00736 }
00737 
00738 
00739 static void addHints(hwNode & n,
00740 long _vendor,
00741 long _device,
00742 long _subvendor,
00743 long _subdevice,
00744 long _class)
00745 {
00746   n.addHint("pci.vendor", _vendor);
00747   n.addHint("pci.device", _device);
00748   if(_subvendor && (_subvendor != 0xffff))
00749   {
00750     n.addHint("pci.subvendor", _subvendor);
00751     n.addHint("pci.subdevice", _subdevice);
00752   }
00753   n.addHint("pci.class", _class);
00754 }
00755 
00756 static hwNode *scan_pci_dev(struct pci_dev &d, hwNode & n)
00757 {
00758   hwNode *result = NULL;
00759   hwNode *core = n.getChild("core");
00760   if (!core)
00761   {
00762     n.addChild(hwNode("core", hw::bus));
00763     core = n.getChild("core");
00764   }
00765 
00766   if(!pcidb_loaded)
00767     pcidb_loaded = load_pcidb();
00768 
00769       d.vendor_id = get_conf_word(d, PCI_VENDOR_ID);
00770       d.device_id = get_conf_word(d, PCI_DEVICE_ID);
00771       u_int16_t dclass = get_conf_word(d, PCI_CLASS_DEVICE);
00772       u_int16_t cmd = get_conf_word(d, PCI_COMMAND);
00773       u_int16_t status = get_conf_word(d, PCI_STATUS);
00774       u_int8_t latency = get_conf_byte(d, PCI_LATENCY_TIMER);
00775       u_int8_t min_gnt = get_conf_byte(d, PCI_MIN_GNT);
00776       u_int8_t max_lat = get_conf_byte(d, PCI_MAX_LAT);
00777       u_int8_t progif = get_conf_byte(d, PCI_CLASS_PROG);
00778       u_int8_t rev = get_conf_byte(d, PCI_REVISION_ID);
00779       u_int8_t htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
00780       u_int16_t subsys_v = 0, subsys_d = 0;
00781 
00782       char revision[10];
00783       snprintf(revision, sizeof(revision), "%02x", rev);
00784       string moredescription = get_class_description(dclass, progif);
00785 
00786       switch (htype)
00787       {
00788         case PCI_HEADER_TYPE_NORMAL:
00789           subsys_v = get_conf_word(d, PCI_SUBSYSTEM_VENDOR_ID);
00790           subsys_d = get_conf_word(d, PCI_SUBSYSTEM_ID);
00791           break;
00792         case PCI_HEADER_TYPE_BRIDGE:
00793           subsys_v = subsys_d = 0;
00794           latency = get_conf_byte(d, PCI_SEC_LATENCY_TIMER);
00795           break;
00796         case PCI_HEADER_TYPE_CARDBUS:
00797           subsys_v = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
00798           subsys_d = get_conf_word(d, PCI_CB_SUBSYSTEM_ID);
00799           latency = get_conf_byte(d, PCI_CB_LATENCY_TIMER);
00800           break;
00801       }
00802 
00803       if (dclass == PCI_CLASS_BRIDGE_HOST)
00804       {
00805         hwNode host("pci",
00806           hw::bridge);
00807 
00808         host.setDescription(get_class_description(dclass, progif));
00809         host.setVendor(get_device_description(d.vendor_id)+(enabled("output:numeric")?" ["+tohex(d.vendor_id)+"]":""));
00810         host.setProduct(get_device_description(d.vendor_id, d.device_id)+(enabled("output:numeric")?" ["+tohex(d.vendor_id)+":"+tohex(d.device_id)+"]":""));
00811         host.setHandle(pci_bushandle(d.bus, d.domain));
00812         host.setVersion(revision);
00813         addHints(host, d.vendor_id, d.device_id, subsys_v, subsys_d, dclass);
00814         host.claim();
00815         if(latency)
00816           host.setConfig("latency", latency);
00817         if (d.size[0] > 0)
00818           host.setPhysId(0x100 + d.domain);
00819 
00820         if (moredescription != "" && moredescription != host.getDescription())
00821         {
00822           host.addCapability(moredescription);
00823           host.setDescription(host.getDescription() + " (" +
00824             moredescription + ")");
00825         }
00826 
00827         if (status & PCI_STATUS_66MHZ)
00828           host.setClock(66000000UL);              // 66MHz
00829         else
00830           host.setClock(33000000UL);              // 33MHz
00831 
00832         scan_resources(host, d);
00833 
00834         if (core)
00835           result = core->addChild(host);
00836         else
00837           result = n.addChild(host);
00838       }
00839       else
00840       {
00841         hw::hwClass deviceclass = hw::generic;
00842         string devicename = "generic";
00843         string deviceicon = "";
00844 
00845         switch (dclass >> 8)
00846         {
00847           case PCI_BASE_CLASS_STORAGE:
00848             deviceclass = hw::storage;
00849             deviceicon = "disc";
00850             if(dclass == PCI_CLASS_STORAGE_SCSI)
00851               deviceicon = "scsi";
00852             if(dclass == PCI_CLASS_STORAGE_RAID)
00853               deviceicon = "raid";
00854             break;
00855           case PCI_BASE_CLASS_NETWORK:
00856             deviceclass = hw::network;
00857             deviceicon = "network";
00858             break;
00859           case PCI_BASE_CLASS_MEMORY:
00860             deviceclass = hw::memory;
00861             deviceicon = "memory";
00862             break;
00863           case PCI_BASE_CLASS_BRIDGE:
00864             deviceclass = hw::bridge;
00865             break;
00866           case PCI_BASE_CLASS_MULTIMEDIA:
00867             deviceclass = hw::multimedia;
00868             if(dclass == PCI_CLASS_MULTIMEDIA_AUDIO)
00869               deviceicon = "audio";
00870             break;
00871           case PCI_BASE_CLASS_DISPLAY:
00872             deviceclass = hw::display;
00873             deviceicon = "display";
00874             break;
00875           case PCI_BASE_CLASS_COMMUNICATION:
00876             deviceclass = hw::communication;
00877             if(dclass == PCI_CLASS_COMMUNICATION_SERIAL)
00878               deviceicon = "serial";
00879             if(dclass == PCI_CLASS_COMMUNICATION_PARALLEL)
00880               deviceicon = "parallel";
00881             if(dclass == PCI_CLASS_COMMUNICATION_MODEM)
00882               deviceicon = "modem";
00883             break;
00884           case PCI_BASE_CLASS_SYSTEM:
00885             deviceclass = hw::generic;
00886             break;
00887           case PCI_BASE_CLASS_INPUT:
00888             deviceclass = hw::input;
00889             break;
00890           case PCI_BASE_CLASS_PROCESSOR:
00891             deviceclass = hw::processor;
00892             break;
00893           case PCI_BASE_CLASS_SERIAL:
00894             deviceclass = hw::bus;
00895             if(dclass == PCI_CLASS_SERIAL_USB)
00896               deviceicon = "usb";
00897             if(dclass == PCI_CLASS_SERIAL_FIREWIRE)
00898               deviceicon = "firewire";
00899             break;
00900         }
00901 
00902         devicename = get_class_name(dclass);
00903         hwNode *device = new hwNode(devicename, deviceclass);
00904 
00905         if (device)
00906         {
00907           if(deviceicon != "") device->addHint("icon", deviceicon);
00908           addHints(*device, d.vendor_id, d.device_id, subsys_v, subsys_d, dclass);
00909 
00910           if (deviceclass == hw::bridge || deviceclass == hw::storage)
00911             device->addCapability(devicename);
00912 
00913           if(device->isCapable("isa") ||
00914             device->isCapable("pci") ||
00915             device->isCapable("agp"))
00916             device->claim();
00917 
00918           scan_resources(*device, d);
00919           scan_capabilities(*device, d);
00920 
00921           if (deviceclass == hw::display)
00922             for (int j = 0; j < 6; j++)
00923               if ((d.size[j] != 0xffffffff)
00924             && (d.size[j] > device->getSize()))
00925                 device->setSize(d.size[j]);
00926 
00927           if (dclass == PCI_CLASS_BRIDGE_PCI)
00928           {
00929             device->setHandle(pci_bushandle(get_conf_byte(d, PCI_SECONDARY_BUS), d.domain));
00930             device->claim();
00931           }
00932           else
00933           {
00934             char irq[10];
00935 
00936             snprintf(irq, sizeof(irq), "%d", d.irq);
00937             device->setHandle(pci_handle(d.bus, d.dev, d.func, d.domain));
00938             device->setConfig("latency", latency);
00939             if(max_lat)
00940               device->setConfig("maxlatency", max_lat);
00941             if(min_gnt)
00942               device->setConfig("mingnt", min_gnt);
00943             if (d.irq != 0)
00944             {
00945 //device->setConfig("irq", irq);
00946               device->addResource(hw::resource::irq(d.irq));
00947             }
00948           }
00949           device->setDescription(get_class_description(dclass));
00950 
00951           if (moredescription != ""
00952             && moredescription != device->getDescription())
00953           {
00954             device->addCapability(moredescription);
00955           }
00956           device->setVendor(get_device_description(d.vendor_id)+(enabled("output:numeric")?" ["+tohex(d.vendor_id)+"]":""));
00957           device->setVersion(revision);
00958           device->setProduct(get_device_description(d.vendor_id, d.device_id)+(enabled("output:numeric")?" ["+tohex(d.vendor_id)+":"+tohex(d.device_id)+"]":""));
00959 
00960           if (cmd & PCI_COMMAND_MASTER)
00961             device->addCapability("bus master", "bus mastering");
00962           if (cmd & PCI_COMMAND_VGA_PALETTE)
00963             device->addCapability("VGA palette", "VGA palette");
00964           if (status & PCI_STATUS_CAP_LIST)
00965             device->addCapability("cap list", "PCI capabilities listing");
00966           if (status & PCI_STATUS_66MHZ)
00967             device->setClock(66000000UL);         // 66MHz
00968           else
00969             device->setClock(33000000UL);         // 33MHz
00970 
00971           device->setPhysId(d.dev, d.func);
00972 
00973           hwNode *bus = NULL;
00974 
00975           bus = n.findChildByHandle(pci_bushandle(d.bus, d.domain));
00976 
00977           device->describeCapability("vga", "VGA graphical framebuffer");
00978           device->describeCapability("pcmcia", "PC-Card (PCMCIA)");
00979           device->describeCapability("generic", "Generic interface");
00980           device->describeCapability("ohci", "Open Host Controller Interface");
00981           device->describeCapability("uhci", "Universal Host Controller Interface (USB1)");
00982           device->describeCapability("ehci", "Enhanced Host Controller Interface (USB2)");
00983           if (bus)
00984             result = bus->addChild(*device);
00985           else
00986           {
00987             if (core)
00988               result = core->addChild(*device);
00989             else
00990               result = n.addChild(*device);
00991           }
00992           delete device;
00993 
00994         }
00995       }
00996   return result;
00997 }
00998 
00999 bool scan_pci_legacy(hwNode & n)
01000 {
01001   FILE *f;
01002   hwNode *core = n.getChild("core");
01003   if (!core)
01004   {
01005     n.addChild(hwNode("core", hw::bus));
01006     core = n.getChild("core");
01007   }
01008 
01009   if(!pcidb_loaded)
01010     pcidb_loaded = load_pcidb();
01011 
01012   f = fopen(PROC_BUS_PCI "/devices", "r");
01013   if (f)
01014   {
01015     char buf[512];
01016 
01017     while (fgets(buf, sizeof(buf) - 1, f))
01018     {
01019       unsigned int dfn, vend, cnt;
01020       struct pci_dev d;
01021       int fd = -1;
01022       string devicepath = "";
01023       char devicename[20];
01024       char businfo[20];
01025       char driver[50];
01026       hwNode *device = NULL;
01027 
01028       memset(&d, 0, sizeof(d));
01029       memset(driver, 0, sizeof(driver));
01030       cnt = sscanf(buf,
01031         "%x %x %x %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %[ -z]s",
01032         &dfn,
01033         &vend,
01034         &d.irq,
01035         &d.base_addr[0],
01036         &d.base_addr[1],
01037         &d.base_addr[2],
01038         &d.base_addr[3],
01039         &d.base_addr[4],
01040         &d.base_addr[5],
01041         &d.rom_base_addr,
01042         &d.size[0],
01043         &d.size[1],
01044         &d.size[2],
01045         &d.size[3], &d.size[4], &d.size[5], &d.rom_size, driver);
01046 
01047       if (cnt != 9 && cnt != 10 && cnt != 17 && cnt != 18)
01048         break;
01049 
01050       d.bus = dfn >> 8;
01051       d.dev = PCI_SLOT(dfn & 0xff);
01052       d.func = PCI_FUNC(dfn & 0xff);
01053       d.vendor_id = vend >> 16;
01054       d.device_id = vend & 0xffff;
01055 
01056       snprintf(devicename, sizeof(devicename), "%02x/%02x.%x", d.bus, d.dev,
01057         d.func);
01058       devicepath = string(PROC_BUS_PCI) + "/" + string(devicename);
01059       snprintf(businfo, sizeof(businfo), "%02x:%02x.%x", d.bus, d.dev,
01060         d.func);
01061 
01062       fd = open(devicepath.c_str(), O_RDONLY);
01063       if (fd >= 0)
01064       {
01065         if(read(fd, d.config, sizeof(d.config)) != sizeof(d.config))
01066           memset(&d.config, 0, sizeof(d.config));
01067         close(fd);
01068       }
01069 
01070       device = scan_pci_dev(d, n);
01071       if(device)
01072       {
01073         device->setBusInfo(businfo);
01074       }
01075 
01076     }
01077     fclose(f);
01078   }
01079 
01080   return false;
01081 }
01082 
01083 bool scan_pci(hwNode & n)
01084 {
01085   bool result = false;
01086   dirent **devices = NULL;
01087   int count = 0;
01088   hwNode *core = n.getChild("core");
01089 
01090   if (!core)
01091   {
01092     n.addChild(hwNode("core", hw::bus));
01093     core = n.getChild("core");
01094   }
01095 
01096   pcidb_loaded = load_pcidb();
01097 
01098   if(!pushd(SYS_BUS_PCI"/devices"))
01099     return false;
01100   count = scandir(".", &devices, selectlink, alphasort);
01101   if(count>=0)
01102   {
01103     int i = 0;
01104     for(i=0; i<count; i++)
01105     if(matches(devices[i]->d_name, "^[[:xdigit:]]+:[[:xdigit:]]+:[[:xdigit:]]+\\.[[:xdigit:]]+$"))
01106     {
01107       string devicepath = string(devices[i]->d_name)+"/config";
01108       struct pci_dev d;
01109       int fd = open(devicepath.c_str(), O_RDONLY);
01110       if (fd >= 0)
01111       {
01112         memset(&d, 0, sizeof(d));
01113         if(read(fd, d.config, 64) == 64)
01114         {
01115           if(read(fd, d.config+64, sizeof(d.config)-64) != sizeof(d.config)-64)
01116             memset(d.config+64, 0, sizeof(d.config)-64);
01117         }
01118         close(fd);
01119       }
01120 
01121       sscanf(devices[i]->d_name, "%hx:%hx:%hhx.%hhx", &d.domain, &d.bus, &d.dev, &d.func);
01122       hwNode *device = scan_pci_dev(d, n);
01123 
01124       if(device)
01125       {
01126         string resourcename = string(devices[i]->d_name)+"/resource";
01127 
01128         device->setBusInfo(devices[i]->d_name);
01129         if(exists(string(devices[i]->d_name)+"/driver"))
01130         {
01131           string drivername = readlink(string(devices[i]->d_name)+"/driver");
01132           string modulename = readlink(string(devices[i]->d_name)+"/driver/module");
01133 
01134           device->setConfig("driver", basename(drivername.c_str()));
01135           if(exists(modulename))
01136             device->setConfig("module", basename(modulename.c_str()));
01137 
01138           if(exists(string(devices[i]->d_name)+"/rom"))
01139           {
01140             device->addCapability("rom", "extension ROM");
01141           }
01142 
01143           if(exists(string(devices[i]->d_name)+"/irq"))
01144           {
01145             long irq = get_number(string(devices[i]->d_name)+"/irq", -1);
01146             if(irq>=0)
01147               device->addResource(hw::resource::irq(irq));
01148           }
01149           device->claim();
01150         }
01151 
01152         if(exists(resourcename))
01153         {
01154             FILE*resource = fopen(resourcename.c_str(), "r");
01155 
01156             if(resource)
01157             {
01158               while(!feof(resource))
01159               {
01160                 unsigned long long start, end, flags;
01161 
01162                 start = end = flags = 0;
01163 
01164                 if(fscanf(resource, "%llx %llx %llx", &start, &end, &flags) != 3)
01165                   break;
01166 
01167                 if(flags & 0x101)
01168                   device->addResource(hw::resource::ioport(start, end));
01169                 else
01170                 if(flags & 0x100)
01171                   device->addResource(hw::resource::iomem(start, end));
01172                 else
01173                 if(flags & 0x200)
01174                   device->addResource(hw::resource::mem(start, end, flags & 0x1000));
01175               }
01176               fclose(resource);
01177             }
01178         }
01179 
01180         result = true;
01181       }
01182 
01183       free(devices[i]);
01184     }
01185 
01186     free(devices);
01187   }
01188   popd();
01189   return result;
01190 }