]> mj.ucw.cz Git - pciutils.git/commitdiff
Finished support for displaying of kernel drivers/modules.
authorMartin Mares <mj@ucw.cz>
Tue, 6 Nov 2007 21:26:48 +0000 (22:26 +0100)
committerMartin Mares <mj@ucw.cz>
Tue, 6 Nov 2007 21:26:48 +0000 (22:26 +0100)
ChangeLog
lspci.c
lspci.man

index cca39ca0578816e8e62b011c2ce641c853401540..b94c85a7164a3556d300226a762becd5d07918a1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2007-11-06  Martin Mares <mj@ucw.cz>
+
+       * lspci.c: Added a new switch `-k' which requests printing
+       of information on kernel drivers attached to each device
+       and on kernel modules reporting the ability to handle the
+       device. So far, this is supported only on Linux with the
+       sysfs back-end, so it is implemented internally in the lspci
+       instead of the libpci. Thanks to Anicka <anicka@anicka.net>
+       for help.
+
 2007-10-19  Martin Mares <mj@ucw.cz>
 
        * Makefile, lib/Makefile: Moved -lz from LDFLAGS to LDLIBS.
diff --git a/lspci.c b/lspci.c
index f933235e5e9c551720b217f3c1ec99735abb533f..3110ea00ef979aaf89ec48249ca58f4e02b5da0a 100644 (file)
--- a/lspci.c
+++ b/lspci.c
@@ -24,11 +24,12 @@ 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 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 options[] = "nvbxs:d:ti:mgp:kMD" GENERIC_OPTIONS ;
 
 static char help_msg[] = "\
 Usage: lspci [<switches>]\n\
@@ -47,6 +48,7 @@ Usage: lspci [<switches>]\n\
 -i <file>\tUse specified ID database instead of %s\n"
 #ifdef PCI_OS_LINUX
 "\
+-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
 "\
@@ -1571,44 +1573,47 @@ match_pcimap(struct device *d, struct pcimap_entry *e)
 #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;
   int n;
 
   if (dev->access->method != PCI_ACCESS_SYS_BUS_PCI)
-    return;
+    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)))
@@ -1620,15 +1625,34 @@ show_module(struct device *d)
     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)
 {
 }
 
@@ -2099,9 +2123,6 @@ show_verbose(struct device *d)
       show_htype2(d);
       break;
     }
-
-  show_driver(d);
-  show_module(d);
 }
 
 /*** Machine-readable dumps ***/
@@ -2174,6 +2195,8 @@ show_machine(struct device *d)
        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
     {
@@ -2203,10 +2226,15 @@ show_device(struct device *d)
 {
   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)
@@ -2691,6 +2719,9 @@ main(int argc, char **argv)
       case 'p':
        opt_pcimap = optarg;
        break;
+      case 'k':
+       opt_kernel++;
+       break;
       case 'M':
        opt_map_mode++;
        break;
index 1d5583bb31d7aa98023593fd0a4d0711cbeb157a..5ce14f00ba2e646acd315024b713430108792296 100644 (file)
--- a/lspci.man
+++ b/lspci.man
@@ -73,6 +73,13 @@ devices are rare, so you needn't worry much.
 Show hexadecimal dump of the extended (4096-byte) PCI configuration space available
 on PCI-X 2.0 and PCI Express buses.
 .TP
+.B -k
+Show kernel drivers handling each device and also kernel modules capable of handling it.
+Turned on by default when
+.B -v
+is given in the normal mode of output.
+(Currently works only on Linux with kernel 2.6 or newer.)
+.TP
 .B -b
 Bus-centric view. Show all IRQ numbers and addresses as seen by the cards on the
 PCI bus instead of as seen by the kernel.
@@ -100,6 +107,14 @@ Use
 <file>
 as the PCI ID list instead of @IDSDIR@/pci.ids.
 .TP
+.B -p <file>
+Use
+.B
+<file>
+as the map of PCI ID's handled by kernel modules. By default, lspci uses
+.RI /lib/modules/ kernel_version /modules.pcimap.
+Applies only to Linux systems with recent enough module tools.
+.TP
 .B -m
 Dump PCI device data in a backward-compatible machine readable form.
 See below for details.
@@ -134,7 +149,8 @@ the following access methods:
 The
 .B /sys
 filesystem on Linux 2.6 and newer. The standard header of the config space is available
-to all users, the rest only to root. Supports extended configuration space and PCI domains.
+to all users, the rest only to root. Supports extended configuration space, PCI domains
+and information on attached kernel drivers.
 .TP
 .B linux_proc
 The
@@ -285,6 +301,15 @@ Revision number (optional).
 .B ProgIf
 Programming interface (optional).
 
+.TP
+.B Driver
+Kernel driver currently handling the device (optional, Linux only).
+
+.TP
+.B Module
+Kernel module reporting that it is capable of handling the device
+(optional, Linux only).
+
 .P
 New tags can be added in future versions, so you should silently ignore any tags you don't recognize.