pci.cc
1 #include "version.h" 2 #include "config.h" 3 #include "pci.h" 4 #include "device-tree.h" 5 #include "osutils.h" 6 #include "options.h" 7 #include "sysfs.h" 8 #include <sys/types.h> 9 #include <sys/stat.h> 10 #include <fcntl.h> 11 #include <stdint.h> 12 #include <unistd.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include <stdlib.h> 16 #include <dirent.h> 17 #include <cstring> 18 19 __ID("@(#) $Id$"); 20 21 #define PROC_BUS_PCI "/proc/bus/pci" 22 #define SYS_BUS_PCI "/sys/bus/pci" 23 #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" 24 25 #define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ 26 #define PCI_VENDOR_ID 0x00 /* 16 bits */ 27 #define PCI_DEVICE_ID 0x02 /* 16 bits */ 28 #define PCI_COMMAND 0x04 /* 16 bits */ 29 #define PCI_REVISION_ID 0x08 /* Revision ID */ 30 #define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ 31 #define PCI_CLASS_DEVICE 0x0a /* Device class */ 32 #define PCI_HEADER_TYPE 0x0e /* 8 bits */ 33 #define PCI_HEADER_TYPE_NORMAL 0 34 #define PCI_HEADER_TYPE_BRIDGE 1 35 #define PCI_HEADER_TYPE_CARDBUS 2 36 #define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ 37 #define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ 38 #define PCI_STATUS 0x06 /* 16 bits */ 39 #define PCI_LATENCY_TIMER 0x0d /* 8 bits */ 40 #define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ 41 #define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ 42 #define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ 43 #define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ 44 #define PCI_COMMAND_IO 0x01 /* Enable response in I/O space */ 45 #define PCI_COMMAND_MEMORY 0x02 /* Enable response in Memory space */ 46 #define PCI_COMMAND_MASTER 0x04 /* Enable bus mastering */ 47 #define PCI_COMMAND_SPECIAL 0x08 /* Enable response to special cycles */ 48 #define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ 49 #define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ 50 #define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ 51 #define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ 52 #define PCI_COMMAND_SERR 0x100 /* Enable SERR */ 53 #define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ 54 55 #define PCI_MIN_GNT 0x3e /* 8 bits */ 56 #define PCI_MAX_LAT 0x3f /* 8 bits */ 57 58 #define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ 59 #define PCI_CAP_LIST_ID 0 /* Capability ID */ 60 #define PCI_CAP_ID_PM 0x01 /* Power Management */ 61 #define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ 62 #define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ 63 #define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ 64 #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ 65 #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ 66 #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ 67 #define PCI_CAP_ID_HT 0x08 /* HyperTransport */ 68 #define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ 69 #define PCI_CAP_ID_DBG 0x0A /* Debug port */ 70 #define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ 71 #define PCI_CAP_ID_AGP3 0x0E /* AGP 8x */ 72 #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ 73 #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ 74 #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ 75 #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ 76 #define PCI_CAP_SIZEOF 4 77 #define PCI_FIND_CAP_TTL 48 78 79 #define PCI_SID_ESR 2 /* Expansion Slot Register */ 80 #define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ 81 82 83 /* 84 * The PCI interface treats multi-function devices as independent 85 * devices. The slot/function address of each device is encoded 86 * in a single byte as follows: 87 * 88 * 7:3 = slot 89 * 2:0 = function 90 */ 91 #define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) 92 #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) 93 #define PCI_FUNC(devfn) ((devfn) & 0x07) 94 95 /* Device classes and subclasses */ 96 97 #define PCI_CLASS_NOT_DEFINED 0x0000 98 #define PCI_CLASS_NOT_DEFINED_VGA 0x0001 99 100 #define PCI_BASE_CLASS_STORAGE 0x01 101 #define PCI_CLASS_STORAGE_SCSI 0x0100 102 #define PCI_CLASS_STORAGE_IDE 0x0101 103 #define PCI_CLASS_STORAGE_FLOPPY 0x0102 104 #define PCI_CLASS_STORAGE_IPI 0x0103 105 #define PCI_CLASS_STORAGE_RAID 0x0104 106 #define PCI_CLASS_STORAGE_SATA 0x0106 107 #define PCI_CLASS_STORAGE_SAS 0x0107 108 #define PCI_CLASS_STORAGE_NVME 0x0108 109 #define PCI_CLASS_STORAGE_OTHER 0x0180 110 111 #define PCI_BASE_CLASS_NETWORK 0x02 112 #define PCI_CLASS_NETWORK_ETHERNET 0x0200 113 #define PCI_CLASS_NETWORK_TOKEN_RING 0x0201 114 #define PCI_CLASS_NETWORK_FDDI 0x0202 115 #define PCI_CLASS_NETWORK_ATM 0x0203 116 #define PCI_CLASS_NETWORK_OTHER 0x0280 117 118 #define PCI_BASE_CLASS_DISPLAY 0x03 119 #define PCI_CLASS_DISPLAY_VGA 0x0300 120 #define PCI_CLASS_DISPLAY_XGA 0x0301 121 #define PCI_CLASS_DISPLAY_OTHER 0x0380 122 123 #define PCI_BASE_CLASS_MULTIMEDIA 0x04 124 #define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400 125 #define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 126 #define PCI_CLASS_MULTIMEDIA_OTHER 0x0480 127 128 #define PCI_BASE_CLASS_MEMORY 0x05 129 #define PCI_CLASS_MEMORY_RAM 0x0500 130 #define PCI_CLASS_MEMORY_FLASH 0x0501 131 #define PCI_CLASS_MEMORY_OTHER 0x0580 132 133 #define PCI_BASE_CLASS_BRIDGE 0x06 134 #define PCI_CLASS_BRIDGE_HOST 0x0600 135 #define PCI_CLASS_BRIDGE_ISA 0x0601 136 #define PCI_CLASS_BRIDGE_EISA 0x0602 137 #define PCI_CLASS_BRIDGE_MC 0x0603 138 #define PCI_CLASS_BRIDGE_PCI 0x0604 139 #define PCI_CLASS_BRIDGE_PCMCIA 0x0605 140 #define PCI_CLASS_BRIDGE_NUBUS 0x0606 141 #define PCI_CLASS_BRIDGE_CARDBUS 0x0607 142 #define PCI_CLASS_BRIDGE_OTHER 0x0680 143 144 #define PCI_BASE_CLASS_COMMUNICATION 0x07 145 #define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 146 #define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701 147 #define PCI_CLASS_COMMUNICATION_MODEM 0x0703 148 #define PCI_CLASS_COMMUNICATION_OTHER 0x0780 149 150 #define PCI_BASE_CLASS_SYSTEM 0x08 151 #define PCI_CLASS_SYSTEM_PIC 0x0800 152 #define PCI_CLASS_SYSTEM_DMA 0x0801 153 #define PCI_CLASS_SYSTEM_TIMER 0x0802 154 #define PCI_CLASS_SYSTEM_RTC 0x0803 155 #define PCI_CLASS_SYSTEM_OTHER 0x0880 156 157 #define PCI_BASE_CLASS_INPUT 0x09 158 #define PCI_CLASS_INPUT_KEYBOARD 0x0900 159 #define PCI_CLASS_INPUT_PEN 0x0901 160 #define PCI_CLASS_INPUT_MOUSE 0x0902 161 #define PCI_CLASS_INPUT_OTHER 0x0980 162 163 #define PCI_BASE_CLASS_DOCKING 0x0a 164 #define PCI_CLASS_DOCKING_GENERIC 0x0a00 165 #define PCI_CLASS_DOCKING_OTHER 0x0a01 166 167 #define PCI_BASE_CLASS_PROCESSOR 0x0b 168 #define PCI_CLASS_PROCESSOR_386 0x0b00 169 #define PCI_CLASS_PROCESSOR_486 0x0b01 170 #define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02 171 #define PCI_CLASS_PROCESSOR_ALPHA 0x0b10 172 #define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 173 #define PCI_CLASS_PROCESSOR_CO 0x0b40 174 175 #define PCI_BASE_CLASS_SERIAL 0x0c 176 #define PCI_CLASS_SERIAL_FIREWIRE 0x0c00 177 #define PCI_CLASS_SERIAL_ACCESS 0x0c01 178 #define PCI_CLASS_SERIAL_SSA 0x0c02 179 #define PCI_CLASS_SERIAL_USB 0x0c03 180 #define PCI_CLASS_SERIAL_FIBER 0x0c04 181 182 #define PCI_BASE_CLASS_ACCELERATOR 0x12 183 #define PCI_CLASS_ACCELERATOR 0x1200 184 185 #define PCI_CLASS_OTHERS 0xff 186 187 #define PCI_ADDR_MEM_MASK (~(pciaddr_t) 0xf) 188 #define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ 189 #define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ 190 #define PCI_BASE_ADDRESS_SPACE_IO 0x01 191 #define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 192 #define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 193 #define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ 194 #define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ 195 #define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ 196 #define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ 197 #define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) 198 #define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) 199 200 #define PCI_SUBSYSTEM_VENDOR_ID 0x2c 201 #define PCI_SUBSYSTEM_ID 0x2e 202 203 #define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 204 #define PCI_CB_SUBSYSTEM_ID 0x42 205 206 bool pcidb_loaded = false; 207 208 typedef unsigned long long pciaddr_t; 209 typedef enum 210 { 211 pcidevice, 212 pcisubdevice, 213 pcisubsystem, 214 pciclass, 215 pcisubclass, 216 pcivendor, 217 pcisubvendor, 218 pciprogif 219 } 220 221 222 catalog; 223 224 struct pci_dev 225 { 226 u_int16_t domain; /* PCI domain (host bridge) */ 227 u_int16_t bus; /* Higher byte can select host bridges */ 228 u_int8_t dev, func; /* Device and function */ 229 230 u_int16_t vendor_id, device_id; /* Identity of the device */ 231 unsigned int irq; /* IRQ number */ 232 pciaddr_t base_addr[6]; /* Base addresses */ 233 pciaddr_t size[6]; /* Region sizes */ 234 pciaddr_t rom_base_addr; /* Expansion ROM base address */ 235 pciaddr_t rom_size; /* Expansion ROM size */ 236 237 u_int8_t config[256]; /* non-root users can only use first 64 bytes */ 238 }; 239 240 struct pci_entry 241 { 242 long ids[4]; 243 string description; 244 245 pci_entry(const string & description, 246 long u1 = -1, 247 long u2 = -1, 248 long u3 = -1, 249 long u4 = -1); 250 251 unsigned int matches(long u1 = -1, 252 long u2 = -1, 253 long u3 = -1, 254 long u4 = -1); 255 }; 256 257 static vector < pci_entry > pci_devices; 258 static vector < pci_entry > pci_classes; 259 260 pci_entry::pci_entry(const string & d, 261 long u1, 262 long u2, 263 long u3, 264 long u4) 265 { 266 description = d; 267 ids[0] = u1; 268 ids[1] = u2; 269 ids[2] = u3; 270 ids[3] = u4; 271 } 272 273 274 unsigned int pci_entry::matches(long u1, 275 long u2, 276 long u3, 277 long u4) 278 { 279 unsigned int result = 0; 280 281 if (ids[0] == u1) 282 { 283 result++; 284 if (ids[1] == u2) 285 { 286 result++; 287 if (ids[2] == u3) 288 { 289 result++; 290 if (ids[3] == u4) 291 result++; 292 } 293 } 294 } 295 296 return result; 297 } 298 299 300 static bool find_best_match(vector < pci_entry > &list, 301 pci_entry & result, 302 long u1 = -1, 303 long u2 = -1, 304 long u3 = -1, 305 long u4 = -1) 306 { 307 int lastmatch = -1; 308 unsigned int lastscore = 0; 309 310 for (unsigned int i = 0; i < list.size(); i++) 311 { 312 unsigned int currentscore = list[i].matches(u1, u2, u3, u4); 313 314 if (currentscore > lastscore) 315 { 316 lastscore = currentscore; 317 lastmatch = i; 318 } 319 } 320 321 if (lastmatch >= 0) 322 { 323 result = list[lastmatch]; 324 return true; 325 } 326 327 return false; 328 } 329 330 331 static const char *get_class_name(unsigned int c) 332 { 333 switch (c) 334 { 335 case PCI_CLASS_NOT_DEFINED_VGA: 336 return "display"; 337 case PCI_CLASS_STORAGE_SCSI: 338 return "scsi"; 339 case PCI_CLASS_STORAGE_IDE: 340 return "ide"; 341 case PCI_CLASS_STORAGE_RAID: 342 return "raid"; 343 case PCI_CLASS_STORAGE_SATA: 344 return "sata"; 345 case PCI_CLASS_STORAGE_SAS: 346 return "sas"; 347 case PCI_CLASS_STORAGE_NVME: 348 return "nvme"; 349 case PCI_CLASS_BRIDGE_HOST: 350 return "host"; 351 case PCI_CLASS_BRIDGE_ISA: 352 return "isa"; 353 case PCI_CLASS_BRIDGE_EISA: 354 return "eisa"; 355 case PCI_CLASS_BRIDGE_MC: 356 return "mc"; 357 case PCI_CLASS_BRIDGE_PCI: 358 return "pci"; 359 case PCI_CLASS_BRIDGE_PCMCIA: 360 return "pcmcia"; 361 case PCI_CLASS_BRIDGE_NUBUS: 362 return "nubus"; 363 case PCI_CLASS_BRIDGE_CARDBUS: 364 return "pcmcia"; 365 case PCI_CLASS_SERIAL_FIREWIRE: 366 return "firewire"; 367 case PCI_CLASS_SERIAL_USB: 368 return "usb"; 369 case PCI_CLASS_SERIAL_FIBER: 370 return "fiber"; 371 } 372 373 switch (c >> 8) 374 { 375 case PCI_BASE_CLASS_STORAGE: 376 return "storage"; 377 case PCI_BASE_CLASS_NETWORK: 378 return "network"; 379 case PCI_BASE_CLASS_DISPLAY: 380 return "display"; 381 case PCI_BASE_CLASS_MULTIMEDIA: 382 return "multimedia"; 383 case PCI_BASE_CLASS_MEMORY: 384 return "memory"; 385 case PCI_BASE_CLASS_BRIDGE: 386 return "bridge"; 387 case PCI_BASE_CLASS_COMMUNICATION: 388 return "communication"; 389 case PCI_BASE_CLASS_SYSTEM: 390 return "generic"; 391 case PCI_BASE_CLASS_INPUT: 392 return "input"; 393 case PCI_BASE_CLASS_DOCKING: 394 return "docking"; 395 case PCI_BASE_CLASS_PROCESSOR: 396 return "processor"; 397 case PCI_BASE_CLASS_SERIAL: 398 return "serial"; 399 case PCI_BASE_CLASS_ACCELERATOR: 400 return "accelerator"; 401 } 402 403 return "generic"; 404 } 405 406 407 static bool parse_pcidb(vector < string > &list) 408 { 409 long u[4]; 410 string line = ""; 411 catalog current_catalog = pcivendor; 412 unsigned int level = 0; 413 414 memset(u, 0, sizeof(u)); 415 416 for (unsigned int i = 0; i < list.size(); i++) 417 { 418 line = hw::strip(list[i]); 419 420 // ignore empty or commented-out lines 421 if (line.length() == 0 || line[0] == '#') 422 continue; 423 424 level = 0; 425 while ((level < list[i].length()) && (list[i][level] == '\t')) 426 level++; 427 428 switch (level) 429 { 430 case 0: 431 if ((line[0] == 'C') && (line.length() > 1) && (line[1] == ' ')) 432 { 433 current_catalog = pciclass; 434 line = line.substr(2); // get rid of 'C ' 435 436 if ((line.length() < 3) || (line[2] != ' ')) 437 return false; 438 if (sscanf(line.c_str(), "%lx", &u[0]) != 1) 439 return false; 440 line = line.substr(3); 441 line = hw::strip(line); 442 } 443 else 444 { 445 current_catalog = pcivendor; 446 447 if ((line.length() < 5) || (line[4] != ' ')) 448 return false; 449 if (sscanf(line.c_str(), "%lx", &u[0]) != 1) 450 return false; 451 line = line.substr(5); 452 line = hw::strip(line); 453 } 454 u[1] = u[2] = u[3] = -1; 455 break; 456 case 1: 457 if ((current_catalog == pciclass) || (current_catalog == pcisubclass) 458 || (current_catalog == pciprogif)) 459 { 460 current_catalog = pcisubclass; 461 462 if ((line.length() < 3) || (line[2] != ' ')) 463 return false; 464 if (sscanf(line.c_str(), "%lx", &u[1]) != 1) 465 return false; 466 line = line.substr(3); 467 line = hw::strip(line); 468 } 469 else 470 { 471 current_catalog = pcidevice; 472 473 if ((line.length() < 5) || (line[4] != ' ')) 474 return false; 475 if (sscanf(line.c_str(), "%lx", &u[1]) != 1) 476 return false; 477 line = line.substr(5); 478 line = hw::strip(line); 479 } 480 u[2] = u[3] = -1; 481 break; 482 case 2: 483 if ((current_catalog != pcidevice) && (current_catalog != pcisubvendor) 484 && (current_catalog != pcisubclass) 485 && (current_catalog != pciprogif)) 486 return false; 487 if ((current_catalog == pcisubclass) || (current_catalog == pciprogif)) 488 { 489 current_catalog = pciprogif; 490 if ((line.length() < 3) || (line[2] != ' ')) 491 return false; 492 if (sscanf(line.c_str(), "%lx", &u[2]) != 1) 493 return false; 494 u[3] = -1; 495 line = line.substr(2); 496 line = hw::strip(line); 497 } 498 else 499 { 500 current_catalog = pcisubvendor; 501 if ((line.length() < 10) || (line[4] != ' ') || (line[9] != ' ')) 502 return false; 503 if (sscanf(line.c_str(), "%lx%lx", &u[2], &u[3]) != 2) 504 return false; 505 line = line.substr(9); 506 line = hw::strip(line); 507 } 508 break; 509 default: 510 return false; 511 } 512 513 //printf("%04x %04x %04x %04x %s\n", u[0], u[1], u[2], u[3], line.c_str()); 514 if ((current_catalog == pciclass) || 515 (current_catalog == pcisubclass) || (current_catalog == pciprogif)) 516 { 517 pci_classes.push_back(pci_entry(line, u[0], u[1], u[2], u[3])); 518 } 519 else 520 { 521 pci_devices.push_back(pci_entry(line, u[0], u[1], u[2], u[3])); 522 } 523 } 524 return true; 525 } 526 527 528 static bool load_pcidb() 529 { 530 vector < string > lines; 531 vector < string > filenames; 532 533 splitlines(PCIID_PATH, filenames, ':'); 534 for (int i = filenames.size() - 1; i >= 0; i--) 535 { 536 lines.clear(); 537 if (loadfile(filenames[i], lines) && (lines.size() > 0)) 538 parse_pcidb(lines); 539 } 540 541 return (pci_devices.size() > 0); 542 } 543 544 545 static string get_class_description(long c, 546 long pi = -1) 547 { 548 pci_entry result(""); 549 550 if (find_best_match(pci_classes, result, c >> 8, c & 0xff, pi)) 551 return result.description; 552 else 553 return ""; 554 } 555 556 557 static string get_device_description(long u1, 558 long u2 = -1, 559 long u3 = -1, 560 long u4 = -1) 561 { 562 pci_entry result(""); 563 564 if (find_best_match(pci_devices, result, u1, u2, u3, u4)) 565 return result.description; 566 else 567 return ""; 568 } 569 570 571 static u_int32_t get_conf_long(struct pci_dev d, 572 unsigned int pos) 573 { 574 if (pos + 3 >= sizeof(d.config)) 575 return 0; 576 577 return d.config[pos] | (d.config[pos + 1] << 8) | 578 (d.config[pos + 2] << 16) | (d.config[pos + 3] << 24); 579 } 580 581 582 static u_int16_t get_conf_word(struct pci_dev d, 583 unsigned int pos) 584 { 585 if (pos + 1 >= sizeof(d.config)) 586 return 0; 587 588 return d.config[pos] | (d.config[pos + 1] << 8); 589 } 590 591 592 static u_int8_t get_conf_byte(struct pci_dev d, 593 unsigned int pos) 594 { 595 if (pos >= sizeof(d.config)) 596 return 0; 597 598 return d.config[pos]; 599 } 600 601 602 static string pci_bushandle(u_int8_t bus, u_int16_t domain = 0) 603 { 604 char buffer[20]; 605 606 if(domain == (u_int16_t)(-1)) 607 snprintf(buffer, sizeof(buffer), "%02x", bus); 608 else 609 snprintf(buffer, sizeof(buffer), "%04x:%02x", domain, bus); 610 611 return "PCIBUS:" + string(buffer); 612 } 613 614 615 static string pci_handle(u_int16_t bus, 616 u_int8_t dev, 617 u_int8_t fct, 618 u_int16_t domain = 0) 619 { 620 char buffer[30]; 621 622 if(domain == (u_int16_t)(-1)) 623 snprintf(buffer, sizeof(buffer), "PCI:%02x:%02x.%x", bus, dev, fct); 624 else 625 snprintf(buffer, sizeof(buffer), "PCI:%04x:%02x:%02x.%x", domain, bus, dev, fct); 626 627 return string(buffer); 628 } 629 630 631 static bool scan_resources(hwNode & n, 632 struct pci_dev &d) 633 { 634 u_int16_t cmd = get_conf_word(d, PCI_COMMAND); 635 636 n.setWidth(32); 637 638 for (int i = 0; i < 6; i++) 639 { 640 u_int32_t flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4 * i); 641 u_int32_t pos = d.base_addr[i]; 642 u_int32_t len = d.size[i]; 643 644 if (flg == 0xffffffff) 645 flg = 0; 646 647 if (!pos && !flg && !len) 648 continue; 649 650 if (pos && !flg) /* Reported by the OS, but not by the device */ 651 { 652 //printf("[virtual] "); 653 flg = pos; 654 } 655 if (flg & PCI_BASE_ADDRESS_SPACE_IO) 656 { 657 u_int32_t a = pos & PCI_BASE_ADDRESS_IO_MASK; 658 if ((a != 0) && (cmd & PCI_COMMAND_IO) != 0) 659 n.addResource(hw::resource::ioport(a, a + len - 1)); 660 } 661 else // resource is memory 662 { 663 int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK; 664 u_int64_t a = pos & PCI_ADDR_MEM_MASK; 665 u_int64_t z = 0; 666 667 if (t == PCI_BASE_ADDRESS_MEM_TYPE_64) 668 { 669 n.setWidth(64); 670 if (i < 5) 671 { 672 i++; 673 z = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4 * i); 674 a += z << 4; 675 } 676 } 677 if (a) 678 n.addResource(hw::resource::iomem(a, a + len - 1)); 679 } 680 } 681 682 return true; 683 } 684 685 static bool scan_capabilities(hwNode & n, struct pci_dev &d) 686 { 687 unsigned int where = get_conf_byte(d, PCI_CAPABILITY_LIST) & ~3; 688 string buffer; 689 unsigned int ttl = PCI_FIND_CAP_TTL; 690 691 while(where && ttl--) 692 { 693 unsigned int id, next, cap; 694 695 id = get_conf_byte(d, where + PCI_CAP_LIST_ID); 696 next = get_conf_byte(d, where + PCI_CAP_LIST_NEXT) & ~3; 697 cap = get_conf_word(d, where + PCI_CAP_FLAGS); 698 699 if(!id || id == 0xff) 700 return false; 701 702 switch(id) 703 { 704 case PCI_CAP_ID_PM: 705 n.addCapability("pm", "Power Management"); 706 break; 707 case PCI_CAP_ID_AGP: 708 n.addCapability("agp", "AGP"); 709 buffer = hw::asString((cap >> 4) & 0x0f) + "." + hw::asString(cap & 0x0f); 710 n.addCapability("agp-"+buffer, "AGP "+buffer); 711 break; 712 case PCI_CAP_ID_VPD: 713 n.addCapability("vpd", "Vital Product Data"); 714 break; 715 case PCI_CAP_ID_SLOTID: 716 n.addCapability("slotid", "Slot Identification"); 717 n.setSlot(hw::asString(cap & PCI_SID_ESR_NSLOTS)+", chassis "+hw::asString(cap>>8)); 718 break; 719 case PCI_CAP_ID_MSI: 720 n.addCapability("msi", "Message Signalled Interrupts"); 721 break; 722 case PCI_CAP_ID_CHSWP: 723 n.addCapability("hotswap", "Hot-swap"); 724 break; 725 case PCI_CAP_ID_PCIX: 726 n.addCapability("pcix", "PCI-X"); 727 break; 728 case PCI_CAP_ID_HT: 729 n.addCapability("ht", "HyperTransport"); 730 break; 731 case PCI_CAP_ID_DBG: 732 n.addCapability("debug", "Debug port"); 733 break; 734 case PCI_CAP_ID_CCRC: 735 n.addCapability("ccrc", "CompactPCI Central Resource Control"); 736 break; 737 case PCI_CAP_ID_AGP3: 738 n.addCapability("agp8x", "AGP 8x"); 739 break; 740 case PCI_CAP_ID_EXP: 741 n.addCapability("pciexpress", _("PCI Express")); 742 break; 743 case PCI_CAP_ID_MSIX: 744 n.addCapability("msix", "MSI-X"); 745 break; 746 } 747 748 where = next; 749 } 750 751 return true; 752 } 753 754 755 static void addHints(hwNode & n, 756 long _vendor, 757 long _device, 758 long _subvendor, 759 long _subdevice, 760 long _class) 761 { 762 n.addHint("pci.vendor", _vendor); 763 n.addHint("pci.device", _device); 764 if(_subvendor && (_subvendor != 0xffff)) 765 { 766 n.addHint("pci.subvendor", _subvendor); 767 n.addHint("pci.subdevice", _subdevice); 768 } 769 n.addHint("pci.class", _class); 770 } 771 772 static hwNode *scan_pci_dev(struct pci_dev &d, hwNode & n) 773 { 774 hwNode *result = NULL; 775 hwNode *core = n.getChild("core"); 776 if (!core) 777 { 778 n.addChild(hwNode("core", hw::bus)); 779 core = n.getChild("core"); 780 } 781 782 if(!pcidb_loaded) 783 pcidb_loaded = load_pcidb(); 784 785 u_int16_t tmp_vendor_id = get_conf_word(d, PCI_VENDOR_ID); 786 u_int16_t tmp_device_id = get_conf_word(d, PCI_DEVICE_ID); 787 if ((tmp_vendor_id & tmp_device_id) != 0xffff) { 788 d.vendor_id = tmp_vendor_id; 789 d.device_id = tmp_device_id; 790 } 791 u_int16_t dclass = get_conf_word(d, PCI_CLASS_DEVICE); 792 u_int16_t cmd = get_conf_word(d, PCI_COMMAND); 793 u_int16_t status = get_conf_word(d, PCI_STATUS); 794 u_int8_t latency = get_conf_byte(d, PCI_LATENCY_TIMER); 795 u_int8_t min_gnt = get_conf_byte(d, PCI_MIN_GNT); 796 u_int8_t max_lat = get_conf_byte(d, PCI_MAX_LAT); 797 u_int8_t progif = get_conf_byte(d, PCI_CLASS_PROG); 798 u_int8_t rev = get_conf_byte(d, PCI_REVISION_ID); 799 u_int8_t htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f; 800 u_int16_t subsys_v = 0, subsys_d = 0; 801 802 char revision[10]; 803 snprintf(revision, sizeof(revision), "%02x", rev); 804 string moredescription = get_class_description(dclass, progif); 805 806 switch (htype) 807 { 808 case PCI_HEADER_TYPE_NORMAL: 809 subsys_v = get_conf_word(d, PCI_SUBSYSTEM_VENDOR_ID); 810 subsys_d = get_conf_word(d, PCI_SUBSYSTEM_ID); 811 break; 812 case PCI_HEADER_TYPE_BRIDGE: 813 subsys_v = subsys_d = 0; 814 latency = get_conf_byte(d, PCI_SEC_LATENCY_TIMER); 815 break; 816 case PCI_HEADER_TYPE_CARDBUS: 817 subsys_v = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID); 818 subsys_d = get_conf_word(d, PCI_CB_SUBSYSTEM_ID); 819 latency = get_conf_byte(d, PCI_CB_LATENCY_TIMER); 820 break; 821 } 822 823 if (dclass == PCI_CLASS_BRIDGE_HOST) 824 { 825 hwNode host("pci", 826 hw::bridge); 827 828 host.setDescription(get_class_description(dclass, progif)); 829 host.setVendor(get_device_description(d.vendor_id)+(enabled("output:numeric")?" ["+tohex(d.vendor_id)+"]":"")); 830 host.setProduct(get_device_description(d.vendor_id, d.device_id)+(enabled("output:numeric")?" ["+tohex(d.vendor_id)+":"+tohex(d.device_id)+"]":"")); 831 if (subsys_v != 0 || subsys_d != 0) 832 { 833 host.setSubVendor(get_device_description(subsys_v)+(enabled("output:numeric")?" ["+tohex(subsys_v)+"]":"")); 834 host.setSubProduct(get_device_description(subsys_v, subsys_d)+(enabled("output:numeric")?" ["+tohex(subsys_v)+":"+tohex(subsys_d)+"]":"")); 835 } 836 host.setHandle(pci_bushandle(d.bus, d.domain)); 837 host.setVersion(revision); 838 addHints(host, d.vendor_id, d.device_id, subsys_v, subsys_d, dclass); 839 host.claim(); 840 if(latency) 841 host.setConfig("latency", latency); 842 if (d.size[0] > 0) 843 host.setPhysId(0x100 + d.domain); 844 845 if (moredescription != "" && moredescription != host.getDescription()) 846 { 847 host.addCapability(moredescription); 848 host.setDescription(host.getDescription() + " (" + 849 moredescription + ")"); 850 } 851 852 if (status & PCI_STATUS_66MHZ) 853 host.setClock(66000000UL); // 66MHz 854 else 855 host.setClock(33000000UL); // 33MHz 856 857 scan_resources(host, d); 858 859 if (core) 860 result = core->addChild(host); 861 else 862 result = n.addChild(host); 863 } 864 else 865 { 866 hw::hwClass deviceclass = hw::generic; 867 string devicename = "generic"; 868 string deviceicon = ""; 869 870 switch (dclass >> 8) 871 { 872 case PCI_BASE_CLASS_STORAGE: 873 deviceclass = hw::storage; 874 deviceicon = "disc"; 875 if(dclass == PCI_CLASS_STORAGE_SCSI) 876 deviceicon = "scsi"; 877 if(dclass == PCI_CLASS_STORAGE_RAID) 878 deviceicon = "raid"; 879 break; 880 case PCI_BASE_CLASS_NETWORK: 881 deviceclass = hw::network; 882 deviceicon = "network"; 883 break; 884 case PCI_BASE_CLASS_MEMORY: 885 deviceclass = hw::memory; 886 deviceicon = "memory"; 887 break; 888 case PCI_BASE_CLASS_BRIDGE: 889 deviceclass = hw::bridge; 890 break; 891 case PCI_BASE_CLASS_MULTIMEDIA: 892 deviceclass = hw::multimedia; 893 if(dclass == PCI_CLASS_MULTIMEDIA_AUDIO) 894 deviceicon = "audio"; 895 break; 896 case PCI_BASE_CLASS_DISPLAY: 897 deviceclass = hw::display; 898 deviceicon = "display"; 899 break; 900 case PCI_BASE_CLASS_COMMUNICATION: 901 deviceclass = hw::communication; 902 if(dclass == PCI_CLASS_COMMUNICATION_SERIAL) 903 deviceicon = "serial"; 904 if(dclass == PCI_CLASS_COMMUNICATION_PARALLEL) 905 deviceicon = "parallel"; 906 if(dclass == PCI_CLASS_COMMUNICATION_MODEM) 907 deviceicon = "modem"; 908 break; 909 case PCI_BASE_CLASS_SYSTEM: 910 deviceclass = hw::generic; 911 break; 912 case PCI_BASE_CLASS_INPUT: 913 deviceclass = hw::input; 914 break; 915 case PCI_BASE_CLASS_ACCELERATOR: 916 deviceclass = hw::accelerator; 917 deviceicon = "accelerator"; 918 break; 919 case PCI_BASE_CLASS_PROCESSOR: 920 deviceclass = hw::processor; 921 break; 922 case PCI_BASE_CLASS_SERIAL: 923 deviceclass = hw::bus; 924 if(dclass == PCI_CLASS_SERIAL_USB) 925 deviceicon = "usb"; 926 if(dclass == PCI_CLASS_SERIAL_FIREWIRE) 927 deviceicon = "firewire"; 928 break; 929 } 930 931 devicename = get_class_name(dclass); 932 hwNode *device = new hwNode(devicename, deviceclass); 933 934 if (device) 935 { 936 if(deviceicon != "") device->addHint("icon", deviceicon); 937 addHints(*device, d.vendor_id, d.device_id, subsys_v, subsys_d, dclass); 938 939 if (deviceclass == hw::bridge || deviceclass == hw::storage) 940 device->addCapability(devicename); 941 942 if(device->isCapable("isa") || 943 device->isCapable("pci") || 944 device->isCapable("agp")) 945 device->claim(); 946 947 scan_resources(*device, d); 948 scan_capabilities(*device, d); 949 950 if (deviceclass == hw::display) 951 for (int j = 0; j < 6; j++) 952 if ((d.size[j] != 0xffffffff) 953 && (d.size[j] > device->getSize())) 954 device->setSize(d.size[j]); 955 956 if (dclass == PCI_CLASS_BRIDGE_PCI) 957 { 958 device->setHandle(pci_bushandle(get_conf_byte(d, PCI_SECONDARY_BUS), d.domain)); 959 device->claim(); 960 } 961 else 962 { 963 char irq[10]; 964 965 snprintf(irq, sizeof(irq), "%d", d.irq); 966 device->setHandle(pci_handle(d.bus, d.dev, d.func, d.domain)); 967 device->setConfig("latency", latency); 968 if(max_lat) 969 device->setConfig("maxlatency", max_lat); 970 if(min_gnt) 971 device->setConfig("mingnt", min_gnt); 972 if (d.irq != 0) 973 { 974 //device->setConfig("irq", irq); 975 device->addResource(hw::resource::irq(d.irq)); 976 } 977 } 978 device->setDescription(get_class_description(dclass)); 979 980 if (dclass == PCI_CLASS_STORAGE_IDE) 981 { 982 // IDE programming interface names are really long and awkward, 983 // so don't add them as capabilities 984 if (progif == 0x00 || progif == 0x80) 985 device->addCapability("isa_compat_mode", "ISA compatibility mode"); 986 else if (progif == 0x05 || progif == 0x85) 987 device->addCapability("pci_native_mode", "PCI native mode"); 988 else if (progif == 0x0a || progif == 0x0f || progif == 0x8a || progif == 0x8f) 989 { 990 device->addCapability("isa_compat_mode", "ISA compatibility mode"); 991 device->addCapability("pci_native_mode", "PCI native mode"); 992 } 993 } 994 else if (moredescription != "" 995 && moredescription != device->getDescription()) 996 { 997 device->addCapability(moredescription); 998 } 999 device->setVendor(get_device_description(d.vendor_id)+(enabled("output:numeric")?" ["+tohex(d.vendor_id)+"]":"")); 1000 device->setVersion(revision); 1001 device->setProduct(get_device_description(d.vendor_id, d.device_id)+(enabled("output:numeric")?" ["+tohex(d.vendor_id)+":"+tohex(d.device_id)+"]":"")); 1002 if (subsys_v != 0 || subsys_d != 0) 1003 { 1004 device->setSubVendor(get_device_description(subsys_v)+(enabled("output:numeric")?" ["+tohex(subsys_v)+"]":"")); 1005 device->setSubProduct(get_device_description(subsys_v, subsys_d)+(enabled("output:numeric")?" ["+tohex(subsys_v)+":"+tohex(subsys_d)+"]":"")); 1006 } 1007 if (cmd & PCI_COMMAND_MASTER) 1008 device->addCapability("bus master", "bus mastering"); 1009 if (cmd & PCI_COMMAND_VGA_PALETTE) 1010 device->addCapability("VGA palette", "VGA palette"); 1011 if (status & PCI_STATUS_CAP_LIST) 1012 device->addCapability("cap list", "PCI capabilities listing"); 1013 if (status & PCI_STATUS_66MHZ) 1014 device->setClock(66000000UL); // 66MHz 1015 else 1016 device->setClock(33000000UL); // 33MHz 1017 1018 device->setPhysId(d.dev, d.func); 1019 1020 hwNode *bus = NULL; 1021 1022 bus = n.findChildByHandle(pci_bushandle(d.bus, d.domain)); 1023 1024 device->describeCapability("vga", "VGA graphical framebuffer"); 1025 device->describeCapability("pcmcia", "PC-Card (PCMCIA)"); 1026 device->describeCapability("generic", "Generic interface"); 1027 device->describeCapability("ohci", "Open Host Controller Interface"); 1028 device->describeCapability("uhci", "Universal Host Controller Interface (USB1)"); 1029 device->describeCapability("ehci", "Enhanced Host Controller Interface (USB2)"); 1030 if (bus) 1031 result = bus->addChild(*device); 1032 else 1033 { 1034 if (core) 1035 result = core->addChild(*device); 1036 else 1037 result = n.addChild(*device); 1038 } 1039 delete device; 1040 1041 } 1042 } 1043 return result; 1044 } 1045 1046 bool scan_pci_legacy(hwNode & n) 1047 { 1048 FILE *f; 1049 hwNode *core = n.getChild("core"); 1050 if (!core) 1051 { 1052 n.addChild(hwNode("core", hw::bus)); 1053 core = n.getChild("core"); 1054 } 1055 1056 if(!pcidb_loaded) 1057 pcidb_loaded = load_pcidb(); 1058 1059 f = fopen(PROC_BUS_PCI "/devices", "r"); 1060 if (f) 1061 { 1062 char buf[512]; 1063 1064 while (fgets(buf, sizeof(buf) - 1, f)) 1065 { 1066 unsigned int dfn, vend, cnt; 1067 struct pci_dev d; 1068 int fd = -1; 1069 string devicepath = ""; 1070 char devicename[20]; 1071 char businfo[20]; 1072 char driver[50]; 1073 hwNode *device = NULL; 1074 1075 memset(&d, 0, sizeof(d)); 1076 memset(driver, 0, sizeof(driver)); 1077 cnt = sscanf(buf, 1078 "%x %x %x %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %[ -z]s", 1079 &dfn, 1080 &vend, 1081 &d.irq, 1082 &d.base_addr[0], 1083 &d.base_addr[1], 1084 &d.base_addr[2], 1085 &d.base_addr[3], 1086 &d.base_addr[4], 1087 &d.base_addr[5], 1088 &d.rom_base_addr, 1089 &d.size[0], 1090 &d.size[1], 1091 &d.size[2], 1092 &d.size[3], &d.size[4], &d.size[5], &d.rom_size, driver); 1093 1094 if (cnt != 9 && cnt != 10 && cnt != 17 && cnt != 18) 1095 break; 1096 1097 d.bus = dfn >> 8; 1098 d.dev = PCI_SLOT(dfn & 0xff); 1099 d.func = PCI_FUNC(dfn & 0xff); 1100 d.vendor_id = vend >> 16; 1101 d.device_id = vend & 0xffff; 1102 1103 snprintf(devicename, sizeof(devicename), "%02x/%02x.%x", d.bus, d.dev, 1104 d.func); 1105 devicepath = string(PROC_BUS_PCI) + "/" + string(devicename); 1106 snprintf(businfo, sizeof(businfo), "%02x:%02x.%x", d.bus, d.dev, 1107 d.func); 1108 1109 fd = open(devicepath.c_str(), O_RDONLY); 1110 if (fd >= 0) 1111 { 1112 if(read(fd, d.config, sizeof(d.config)) != sizeof(d.config)) 1113 memset(&d.config, 0, sizeof(d.config)); 1114 close(fd); 1115 } 1116 1117 device = scan_pci_dev(d, n); 1118 if(device) 1119 { 1120 device->setBusInfo(businfo); 1121 } 1122 1123 } 1124 fclose(f); 1125 } 1126 1127 return false; 1128 } 1129 1130 bool scan_pci(hwNode & n) 1131 { 1132 bool result = false; 1133 dirent **devices = NULL; 1134 int count = 0; 1135 hwNode *core = n.getChild("core"); 1136 1137 if (!core) 1138 { 1139 n.addChild(hwNode("core", hw::bus)); 1140 core = n.getChild("core"); 1141 } 1142 1143 pcidb_loaded = load_pcidb(); 1144 1145 if(!pushd(SYS_BUS_PCI"/devices")) 1146 return false; 1147 count = scandir(".", &devices, selectlink, alphasort); 1148 if(count>=0) 1149 { 1150 int i = 0; 1151 for(i=0; i<count; i++) 1152 if(matches(devices[i]->d_name, "^[[:xdigit:]]+:[[:xdigit:]]+:[[:xdigit:]]+\\.[[:xdigit:]]+$")) 1153 { 1154 string devicepath = string(devices[i]->d_name)+"/config"; 1155 sysfs::entry device_entry = sysfs::entry::byBus("pci", devices[i]->d_name); 1156 struct pci_dev d; 1157 memset(&d, 0, sizeof(d)); 1158 int fd = open(devicepath.c_str(), O_RDONLY); 1159 if (fd >= 0) 1160 { 1161 if(read(fd, d.config, 64) == 64) 1162 { 1163 if(read(fd, d.config+64, sizeof(d.config)-64) != sizeof(d.config)-64) 1164 memset(d.config+64, 0, sizeof(d.config)-64); 1165 } 1166 close(fd); 1167 } 1168 1169 sscanf(devices[i]->d_name, "%hx:%hx:%hhx.%hhx", &d.domain, &d.bus, &d.dev, &d.func); 1170 sscanf(device_entry.vendor().c_str(), "%hx", &d.vendor_id); 1171 sscanf(device_entry.device().c_str(), "%hx", &d.device_id); 1172 hwNode *device = scan_pci_dev(d, n); 1173 1174 if(device) 1175 { 1176 string resourcename = string(devices[i]->d_name)+"/resource"; 1177 1178 device->setBusInfo(devices[i]->d_name); 1179 if(exists(string(devices[i]->d_name)+"/driver")) 1180 { 1181 string drivername = readlink(string(devices[i]->d_name)+"/driver"); 1182 string modulename = readlink(string(devices[i]->d_name)+"/driver/module"); 1183 1184 device->setConfig("driver", shortname(drivername)); 1185 if(exists(modulename)) 1186 device->setConfig("module", shortname(modulename)); 1187 1188 if(exists(string(devices[i]->d_name)+"/rom")) 1189 { 1190 device->addCapability("rom", "extension ROM"); 1191 } 1192 1193 if(exists(string(devices[i]->d_name)+"/irq")) 1194 { 1195 long irq = get_number(string(devices[i]->d_name)+"/irq", -1); 1196 if(irq>=0) 1197 device->addResource(hw::resource::irq(irq)); 1198 } 1199 device->claim(); 1200 } 1201 1202 device->setModalias(device_entry.modalias()); 1203 1204 if(exists(resourcename)) 1205 { 1206 FILE*resource = fopen(resourcename.c_str(), "r"); 1207 1208 if(resource) 1209 { 1210 while(!feof(resource)) 1211 { 1212 unsigned long long start, end, flags; 1213 1214 start = end = flags = 0; 1215 1216 if(fscanf(resource, "%llx %llx %llx", &start, &end, &flags) != 3) 1217 break; 1218 1219 if(flags & 0x101) 1220 device->addResource(hw::resource::ioport(start, end)); 1221 else 1222 if(flags & 0x100) 1223 device->addResource(hw::resource::iomem(start, end)); 1224 else 1225 if(flags & 0x200) 1226 device->addResource(hw::resource::mem(start, end, flags & 0x1000)); 1227 } 1228 fclose(resource); 1229 } 1230 } 1231 add_device_tree_info(*device, devices[i]->d_name); 1232 1233 result = true; 1234 } 1235 1236 free(devices[i]); 1237 } 1238 1239 free(devices); 1240 } 1241 popd(); 1242 return result; 1243 }