summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>1998-03-31 21:02:11 +0000
committerMartin Mares <mj@ucw.cz>2006-05-05 14:09:50 +0200
commite4842ff3b1ab7e061e0fb7f81fcb88d9995a63a2 (patch)
tree91dc1691026918e7a39b66e3c65e9b9503be9d55
parent008407bd7f3ff2efe3d896a1c48bd2f3e3dd17a3 (diff)
downloadpciutils-e4842ff3b1ab7e061e0fb7f81fcb88d9995a63a2.tar.gz
Intermediate version of pciutils.
- 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.
-rw-r--r--ChangeLog12
-rw-r--r--Makefile13
-rw-r--r--README5
-rw-r--r--filter.c106
-rw-r--r--lspci.828
-rw-r--r--lspci.c66
-rw-r--r--pciutils.h14
-rw-r--r--pciutils.lsm2
-rw-r--r--setpci.c322
9 files changed, 503 insertions, 65 deletions
diff --git a/ChangeLog b/ChangeLog
index b61db0c..5b34d8e 100644
--- 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
diff --git a/Makefile b/Makefile
index 7dbdb1e..bb58e36 100644
--- 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 eb5ce0b..dfe0cbf 100644
--- 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
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 def2859..3ccedb4 100644
--- 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 19c6660..f59ce91 100644
--- 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
*
@@ -21,27 +21,24 @@
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++;
diff --git a/pciutils.h b/pciutils.h
index ddbf67b..d7fab90 100644
--- a/pciutils.h
+++ b/pciutils.h
@@ -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);
diff --git a/pciutils.lsm b/pciutils.lsm
index 48a7904..63d6f3a 100644
--- a/pciutils.lsm
+++ b/pciutils.lsm
@@ -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
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;
+}