/*
* The PCI Utilities -- List All PCI Devices
*
- * Copyright (c) 1997--2007 Martin Mares <mj@ucw.cz>
+ * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
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 */
static char *opt_pcimap; /* Override path to Linux modules.pcimap */
const char program_name[] = "lspci";
-static char options[] = "nvbxs:d:ti:mgp:MD" 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"
+static char options[] = "nvbxs:d:ti:mgp:qkMDQ" 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"
+#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
+"-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"
#ifdef PCI_OS_LINUX
-"\
--p <file>\tLook up kernel modules in a given file instead of default modules.pcimap\n"
+"-k\t\tShow kernel drivers handling each device\n"
+"-p <file>\tLook up kernel modules in a given file instead of default modules.pcimap\n"
#endif
-"\
--D\t\tAlways show domain numbers\n\
--M\t\tEnable `bus mapping' mode (dangerous; root only)\n"
+"-D\t\tAlways show domain numbers\n"
+"-M\t\tEnable `bus mapping' mode (dangerous; root only)\n"
GENERIC_HELP
;
#undef MATCH
}
-static void
-show_driver(struct device *d)
+#define DRIVER_BUF_SIZE 1024
+
+static char *
+find_driver(struct device *d, char *buf)
{
struct pci_dev *dev = d->dev;
- char *base = dev->access->method_params[PCI_ACCESS_SYS_BUS_PCI];
- char name[1024], driver[1024], *drv;
+ char name[1024], *drv, *base;
int n;
if (dev->access->method != PCI_ACCESS_SYS_BUS_PCI)
- return;
+ return NULL;
+
+ base = pci_get_param(dev->access, "sysfs.path");
+ if (!base || !base[0])
+ return NULL;
n = snprintf(name, sizeof(name), "%s/devices/%04x:%02x:%02x.%d/driver",
base, dev->domain, dev->bus, dev->dev, dev->func);
- if (n < 0 || n >= 1024)
+ if (n < 0 || n >= (int)sizeof(name))
die("show_driver: sysfs device name too long, why?");
- n = readlink(name, driver, sizeof(driver));
+ n = readlink(name, buf, DRIVER_BUF_SIZE);
if (n < 0)
- return;
- if (n >= (int)sizeof(driver))
- {
- printf("\t!!! Driver name too long\n");
- return;
- }
- driver[n] = 0;
+ return NULL;
+ if (n >= DRIVER_BUF_SIZE)
+ return "<name-too-long>";
+ buf[n] = 0;
- if (drv = strrchr(driver, '/'))
- drv++;
+ if (drv = strrchr(buf, '/'))
+ return drv+1;
else
- drv = driver;
- printf("\tKernel driver in use: %s\n", drv);
+ return buf;
}
static void
-show_module(struct device *d)
+show_kernel(struct device *d)
{
+ char buf[DRIVER_BUF_SIZE];
+ char *driver;
struct pcimap_entry *e, *last = NULL;
+ if (driver = find_driver(d, buf))
+ printf("\tKernel driver in use: %s\n", driver);
+
load_pcimap();
for (e=pcimap_head; e; e=e->next)
if (match_pcimap(d, e) && (!last || strcmp(last->module, e->module)))
putchar('\n');
}
+static void
+show_kernel_machine(struct device *d)
+{
+ char buf[DRIVER_BUF_SIZE];
+ char *driver;
+ struct pcimap_entry *e, *last = NULL;
+
+ if (driver = find_driver(d, buf))
+ printf("Driver:\t%s\n", driver);
+
+ load_pcimap();
+ for (e=pcimap_head; e; e=e->next)
+ if (match_pcimap(d, e) && (!last || strcmp(last->module, e->module)))
+ {
+ printf("Module:\t%s\n", e->module);
+ last = e;
+ }
+}
+
#else
static void
-show_driver(void)
+show_kernel(struct device *d UNUSED)
{
}
static void
-show_module(void)
+show_kernel_machine(struct device *d UNUSED)
{
}
show_htype2(d);
break;
}
-
- show_driver(d);
- show_module(d);
}
/*** Machine-readable dumps ***/
printf("Rev:\t%02x\n", c);
if (c = get_conf_byte(d, PCI_CLASS_PROG))
printf("ProgIf:\t%02x\n", c);
+ if (opt_kernel)
+ show_kernel_machine(d);
}
else
{
{
if (opt_machine)
show_machine(d);
- else if (verbose)
- show_verbose(d);
else
- show_terse(d);
+ {
+ if (verbose)
+ show_verbose(d);
+ else
+ show_terse(d);
+ if (opt_kernel || verbose)
+ show_kernel(d);
+ }
if (opt_hex)
show_hex_dump(d);
if (verbose || opt_hex)
case 'p':
opt_pcimap = optarg;
break;
+ case 'k':
+ opt_kernel++;
+ break;
case 'M':
opt_map_mode++;
break;
case 'D':
opt_domains = 2;
break;
+#ifdef PCI_USE_DNS
+ case 'q':
+ opt_query_dns++;
+ break;
+ case 'Q':
+ opt_query_all = 1;
+ break;
+#else
+ case 'q':
+ case 'Q':
+ die("DNS queries are not available in this version");
+#endif
default:
if (parse_generic_option(i, pacc, optarg))
break;
if (optind < argc)
goto bad;
+ if (opt_query_dns)
+ {
+ pacc->id_lookup_mode |= PCI_LOOKUP_NETWORK;
+ if (opt_query_dns > 1)
+ pacc->id_lookup_mode |= PCI_LOOKUP_REFRESH_CACHE;
+ }
+ if (opt_query_all)
+ pacc->id_lookup_mode |= PCI_LOOKUP_NETWORK | PCI_LOOKUP_SKIP_LOCAL;
+
pci_init(pacc);
if (opt_map_mode)
map_the_bus();