📄 lspci.c
字号:
/* * The PCI Utilities -- List All PCI Devices * * Copyright (c) 1997--2007 Martin Mares <mj@ucw.cz> * * Can be freely distributed and used under the terms of the GNU GPL. */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <stdarg.h>#include <unistd.h>#include "pciutils.h"/* Options */static int verbose; /* Show detailed information */static int opt_buscentric; /* Show bus addresses/IRQ's instead of CPU-visible ones */static int opt_hex; /* Show contents of config space as hexadecimal numbers */static struct pci_filter filter; /* Device filter */static int opt_tree; /* Show bus tree */static int opt_machine; /* Generate machine-readable output */static int opt_map_mode; /* Bus mapping mode enabled */static int opt_domains; /* Show domain numbers (0=disabled, 1=auto-detected, 2=requested) */const char program_name[] = "lspci";static char options[] = "nvbxs:d:ti:mgMD" GENERIC_OPTIONS ;static char help_msg[] = "\Usage: lspci [<switches>]\n\\n\-v\t\tBe verbose\n\-n\t\tShow numeric ID's\n\-nn\t\tShow both textual and numeric ID's (names & numbers)\n\-b\t\tBus-centric view (PCI addresses and IRQ's instead of those seen by the CPU)\n\-x\t\tShow hex-dump of the standard portion of config space\n\-xxx\t\tShow hex-dump of the whole config space (dangerous; root only)\n\-xxxx\t\tShow hex-dump of the 4096-byte extended config space (root only)\n\-s [[[[<domain>]:]<bus>]:][<slot>][.[<func>]]\tShow only devices in selected slots\n\-d [<vendor>]:[<device>]\tShow only selected devices\n\-t\t\tShow bus tree\n\-m\t\tProduce machine-readable output\n\-i <file>\tUse specified ID database instead of %s\n\-D\t\tAlways show domain numbers\n\-M\t\tEnable `bus mapping' mode (dangerous; root only)\n"GENERIC_HELP;/*** Communication with libpci ***/static struct pci_access *pacc;/* * If we aren't being compiled by GCC, use xmalloc() instead of alloca(). * This increases our memory footprint, but only slightly since we don't * use alloca() much. */#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__DragonFly__)/* alloca() is defined in stdlib.h */#elif defined(__GNUC__) && !defined(PCI_OS_WINDOWS)#include <alloca.h>#else#undef alloca#define alloca xmalloc#endif/*** Our view of the PCI bus ***/struct device { struct device *next; struct pci_dev *dev; unsigned int config_cached, config_bufsize; byte *config; /* Cached configuration space data */ byte *present; /* Maps which configuration bytes are present */};static struct device *first_dev;static int seen_errors;static intconfig_fetch(struct device *d, unsigned int pos, unsigned int len){ unsigned int end = pos+len; int result; while (pos < d->config_bufsize && len && d->present[pos]) pos++, len--; while (pos+len <= d->config_bufsize && len && d->present[pos+len-1]) len--; if (!len) return 1; if (end > d->config_bufsize) { int orig_size = d->config_bufsize; while (end > d->config_bufsize) d->config_bufsize *= 2; d->config = xrealloc(d->config, d->config_bufsize); d->present = xrealloc(d->present, d->config_bufsize); memset(d->present + orig_size, 0, d->config_bufsize - orig_size); } result = pci_read_block(d->dev, pos, d->config + pos, len); if (result) memset(d->present + pos, 1, len); return result;}static struct device *scan_device(struct pci_dev *p){ struct device *d; if (p->domain && !opt_domains) opt_domains = 1; if (!pci_filter_match(&filter, p)) return NULL; d = xmalloc(sizeof(struct device)); memset(d, 0, sizeof(*d)); d->dev = p; d->config_cached = d->config_bufsize = 64; d->config = xmalloc(64); d->present = xmalloc(64); memset(d->present, 1, 64); if (!pci_read_block(p, 0, d->config, 64)) { fprintf(stderr, "lspci: Unable to read the standard configuration space header of device %04x:%02x:%02x.%d\n", p->domain, p->bus, p->dev, p->func); seen_errors++; return NULL; } if ((d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS) { /* For cardbus bridges, we need to fetch 64 bytes more to get the * full standard header... */ if (config_fetch(d, 64, 64)) d->config_cached += 64; } pci_setup_cache(p, d->config, d->config_cached); pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES); return d;}static voidscan_devices(void){ struct device *d; struct pci_dev *p; pci_scan_bus(pacc); for(p=pacc->devices; p; p=p->next) if (d = scan_device(p)) { d->next = first_dev; first_dev = d; }}/*** Config space accesses ***/static voidcheck_conf_range(struct device *d, unsigned int pos, unsigned int len){ while (len) if (!d->present[pos]) die("Internal bug: Accessing non-read configuration byte at position %x", pos); else pos++, len--;}static inline byteget_conf_byte(struct device *d, unsigned int pos){ check_conf_range(d, pos, 1); return d->config[pos];}static wordget_conf_word(struct device *d, unsigned int pos){ check_conf_range(d, pos, 2); return d->config[pos] | (d->config[pos+1] << 8);}static u32get_conf_long(struct device *d, unsigned int pos){ check_conf_range(d, pos, 4); return d->config[pos] | (d->config[pos+1] << 8) | (d->config[pos+2] << 16) | (d->config[pos+3] << 24);}/*** Sorting ***/static intcompare_them(const void *A, const void *B){ const struct pci_dev *a = (*(const struct device **)A)->dev; const struct pci_dev *b = (*(const struct device **)B)->dev; if (a->domain < b->domain) return -1; if (a->domain > b->domain) return 1; if (a->bus < b->bus) return -1; if (a->bus > b->bus) return 1; if (a->dev < b->dev) return -1; if (a->dev > b->dev) return 1; if (a->func < b->func) return -1; if (a->func > b->func) return 1; return 0;}static voidsort_them(void){ struct device **index, **h, **last_dev; int cnt; struct device *d; cnt = 0; for(d=first_dev; d; d=d->next) cnt++; h = index = alloca(sizeof(struct device *) * cnt); for(d=first_dev; d; d=d->next) *h++ = d; qsort(index, cnt, sizeof(struct device *), compare_them); last_dev = &first_dev; h = index; while (cnt--) { *last_dev = *h; last_dev = &(*h)->next; h++; } *last_dev = NULL;}/*** Normal output ***/#define FLAG(x,y) ((x & y) ? '+' : '-')static voidshow_slot_name(struct device *d){ struct pci_dev *p = d->dev; if (!opt_machine ? opt_domains : (p->domain || opt_domains >= 2)) printf("%04x:", p->domain); printf("%02x:%02x.%d", p->bus, p->dev, p->func);}static voidshow_terse(struct device *d){ int c; struct pci_dev *p = d->dev; char classbuf[128], devbuf[128]; show_slot_name(d); printf(" %s: %s", pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, p->device_class), pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id)); if (c = get_conf_byte(d, PCI_REVISION_ID)) printf(" (rev %02x)", c); if (verbose) { char *x; c = get_conf_byte(d, PCI_CLASS_PROG); x = pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_PROGIF | PCI_LOOKUP_NO_NUMBERS, p->device_class, c); if (c || x) { printf(" (prog-if %02x", c); if (x) printf(" [%s]", x); putchar(')'); } } putchar('\n');}/*** Capabilities ***/static voidcap_pm(struct device *d, int where, int cap){ int t, b; static int pm_aux_current[8] = { 0, 55, 100, 160, 220, 270, 320, 375 }; printf("Power Management version %d\n", cap & PCI_PM_CAP_VER_MASK); if (verbose < 2) return; printf("\t\tFlags: PMEClk%c DSI%c D1%c D2%c AuxCurrent=%dmA PME(D0%c,D1%c,D2%c,D3hot%c,D3cold%c)\n", FLAG(cap, PCI_PM_CAP_PME_CLOCK), FLAG(cap, PCI_PM_CAP_DSI), FLAG(cap, PCI_PM_CAP_D1), FLAG(cap, PCI_PM_CAP_D2), pm_aux_current[(cap >> 6) & 7], FLAG(cap, PCI_PM_CAP_PME_D0), FLAG(cap, PCI_PM_CAP_PME_D1), FLAG(cap, PCI_PM_CAP_PME_D2), FLAG(cap, PCI_PM_CAP_PME_D3_HOT), FLAG(cap, PCI_PM_CAP_PME_D3_COLD)); if (!config_fetch(d, where + PCI_PM_CTRL, PCI_PM_SIZEOF - PCI_PM_CTRL)) return; t = get_conf_word(d, where + PCI_PM_CTRL); printf("\t\tStatus: D%d PME-Enable%c DSel=%d DScale=%d PME%c\n", t & PCI_PM_CTRL_STATE_MASK, FLAG(t, PCI_PM_CTRL_PME_ENABLE), (t & PCI_PM_CTRL_DATA_SEL_MASK) >> 9, (t & PCI_PM_CTRL_DATA_SCALE_MASK) >> 13, FLAG(t, PCI_PM_CTRL_PME_STATUS)); b = get_conf_byte(d, where + PCI_PM_PPB_EXTENSIONS); if (b) printf("\t\tBridge: PM%c B3%c\n", FLAG(t, PCI_PM_BPCC_ENABLE), FLAG(~t, PCI_PM_PPB_B2_B3));}static voidformat_agp_rate(int rate, char *buf, int agp3){ char *c = buf; int i; for(i=0; i<=2; i++) if (rate & (1 << i)) { if (c != buf) *c++ = ','; c += sprintf(c, "x%d", 1 << (i + 2*agp3)); } if (c != buf) *c = 0; else strcpy(buf, "<none>");}static voidcap_agp(struct device *d, int where, int cap){ u32 t; char rate[16]; int ver, rev; int agp3 = 0; ver = (cap >> 4) & 0x0f; rev = cap & 0x0f; printf("AGP version %x.%x\n", ver, rev); if (verbose < 2) return; if (!config_fetch(d, where + PCI_AGP_STATUS, PCI_AGP_SIZEOF - PCI_AGP_STATUS)) return; t = get_conf_long(d, where + PCI_AGP_STATUS); if (ver >= 3 && (t & PCI_AGP_STATUS_AGP3)) agp3 = 1; format_agp_rate(t & 7, rate, agp3); printf("\t\tStatus: RQ=%d Iso%c ArqSz=%d Cal=%d SBA%c ITACoh%c GART64%c HTrans%c 64bit%c FW%c AGP3%c Rate=%s\n", ((t & PCI_AGP_STATUS_RQ_MASK) >> 24U) + 1, FLAG(t, PCI_AGP_STATUS_ISOCH), ((t & PCI_AGP_STATUS_ARQSZ_MASK) >> 13), ((t & PCI_AGP_STATUS_CAL_MASK) >> 10), FLAG(t, PCI_AGP_STATUS_SBA), FLAG(t, PCI_AGP_STATUS_ITA_COH), FLAG(t, PCI_AGP_STATUS_GART64), FLAG(t, PCI_AGP_STATUS_HTRANS), FLAG(t, PCI_AGP_STATUS_64BIT), FLAG(t, PCI_AGP_STATUS_FW), FLAG(t, PCI_AGP_STATUS_AGP3), rate); t = get_conf_long(d, where + PCI_AGP_COMMAND); format_agp_rate(t & 7, rate, agp3); printf("\t\tCommand: RQ=%d ArqSz=%d Cal=%d SBA%c AGP%c GART64%c 64bit%c FW%c Rate=%s\n", ((t & PCI_AGP_COMMAND_RQ_MASK) >> 24U) + 1, ((t & PCI_AGP_COMMAND_ARQSZ_MASK) >> 13), ((t & PCI_AGP_COMMAND_CAL_MASK) >> 10), FLAG(t, PCI_AGP_COMMAND_SBA), FLAG(t, PCI_AGP_COMMAND_AGP), FLAG(t, PCI_AGP_COMMAND_GART64), FLAG(t, PCI_AGP_COMMAND_64BIT), FLAG(t, PCI_AGP_COMMAND_FW), rate);}static voidcap_pcix_nobridge(struct device *d, int where){ u16 command; u32 status; static const byte max_outstanding[8] = { 1, 2, 3, 4, 8, 12, 16, 32 }; printf("PCI-X non-bridge device\n"); if (verbose < 2) return; if (!config_fetch(d, where + PCI_PCIX_STATUS, 4)) return; command = get_conf_word(d, where + PCI_PCIX_COMMAND); status = get_conf_long(d, where + PCI_PCIX_STATUS); printf("\t\tCommand: DPERE%c ERO%c RBC=%d OST=%d\n", FLAG(command, PCI_PCIX_COMMAND_DPERE), FLAG(command, PCI_PCIX_COMMAND_ERO), 1 << (9 + ((command & PCI_PCIX_COMMAND_MAX_MEM_READ_BYTE_COUNT) >> 2U)), max_outstanding[(command & PCI_PCIX_COMMAND_MAX_OUTSTANDING_SPLIT_TRANS) >> 4U]); printf("\t\tStatus: Dev=%02x:%02x.%d 64bit%c 133MHz%c SCD%c USC%c DC=%s DMMRBC=%u DMOST=%u DMCRS=%u RSCEM%c 266MHz%c 533MHz%c\n", ((status >> 8) & 0xff), ((status >> 3) & 0x1f), (status & PCI_PCIX_STATUS_FUNCTION), FLAG(status, PCI_PCIX_STATUS_64BIT), FLAG(status, PCI_PCIX_STATUS_133MHZ), FLAG(status, PCI_PCIX_STATUS_SC_DISCARDED), FLAG(status, PCI_PCIX_STATUS_UNEXPECTED_SC), ((status & PCI_PCIX_STATUS_DEVICE_COMPLEXITY) ? "bridge" : "simple"), 1 << (9 + ((status >> 21) & 3U)),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -