]> mj.ucw.cz Git - pciutils.git/commitdiff
Intermediate version of pciutils.
authorMartin Mares <mj@ucw.cz>
Tue, 31 Mar 1998 21:02:11 +0000 (21:02 +0000)
committerMartin Mares <mj@ucw.cz>
Fri, 5 May 2006 12:09:50 +0000 (14:09 +0200)
- New filtering code (see ChangeLog and man page), lspci modified
  to use it.

- First attempt to write setpci, but just now doesn't compile.
  (It's commented out in Makefile and I commit it only because
  I need to work on it on different computer.)

Will be released as 1.03 as soon as setpci starts working.

ChangeLog
Makefile
README
filter.c [new file with mode: 0644]
lspci.8
lspci.c
pciutils.h
pciutils.lsm
setpci.c [new file with mode: 0644]

index b61db0c91856b9d773c3695272e81223cded467e..5b34d8e3a50213e1ebc7a26c59878a4619a24989 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Tue Mar 31 23:11:57 1998  Martin Mares  <mj@albireo.ucw.cz>
+
+       * setpci.c: Added.
+
+Sun Mar 22 15:39:08 1998  Martin Mares  <mj@albireo.ucw.cz>
+
+       * lspci.8: Updated the documentation.
+
+       * lspci.c: Modified to use the new filtering mechanism (options -f and -d).
+
+       * filter.c: Introduced new generic device filter.
+
 Thu Mar 19 17:03:48 1998  Martin Mares  <mj@lomikel.karlin.mff.cuni.cz>
 
        * lspci.c (grow_tree, show_tree_dev, print_it): Fixed displaying
index 7dbdb1e149d612b6e7e343c98a2771ec9bf85c61..bb58e3640573f3de5b3ae21259710ac387c13a0a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.6 1998/02/09 12:32:52 mj Exp $
+# $Id: Makefile,v 1.7 1998/03/31 21:02:12 mj Exp $
 # Makefile for Linux PCI Utilities
 # (c) 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
 
@@ -12,14 +12,21 @@ MANPREFIX=/usr
 
 all: lspci
 
-lspci: lspci.o names.o
+#all: lspci setpci
+
+lspci: lspci.o names.o filter.o
 
 lspci.o: lspci.c pciutils.h
 names.o: names.c pciutils.h
+filter.o: filter.c pciutils.h
+
+setpci: setpci.o filter.o
+
+setpci.o: setpci.c
 
 clean:
        rm -f `find . -name "*~" -or -name "*.[oa]" -or -name "\#*\#" -or -name TAGS -or -name core`
-       rm -f lspci pci.h
+       rm -f lspci setpci pci.h
 
 install: all
        install -o root -g root -m 755 -s lspci $(PREFIX)/sbin
diff --git a/README b/README
index eb5ce0b10de81d69dedb701cc62842ecf130f66f..dfe0cbfca4bd8cfd201feb9b906123d96d028de4 100644 (file)
--- a/README
+++ b/README
@@ -22,12 +22,13 @@ the manual page (lspci.8) for more details.
 Release notes about new versions will be send to the list and problems with
 the Linux PCI support will be probably discussed there, too.
 
+   You also might want to look at the pciutils web page containing release
+notes and other news: http://atrey.karlin.mff.cuni.cz/~mj/pciutils.html.
+
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 TODO:
 
-       - Work-around the PIIX4 ACPI crash?
-
        - Better displaying of IRQ's generated by both PCI and CardBus bridges.
 
        - Full displaying of CardBus bridge configuration. (Has anyone seen
diff --git a/filter.c b/filter.c
new file mode 100644 (file)
index 0000000..db4ce13
--- /dev/null
+++ b/filter.c
@@ -0,0 +1,106 @@
+/*
+ *     $Id: filter.c,v 1.1 1998/03/31 21:02:14 mj Exp $
+ *
+ *     Linux PCI Utilities -- Device Filtering
+ *
+ *     Copyright (c) 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/pci.h>
+
+#include "pciutils.h"
+
+void
+filter_init(struct pci_filter *f)
+{
+  f->bus = f->slot = f->func = -1;
+  f->vendor = f->device = -1;
+}
+
+/* Slot filter syntax: [[bus]:][slot][.[func]] */
+
+char *
+filter_parse_slot(struct pci_filter *f, char *str)
+{
+  char *colon = strchr(str, ':');
+  char *dot = strchr((colon ? colon + 1 : str), '.');
+  char *mid = str;
+  char *e;
+
+  if (colon)
+    {
+      *colon++ = 0;
+      mid = colon;
+      if (str[0] && strcmp(str, "*"))
+       {
+         long int x = strtol(str, &e, 16);
+         if ((e && *e) || (x < 0 || x >= 0xff))
+           return "Invalid bus number";
+         f->bus = x;
+       }
+    }
+  if (dot)
+    *dot++ = 0;
+  if (mid[0] && strcmp(mid, "*"))
+    {
+      long int x = strtol(str, &e, 16);
+      if ((e && *e) || (x < 0 || x >= 0x1f))
+       return "Invalid slot number";
+      f->slot = x;
+    }
+  if (dot && dot[0] && strcmp(dot, "*"))
+    {
+      long int x = strtol(dot, &e, 16);
+      if ((e && *e) || (x < 0 || x >= 7))
+       return "Invalid function number";
+      f->func = x;
+    }
+  return NULL;
+}
+
+/* ID filter syntax: [vendor]:[device] */
+
+char *
+filter_parse_id(struct pci_filter *f, char *str)
+{
+  char *s, *e;
+
+  if (!*str)
+    return NULL;
+  s = strchr(str, ':');
+  if (!s)
+    return "':' expected";
+  *s++ = 0;
+  if (str[0] && strcmp(str, "*"))
+    {
+      long int x = strtol(str, &e, 16);
+      if ((e && *e) || (x < 0 || x >= 0xffff))
+       return "Invalid vendor ID";
+      f->vendor = x;
+    }
+  if (s[0] && strcmp(s, "*"))
+    {
+      long int x = strtol(s, &e, 16);
+      if ((e && *e) || (x < 0 || x >= 0xffff))
+       return "Invalid device ID";
+      f->device = x;
+    }
+  return NULL;
+}
+
+int
+filter_match(struct pci_filter *f, byte bus, byte devfn, word vendid, word devid)
+{
+  if ((f->bus >= 0 && f->bus != bus) ||
+      (f->slot >= 0 && f->slot != PCI_SLOT(devfn)) ||
+      (f->func >= 0 && f->func != PCI_FUNC(devfn)) ||
+      (f->device >= 0 && f->device != devid) ||
+      (f->vendor >= 0 && f->vendor != vendid))
+    return 0;
+  return 1;
+}
diff --git a/lspci.8 b/lspci.8
index def285952d49e88d0a26797dd97b93cf0e981b95..3ccedb427af9785ea39274c32f951b27fcb21df2 100644 (file)
--- a/lspci.8
+++ b/lspci.8
@@ -54,24 +54,16 @@ PCI bus instead of as seen by the kernel.
 Show a tree-like diagram containing all busses, bridges, devices and connections
 between them.
 .TP
-.B -B <bus>
-Show only devices on specified bus.
-.TP
-.B -S <slot>
-Show only devices in specified slot number.
-.TP
-.B -F <func>
-Show only specified function number of all devices (you can mix it with
-.B -B
-and
-.B -S
-to select single device).
-.TP
-.B -V <vendor>
-Show only devices having specified vendor ID.
-.TP
-.B -D <devid>
-Show only devices having specified device ID.
+.B -s [[<bus>]:][<slot>][.[<func>]]
+Show only devices in specified bus, slot and function. Each component of the device
+address can be omitted or set as "*" meaning "any value". All numbers are
+hexadecimal.  E.g., "0:" means all devices on bus 0, "0" means all functions of device 0
+on any bus, "0.3" selects third function of device 0 on all busses and ".4" shows only
+fourth function of each device.
+.TP
+.B -d [<vendor>]:[<device>]
+Show only devices with specified vendor and device ID. Both ID's are given in
+hexadecimal and may be omitted or given as "*" meaning "any value".
 .TP
 .B -i <file>
 Use
diff --git a/lspci.c b/lspci.c
index 19c66609c405c7d71d4776866a3329cff12883ed..f59ce9121e601d2a878e148c44edf1beb0a162aa 100644 (file)
--- a/lspci.c
+++ b/lspci.c
@@ -1,5 +1,5 @@
 /*
- *     $Id: lspci.c,v 1.9 1998/03/19 15:56:43 mj Exp $
+ *     $Id: lspci.c,v 1.10 1998/03/31 21:02:16 mj Exp $
  *
  *     Linux PCI Utilities -- List All PCI Devices
  *
 static int verbose;                    /* Show detailed information */
 static int buscentric_view;            /* Show bus addresses/IRQ's instead of CPU-visible ones */
 static int show_hex;                   /* Show contents of config space as hexadecimal numbers */
-static int bus_filter = -1;            /* Bus, slot, function, vendor and device ID filtering */
-static int slot_filter = -1;
-static int func_filter = -1;
-static int vend_filter = -1;
-static int dev_filter = -1;
+static struct pci_filter filter;       /* Device filter */
 static int show_tree;                  /* Show bus tree */
 static int machine_readable;           /* Generate machine-readable output */
 static char *pci_dir = PROC_BUS_PCI;
 
-static char options[] = "nvbxB:S:F:V:D:ti:p:m";
+static char options[] = "nvbxs:d:ti:p:m";
 
 static char help_msg[] = "\
 Usage: lspci [<switches>]\n\
 \n\
--v\tBe verbose\n\
--n\tShow numeric ID's\n\
--b\tBus-centric view (PCI addresses and IRQ's instead of those seen by the CPU)\n\
--x\tShow hex-dump of config space (-xx shows full 256 bytes)\n\
--B <bus>, -S <slot>, -F <func>, -V <vendor>, -D <device>  Show only selected devices\n\
--t\tShow bus tree\n\
--m\tProduce machine-readable output\n\
+-v\t\tBe verbose\n\
+-n\t\tShow numeric ID's\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 config space (-xx shows full 256 bytes)\n\
+-s [[<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 " ETC_PCI_IDS "\n\
 -p <dir>\tUse specified bus directory instead of " PROC_BUS_PCI "\n\
 ";
@@ -81,18 +78,6 @@ xmalloc(unsigned int howmuch)
   return p;
 }
 
-/* Filtering */
-
-static inline int
-filter_out(struct device *d)
-{
-  return (bus_filter >= 0 && d->bus != bus_filter ||
-         slot_filter >= 0 && PCI_SLOT(d->devfn) != slot_filter ||
-         func_filter >= 0 && PCI_FUNC(d->devfn) != func_filter ||
-         vend_filter >= 0 && d->vendid != vend_filter ||
-         dev_filter >= 0 && d->devid != dev_filter);
-}
-
 /* Interface for /proc/bus/pci */
 
 static void
@@ -127,7 +112,7 @@ scan_dev_list(void)
       d->devfn = dfn & 0xff;
       d->vendid = vend >> 16U;
       d->devid = vend & 0xffff;
-      if (!filter_out(d))
+      if (filter_match(&filter, d->bus, d->devfn, d->vendid, d->devid))
        {
          *last_dev = d;
          last_dev = &d->next;
@@ -875,7 +860,9 @@ int
 main(int argc, char **argv)
 {
   int i;
+  char *msg;
 
+  filter_init(&filter);
   while ((i = getopt(argc, argv, options)) != -1)
     switch (i)
       {
@@ -888,20 +875,19 @@ main(int argc, char **argv)
       case 'b':
        buscentric_view = 1;
        break;
-      case 'B':
-       bus_filter = strtol(optarg, NULL, 16);
-       break;
-      case 'S':
-       slot_filter = strtol(optarg, NULL, 16);
-       break;
-      case 'F':
-       func_filter = strtol(optarg, NULL, 16);
-       break;
-      case 'V':
-       vend_filter = strtol(optarg, NULL, 16);
+      case 's':
+       if (msg = filter_parse_slot(&filter, optarg))
+         {
+           fprintf(stderr, "lspci: -f: %s\n", msg);
+           return 1;
+         }
        break;
-      case 'D':
-       dev_filter = strtol(optarg, NULL, 16);
+      case 'd':
+       if (msg = filter_parse_id(&filter, optarg))
+         {
+           fprintf(stderr, "lspci: -d: %s\n", msg);
+           return 1;
+         }
        break;
       case 'x':
        show_hex++;
index ddbf67b10d983efeefad3eaea7d188931d94f684..d7fab9036b1dfb5b22feed3b40bc1edf182a0383 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     $Id: pciutils.h,v 1.3 1998/02/09 12:32:56 mj Exp $
+ *     $Id: pciutils.h,v 1.4 1998/03/31 21:02:18 mj Exp $
  *
  *     Linux PCI Utilities -- Declarations
  *
@@ -38,3 +38,15 @@ char *lookup_vendor(word);
 char *lookup_device(word, word);
 char *lookup_device_full(word, word);
 char *lookup_class(word);
+
+/* filter.c */
+
+struct pci_filter {
+  int bus, slot, func;                 /* -1 = ANY */
+  int vendor, device;
+};
+
+void filter_init(struct pci_filter *);
+char *filter_parse_slot(struct pci_filter *, char *);
+char *filter_parse_id(struct pci_filter *, char *);
+int filter_match(struct pci_filter *, byte bus, byte devfn, word vendid, word devid);
index 48a7904e5eac116153b24c9f032f1a4227538a7d..63d6f3a9ca1609cd3d6613e3defe7fd0179cb665 100644 (file)
@@ -10,6 +10,6 @@ Keywords:       kernel, pci, proc, lspci
 Author:         mj@atrey.karlin.mff.cuni.cz (Martin Mares)
 Maintained-by:  mj@atrey.karlin.mff.cuni.cz (Martin Mares)
 Primary-site:   atrey.karlin.mff.cuni.cz pub/local/mj/linux/pciutils-1.02.tar.gz
-Alternate-site: sunsite.unc.edu pub/Linux/system/hardware/pciutils-1.02.tar.gz
+Alternate-site: sunsite.unc.edu pub/Linux/hardware/pciutils-1.02.tar.gz
 Copying-policy: GPL
 End
diff --git a/setpci.c b/setpci.c
new file mode 100644 (file)
index 0000000..189b96a
--- /dev/null
+++ b/setpci.c
@@ -0,0 +1,322 @@
+/*
+ *     $Id: setpci.c,v 1.1 1998/03/31 21:02:20 mj Exp $
+ *
+ *     Linux PCI Utilities -- Manipulate PCI Configuration Registers
+ *
+ *     Copyright (c) 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "pciutils.h"
+
+static int force;                      /* Don't complain if no devices match */
+static int verbose;                    /* Verbosity level */
+
+struct device {
+  struct device *next;
+  byte bus, devfn, mark;
+  word vendid, devid;
+  int fd;
+};
+
+static struct device *first_dev;
+
+struct op {
+  struct op *next;
+  struct device **dev_vector;
+  unsigned int addr;
+  unsigned int width;                  /* Byte width of the access */
+  int num_values;                      /* Number of values to write; <0=read */
+  unsigned int values[0];
+};
+
+static struct op *first_op, **last_op = &first_op;
+
+void *
+xmalloc(unsigned int howmuch)
+{
+  void *p = malloc(howmuch);
+  if (!p)
+    {
+      fprintf(stderr, "setpci: Unable to allocate %d bytes of memory\n", howmuch);
+      exit(1);
+    }
+  return p;
+}
+
+static void
+scan_devices(void)
+{
+  struct device **last = &first_dev;
+  byte line[256];
+  FILE *f;
+
+  if (!(f = fopen(PROC_BUS_PCI "/devices", "r")))
+    {
+      perror(PROC_BUS_PCI "/devices");
+      exit(1);
+    }
+  while (fgets(line, sizeof(line), f))
+    {
+      struct device *d = xmalloc(sizeof(struct device));
+      unsigned int dfn, vend;
+
+      sscanf(line, "%x %x", &dfn, &vend);
+      d->bus = dfn >> 8U;
+      d->devfn = dfn & 0xff;
+      d->vendid = vend >> 16U;
+      d->devid = vend & 0xffff;
+      d->fd = -1;
+      *last = d;
+      last = &d->next;
+    }
+  fclose(f);
+  *last = NULL;
+}
+
+static struct device **
+select_devices(struct pci_filter *filt)
+{
+  struct device *z, **a, **b;
+  int cnt = 1;
+
+  for(z=first_dev; z; z=z->next)
+    if (z->mark = filter_match(filt, z->bus, z->devfn, z->vendid, z->devid))
+      cnt++;
+  a = b = xmalloc(sizeof(struct device *) * cnt);
+  for(z=first_dev; z; z=z->next)
+    if (z->mark)
+      *a++ = z;
+  *a = NULL;
+  return b;
+}
+
+static void
+exec_op(struct op *op, struct device *dev)
+{
+  char *mm[] = { NULL, "%02x", "%04x", NULL, "%08x" };
+  char *m = mm[op->width];
+
+  if (dev->fd < 0)
+    {
+      char name[64];
+      sprintf(name, PROC_BUS_PCI "/%02x/%02x.%x", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+      dev->fd = open(name, O_RDWR ????
+    }
+
+  if (verbose)
+    printf("%02x.%02x:%x.%c ", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+          "?BW?L"[op->width]);
+  if (op->num_values > 0)
+    {
+    }
+  else
+    {
+      if (verbose)
+       printf("= ");
+    }
+}
+
+static void
+execute(struct op *op)
+{
+  struct device **vec = NULL;
+  struct device **pdev, *dev;
+  struct op *oops;
+
+  while (op)
+    {
+      pdev = vec = op->dev_vector;
+      while (dev = *pdev++)
+       for(oops=op; oops && oops->dev_vector == vec; oops=oops->next)
+         exec_op(oops, dev);
+      while (op && op->dev_vector == vec)
+       op = op->next;
+    }
+}
+
+static void usage(void) __attribute__((noreturn));
+
+static void
+usage(void)
+{
+  fprintf(stderr,
+"Usage: setpci [-f] [-v] (<device>+ <reg>[=<values>]*)*\n\
+<device>:  -s [[<bus>]:][<slot>][.[<func>]]\n\
+\t|  -d [<vendor>]:[<device>]\n\
+<reg>:     <number>[.(B|W|L)]\n\
+<values>:  <value>[,<value>...]\n\
+");
+  exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+  enum { STATE_INIT, STATE_GOT_FILTER, STATE_GOT_OP } state = STATE_INIT;
+  struct pci_filter filter;
+  struct device **selected_devices = NULL;
+
+  argc--;
+  argv++;
+  while (argc && argv[0][0] == '-')
+    {
+      char *c = argv[0]+1;
+      char *d = c;
+      while (*c)
+       switch (*c)
+         {
+         case 'v':
+           verbose++;
+           c++;
+           break;
+         case 'f':
+           force++;
+           c++;
+           break;
+         case 0:
+           break;
+         default:
+           if (c != d)
+             usage();
+           goto next;
+         }
+      argc--;
+      argv++;
+    }
+next:
+
+  scan_devices();
+
+  while (argc)
+    {
+      char *c = argv[0];
+      char *d, *e, *f;
+      int n, i;
+      struct op *op;
+      unsigned long ll, lim;
+
+      if (*c == '-')
+       {
+         if (!c[1] || !strchr("sd", c[1]))
+           usage();
+         if (c[2])
+           d = (c[2] == '=') ? c+3 : c+2;
+         else if (argc)
+           {
+             argc--;
+             argv++;
+             d = argv[0];
+           }
+         else
+           usage();
+         if (state != STATE_GOT_FILTER)
+           {
+             filter_init(&filter);
+             state = STATE_GOT_FILTER;
+           }
+         switch (c[1])
+           {
+           case 's':
+             if (d = filter_parse_slot(&filter, d))
+               {
+                 fprintf(stderr, "setpci: -s: %s\n", d);
+                 return 1;
+               }
+             break;
+           case 'd':
+             if (d = filter_parse_id(&filter, d))
+               {
+                 fprintf(stderr, "setpci: -d: %s\n", d);
+                 return 1;
+               }
+             break;
+           default:
+             usage();
+           }
+       }
+      else if (state == STATE_INIT)
+       usage();
+      else
+       {
+         if (state == STATE_GOT_FILTER)
+           selected_devices = select_devices(&filter);
+         if (!selected_devices[0] && !force)
+           fprintf(stderr, "setpci: Warning: No devices selected for `%s'.\n", c);
+         state = STATE_GOT_OP;
+         d = strchr(c, '=');
+         if (d)
+           {
+             *d++ = 0;
+             for(e=d, n=1; *e; e++)
+               if (*e == ',')
+                 n++;
+             op = xmalloc(sizeof(struct op) + n*sizeof(unsigned int));
+           }
+         else
+           {
+             n = -1;
+             op = xmalloc(sizeof(struct op));
+           }
+         op->dev_vector = selected_devices;
+         op->num_values = n;
+         e = strchr(c, '.');
+         if (e)
+           {
+             *e++ = 0;
+             if (e[1])
+               usage();
+             switch (*e & 0xdf)
+               {
+               case 'B':
+                 op->width = 1; break;
+               case 'W':
+                 op->width = 2; break;
+               case 'L':
+                 op->width = 4; break;
+               default:
+                 usage();
+               }
+           }
+         else
+           op->width = 1;
+         ll = strtol(c, &f, 16);
+         if (ll > 0x100 || ll + op->width*n > 0x100)
+           {
+             fprintf(stderr, "setpci: Register number out of range!\n");
+             return 1;
+           }
+         for(i=0; i<n; i++)
+           {
+             e = strchr(d, ',');
+             if (e)
+               *e++ = 0;
+             ll = strtoul(d, &f, 16);
+             lim = (2 << ((op->width << 3) - 1)) - 1;
+             if (f && *f ||
+                 (ll > lim && ll < ~0UL - lim))
+               usage();
+             op->values[i] = ll;
+             d = e;
+           }
+         *last_op = op;
+         last_op = &op->next;
+         op->next = NULL;
+       }
+      argc--;
+      argv++;
+    }
+  if (state == STATE_INIT)
+    usage();
+
+  execute(first_op);
+
+  return 0;
+}