📄 lspci.c
字号:
/* * The PCI Utilities -- List All PCI Devices * * Copyright (c) 1997--2008 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 "lspci.h"/* Options */int verbose; /* Show detailed information */static int opt_hex; /* Show contents of config space as hexadecimal numbers */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) */static int opt_kernel; /* Show kernel drivers */static int opt_query_dns; /* Query the DNS (0=disabled, 1=enabled, 2=refresh cache) */static int opt_query_all; /* Query the DNS for all entries */char *opt_pcimap; /* Override path to Linux modules.pcimap */const char program_name[] = "lspci";static char options[] = "nvbxs:d:ti:mgp:qkMDQ" GENERIC_OPTIONS ;static char help_msg[] ="Usage: lspci [<switches>]\n""\n""Basic display modes:\n""-mm\t\tProduce machine-readable output (single -m for an obsolete format)\n""-t\t\tShow bus tree\n""\n""Display options:\n""-v\t\tBe verbose (-vv for very verbose)\n"#ifdef PCI_OS_LINUX"-k\t\tShow kernel drivers handling each device\n"#endif"-x\t\tShow hex-dump of the standard part of the 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""-b\t\tBus-centric view (addresses and IRQ's as seen by the bus)\n""-D\t\tAlways show domain numbers\n""\n""Resolving of device ID's to names:\n""-n\t\tShow numeric ID's\n""-nn\t\tShow both textual and numeric ID's (names & numbers)\n"#ifdef PCI_USE_DNS"-q\t\tQuery the PCI ID database for unknown ID's via DNS\n""-qq\t\tAs above, but re-query locally cached entries\n""-Q\t\tQuery the PCI ID database for all ID's via DNS\n"#endif"\n""Selection of devices:\n""-s [[[[<domain>]:]<bus>]:][<slot>][.[<func>]]\tShow only devices in selected slots\n""-d [<vendor>]:[<device>]\t\t\tShow only devices with specified ID's\n""\n""Other options:\n""-i <file>\tUse specified ID database instead of %s\n"#ifdef PCI_OS_LINUX"-p <file>\tLook up kernel modules in a given file instead of default modules.pcimap\n"#endif"-M\t\tEnable `bus mapping' mode (dangerous; root only)\n""\n""PCI access options:\n"GENERIC_HELP;/*** Our view of the PCI bus ***/struct pci_access *pacc;struct device *first_dev;static int seen_errors;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;}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 | PCI_FILL_PHYS_SLOT); 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--;}byteget_conf_byte(struct device *d, unsigned int pos){ check_conf_range(d, pos, 1); return d->config[pos];}wordget_conf_word(struct device *d, unsigned int pos){ check_conf_range(d, pos, 2); return d->config[pos] | (d->config[pos+1] << 8);}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 ***/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);}voidget_subid(struct device *d, word *subvp, word *subdp){ byte htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f; if (htype == PCI_HEADER_TYPE_NORMAL) { *subvp = get_conf_word(d, PCI_SUBSYSTEM_VENDOR_ID); *subdp = get_conf_word(d, PCI_SUBSYSTEM_ID); } else if (htype == PCI_HEADER_TYPE_CARDBUS && d->config_cached >= 128) { *subvp = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID); *subdp = get_conf_word(d, PCI_CB_SUBSYSTEM_ID); } else *subvp = *subdp = 0xffff;}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'); if (verbose || opt_kernel) { word subsys_v, subsys_d; char ssnamebuf[256]; get_subid(d, &subsys_v, &subsys_d); if (subsys_v && subsys_v != 0xffff) printf("\tSubsystem: %s\n", pci_lookup_name(pacc, ssnamebuf, sizeof(ssnamebuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, subsys_v, subsys_d)); }}/*** Verbose output ***/static voidshow_size(pciaddr_t x){ if (!x) return; printf(" [size="); if (x < 1024) printf("%d", (int) x); else if (x < 1048576) printf("%dK", (int)(x / 1024)); else if (x < 0x80000000) printf("%dM", (int)(x / 1048576)); else printf(PCIADDR_T_FMT, x); putchar(']');}static voidshow_bases(struct device *d, int cnt){ struct pci_dev *p = d->dev; word cmd = get_conf_word(d, PCI_COMMAND); int i; int virtual = 0; for (i=0; i<cnt; i++) { pciaddr_t pos = p->base_addr[i]; pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->size[i] : 0; u32 flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i); if (flg == 0xffffffff) flg = 0; if (!pos && !flg && !len) continue; if (verbose > 1) printf("\tRegion %d: ", i); else putchar('\t'); if (pos && !flg) /* Reported by the OS, but not by the device */ { printf("[virtual] "); flg = pos; virtual = 1; } if (flg & PCI_BASE_ADDRESS_SPACE_IO) { pciaddr_t a = pos & PCI_BASE_ADDRESS_IO_MASK; printf("I/O ports at "); if (a) printf(PCIADDR_PORT_FMT, a); else if (flg & PCI_BASE_ADDRESS_IO_MASK) printf("<ignored>"); else printf("<unassigned>"); if (!virtual && !(cmd & PCI_COMMAND_IO)) printf(" [disabled]"); } else { int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK; pciaddr_t a = pos & PCI_ADDR_MEM_MASK; int done = 0; u32 z = 0; printf("Memory at "); if (t == PCI_BASE_ADDRESS_MEM_TYPE_64) { if (i >= cnt - 1) { printf("<invalid-64bit-slot>"); done = 1; } else { i++; z = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i); } } if (!done) { if (a) printf(PCIADDR_T_FMT, a); else printf(((flg & PCI_BASE_ADDRESS_MEM_MASK) || z) ? "<ignored>" : "<unassigned>"); } printf(" (%s, %sprefetchable)", (t == PCI_BASE_ADDRESS_MEM_TYPE_32) ? "32-bit" : (t == PCI_BASE_ADDRESS_MEM_TYPE_64) ? "64-bit" : (t == PCI_BASE_ADDRESS_MEM_TYPE_1M) ? "low-1M" : "type 3", (flg & PCI_BASE_ADDRESS_MEM_PREFETCH) ? "" : "non-"); if (!virtual && !(cmd & PCI_COMMAND_MEMORY)) printf(" [disabled]"); } show_size(len); putchar('\n'); }}static voidshow_rom(struct device *d, int reg){ struct pci_dev *p = d->dev; pciaddr_t rom = p->rom_base_addr; pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->rom_size : 0; u32 flg = get_conf_long(d, reg); word cmd = get_conf_word(d, PCI_COMMAND); int virtual = 0; if (!rom && !flg && !len) return; putchar('\t'); if ((rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK)) { printf("[virtual] "); flg = rom; virtual = 1; } printf("Expansion ROM at "); if (rom & PCI_ROM_ADDRESS_MASK) printf(PCIADDR_T_FMT, rom & PCI_ROM_ADDRESS_MASK); else if (flg & PCI_ROM_ADDRESS_MASK) printf("<ignored>"); else printf("<unassigned>"); if (!(flg & PCI_ROM_ADDRESS_ENABLE)) printf(" [disabled]"); else if (!virtual && !(cmd & PCI_COMMAND_MEMORY)) printf(" [disabled by cmd]"); show_size(len); putchar('\n');}static voidshow_htype0(struct device *d){ show_bases(d, 6); show_rom(d, PCI_ROM_ADDRESS); show_caps(d);}static voidshow_htype1(struct device *d){ u32 io_base = get_conf_byte(d, PCI_IO_BASE); u32 io_limit = get_conf_byte(d, PCI_IO_LIMIT); u32 io_type = io_base & PCI_IO_RANGE_TYPE_MASK; u32 mem_base = get_conf_word(d, PCI_MEMORY_BASE); u32 mem_limit = get_conf_word(d, PCI_MEMORY_LIMIT); u32 mem_type = mem_base & PCI_MEMORY_RANGE_TYPE_MASK; u32 pref_base = get_conf_word(d, PCI_PREF_MEMORY_BASE); u32 pref_limit = get_conf_word(d, PCI_PREF_MEMORY_LIMIT); u32 pref_type = pref_base & PCI_PREF_RANGE_TYPE_MASK; word sec_stat = get_conf_word(d, PCI_SEC_STATUS); word brc = get_conf_word(d, PCI_BRIDGE_CONTROL); int verb = verbose > 2; show_bases(d, 2); printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n", get_conf_byte(d, PCI_PRIMARY_BUS), get_conf_byte(d, PCI_SECONDARY_BUS), get_conf_byte(d, PCI_SUBORDINATE_BUS), get_conf_byte(d, PCI_SEC_LATENCY_TIMER)); if (io_type != (io_limit & PCI_IO_RANGE_TYPE_MASK) || (io_type != PCI_IO_RANGE_TYPE_16 && io_type != PCI_IO_RANGE_TYPE_32)) printf("\t!!! Unknown I/O range types %x/%x\n", io_base, io_limit); else { io_base = (io_base & PCI_IO_RANGE_MASK) << 8; io_limit = (io_limit & PCI_IO_RANGE_MASK) << 8; if (io_type == PCI_IO_RANGE_TYPE_32) { io_base |= (get_conf_word(d, PCI_IO_BASE_UPPER16) << 16); io_limit |= (get_conf_word(d, PCI_IO_LIMIT_UPPER16) << 16); } if (io_base <= io_limit || verb) printf("\tI/O behind bridge: %08x-%08x\n", io_base, io_limit+0xfff); } if (mem_type != (mem_limit & PCI_MEMORY_RANGE_TYPE_MASK) || mem_type) printf("\t!!! Unknown memory range types %x/%x\n", mem_base, mem_limit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -