+Fri Jan 22 19:29:31 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Version string is now defined in top-level Makefile, exported
+ to the configure script and also substituted to man pages.
+
+ * lspci.c (show_bases): Rewrote displaying of 64-bit addresses.
+ (show_verbose): Rewrote interrupt display logic.
+
+ * lib/i386-ports.c: Include sys/io.h only on glibc systems.
+
+ * lib/configure: Rewrote detection of Linux versions. Now it
+ works on 2.0 kernels (only with direct/dump access, of course).
+
+ * lib/internal.h: New bytesex macros using <asm/byteorder.h>
+ whenever available.
+
+ * lib/proc.c (proc_read, proc_write): Distinguish between short
+ read/write and real errors.
+
+ * lspci.c (show_htype{0,1}): Always use d->dev->rom_base_addr since
+ libpci respects buscentric mode automatically.
+
+ * lspci.c (show_hex_dump): For CardBus bridges, print out 128
+ bytes of header (the whole standard part).
+
+ * common.c: pcilib options are now all uppercase. Also moved
+ PCI access debugging option here.
+
+ * Released as 1.99.2.
+
+Wed Jan 20 22:50:35 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Wrote configure script and rewrote Makefiles.
+
+ * Removed few unused variables.
+
+Wed Jan 20 12:21:56 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * common.c: Moved several functions used in both setpci and lspci
+ here. This includes parsing of libpci-related options.
+
+ * More library tweaks.
+
+ * filter.c, names.c: Moved to library.
+
+ * setpci: Rewritten to use the library.
+
+ * Released as 1.99.1.
+
+Tue Jan 19 23:00:12 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (scan_devices): For cardbus bridges, read first 128
+ bytes of config space to get full standard header.
+
+ * Makefile (CFLAGS): Removed "-Wno-unused".
+
+ * Started the "New Generation" branch and introduced the
+ PCI library.
+
+ * lspci: Rewritten to use the library.
+
Tue Jan 19 22:24:08 1999 Martin Mares <mj@albireo.ucw.cz>
* Released as version 1.10.
-# $Id: Makefile,v 1.9 1998/11/22 08:56:00 mj Exp $
+# $Id: Makefile,v 1.10 1999/01/22 21:04:46 mj Exp $
# Makefile for Linux PCI Utilities
-# (c) 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+# (c) 1998--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
-ARCH=$(shell uname -m | sed -e 's/i.86/i386/' -e 's/sun4u/sparc64/' | tr 'a-z' 'A-Z')
-KERN_H=$(shell if [ ! -f pci.h ] ; then echo '-DKERNEL_PCI_H' ; fi)
OPT=-O2 -fomit-frame-pointer
-CFLAGS=$(OPT) -Wall -W -Wno-parentheses -Wstrict-prototypes -Wno-unused -Werror -DARCH_$(ARCH) $(KERN_H)
+#OPT=-O2 -g
+CFLAGS=$(OPT) -Wall -W -Wno-parentheses -Wstrict-prototypes -Werror
+
+VERSION=1.99.2-alpha
+DATE=22 January 1999
ROOT=/
PREFIX=/usr
-all: lspci setpci
+export
+
+all: lib lspci setpci lspci.8 setpci.8
+
+lib: lib/config.h
+ $(MAKE) -C lib all
-lspci: lspci.o names.o filter.o
-setpci: setpci.o filter.o
+lib/config.h:
+ cd lib && ./configure $(PREFIX) $(VERSION)
-lspci.o: lspci.c pciutils.h
-names.o: names.c pciutils.h
-filter.o: filter.c pciutils.h
-setpci.o: setpci.c pciutils.h
+lspci: lspci.o common.o lib/libpci.a
+setpci: setpci.o common.o lib/libpci.a
+
+lspci.o: lspci.c pciutils.h lib/libpci.a
+setpci.o: setpci.c pciutils.h lib/libpci.a
+common.o: common.c pciutils.h lib/libpci.a
+
+%.8: %.man
+ sed <$< >$@ "s/@TODAY@/$(DATE)/;s/@VERSION@/pciutils-$(VERSION)/"
clean:
rm -f `find . -name "*~" -or -name "*.[oa]" -or -name "\#*\#" -or -name TAGS -or -name core`
- rm -f lspci setpci pci.h
+ rm -f lspci setpci lib/config.* lib/header.h *.8
install: all
install -o root -g root -m 755 -s lspci setpci $(ROOT)/sbin
rm -f $(ROOT)/etc/pci.ids
dist: clean
- cp /usr/src/linux/include/linux/pci.h .
+ cp /usr/src/linux/include/linux/pci.h lib/header.h
sh -c 'X=`pwd` ; X=`basename $$X` ; cd .. ; tar czvvf /tmp/$$X.tar.gz $$X --exclude CVS --exclude tmp'
- rm -f pci.h
+ rm -f lib/header.h
+
+.PHONY: all lib clean install dist man
-This package contains the Linux PCI Utilities, version 1.10.
+This package contains the Linux PCI Utilities, version 1.99.2-alpha.
Copyright (c) 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
policy as for the Linux kernel itself -- see /usr/src/linux/COPYING
for details.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+BIG FAT WARNING: This is an ALPHA version. The documentation is out of date
+ and the same holds for spec files and even for this README.
+ And, of course, you should expect this release to contain BUGS.
+
+WHY ALPHA? I've split the real PCI access primitives from the rest
+ of the code and created libpci, which supports not only
+ /proc/bus/pci, but also direct hardware access and reading
+ of configuration space dumps and it's intended to work
+ on all Linux versions and even on non-Linux systems, making
+ creation of portable programs communicating with PCI devices
+ possible.
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Linux PCI Utilities contain various utilities for dealing with the PCI
See manual pages for more details.
- You _NEED_ kernel 2.1.82 or newer which supports /proc/bus/pci.
+ You need kernel 2.1.82 or newer to use all functions of this package.
+For older kernels, only direct hardware access is supported and you must
+be root to use it.
If you have any bug reports or suggestions, send them to the author.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TODO:
-
- - Better displaying of IRQ's generated by both PCI and CardBus bridges.
+ - lspci: "scan hard" function
+ - lib: "syscall" access method
--- /dev/null
+/*
+ * $Id: common.c,v 1.1 1999/01/22 21:04:50 mj Exp $
+ *
+ * Linux PCI Utilities -- Common Functions
+ *
+ * Copyright (c) 1997--1999 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 <stdarg.h>
+#include <unistd.h>
+
+#include "pciutils.h"
+
+void __attribute__((noreturn))
+die(char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ fputs("lspci: ", stderr);
+ vfprintf(stderr, msg, args);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+void *
+xmalloc(unsigned int howmuch)
+{
+ void *p = malloc(howmuch);
+ if (!p)
+ die("Unable to allocate %d bytes of memory", howmuch);
+ return p;
+}
+
+int
+parse_generic_option(int i, struct pci_access *pacc, char *optarg)
+{
+ switch (i)
+ {
+#ifdef HAVE_PM_LINUX_PROC
+ case 'P':
+ pacc->method_params[PCI_ACCESS_PROC_BUS_PCI] = optarg;
+ pacc->method = PCI_ACCESS_PROC_BUS_PCI;
+ break;
+#endif
+#ifdef HAVE_PM_INTEL_CONF
+ case 'H':
+ if (!strcmp(optarg, "1"))
+ pacc->method = PCI_ACCESS_I386_TYPE1;
+ else if (!strcmp(optarg, "2"))
+ pacc->method = PCI_ACCESS_I386_TYPE2;
+ else
+ die("Unknown hardware configuration type %s", optarg);
+ break;
+#endif
+#ifdef HAVE_PM_SYSCALLS
+ case 'S':
+ pacc->method = PCI_ACCESS_SYSCALLS;
+ break;
+#endif
+#ifdef HAVE_PM_DUMP
+ case 'F':
+ pacc->method_params[PCI_ACCESS_DUMP] = optarg;
+ pacc->method = PCI_ACCESS_DUMP;
+ break;
+#endif
+ case 'G':
+ pacc->debugging++;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+++ /dev/null
-/*
- * $Id: filter.c,v 1.2 1998/06/08 07:51:45 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 "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(mid, &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;
-}
--- /dev/null
+# $Id: Makefile,v 1.1 1999/01/22 21:05:10 mj Exp $
+# Makefile for The PCI Library
+# (c) 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+
+include config.mk
+
+OBJS=access.o generic.o dump.o names.o filter.o buffer.o
+INCL=internal.h pci.h config.h
+
+ifdef HAVE_PM_LINUX_PROC
+OBJS += proc.o
+endif
+
+ifdef HAVE_PM_INTEL_CONF
+OBJS += i386-ports.o
+endif
+
+ifdef HAVE_PM_DUMP
+OBJS += dump.o
+endif
+
+ifdef HAVE_PM_SYSCALLS
+OBJS += syscalls.o
+endif
+
+ifdef HAVE_OWN_HEADER_H
+INCL += header.h
+endif
+
+all: libpci.a
+
+libpci.a: $(OBJS)
+ rm -f $@
+ ar rcs $@ $^
+ ranlib $@
+
+access.o: access.c $(INCL)
+i386-ports.o: i386-ports.c $(INCL)
+proc.o: proc.c $(INCL)
+generic.o: generic.c $(INCL)
+syscalls.o: syscalls.c $(INCL)
+dump.o: dump.c $(INCL)
+names.o: names.c $(INCL)
+filter.o: filter.c $(INCL)
--- /dev/null
+/*
+ * $Id: access.c,v 1.1 1999/01/22 21:05:12 mj Exp $
+ *
+ * The PCI Library -- User Access
+ *
+ * Copyright (c) 1997--1999 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 <stdarg.h>
+#include <string.h>
+
+#include "internal.h"
+
+static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = {
+ NULL,
+#ifdef HAVE_PM_LINUX_PROC
+ &pm_linux_proc,
+#else
+ NULL,
+#endif
+#ifdef HAVE_PM_SYSCALLS
+ &pm_syscalls,
+#else
+ NULL,
+#endif
+#ifdef HAVE_PM_INTEL_CONF
+ &pm_intel_conf1,
+ &pm_intel_conf2,
+#else
+ NULL,
+ NULL,
+#endif
+#ifdef HAVE_PM_DUMP
+ &pm_dump,
+#else
+ NULL,
+#endif
+};
+
+struct pci_access *
+pci_alloc(void)
+{
+ struct pci_access *a = malloc(sizeof(struct pci_access));
+ int i;
+
+ bzero(a, sizeof(*a));
+ a->id_file_name = PATH_PCI_IDS;
+ for(i=0; i<PCI_ACCESS_MAX; i++)
+ if (pci_methods[i] && pci_methods[i]->config)
+ pci_methods[i]->config(a);
+ return a;
+}
+
+void *
+pci_malloc(struct pci_access *a, int size)
+{
+ void *x = malloc(size);
+
+ if (!x)
+ a->error("Out of memory (allocation of %d bytes failed)", size);
+ return x;
+}
+
+void
+pci_mfree(void *x)
+{
+ if (x)
+ free(x);
+}
+
+static void
+pci_generic_error(char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ fputs("pcilib: ", stderr);
+ vfprintf(stderr, msg, args);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+static void
+pci_generic_warn(char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ fputs("pcilib: ", stderr);
+ vfprintf(stderr, msg, args);
+ fputc('\n', stderr);
+}
+
+static void
+pci_generic_debug(char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ vfprintf(stdout, msg, args);
+ va_end(args);
+}
+
+static void
+pci_null_debug(char * UNUSED msg, ...)
+{
+}
+
+void
+pci_init(struct pci_access *a)
+{
+ if (!a->error)
+ a->error = pci_generic_error;
+ if (!a->warning)
+ a->warning = pci_generic_warn;
+ if (!a->debug)
+ a->debug = pci_generic_debug;
+ if (!a->debugging)
+ a->debug = pci_null_debug;
+
+ if (a->method)
+ {
+ if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
+ a->error("This access method is not supported.");
+ a->methods = pci_methods[a->method];
+ }
+ else
+ {
+ unsigned int i;
+ for(i=0; i<PCI_ACCESS_MAX; i++)
+ if (pci_methods[i])
+ {
+ a->debug("Trying method %d...", i);
+ if (pci_methods[i]->detect(a))
+ {
+ a->debug("...OK\n");
+ a->methods = pci_methods[i];
+ break;
+ }
+ a->debug("...No.\n");
+ }
+ if (!a->methods)
+ a->error("Cannot find any working access method.");
+ }
+ a->debug("Decided to use %s\n", a->methods->name);
+ a->methods->init(a);
+}
+
+void
+pci_cleanup(struct pci_access *a)
+{
+ struct pci_dev *d, *e;
+
+ for(d=a->devices; d; d=e)
+ {
+ e = d->next;
+ pci_free_dev(d);
+ }
+ if (a->methods)
+ a->methods->cleanup(a);
+ pci_free_name_list(a);
+ pci_mfree(a);
+}
+
+void
+pci_scan_bus(struct pci_access *a)
+{
+ a->methods->scan(a);
+}
+
+struct pci_dev *
+pci_alloc_dev(struct pci_access *a)
+{
+ struct pci_dev *d = pci_malloc(a, sizeof(struct pci_dev));
+
+ bzero(d, sizeof(*d));
+ d->access = a;
+ d->methods = a->methods;
+ if (d->methods->init_dev)
+ d->methods->init_dev(d);
+ return d;
+}
+
+int
+pci_link_dev(struct pci_access *a, struct pci_dev *d)
+{
+ d->next = a->devices;
+ a->devices = d;
+
+ return 1;
+}
+
+struct pci_dev *
+pci_get_dev(struct pci_access *a, int bus, int dev, int func)
+{
+ struct pci_dev *d = pci_alloc_dev(a);
+
+ d->bus = bus;
+ d->dev = dev;
+ d->func = func;
+ return d;
+}
+
+void pci_free_dev(struct pci_dev *d)
+{
+ if (d->methods->cleanup_dev)
+ d->methods->cleanup_dev(d);
+ pci_mfree(d);
+}
+
+static inline void
+pci_read_data(struct pci_dev *d, void *buf, int pos, int len)
+{
+ if (pos & (len-1))
+ d->access->error("Unaligned read: pos=%02x, len=%d", pos, len);
+ if (!d->methods->read(d, pos, buf, len))
+ memset(buf, 0xff, len);
+}
+
+byte
+pci_read_byte(struct pci_dev *d, int pos)
+{
+ byte buf;
+ pci_read_data(d, &buf, pos, 1);
+ return buf;
+}
+
+word
+pci_read_word(struct pci_dev *d, int pos)
+{
+ word buf;
+ pci_read_data(d, &buf, pos, 2);
+ return le16_to_cpu(buf);
+}
+
+u32
+pci_read_long(struct pci_dev *d, int pos)
+{
+ u32 buf;
+ pci_read_data(d, &buf, pos, 4);
+ return le32_to_cpu(buf);
+}
+
+int
+pci_read_block(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return d->methods->read(d, pos, buf, len);
+}
+
+static inline int
+pci_write_data(struct pci_dev *d, void *buf, int pos, int len)
+{
+ if (pos & (len-1))
+ d->access->error("Unaligned write: pos=%02x,len=%d", pos, len);
+ return d->methods->write(d, pos, buf, len);
+}
+
+int
+pci_write_byte(struct pci_dev *d, int pos, byte data)
+{
+ return pci_write_data(d, &data, pos, 1);
+}
+
+int
+pci_write_word(struct pci_dev *d, int pos, word data)
+{
+ word buf = cpu_to_le16(data);
+ return pci_write_data(d, &buf, pos, 2);
+}
+
+int
+pci_write_long(struct pci_dev *d, int pos, u32 data)
+{
+ u32 buf = cpu_to_le32(data);
+ return pci_write_data(d, &buf, pos, 4);
+}
+
+int
+pci_write_block(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return d->methods->write(d, pos, buf, len);
+}
+
+void
+pci_fill_info(struct pci_dev *d, int flags)
+{
+ if (flags & PCI_FILL_RESCAN)
+ {
+ flags &= ~PCI_FILL_RESCAN;
+ d->known_fields = 0;
+ }
+ if (flags & ~d->known_fields)
+ d->methods->fill_info(d, flags & ~d->known_fields);
+ d->known_fields |= flags;
+}
--- /dev/null
+/*
+ * $Id: buffer.c,v 1.1 1999/01/22 21:05:14 mj Exp $
+ *
+ * The PCI Library -- Buffered Access
+ *
+ * Copyright (c) 1997--1999 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 <stdarg.h>
+#include <string.h>
+
+#include "internal.h"
+
+static int
+buff_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ memcpy(buf, (byte *)d->aux + pos, len);
+ return 1;
+}
+
+static int
+buff_write(struct pci_dev *d, int UNUSED pos, byte * UNUSED buf, int UNUSED len)
+{
+ d->access->error("buffer: Writing to configuration space not supported.");
+ return 0;
+}
+
+static struct pci_methods pm_buffer = {
+ "Buffer",
+ NULL, /* config */
+ NULL, /* Shall not be called */
+ NULL, /* No init nor cleanup */
+ NULL,
+ NULL, /* No scanning */
+ pci_generic_fill_info,
+ buff_read,
+ buff_write,
+ NULL, /* init_dev */
+ NULL /* cleanup_dev */
+};
+
+void
+pci_setup_buffer(struct pci_dev *d, byte *buf)
+{
+ if (d->methods->cleanup_dev)
+ d->methods->cleanup_dev(d);
+ d->methods = &pm_buffer;
+ d->aux = buf;
+}
--- /dev/null
+#!/bin/sh
+
+echo -n "Configuring libpci for your system..."
+prefix=${1:-/usr}
+version=${2:-0.0}
+sys=`uname -s`
+rel=`uname -r`
+cpu=`uname -m | sed 's/^i.86$/i386/;s/^sun4u$/sparc64/'`
+echo "$sys/$cpu $rel"
+if [ "$sys" != Linux ] ; then
+ echo "libpci currently supports only Linux"
+ exit 1
+fi
+echo -n "Looking for access methods..."
+c=config.h
+echo >$c "#define ARCH_`echo $cpu | tr 'a-z' 'A-Z'`"
+case $rel in
+ 2.[1-9]*|[3-9]*) echo -n " proc"
+ echo >>$c '#define HAVE_PM_LINUX_PROC'
+ echo >>$c '#define HAVE_LINUX_BYTEORDER_H'
+ echo >>$c '#define PATH_PROC_BUS_PCI "/proc/bus/pci"'
+ ok=1
+ ;;
+esac
+case $cpu in
+ i386) echo -n " i386-ports"
+ echo >>$c '#define HAVE_PM_INTEL_CONF'
+ ok=1
+ ;;
+ sparc) echo -n " syscalls"
+ echo >>$c '#define HAVE_PM_SYSCALLS'
+ ok=1
+ ;;
+ alpha|sparc64) echo >>$c '#define HAVE_64BIT_LONG_INT'
+# echo -n " syscalls"
+# echo >>$c '#define HAVE_PM_SYSCALLS'
+# ok=1
+ ;;
+esac
+echo >>$c '#define HAVE_PM_DUMP'
+echo " dump"
+if [ -z "$ok" ] ; then
+ echo "WARNING: No real configuration access method is available."
+fi
+echo >>$c "#define PATH_PCI_IDS \"$prefix/share/pci.ids\""
+if [ -f header.h ] ; then
+ echo >>$c '#define HAVE_OWN_HEADER_H'
+fi
+echo >>$c "#define PCILIB_VERSION \"$version\""
+sed '/^#define [^ ]*$/!d;s/^#define \(.*\)/\1=1/' <$c >config.mk
--- /dev/null
+/*
+ * $Id: dump.c,v 1.1 1999/01/22 21:05:20 mj Exp $
+ *
+ * The PCI Library -- Reading of Bus Dumps
+ *
+ * Copyright (c) 1997--1999 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 <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include "internal.h"
+
+static int
+dump_detect(struct pci_access *a)
+{
+ return !!a->method_params[PCI_ACCESS_DUMP];
+}
+
+static void
+dump_init(struct pci_access *a)
+{
+ char *name = a->method_params[PCI_ACCESS_DUMP];
+ FILE *f;
+ char buf[256];
+ struct pci_dev *dev = NULL;
+ int len, bn, dn, fn, i, j;
+
+ if (!a)
+ a->error("dump: File name not given.");
+ if (!(f = fopen(name, "r")))
+ a->error("dump: Cannot open %s: %s", name, strerror(errno));
+ while (fgets(buf, sizeof(buf)-1, f))
+ {
+ char *z = strchr(buf, '\n');
+ if (!z)
+ a->error("dump: line too long or unterminated");
+ *z-- = 0;
+ if (z >= buf && *z == '\r')
+ *z-- = 0;
+ len = z - buf + 1;
+ if (len >= 8 && buf[2] == ':' && buf[5] == '.' && buf[7] == ' ' &&
+ sscanf(buf, "%x:%x.%d ", &bn, &dn, &fn) == 3)
+ {
+ dev = pci_get_dev(a, bn, dn, fn);
+ dev->aux = pci_malloc(a, 256);
+ memset(dev->aux, 0xff, 256);
+ pci_link_dev(a, dev);
+ }
+ else if (!len)
+ dev = NULL;
+ else if (dev && len >= 51 && buf[2] == ':' && buf[3] == ' ' &&
+ sscanf(buf, "%x: ", &i) == 1)
+ {
+ z = buf+3;
+ while (isspace(z[0]) && isxdigit(z[1]) && isxdigit(z[2]))
+ {
+ z++;
+ if (sscanf(z, "%x", &j) != 1 || i >= 256)
+ a->error("dump: Malformed line");
+ ((byte *) dev->aux)[i++] = j;
+ z += 2;
+ }
+ }
+ }
+}
+
+static void
+dump_cleanup(struct pci_access * UNUSED a)
+{
+}
+
+static void
+dump_scan(struct pci_access * UNUSED a)
+{
+}
+
+static int
+dump_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ if (!d->aux)
+ {
+ struct pci_dev *e = d->access->devices;
+ while (e && (e->bus != d->bus || e->dev != d->dev || e->func != d->func))
+ e = e->next;
+ if (e)
+ d = e;
+ else
+ return 0;
+ }
+ memcpy(buf, (byte *) d->aux + pos, len);
+ return 1;
+}
+
+static int
+dump_write(struct pci_dev * UNUSED d, int UNUSED pos, byte * UNUSED buf, int UNUSED len)
+{
+ d->access->error("Writing to dump files is not supported.");
+ return 0;
+}
+
+static void
+dump_cleanup_dev(struct pci_dev *d)
+{
+ if (d->aux)
+ {
+ pci_mfree(d->aux);
+ d->aux = NULL;
+ }
+}
+
+struct pci_methods pm_dump = {
+ "dump",
+ NULL, /* config */
+ dump_detect,
+ dump_init,
+ dump_cleanup,
+ dump_scan,
+ pci_generic_fill_info,
+ dump_read,
+ dump_write,
+ NULL, /* init_dev */
+ dump_cleanup_dev
+};
--- /dev/null
+/*
+ * $Id: filter.c,v 1.1 1999/01/22 21:05:22 mj Exp $
+ *
+ * Linux PCI Library -- Device Filtering
+ *
+ * Copyright (c) 1998--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "internal.h"
+
+void
+pci_filter_init(struct pci_access * UNUSED a, struct pci_filter *f)
+{
+ f->bus = f->slot = f->func = -1;
+ f->vendor = f->device = -1;
+}
+
+/* Slot filter syntax: [[bus]:][slot][.[func]] */
+
+char *
+pci_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(mid, &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 *
+pci_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
+pci_filter_match(struct pci_filter *f, struct pci_dev *d)
+{
+ if ((f->bus >= 0 && f->bus != d->bus) ||
+ (f->slot >= 0 && f->slot != d->dev) ||
+ (f->func >= 0 && f->func != d->func))
+ return 0;
+ if (f->device >= 0 || f->vendor >= 0)
+ {
+ pci_fill_info(d, PCI_FILL_IDENT);
+ if ((f->device >= 0 && f->device != d->device_id) ||
+ (f->vendor >= 0 && f->vendor != d->vendor_id))
+ return 0;
+ }
+ return 1;
+}
--- /dev/null
+/*
+ * $Id: generic.c,v 1.1 1999/01/22 21:05:24 mj Exp $
+ *
+ * The PCI Library -- Generic Direct Access Functions
+ *
+ * Copyright (c) 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <string.h>
+
+#include "internal.h"
+
+static void
+pci_generic_scan_bus(struct pci_access *a, byte *busmap, int bus)
+{
+ int dev, multi, ht;
+ struct pci_dev *t = pci_alloc_dev(a);
+
+ a->debug("Scanning bus %02x for devices...\n", bus);
+ if (busmap[bus])
+ {
+ a->warning("Bus %02x seen twice (firmware bug). Ignored.", bus);
+ return;
+ }
+ busmap[bus] = 1;
+ t->bus = bus;
+ for(dev=0; dev<32; dev++)
+ {
+ t->dev = dev;
+ multi = 0;
+ for(t->func=0; t->func<8; t->func++)
+ {
+ u32 vd = pci_read_long(t, PCI_VENDOR_ID);
+ struct pci_dev *d;
+
+ if (!vd || vd == 0xffffffff)
+ break;
+ ht = pci_read_byte(t, PCI_HEADER_TYPE);
+ if (!t->func)
+ multi = ht & 0x80;
+ ht &= 0x7f;
+ d = pci_alloc_dev(a);
+ d->bus = t->bus;
+ d->dev = t->dev;
+ d->func = t->func;
+ d->vendor_id = vd & 0xffff;
+ d->device_id = vd >> 16U;
+ d->known_fields = PCI_FILL_IDENT;
+ d->hdrtype = ht;
+ pci_link_dev(a, d);
+ switch (ht)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ case PCI_HEADER_TYPE_CARDBUS:
+ pci_generic_scan_bus(a, busmap, pci_read_byte(t, PCI_SECONDARY_BUS));
+ break;
+ default:
+ a->debug("Device %02x:%02x.%d has unknown header type %02x.\n", d->bus, d->dev, d->func);
+ }
+ if (!multi)
+ break;
+ }
+ }
+}
+
+void
+pci_generic_scan(struct pci_access *a)
+{
+ byte busmap[256];
+
+ bzero(busmap, sizeof(busmap));
+ pci_generic_scan_bus(a, busmap, 0);
+}
+
+void
+pci_generic_fill_info(struct pci_dev *d, int flags)
+{
+ struct pci_access *a = d->access;
+
+ if (flags & PCI_FILL_IDENT)
+ {
+ d->vendor_id = pci_read_word(d, PCI_VENDOR_ID);
+ d->device_id = pci_read_word(d, PCI_DEVICE_ID);
+ }
+ if (flags & PCI_FILL_IRQ)
+ d->irq = pci_read_byte(d, PCI_INTERRUPT_LINE);
+ if (flags & PCI_FILL_BASES)
+ {
+ int cnt = 0, i;
+ bzero(d->base_addr, sizeof(d->base_addr));
+ switch (d->hdrtype)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ cnt = 6;
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ cnt = 2;
+ break;
+ case PCI_HEADER_TYPE_CARDBUS:
+ cnt = 1;
+ break;
+ }
+ if (cnt)
+ {
+ u16 cmd = pci_read_word(d, PCI_COMMAND);
+ for(i=0; i<cnt; i++)
+ {
+ u32 x = pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4);
+ if (!x || x == (u32) ~0)
+ continue;
+ d->base_addr[i] = x;
+ if (x & PCI_BASE_ADDRESS_SPACE_IO)
+ {
+ if (!(cmd & PCI_COMMAND_IO))
+ d->base_addr[i] = 0;
+ }
+ else if (cmd & PCI_COMMAND_MEMORY)
+ {
+ if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ {
+ if (i >= cnt-1)
+ a->warning("%02x:%02x.%d: Invalid 64-bit address seen.", d->bus, d->dev, d->func);
+ else
+ {
+ u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4);
+#ifdef HAVE_64BIT_LONG_INT
+ d->base_addr[i-1] |= ((unsigned long) y) << 32;
+#else
+ if (y)
+ {
+ a->warning("%02x:%02x.%d 64-bit device address ignored.", d->bus, d->dev, d->func);
+ d->base_addr[i-1] = 0;
+ }
+#endif
+ }
+ }
+ }
+ else
+ d->base_addr[i] = 0;
+ }
+ }
+ }
+ if (flags & PCI_FILL_ROM_BASE)
+ {
+ int reg = 0;
+ d->rom_base_addr = 0;
+ switch (d->hdrtype)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ reg = PCI_ROM_ADDRESS;
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ reg = PCI_ROM_ADDRESS1;
+ break;
+ }
+ if (reg)
+ {
+ u32 a = pci_read_long(d, reg);
+ if (a & PCI_ROM_ADDRESS_ENABLE)
+ d->rom_base_addr = a;
+ }
+ }
+}
+
+static int
+pci_generic_block_op(struct pci_dev *d, int pos, byte *buf, int len,
+ int (*r)(struct pci_dev *d, int pos, byte *buf, int len))
+{
+ if ((pos & 1) && len >= 1)
+ {
+ if (!r(d, pos, buf, 1))
+ return 0;
+ pos++; buf++; len--;
+ }
+ if ((pos & 3) && len >= 2)
+ {
+ if (!r(d, pos, buf, 2))
+ return 0;
+ pos += 2; buf += 2; len -= 2;
+ }
+ while (len >= 4)
+ {
+ if (!r(d, pos, buf, 4))
+ return 0;
+ pos += 4; buf += 4; len -= 4;
+ }
+ if (len >= 2)
+ {
+ if (!r(d, pos, buf, 2))
+ return 0;
+ pos += 2; buf += 2; len -= 2;
+ }
+ if (len && !r(d, pos, buf, 1))
+ return 0;
+ return 1;
+}
+
+int
+pci_generic_block_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return pci_generic_block_op(d, pos, buf, len, d->access->methods->read);
+}
+
+int
+pci_generic_block_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return pci_generic_block_op(d, pos, buf, len, d->access->methods->write);
+}
--- /dev/null
+/*
+ * $Id: i386-ports.c,v 1.1 1999/01/22 21:05:26 mj Exp $
+ *
+ * The PCI Library -- Direct Configuration access via i386 Ports
+ *
+ * Copyright (c) 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <asm/io.h>
+#include <unistd.h>
+
+#ifdef __GLIBC__
+#include <sys/io.h>
+#endif
+
+#include "internal.h"
+
+static int intel_iopl_set = -1;
+
+static int
+intel_setup_io(void)
+{
+ if (intel_iopl_set < 0)
+ intel_iopl_set = (iopl(3) < 0) ? 0 : 1;
+ return intel_iopl_set;
+}
+
+static void
+conf12_init(struct pci_access *a)
+{
+ if (!intel_setup_io())
+ a->error("You need to be root to have access to I/O ports.");
+}
+
+static void
+conf12_cleanup(struct pci_access * UNUSED a)
+{
+ iopl(3);
+ intel_iopl_set = -1;
+}
+
+/*
+ * Before we decide to use direct hardware access mechanisms, we try to do some
+ * trivial checks to ensure it at least _seems_ to be working -- we just test
+ * whether bus 00 contains a host bridge (this is similar to checking
+ * techniques used in XFree86, but ours should be more reliable since we
+ * attempt to make use of direct access hints provided by the PCI BIOS).
+ *
+ * This should be close to trivial, but it isn't, because there are buggy
+ * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
+ */
+
+static int
+intel_sanity_check(struct pci_access *a, struct pci_methods *m)
+{
+ struct pci_dev d;
+
+ a->debug("...sanity check");
+ d.bus = 0;
+ d.func = 0;
+ for(d.dev = 0; d.dev < 32; d.dev++)
+ {
+ u16 class, vendor;
+ if (m->read(&d, PCI_CLASS_DEVICE, (byte *) &class, sizeof(class)) &&
+ (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST) || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA)) ||
+ m->read(&d, PCI_VENDOR_ID, (byte *) &vendor, sizeof(vendor)) &&
+ (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL) || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ)))
+ {
+ a->debug("...outside the Asylum at 0/%02x/0", d.dev);
+ return 1;
+ }
+ }
+ a->debug("...insane");
+ return 0;
+}
+
+/*
+ * Configuration type 1
+ */
+
+#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
+
+static int
+conf1_detect(struct pci_access *a)
+{
+ unsigned int tmp;
+ int res = 0;
+
+ if (!intel_setup_io())
+ {
+ a->debug("...no I/O permission");
+ return 0;
+ }
+ outb (0x01, 0xCFB);
+ tmp = inl (0xCF8);
+ outl (0x80000000, 0xCF8);
+ if (inl (0xCF8) == 0x80000000)
+ res = 1;
+ outl (tmp, 0xCF8);
+ if (res)
+ res = intel_sanity_check(a, &pm_intel_conf1);
+ return res;
+}
+
+static int
+conf1_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int addr = 0xcfc + (pos&3);
+ outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
+
+ switch (len)
+ {
+ case 1:
+ buf[0] = inb(addr);
+ break;
+ case 2:
+ ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
+ break;
+ case 4:
+ ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
+ break;
+ default:
+ return pci_generic_block_read(d, pos, buf, len);
+ }
+ return 1;
+}
+
+static int
+conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int addr = 0xcfc + (pos&3);
+ outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
+
+ switch (len)
+ {
+ case 1:
+ outb(buf[0], addr);
+ break;
+ case 2:
+ outw(le16_to_cpu(((u16 *) buf)[0]), addr);
+ break;
+ case 4:
+ outl(le32_to_cpu(((u32 *) buf)[0]), addr);
+ break;
+ default:
+ return pci_generic_block_write(d, pos, buf, len);
+ }
+ return 1;
+}
+
+/*
+ * Configuration type 2. Obsolete and brain-damaged, but existing.
+ */
+
+static int
+conf2_detect(struct pci_access *a)
+{
+ if (!intel_setup_io())
+ {
+ a->debug("...no I/O permission");
+ return 0;
+ }
+
+ /* This is ugly and tends to produce false positives. Beware. */
+
+ outb(0x00, 0xCFB);
+ outb(0x00, 0xCF8);
+ outb(0x00, 0xCFA);
+ if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00)
+ return intel_sanity_check(a, &pm_intel_conf2);
+ else
+ return 0;
+}
+
+static int
+conf2_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int addr = 0xc000 | (d->dev << 8) | pos;
+
+ if (d->dev >= 16)
+ /* conf2 supports only 16 devices per bus */
+ return 0;
+ outb((d->func << 1) | 0xf0, 0xcf8);
+ outb(d->bus, 0xcfa);
+ switch (len)
+ {
+ case 1:
+ buf[0] = inb(addr);
+ break;
+ case 2:
+ ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
+ break;
+ case 4:
+ ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
+ break;
+ default:
+ outb(0, 0xcf8);
+ return pci_generic_block_read(d, pos, buf, len);
+ }
+ outb(0, 0xcf8);
+ return 1;
+}
+
+static int
+conf2_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int addr = 0xc000 | (d->dev << 8) | pos;
+
+ if (d->dev >= 16)
+ d->access->error("conf2_write: only first 16 devices exist.");
+ outb((d->func << 1) | 0xf0, 0xcf8);
+ outb(d->bus, 0xcfa);
+ switch (len)
+ {
+ case 1:
+ outb(buf[0], addr);
+ break;
+ case 2:
+ outw(le16_to_cpu(* (u16 *) buf), addr);
+ break;
+ case 4:
+ outl(le32_to_cpu(* (u32 *) buf), addr);
+ break;
+ default:
+ outb(0, 0xcf8);
+ return pci_generic_block_write(d, pos, buf, len);
+ }
+ outb(0, 0xcf8);
+ return 1;
+}
+
+struct pci_methods pm_intel_conf1 = {
+ "Intel-conf1",
+ NULL, /* config */
+ conf1_detect,
+ conf12_init,
+ conf12_cleanup,
+ pci_generic_scan,
+ pci_generic_fill_info,
+ conf1_read,
+ conf1_write,
+ NULL, /* init_dev */
+ NULL /* cleanup_dev */
+};
+
+struct pci_methods pm_intel_conf2 = {
+ "Intel-conf2",
+ NULL, /* config */
+ conf2_detect,
+ conf12_init,
+ conf12_cleanup,
+ pci_generic_scan,
+ pci_generic_fill_info,
+ conf2_read,
+ conf2_write,
+ NULL, /* init_dev */
+ NULL /* cleanup_dev */
+};
--- /dev/null
+/*
+ * $Id: internal.h,v 1.1 1999/01/22 21:05:29 mj Exp $
+ *
+ * The PCI Library -- Internal Include File
+ *
+ * Copyright (c) 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "pci.h"
+
+#ifdef HAVE_PM_LINUX_BYTEORDER_H
+
+#include <asm/byteorder.h>
+#define cpu_to_le16 __cpu_to_le16
+#define cpu_to_le32 __cpu_to_le32
+#define le16_to_cpu __le16_to_cpu
+#define le32_to_cpu __le32_to_cpu
+
+#else
+
+#include <endian.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le16 swab16
+#define cpu_to_le32 swab32
+#define le16_to_cpu swab16
+#define le32_to_cpu swab32
+
+static inline word swab16(word w)
+{
+ return (w << 8) | ((w >> 8) & 0xff);
+}
+
+static inline u32 swab32(u32 w)
+{
+ return ((w & 0xff000000) >> 24) |
+ ((w & 0x00ff0000) >> 8) |
+ ((w & 0x0000ff00) << 8) |
+ ((w & 0x000000ff) << 24);
+}
+#else
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define le16_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#endif
+
+#endif
+
+struct pci_methods {
+ char *name;
+ void (*config)(struct pci_access *);
+ int (*detect)(struct pci_access *);
+ void (*init)(struct pci_access *);
+ void (*cleanup)(struct pci_access *);
+ void (*scan)(struct pci_access *);
+ void (*fill_info)(struct pci_dev *, int flags);
+ int (*read)(struct pci_dev *, int pos, byte *buf, int len);
+ int (*write)(struct pci_dev *, int pos, byte *buf, int len);
+ void (*init_dev)(struct pci_dev *);
+ void (*cleanup_dev)(struct pci_dev *);
+};
+
+void pci_generic_scan(struct pci_access *);
+void pci_generic_fill_info(struct pci_dev *, int flags);
+int pci_generic_block_read(struct pci_dev *, int pos, byte *buf, int len);
+int pci_generic_block_write(struct pci_dev *, int pos, byte *buf, int len);
+
+void *pci_malloc(struct pci_access *, int);
+void pci_mfree(void *);
+
+struct pci_dev *pci_alloc_dev(struct pci_access *);
+int pci_link_dev(struct pci_access *, struct pci_dev *);
+
+extern struct pci_methods pm_intel_conf1, pm_intel_conf2, pm_linux_proc,
+ pm_syscalls, pm_dump;
+
+#define UNUSED __attribute__((unused))
--- /dev/null
+/*
+ * $Id: names.c,v 1.1 1999/01/22 21:05:33 mj Exp $
+ *
+ * The PCI Library -- ID to Name Translation
+ *
+ * Copyright (c) 1997--1999 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 <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "internal.h"
+
+struct nl_entry {
+ struct nl_entry *next;
+ word id1, id2;
+ int cat;
+ byte *name;
+};
+
+#define NL_VENDOR 0
+#define NL_DEVICE 1
+#define NL_CLASS 2
+#define NL_SUBCLASS 3
+#define NL_SUBSYSTEM_VENDOR 4
+#define NL_SUBSYSTEM_DEVICE 5
+
+#define HASH_SIZE 1024
+
+static inline unsigned int nl_calc_hash(int cat, int id1, int id2)
+{
+ unsigned int h;
+
+ h = id1 ^ id2 ^ (cat << 5);
+ h += (h >> 6);
+ return h & (HASH_SIZE-1);
+}
+
+static struct nl_entry *nl_lookup(struct pci_access *a, int num, int cat, int id1, int id2)
+{
+ unsigned int h;
+ struct nl_entry *n;
+
+ if (num)
+ return NULL;
+ h = nl_calc_hash(cat, id1, id2);
+ n = a->nl_hash[h];
+ while (n && (n->id1 != id1 || n->id2 != id2 || n->cat != cat))
+ n = n->next;
+ return n;
+}
+
+static int nl_add(struct pci_access *a, int cat, int id1, int id2, byte *text)
+{
+ unsigned int h = nl_calc_hash(cat, id1, id2);
+ struct nl_entry *n = a->nl_hash[h];
+
+ while (n && (n->id1 != id1 || n->id2 != id2 || n->cat != cat))
+ n = n->next;
+ if (n)
+ return 1;
+ n = pci_malloc(a, sizeof(struct nl_entry));
+ n->id1 = id1;
+ n->id2 = id2;
+ n->cat = cat;
+ n->name = text;
+ n->next = a->nl_hash[h];
+ a->nl_hash[h] = n;
+ return 0;
+}
+
+static void
+err_name_list(struct pci_access *a, char *msg)
+{
+ a->error("%s: %s: %s\n", a->id_file_name, msg, strerror(errno));
+}
+
+static void
+parse_name_list(struct pci_access *a)
+{
+ byte *p = a->nl_list;
+ byte *q, *r;
+ int lino = 0;
+ unsigned int id1=0, id2=0;
+ int cat, last_cat = -1;
+
+ while (*p)
+ {
+ lino++;
+ q = p;
+ while (*p && *p != '\n')
+ {
+ if (*p == '#')
+ {
+ *p++ = 0;
+ while (*p && *p != '\n')
+ p++;
+ break;
+ }
+ if (*p == '\t')
+ *p = ' ';
+ p++;
+ }
+ if (*p == '\n')
+ *p++ = 0;
+ if (!*q)
+ continue;
+ r = p;
+ while (r > q && r[-1] == ' ')
+ *--r = 0;
+ r = q;
+ while (*q == ' ')
+ q++;
+ if (r == q)
+ {
+ if (q[0] == 'C' && q[1] == ' ')
+ {
+ if (strlen(q+2) < 3 ||
+ q[4] != ' ' ||
+ sscanf(q+2, "%x", &id1) != 1)
+ goto parserr;
+ cat = last_cat = NL_CLASS;
+ }
+ else if (q[0] == 'S' && q[1] == ' ')
+ {
+ if (strlen(q+2) < 5 ||
+ q[6] != ' ' ||
+ sscanf(q+2, "%x", &id1) != 1)
+ goto parserr;
+ cat = last_cat = NL_SUBSYSTEM_VENDOR;
+ q += 2;
+ }
+ else
+ {
+ if (strlen(q) < 5 ||
+ q[4] != ' ' ||
+ sscanf(q, "%x", &id1) != 1)
+ goto parserr;
+ cat = last_cat = NL_VENDOR;
+ }
+ id2 = 0;
+ }
+ else
+ {
+ if (sscanf(q, "%x", &id2) != 1)
+ goto parserr;
+ if (last_cat < 0)
+ goto parserr;
+ if (last_cat == NL_CLASS)
+ cat = NL_SUBCLASS;
+ else
+ cat = last_cat+1;
+ }
+ q += 4;
+ while (*q == ' ')
+ q++;
+ if (!*q)
+ goto parserr;
+ if (nl_add(a, cat, id1, id2, q))
+ a->error("%s, line %d: duplicate entry", a->id_file_name, lino);
+ }
+ return;
+
+parserr:
+ a->error("%s, line %d: parse error", a->id_file_name, lino);
+}
+
+static void
+load_name_list(struct pci_access *a)
+{
+ int fd;
+ struct stat st;
+
+ fd = open(a->id_file_name, O_RDONLY);
+ if (fd < 0)
+ {
+ a->numeric_ids = 1;
+ return;
+ }
+ if (fstat(fd, &st) < 0)
+ err_name_list(a, "stat");
+ a->nl_list = pci_malloc(a, st.st_size + 1);
+ if (read(fd, a->nl_list, st.st_size) != st.st_size)
+ err_name_list(a, "read");
+ a->nl_list[st.st_size] = 0;
+ a->nl_hash = pci_malloc(a, sizeof(struct nl_entry *) * HASH_SIZE);
+ bzero(a->nl_hash, sizeof(struct nl_entry *) * HASH_SIZE);
+ parse_name_list(a);
+ close(fd);
+}
+
+void
+pci_free_name_list(struct pci_access *a)
+{
+ pci_mfree(a->nl_list);
+ a->nl_list = NULL;
+ pci_mfree(a->nl_hash);
+ a->nl_hash = NULL;
+}
+
+static int
+compound_name(struct pci_access *a, int num, char *buf, int size, int cat, int v, int i)
+{
+ if (!num)
+ {
+ struct nl_entry *e, *e2;
+
+ e = nl_lookup(a, 0, cat, v, 0);
+ e2 = nl_lookup(a, 0, cat+1, v, i);
+ if (!e)
+ return snprintf(buf, size, "Unknown device %04x:%04x", v, i);
+ else if (!e2)
+ return snprintf(buf, size, "%s: Unknown device %04x", e->name, i);
+ else
+ return snprintf(buf, size, "%s %s", e->name, e2->name);
+ }
+ else
+ return snprintf(buf, size, "%04x:%04x", v, i);
+}
+
+char *
+pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, u32 arg1, u32 arg2)
+{
+ int num = a->numeric_ids;
+ int res;
+ struct nl_entry *n;
+
+ if (flags & PCI_LOOKUP_NUMERIC)
+ {
+ flags &= PCI_LOOKUP_NUMERIC;
+ num = 1;
+ }
+ if (!a->nl_hash && !num)
+ {
+ load_name_list(a);
+ num = a->numeric_ids;
+ }
+ switch (flags)
+ {
+ case PCI_LOOKUP_VENDOR:
+ if (n = nl_lookup(a, num, NL_VENDOR, arg1, 0))
+ return n->name;
+ else
+ res = snprintf(buf, size, "%04x", arg1);
+ break;
+ case PCI_LOOKUP_DEVICE:
+ if (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2))
+ return n->name;
+ else
+ res = snprintf(buf, size, "%04x", arg1);
+ break;
+ case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE:
+ res = compound_name(a, num, buf, size, NL_VENDOR, arg1, arg2);
+ break;
+ case PCI_LOOKUP_VENDOR | PCI_LOOKUP_SUBSYSTEM:
+ if (n = nl_lookup(a, num, NL_SUBSYSTEM_VENDOR, arg1, 0))
+ return n->name;
+ else
+ res = snprintf(buf, size, "%04x", arg1);
+ break;
+ case PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
+ if (n = nl_lookup(a, num, NL_SUBSYSTEM_DEVICE, arg1, arg2))
+ return n->name;
+ else
+ res = snprintf(buf, size, "%04x", arg1);
+ break;
+ case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
+ res = compound_name(a, num, buf, size, NL_SUBSYSTEM_VENDOR, arg1, arg2);
+ break;
+ case PCI_LOOKUP_CLASS:
+ if (n = nl_lookup(a, num, NL_SUBCLASS, arg1 >> 8, arg1 & 0xff))
+ return n->name;
+ else if (n = nl_lookup(a, num, NL_CLASS, arg1, 0))
+ res = snprintf(buf, size, "%s [%04x]", n->name, arg1);
+ else
+ res = snprintf(buf, size, "Class %04x", arg1);
+ break;
+ default:
+ return "<pci_lookup_name: invalid request>";
+ }
+ return (res == size) ? "<too-large>" : buf;
+}
--- /dev/null
+/*
+ * $Id: pci.h,v 1.1 1999/01/22 21:05:34 mj Exp $
+ *
+ * The PCI Library
+ *
+ * Copyright (c) 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _PCI_LIB_H
+#define _PCI_LIB_H
+
+#include "config.h"
+
+#ifdef HAVE_OWN_HEADER_H
+#include "header.h"
+#else
+#include <linux/pci.h>
+#endif
+
+/*
+ * Types
+ */
+
+#include <linux/types.h>
+
+typedef __u8 byte;
+typedef __u8 u8;
+typedef __u16 word;
+typedef __u16 u16;
+typedef __u32 u32;
+
+/*
+ * PCI Access Structure
+ */
+
+struct pci_methods;
+struct nl_entry;
+
+#define PCI_ACCESS_AUTO 0 /* Autodetection (params: none) */
+#define PCI_ACCESS_PROC_BUS_PCI 1 /* Linux /proc/bus/pci (params: path) */
+#define PCI_ACCESS_SYSCALLS 2 /* pciconfig_read() syscalls (params: none) */
+#define PCI_ACCESS_I386_TYPE1 3 /* i386 ports, type 1 (params: none) */
+#define PCI_ACCESS_I386_TYPE2 4 /* i386 ports, type 2 (params: none) */
+#define PCI_ACCESS_DUMP 5 /* Dump file (params: filename) */
+#define PCI_ACCESS_MAX 6
+
+struct pci_access {
+ /* Options you can change: */
+ unsigned int method; /* Access method */
+ char *method_params[PCI_ACCESS_MAX]; /* Parameters for the methods */
+ int writeable; /* Open in read/write mode */
+ int buscentric; /* Bus-centric view of the world */
+ char *id_file_name; /* Name of ID list file */
+ int numeric_ids; /* Don't resolve device IDs to names */
+ int debugging; /* Turn on debugging messages */
+
+ /* Functions you can override: */
+ void (*error)(char *msg, ...); /* Write error message and quit */
+ void (*warning)(char *msg, ...); /* Write a warning message */
+ void (*debug)(char *msg, ...); /* Write a debugging message */
+
+ struct pci_dev *devices; /* Devices found on this bus */
+
+ /* Fields used internally: */
+ struct pci_methods *methods;
+ char *nl_list; /* Name list cache */
+ struct nl_entry **nl_hash;
+ int fd; /* proc: fd */
+ int fd_rw; /* proc: fd opened read-write */
+ struct pci_dev *cached_dev; /* proc: device the fd is for */
+};
+
+/* Initialize PCI access */
+struct pci_access *pci_alloc(void);
+void pci_init(struct pci_access *);
+void pci_cleanup(struct pci_access *);
+
+/* Scanning of devices */
+void pci_scan_bus(struct pci_access *acc);
+struct pci_dev *pci_get_dev(struct pci_access *acc, int bus, int dev, int func); /* Raw access to specified device */
+void pci_free_dev(struct pci_dev *);
+
+/*
+ * Devices
+ */
+
+struct pci_dev {
+ struct pci_dev *next; /* Next device in the chain */
+ word bus; /* Higher byte can select host bridges */
+ byte dev, func; /* Device and function */
+
+ /* These fields are set by pci_fill_info() */
+ word vendor_id, device_id; /* Identity of the device */
+ int irq; /* IRQ number */
+ unsigned long base_addr[6]; /* Base addresses */
+ unsigned long rom_base_addr; /* Expansion ROM base address */
+
+ /* Fields used internally: */
+ struct pci_access *access;
+ struct pci_methods *methods;
+ int known_fields; /* Set of info fields that is already known */
+ int hdrtype; /* Direct methods: header type */
+ void *aux; /* Auxillary data */
+};
+
+byte pci_read_byte(struct pci_dev *, int pos); /* Access to configuration space */
+word pci_read_word(struct pci_dev *, int pos);
+u32 pci_read_long(struct pci_dev *, int pos);
+int pci_read_block(struct pci_dev *, int pos, byte *buf, int len);
+int pci_write_byte(struct pci_dev *, int pos, byte data);
+int pci_write_word(struct pci_dev *, int pos, word data);
+int pci_write_long(struct pci_dev *, int pos, u32 data);
+int pci_write_block(struct pci_dev *, int pos, byte *buf, int len);
+
+void pci_fill_info(struct pci_dev *, int flags); /* Fill in device information */
+
+#define PCI_FILL_IDENT 1
+#define PCI_FILL_IRQ 2
+#define PCI_FILL_BASES 4
+#define PCI_FILL_ROM_BASE 8
+#define PCI_FILL_RESCAN 0x10000
+
+/*
+ * Buffered access
+ */
+
+void pci_setup_buffer(struct pci_dev *, byte *buf);
+
+/*
+ * Filters
+ */
+
+struct pci_filter {
+ int bus, slot, func; /* -1 = ANY */
+ int vendor, device;
+};
+
+void pci_filter_init(struct pci_access *, struct pci_filter *);
+char *pci_filter_parse_slot(struct pci_filter *, char *);
+char *pci_filter_parse_id(struct pci_filter *, char *);
+int pci_filter_match(struct pci_filter *, struct pci_dev *);
+
+/*
+ * Device names
+ */
+
+char *pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, u32 arg1, u32 arg2);
+void pci_free_name_list(struct pci_access *a);
+
+#define PCI_LOOKUP_VENDOR 1
+#define PCI_LOOKUP_DEVICE 2
+#define PCI_LOOKUP_CLASS 4
+#define PCI_LOOKUP_SUBSYSTEM 8
+#define PCI_LOOKUP_NUMERIC 0x10000
+
+#endif
--- /dev/null
+/*
+ * $Id: proc.c,v 1.1 1999/01/22 21:05:39 mj Exp $
+ *
+ * The PCI Library -- Configuration Access via /proc/bus/pci
+ *
+ * Copyright (c) 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include "internal.h"
+
+#include <asm/unistd.h>
+#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
+#include <syscall-list.h>
+#endif
+
+/*
+ * As libc doesn't support pread/pwrite yet, we have to call them directly
+ * or use lseek/read/write instead.
+ */
+#if !(defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0)
+
+#if defined(__GLIBC__) && !(defined(__powerpc__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+#ifndef SYS_pread
+#define SYS_pread __NR_pread
+#endif
+static int
+pread(unsigned int fd, void *buf, size_t size, loff_t where)
+{
+ return syscall(SYS_pread, fd, buf, size, where);
+}
+
+#ifndef SYS_pwrite
+#define SYS_pwrite __NR_pwrite
+#endif
+static int
+pwrite(unsigned int fd, void *buf, size_t size, loff_t where)
+{
+ return syscall(SYS_pwrite, fd, buf, size, where);
+}
+#else
+static _syscall4(int, pread, unsigned int, fd, void *, buf, size_t, size, loff_t, where);
+static _syscall4(int, pwrite, unsigned int, fd, void *, buf, size_t, size, loff_t, where);
+#endif
+
+#endif
+
+static void
+proc_config(struct pci_access *a)
+{
+ a->method_params[PCI_ACCESS_PROC_BUS_PCI] = PATH_PROC_BUS_PCI;
+}
+
+static int
+proc_detect(struct pci_access *a)
+{
+ char *name = a->method_params[PCI_ACCESS_PROC_BUS_PCI];
+
+ if (access(name, R_OK))
+ {
+ a->warning("Cannot open %s", name);
+ return 0;
+ }
+ a->debug("...using %s", name);
+ return 1;
+}
+
+static void
+proc_init(struct pci_access *a)
+{
+ a->fd = -1;
+}
+
+static void
+proc_cleanup(struct pci_access *a)
+{
+ if (a->fd >= 0)
+ {
+ close(a->fd);
+ a->fd = -1;
+ }
+}
+
+static void
+proc_scan(struct pci_access *a)
+{
+ FILE *f;
+ char buf[256];
+
+ if (snprintf(buf, sizeof(buf), "%s/devices", a->method_params[PCI_ACCESS_PROC_BUS_PCI]) == sizeof(buf))
+ a->error("File name too long");
+ f = fopen(buf, "r");
+ if (!f)
+ a->error("Cannot open %s", buf);
+ while (fgets(buf, sizeof(buf)-1, f))
+ {
+ struct pci_dev *d = pci_alloc_dev(a);
+ unsigned int dfn, vend;
+
+ sscanf(buf, "%x %x %x %lx %lx %lx %lx %lx %lx %lx",
+ &dfn,
+ &vend,
+ &d->irq,
+ &d->base_addr[0],
+ &d->base_addr[1],
+ &d->base_addr[2],
+ &d->base_addr[3],
+ &d->base_addr[4],
+ &d->base_addr[5],
+ &d->rom_base_addr);
+ d->bus = dfn >> 8U;
+ d->dev = PCI_SLOT(dfn & 0xff);
+ d->func = PCI_FUNC(dfn & 0xff);
+ d->vendor_id = vend >> 16U;
+ d->device_id = vend & 0xffff;
+ d->known_fields = a->buscentric ? PCI_FILL_IDENT
+ : (PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE);
+ pci_link_dev(a, d);
+ }
+ fclose(f);
+}
+
+static int
+proc_setup(struct pci_dev *d, int rw)
+{
+ struct pci_access *a = d->access;
+
+ if (a->cached_dev != d || a->fd_rw < rw)
+ {
+ char buf[256];
+ if (a->fd >= 0)
+ close(a->fd);
+ if (snprintf(buf, sizeof(buf), "%s/%02x/%02x.%d", a->method_params[PCI_ACCESS_PROC_BUS_PCI],
+ d->bus, d->dev, d->func) == sizeof(buf))
+ a->error("File name too long");
+ a->fd_rw = a->writeable || rw;
+ a->fd = open(buf, a->fd_rw ? O_RDWR : O_RDONLY);
+ if (a->fd < 0)
+ a->warning("Cannot open %s", buf);
+ a->cached_dev = d;
+ }
+ return a->fd;
+}
+
+static int
+proc_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int fd = proc_setup(d, 0);
+ int res;
+
+ if (fd < 0)
+ return 0;
+ res = pread(fd, buf, len, pos);
+ if (res < 0)
+ {
+ d->access->warning("proc_read: read failed: %s", strerror(errno));
+ return 0;
+ }
+ else if (res != len)
+ {
+ d->access->warning("proc_read: tried to read %d bytes at %d, but got only %d", len, pos, res);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+proc_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int fd = proc_setup(d, 1);
+ int res;
+
+ if (fd < 0)
+ return 0;
+ res = pwrite(fd, buf, len, pos);
+ if (res < 0)
+ {
+ d->access->warning("proc_write: write failed: %s", strerror(errno));
+ return 0;
+ }
+ else if (res != len)
+ {
+ d->access->warning("proc_write: tried to write %d bytes at %d, but got only %d", len, pos, res);
+ return 0;
+ }
+ return 1;
+}
+
+static void
+proc_cleanup_dev(struct pci_dev *d)
+{
+ if (d->access->cached_dev == d)
+ d->access->cached_dev = NULL;
+}
+
+struct pci_methods pm_linux_proc = {
+ "/proc/bus/pci",
+ proc_config,
+ proc_detect,
+ proc_init,
+ proc_cleanup,
+ proc_scan,
+ pci_generic_fill_info,
+ proc_read,
+ proc_write,
+ NULL, /* init_dev */
+ proc_cleanup_dev
+};
--- /dev/null
+/*
+ * $Id: syscalls.c,v 1.1 1999/01/22 21:05:42 mj Exp $
+ *
+ * The PCI Library -- Configuration Access via Syscalls
+ *
+ * Copyright (c) 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "internal.h"
+
+static int
+sysc_detect(struct pci_access *a)
+{
+ return 0;
+}
+
+static void
+sysc_init(struct pci_access *a)
+{
+}
+
+static void
+sysc_cleanup(struct pci_access *a)
+{
+}
+
+static int
+sysc_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return 0;
+}
+
+static int
+sysc_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return 0;
+}
+
+struct pci_methods pm_syscalls = {
+ "syscalls",
+ NULL, /* config */
+ sysc_detect,
+ sysc_init,
+ sysc_cleanup,
+ pci_generic_scan,
+ pci_generic_fill_info,
+ sysc_read,
+ sysc_write,
+ NULL, /* init_dev */
+ NULL /* cleanup_dev */
+};
+++ /dev/null
-.TH lspci 8 "19 January 1999" "pciutils-1.10" "Linux PCI Utilities"
-.IX lspci
-.SH NAME
-lspci \- list all PCI devices
-.SH SYNOPSIS
-.B lspci
-.RB [ options ]
-.SH DESCRIPTION
-.B lspci
-is a utility for displaying information about all PCI busses in the system and
-all devices connected to them. It requires Linux kernel 2.1.82 or newer and
-supersedes the original /proc/pci interface found in earlier kernels.
-
-If you are going to report bugs in PCI device drivers or in
-.I lspci
-itself, please include output of "lspci -vvx".
-
-.SH OPTIONS
-.TP
-.B -v
-Tells
-.I lspci
-to be verbose and display detailed information about all devices.
-.TP
-.B -vv
-Tells
-.I lspci
-to be very verbose and display even more information (actually everything the
-PCI device is able to tell). The exact meaning of these data is not explained
-in this manual page, if you want to know more, consult
-.B /usr/include/linux/pci.h
-or the PCI specs.
-.TP
-.B -n
-Show PCI vendor and device codes as numbers instead of looking them up in the
-PCI ID database.
-.TP
-.B -x
-Show hexadecimal dump of first 64 bytes of the PCI configuration space (the standard
-header). Useful for debugging of drivers and
-.I lspci
-itself.
-.TP
-.B -xxx
-Show hexadecimal dump of whole PCI configuration space. Available only for root
-as several PCI devices
-.B crash
-when you try to read undefined portions of the config space (this behaviour probably
-doesn't violate the PCI standard, but it's at least very stupid).
-.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.
-.TP
-.B -t
-Show a tree-like diagram containing all busses, bridges, devices and connections
-between them.
-.TP
-.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
-.B
-<file>
-as PCI ID database instead of /usr/share/pci.ids.
-.TP
-.B -p <dir>
-Use
-.B <dir>
-as directory containing PCI bus information instead of /proc/bus/pci.
-.TP
-.B -m
-Dump PCI device data in machine readable form (both normal and verbose format supported)
-for easy parsing by scripts.
-
-.SH FILES
-.TP
-.B /usr/share/pci.ids
-A list of all known PCI ID's (vendors, devices, classes and subclasses).
-.TP
-.B /proc/bus/pci
-An interface to PCI bus configuration space provided by the kernel. Contains
-per-bus subdirectories with per-card config space files and a
-.I
-devices
-file containing a list of all PCI devices.
-
-.SH AUTHOR
-The Linux PCI Utilities are maintained by Martin Mares <mj@atrey.karlin.mff.cuni.cz>.
/*
- * $Id: lspci.c,v 1.18 1999/01/19 21:24:38 mj Exp $
+ * $Id: lspci.c,v 1.19 1999/01/22 21:04:54 mj Exp $
*
* Linux PCI Utilities -- List All PCI Devices
*
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <fcntl.h>
+#include <stdarg.h>
#include <unistd.h>
#include "pciutils.h"
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[] = "nvbxs:d:ti:p:m";
+static char options[] = "nvbxs:d:ti:mg" GENERIC_OPTIONS ;
static char help_msg[] = "\
Usage: lspci [<switches>]\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\
-";
+-i <file>\tUse specified ID database instead of %s\n"
+GENERIC_HELP
+;
-/* Format strings used for IRQ numbers */
+/* Communication with libpci */
+
+static struct pci_access *pacc;
+
+/* Format strings used for IRQ numbers and memory addresses */
#ifdef ARCH_SPARC64
#define IRQ_FORMAT "%08x"
#define IRQ_FORMAT "%d"
#endif
+#ifdef HAVE_64BIT_LONG_INT
+#define LONG_FORMAT "%016lx"
+#else
+#define LONG_FORMAT "%08lx"
+#endif
+
/* Our view of the PCI bus */
struct device {
struct device *next;
- byte bus, devfn;
- word vendid, devid;
- unsigned int kernel_irq;
- unsigned long kernel_base_addr[6], kernel_rom_base_addr;
+ struct pci_dev *dev;
+ int config_cnt;
byte config[256];
};
-static struct device *first_dev, **last_dev = &first_dev;
-
-/* Miscellaneous routines */
-
-void *
-xmalloc(unsigned int howmuch)
-{
- void *p = malloc(howmuch);
- if (!p)
- {
- fprintf(stderr, "lspci: Unable to allocate %d bytes of memory\n", howmuch);
- exit(1);
- }
- return p;
-}
-
-/* Interface for /proc/bus/pci */
-
-static void
-scan_dev_list(void)
-{
- FILE *f;
- byte line[256];
- byte name[256];
-
- sprintf(name, "%s/devices", pci_dir);
- if (! (f = fopen(name, "r")))
- {
- perror(name);
- exit(1);
- }
- while (fgets(line, sizeof(line), f))
- {
- struct device *d = xmalloc(sizeof(struct device));
- unsigned int dfn, vend;
-
- bzero(d, sizeof(*d));
- sscanf(line, "%x %x %x %lx %lx %lx %lx %lx %lx %lx",
- &dfn,
- &vend,
- &d->kernel_irq,
- &d->kernel_base_addr[0],
- &d->kernel_base_addr[1],
- &d->kernel_base_addr[2],
- &d->kernel_base_addr[3],
- &d->kernel_base_addr[4],
- &d->kernel_base_addr[5],
- &d->kernel_rom_base_addr);
- d->bus = dfn >> 8U;
- d->devfn = dfn & 0xff;
- d->vendid = vend >> 16U;
- d->devid = vend & 0xffff;
- if (filter_match(&filter, d->bus, d->devfn, d->vendid, d->devid))
- {
- *last_dev = d;
- last_dev = &d->next;
- d->next = NULL;
- }
- }
- fclose(f);
-}
-
-static inline void
-make_proc_pci_name(struct device *d, char *p)
-{
- sprintf(p, "%s/%02x/%02x.%x",
- pci_dir, d->bus, PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
-}
+static struct device *first_dev;
static void
-scan_config(void)
+scan_devices(void)
{
struct device *d;
- char name[64];
- int fd, res;
int how_much = (show_hex > 2) ? 256 : 64;
+ struct pci_dev *p;
- for(d=first_dev; d; d=d->next)
+ pci_scan_bus(pacc);
+ for(p=pacc->devices; p; p=p->next)
{
- make_proc_pci_name(d, name);
- if ((fd = open(name, O_RDONLY)) < 0)
- {
- fprintf(stderr, "lspci: Unable to open %s: %m\n", name);
- exit(1);
- }
- res = read(fd, d->config, how_much);
- if (res < 0)
- {
- fprintf(stderr, "lspci: Error reading %s: %m\n", name);
- exit(1);
- }
- if (res != how_much)
+ if (!pci_filter_match(&filter, p))
+ continue;
+ d = xmalloc(sizeof(struct device));
+ d->next = first_dev;
+ first_dev = d;
+ d->dev = p;
+ if (!pci_read_block(p, 0, d->config, how_much))
+ die("Unable to read %d bytes of configuration space.", how_much);
+ if (how_much < 128 && (d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
{
- fprintf(stderr, "lspci: Only %d bytes of config space available to you\n", res);
- exit(1);
+ /* For cardbus bridges, we need to fetch 64 bytes more to get the full standard header... */
+ if (!pci_read_block(p, 0, d->config+64, 64))
+ die("Unable to read cardbus bridge extension data.");
+ how_much = 128;
}
- close(fd);
+ d->config_cnt = how_much;
+ pci_setup_buffer(p, d->config);
+ pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE);
}
}
-static void
-scan_proc(void)
-{
- scan_dev_list();
- scan_config();
-}
-
/* Config space accesses */
static inline byte
static int
compare_them(const void *A, const void *B)
{
- const struct device *a = *(const struct device **)A;
- const struct device *b = *(const struct device **)B;
+ const struct pci_dev *a = (*(const struct device **)A)->dev;
+ const struct pci_dev *b = (*(const struct device **)B)->dev;
if (a->bus < b->bus)
return -1;
if (a->bus > b->bus)
return 1;
- if (a->devfn < b->devfn)
+ if (a->dev < b->dev)
+ return -1;
+ if (a->dev > b->dev)
+ return 1;
+ if (a->func < b->func)
return -1;
- if (a->devfn > b->devfn)
+ if (a->func > b->func)
return 1;
return 0;
}
static void
sort_them(void)
{
- struct device **index, **h;
+ struct device **index, **h, **last_dev;
int cnt;
struct device *d;
show_terse(struct device *d)
{
int c;
+ struct pci_dev *p = d->dev;
+ byte classbuf[128], devbuf[128];
printf("%02x:%02x.%x %s: %s",
- d->bus,
- PCI_SLOT(d->devfn),
- PCI_FUNC(d->devfn),
- lookup_class(get_conf_word(d, PCI_CLASS_DEVICE)),
- lookup_device_full(d->vendid, d->devid));
+ p->bus,
+ p->dev,
+ p->func,
+ pci_lookup_name(pacc, classbuf, sizeof(classbuf),
+ PCI_LOOKUP_CLASS,
+ get_conf_word(d, PCI_CLASS_DEVICE), 0),
+ 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 && (c = get_conf_byte(d, PCI_CLASS_PROG)))
static void
show_bases(struct device *d, int cnt)
{
+ struct pci_dev *p = d->dev;
word cmd = get_conf_word(d, PCI_COMMAND);
int i;
{
unsigned long pos;
unsigned int flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
- if (buscentric_view)
- pos = flg;
- else
- {
- pos = d->kernel_base_addr[i];
- if (!pos)
- continue;
- }
- if (pos == 0xffffffff)
+ pos = p->base_addr[i];
+ if (flg == 0xffffffff)
+ flg = 0;
+ if (!pos && !flg)
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;
+ }
if (flg & PCI_BASE_ADDRESS_SPACE_IO)
{
unsigned long a = pos & PCI_BASE_ADDRESS_IO_MASK;
printf("I/O ports at ");
if (a)
printf("%04lx", a);
+ else if (flg & PCI_BASE_ADDRESS_IO_MASK)
+ printf("<ignored>");
else
printf("<unassigned>");
if (!(cmd & PCI_COMMAND_IO))
{
int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
unsigned long a = pos & PCI_BASE_ADDRESS_MEM_MASK;
- int x64 = 0;
+ int done = 0;
+ u32 z = 0;
+
printf("Memory at ");
if (t == PCI_BASE_ADDRESS_MEM_TYPE_64)
{
- if (i < cnt - 1)
+ if (i >= cnt - 1)
+ {
+ printf("<invalid-64bit-slot>\n");
+ done = 1;
+ }
+ else
{
- u32 z;
i++;
z = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
if (buscentric_view)
- printf("%08x", z);
- if (z)
- x64 = 1;
+ {
+ if (a || z)
+ printf("%08x%08lx", z, a);
+ else
+ printf("<unassigned>");
+ done = 1;
+ }
}
+ }
+ if (!done)
+ {
+ if (a)
+ printf(LONG_FORMAT, a);
else
- {
- printf("????????");
- x64 = 1;
- }
+ printf(((flg & PCI_BASE_ADDRESS_MEM_MASK) || z) ? "<ignored>" : "<unassigned>");
}
- if (x64 || a)
- printf("%08lx", a);
- else
- printf("<unassigned>");
printf(" (%s, %sprefetchable)",
(t == PCI_BASE_ADDRESS_MEM_TYPE_32) ? "32-bit" :
(t == PCI_BASE_ADDRESS_MEM_TYPE_64) ? "64-bit" :
static void
show_htype0(struct device *d)
{
- unsigned long rom = buscentric_view ? get_conf_long(d, PCI_ROM_ADDRESS) : d->kernel_rom_base_addr;
+ unsigned long rom = d->dev->rom_base_addr;
show_bases(d, 6);
-
if (rom & 1)
printf("\tExpansion ROM at %08lx%s\n", rom & PCI_ROM_ADDRESS_MASK,
(rom & PCI_ROM_ADDRESS_ENABLE) ? "" : " [disabled]");
static void
show_htype1(struct device *d)
{
+ struct pci_dev *p = d->dev;
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 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;
- unsigned long rom = buscentric_view ? get_conf_long(d, PCI_ROM_ADDRESS) : d->kernel_rom_base_addr;
+ unsigned long rom = p->rom_base_addr;
word brc = get_conf_word(d, PCI_BRIDGE_CONTROL);
show_bases(d, 2);
static void
show_verbose(struct device *d)
{
+ struct pci_dev *p = d->dev;
word status = get_conf_word(d, PCI_STATUS);
word cmd = get_conf_word(d, PCI_COMMAND);
word class = get_conf_word(d, PCI_CLASS_DEVICE);
byte cache_line = get_conf_byte(d, PCI_CACHE_LINE_SIZE);
byte max_lat, min_gnt;
byte int_pin = get_conf_byte(d, PCI_INTERRUPT_PIN);
- byte int_line = get_conf_byte(d, PCI_INTERRUPT_LINE);
- unsigned int irq;
+ unsigned int irq = p->irq;
word subsys_v, subsys_d;
+ char ssnamebuf[256];
show_terse(d);
case PCI_HEADER_TYPE_BRIDGE:
if (class != PCI_CLASS_BRIDGE_PCI)
goto badhdr;
- irq = int_line = int_pin = min_gnt = max_lat = 0;
+ irq = int_pin = min_gnt = max_lat = 0;
subsys_v = subsys_d = 0;
break;
case PCI_HEADER_TYPE_CARDBUS:
return;
}
- if (buscentric_view)
- irq = int_line;
- else
- irq = d->kernel_irq;
-
if (verbose && subsys_v && subsys_v != 0xffff)
- printf("\tSubsystem: %s\n", lookup_subsys_device_full(subsys_v, subsys_d));
+ printf("\tSubsystem: %s\n",
+ pci_lookup_name(pacc, ssnamebuf, sizeof(ssnamebuf),
+ PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
+ subsys_v, subsys_d));
if (verbose > 1)
{
printf(", cache line size %02x", cache_line);
putchar('\n');
}
- if (int_pin)
- printf("\tInterrupt: pin %c routed to IRQ " IRQ_FORMAT "\n", 'A' + int_pin - 1, irq);
+ if (int_pin || irq)
+ printf("\tInterrupt: pin %c routed to IRQ " IRQ_FORMAT "\n",
+ (int_pin ? 'A' + int_pin - 1 : '?'), irq);
}
else
{
((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??");
if (cmd & PCI_COMMAND_MASTER)
printf(", latency %d", latency);
- if (int_pin)
- if (d->kernel_irq)
- printf(", IRQ " IRQ_FORMAT, irq);
- else
- printf(", IRQ ?");
+ if (irq)
+ printf(", IRQ " IRQ_FORMAT, irq);
putchar('\n');
}
show_hex_dump(struct device *d)
{
int i;
- int limit = (show_hex > 2) ? 256 : 64;
- for(i=0; i<limit; i++)
+ for(i=0; i<d->config_cnt; i++)
{
if (! (i & 15))
printf("%02x:", i);
static void
show_machine(struct device *d)
{
+ struct pci_dev *p = d->dev;
int c;
word sv_id=0, sd_id=0;
+ char classbuf[128], vendbuf[128], devbuf[128], svbuf[128], sdbuf[128];
switch (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f)
{
if (verbose)
{
- printf("Device:\t%02x:%02x.%x\n", d->bus, PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
- printf("Class:\t%s\n", lookup_class(get_conf_word(d, PCI_CLASS_DEVICE)));
- printf("Vendor:\t%s\n", lookup_vendor(d->vendid));
- printf("Device:\t%s\n", lookup_device(d->vendid, d->devid));
+ printf("Device:\t%02x:%02x.%x\n", p->bus, p->dev, p->func);
+ printf("Class:\t%s\n",
+ pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, get_conf_word(d, PCI_CLASS_DEVICE), 0));
+ printf("Vendor:\t%s\n",
+ pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR, p->vendor_id, p->device_id));
+ printf("Device:\t%s\n",
+ pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id));
if (sv_id && sv_id != 0xffff)
{
- printf("SVendor:\t%s\n", lookup_subsys_vendor(sv_id));
- printf("SDevice:\t%s\n", lookup_subsys_device(sv_id, sd_id));
+ printf("SVendor:\t%s\n",
+ pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, sv_id, sd_id));
+ printf("SDevice:\t%s\n",
+ pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, sv_id, sd_id));
}
if (c = get_conf_byte(d, PCI_REVISION_ID))
printf("Rev:\t%02x\n", c);
}
else
{
- printf("%02x:%02x.%x ", d->bus, PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
+ printf("%02x:%02x.%x ", p->bus, p->dev, p->func);
printf("\"%s\" \"%s\" \"%s\"",
- lookup_class(get_conf_word(d, PCI_CLASS_DEVICE)),
- lookup_vendor(d->vendid),
- lookup_device(d->vendid, d->devid));
+ pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS,
+ get_conf_word(d, PCI_CLASS_DEVICE), 0),
+ pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR,
+ p->vendor_id, p->device_id),
+ pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE,
+ p->vendor_id, p->device_id));
if (c = get_conf_byte(d, PCI_REVISION_ID))
printf(" -r%02x", c);
if (c = get_conf_byte(d, PCI_CLASS_PROG))
printf(" -p%02x", c);
if (sv_id && sv_id != 0xffff)
- printf(" \"%s\" \"%s\"", lookup_subsys_vendor(sv_id), lookup_subsys_device(sv_id, sd_id));
+ printf(" \"%s\" \"%s\"",
+ pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, sv_id, sd_id),
+ pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, sv_id, sd_id));
else
printf(" \"\" \"\"");
putchar('\n');
static void
insert_dev(struct device *d, struct bridge *b)
{
+ struct pci_dev *p = d->dev;
struct bus *bus;
- if (! (bus = find_bus(b, d->bus)))
+ if (! (bus = find_bus(b, p->bus)))
{
struct bridge *c;
for(c=b->child; c; c=c->next)
- if (c->secondary <= d->bus && d->bus <= c->subordinate)
+ if (c->secondary <= p->bus && p->bus <= c->subordinate)
return insert_dev(d, c);
- bus = new_bus(b, d->bus);
+ bus = new_bus(b, p->bus);
}
/* Simple insertion at the end _does_ guarantee the correct order as the
* original device list was sorted by (bus, devfn) lexicographically
static void
show_tree_dev(struct device *d, byte *line, byte *p)
{
+ struct pci_dev *q = d->dev;
struct bridge *b;
+ char namebuf[256];
- p += sprintf(p, "%02x.%x", PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
+ p += sprintf(p, "%02x.%x", q->dev, q->func);
for(b=&host_bridge; b; b=b->chain)
if (b->br_dev == d)
{
return;
}
if (verbose)
- p += sprintf(p, " %s", lookup_device_full(d->vendid, d->devid));
+ p += sprintf(p, " %s",
+ pci_lookup_name(pacc, namebuf, sizeof(namebuf),
+ PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
+ q->vendor_id, q->device_id));
print_it(line, p);
}
puts("lspci version " PCIUTILS_VERSION);
return 0;
}
- filter_init(&filter);
+
+ pacc = pci_alloc();
+ pacc->error = die;
+ pci_filter_init(pacc, &filter);
+
while ((i = getopt(argc, argv, options)) != -1)
switch (i)
{
case 'n':
- show_numeric_ids = 1;
+ pacc->numeric_ids = 1;
break;
case 'v':
verbose++;
break;
case 'b':
+ pacc->buscentric = 1;
buscentric_view = 1;
break;
case 's':
- if (msg = filter_parse_slot(&filter, optarg))
- {
- fprintf(stderr, "lspci: -f: %s\n", msg);
- return 1;
- }
+ if (msg = pci_filter_parse_slot(&filter, optarg))
+ die("-f: %s", msg);
break;
case 'd':
- if (msg = filter_parse_id(&filter, optarg))
- {
- fprintf(stderr, "lspci: -d: %s\n", msg);
- return 1;
- }
+ if (msg = pci_filter_parse_id(&filter, optarg))
+ die("-d: %s", msg);
break;
case 'x':
show_hex++;
show_tree++;
break;
case 'i':
- pci_ids = optarg;
- break;
- case 'p':
- pci_dir = optarg;
+ pacc->id_file_name = optarg;
break;
case 'm':
machine_readable++;
break;
default:
+ if (parse_generic_option(i, pacc, optarg))
+ break;
bad:
- fprintf(stderr, help_msg);
+ fprintf(stderr, help_msg, pacc->id_file_name);
return 1;
}
if (optind < argc)
goto bad;
- scan_proc();
+ pci_init(pacc);
+ scan_devices();
sort_them();
if (show_tree)
show_forest();
else
show();
+ pci_cleanup(pacc);
return 0;
}
--- /dev/null
+.TH lspci 8 "@TODAY@" "@VERSION@" "Linux PCI Utilities"
+.IX lspci
+.SH NAME
+lspci \- list all PCI devices
+.SH SYNOPSIS
+.B lspci
+.RB [ options ]
+.SH DESCRIPTION
+.B lspci
+is a utility for displaying information about all PCI buses in the system and
+all devices connected to them.
+
+To make use of all the features of this program, you need to have Linux kernel
+2.1.82 or newer which supports the /proc/bus/pci interface. With older kernels,
+the PCI utilities have to use direct hardware access which is available
+only to root and it suffers from numerous race conditions and other problems.
+
+If you are going to report bugs in PCI device drivers or in
+.I lspci
+itself, please include output of "lspci -vvx".
+
+.SH OPTIONS
+.TP
+.B -v
+Tells
+.I lspci
+to be verbose and display detailed information about all devices.
+.TP
+.B -vv
+Tells
+.I lspci
+to be very verbose and display even more information (actually everything the
+PCI device is able to tell). The exact meaning of these data is not explained
+in this manual page, if you want to know more, consult
+.B /usr/include/linux/pci.h
+or the PCI specs.
+.TP
+.B -n
+Show PCI vendor and device codes as numbers instead of looking them up in the
+PCI ID database.
+.TP
+.B -x
+Show hexadecimal dump of first 64 bytes of the PCI configuration space (the standard
+header). Useful for debugging of drivers and
+.I lspci
+itself.
+.TP
+.B -xxx
+Show hexadecimal dump of whole PCI configuration space. Available only for root
+as several PCI devices
+.B crash
+when you try to read undefined portions of the config space (this behaviour probably
+doesn't violate the PCI standard, but it's at least very stupid).
+.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.
+.TP
+.B -t
+Show a tree-like diagram containing all buses, bridges, devices and connections
+between them.
+.TP
+.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 buses 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
+.B
+<file>
+as PCI ID database instead of /usr/share/pci.ids.
+.TP
+.B -p <dir>
+Use
+.B <dir>
+as directory containing PCI bus information instead of /proc/bus/pci.
+.TP
+.B -m
+Dump PCI device data in machine readable form (both normal and verbose format supported)
+for easy parsing by scripts.
+
+.SH PCILIB OPTIONS
+The PCI utilities use PCILIB (a portable library providing platform-independent
+functions for PCI configuration space access) to talk to the PCI cards. The following
+options control parameters of the library, especially what access method it uses.
+By default, PCILIB uses the first available access method and displays no debugging
+messages. Each switch is accompanied by a list of hardware/software configurations
+it's supported in.
+
+.TP
+.B -P <dir>
+Use Linux 2.1 style configuration access to directory
+.B <dir>
+instead of /proc/bus/pci. (Linux 2.1 or newer only)
+.TP
+.B -H1
+Use direct hardware access via Intel configuration mechanism 1. (i386 and compatible only)
+.TP
+.B -H2
+Use direct hardware access via Intel configuration mechanism 2. Warning: This method
+is able to address only first 16 devices on any bus and it seems to be very
+unrealiable in many cases. (i386 and compatible only)
+.TP
+.B -S
+Use PCI access syscalls. (Linux on Alpha and UltraSparc only)
+.TP
+.B -F <file>
+Extract all information from given file containing output of lspci -x. This is very
+useful for analysis of user-supplied bug reports, because you can display the
+hardware configuration in any way you want without disturbing the user with
+requests for more dumps. (All systems)
+.TP
+.B -G
+Increase debug level of the library. (All systems)
+
+.SH FILES
+.TP
+.B /usr/share/pci.ids
+A list of all known PCI ID's (vendors, devices, classes and subclasses).
+.TP
+.B /proc/bus/pci
+An interface to PCI bus configuration space provided by the post-2.1.82 Linux
+kernels. Contains per-bus subdirectories with per-card config space files and a
+.I devices
+file containing a list of all PCI devices.
+
+.SH SEE ALSO
+.BR setpci (8)
+
+.SH AUTHOR
+The Linux PCI Utilities are maintained by Martin Mares <mj@atrey.karlin.mff.cuni.cz>.
+++ /dev/null
-/*
- * $Id: names.c,v 1.6 1998/07/17 08:57:16 mj Exp $
- *
- * Linux PCI Utilities -- Device ID to Name Translation
- *
- * Copyright (c) 1997, 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 <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "pciutils.h"
-
-int show_numeric_ids;
-
-char *pci_ids = ETC_PCI_IDS;
-
-static byte *name_list;
-static int name_list_loaded;
-
-struct nl_entry {
- struct nl_entry *next;
- word id1, id2;
- int cat;
- byte *name;
-};
-
-#define NL_VENDOR 0
-#define NL_DEVICE 1
-#define NL_CLASS 2
-#define NL_SUBCLASS 3
-#define NL_SUBSYSTEM_VENDOR 4
-#define NL_SUBSYSTEM_DEVICE 5
-
-#define HASH_SIZE 1024
-
-static struct nl_entry *nl_hash[HASH_SIZE];
-
-static inline unsigned int nl_calc_hash(int cat, int id1, int id2)
-{
- unsigned int h;
-
- h = id1 ^ id2 ^ (cat << 5);
- h += (h >> 6);
- return h & (HASH_SIZE-1);
-}
-
-static struct nl_entry *nl_lookup(int cat, int id1, int id2)
-{
- unsigned int h = nl_calc_hash(cat, id1, id2);
- struct nl_entry *n = nl_hash[h];
-
- while (n && (n->id1 != id1 || n->id2 != id2 || n->cat != cat))
- n = n->next;
- return n;
-}
-
-static int nl_add(int cat, int id1, int id2, byte *text)
-{
- unsigned int h = nl_calc_hash(cat, id1, id2);
- struct nl_entry *n = nl_hash[h];
-
- while (n && (n->id1 != id1 || n->id2 != id2 || n->cat != cat))
- n = n->next;
- if (n)
- return 1;
- n = xmalloc(sizeof(struct nl_entry));
- n->id1 = id1;
- n->id2 = id2;
- n->cat = cat;
- n->name = text;
- n->next = nl_hash[h];
- nl_hash[h] = n;
- return 0;
-}
-
-static void
-err_name_list(char *msg)
-{
- fprintf(stderr, "%s: %s: %m\n", pci_ids, msg);
- exit(1);
-}
-
-static void
-parse_name_list(void)
-{
- byte *p = name_list;
- byte *q, *r;
- int lino = 0;
- unsigned int id1=0, id2=0;
- int cat, last_cat = -1;
-
- while (*p)
- {
- lino++;
- q = p;
- while (*p && *p != '\n')
- {
- if (*p == '#')
- {
- *p++ = 0;
- while (*p && *p != '\n')
- p++;
- break;
- }
- if (*p == '\t')
- *p = ' ';
- p++;
- }
- if (*p == '\n')
- *p++ = 0;
- if (!*q)
- continue;
- r = p;
- while (r > q && r[-1] == ' ')
- *--r = 0;
- r = q;
- while (*q == ' ')
- q++;
- if (r == q)
- {
- if (q[0] == 'C' && q[1] == ' ')
- {
- if (strlen(q+2) < 3 ||
- q[4] != ' ' ||
- sscanf(q+2, "%x", &id1) != 1)
- goto parserr;
- cat = last_cat = NL_CLASS;
- }
- else if (q[0] == 'S' && q[1] == ' ')
- {
- if (strlen(q+2) < 5 ||
- q[6] != ' ' ||
- sscanf(q+2, "%x", &id1) != 1)
- goto parserr;
- cat = last_cat = NL_SUBSYSTEM_VENDOR;
- q += 2;
- }
- else
- {
- if (strlen(q) < 5 ||
- q[4] != ' ' ||
- sscanf(q, "%x", &id1) != 1)
- goto parserr;
- cat = last_cat = NL_VENDOR;
- }
- id2 = 0;
- }
- else
- {
- if (sscanf(q, "%x", &id2) != 1)
- goto parserr;
- if (last_cat < 0)
- goto parserr;
- if (last_cat == NL_CLASS)
- cat = NL_SUBCLASS;
- else
- cat = last_cat+1;
- }
- q += 4;
- while (*q == ' ')
- q++;
- if (!*q)
- goto parserr;
- if (nl_add(cat, id1, id2, q))
- {
- fprintf(stderr, "%s, line %d: duplicate entry\n", pci_ids, lino);
- exit(1);
- }
- }
- return;
-
-parserr:
- fprintf(stderr, "%s, line %d: parse error\n", pci_ids, lino);
- exit(1);
-}
-
-static void
-load_name_list(void)
-{
- int fd;
- struct stat st;
-
- fd = open(pci_ids, O_RDONLY);
- if (fd < 0)
- {
- show_numeric_ids = 1;
- return;
- }
- if (fstat(fd, &st) < 0)
- err_name_list("stat");
- name_list = xmalloc(st.st_size + 1);
- if (read(fd, name_list, st.st_size) != st.st_size)
- err_name_list("read");
- name_list[st.st_size] = 0;
- parse_name_list();
- close(fd);
- name_list_loaded = 1;
-}
-
-char *
-do_lookup_vendor(int cat, word i)
-{
- static char vendbuf[6];
-
- if (!show_numeric_ids && !name_list_loaded)
- load_name_list();
- if (!show_numeric_ids)
- {
- struct nl_entry *e;
-
- e = nl_lookup(cat, i, 0);
- if (e)
- return e->name;
- }
- sprintf(vendbuf, "%04x", i);
- return vendbuf;
-}
-
-char *
-do_lookup_device(int cat, word v, word i)
-{
- static char devbuf[6];
-
- if (!show_numeric_ids && !name_list_loaded)
- load_name_list();
- if (!show_numeric_ids)
- {
- struct nl_entry *e;
-
- e = nl_lookup(cat, v, i);
- if (e)
- return e->name;
- }
- sprintf(devbuf, "%04x", i);
- return devbuf;
-}
-
-char *
-do_lookup_device_full(int cat, word v, word i)
-{
- static char fullbuf[256];
-
- if (!show_numeric_ids && !name_list_loaded)
- load_name_list();
- if (!show_numeric_ids)
- {
- struct nl_entry *e, *e2;
-
- e = nl_lookup(cat, v, 0);
- e2 = nl_lookup(cat+1, v, i);
- if (!e)
- sprintf(fullbuf, "Unknown device %04x:%04x", v, i);
- else if (!e2)
- sprintf(fullbuf, "%s: Unknown device %04x", e->name, i);
- else
- sprintf(fullbuf, "%s %s", e->name, e2->name);
- }
- else
- sprintf(fullbuf, "%04x:%04x", v, i);
- return fullbuf;
-}
-
-char *
-lookup_vendor(word i)
-{
- return do_lookup_vendor(NL_VENDOR, i);
-}
-
-char *
-lookup_subsys_vendor(word i)
-{
- return do_lookup_vendor(NL_SUBSYSTEM_VENDOR, i);
-}
-
-char *
-lookup_device(word i, word v)
-{
- return do_lookup_device(NL_DEVICE, v, i);
-}
-
-char *
-lookup_subsys_device(word v, word i)
-{
- return do_lookup_device(NL_SUBSYSTEM_DEVICE, v, i);
-}
-
-char *
-lookup_device_full(word v, word i)
-{
- return do_lookup_device_full(NL_VENDOR, v, i);
-}
-
-char *
-lookup_subsys_device_full(word v, word i)
-{
- return do_lookup_device_full(NL_SUBSYSTEM_VENDOR, v, i);
-}
-
-char *
-lookup_class(word c)
-{
- static char classbuf[80];
-
- if (!show_numeric_ids && !name_list_loaded)
- load_name_list();
- if (!show_numeric_ids)
- {
- struct nl_entry *e;
-
- e = nl_lookup(NL_SUBCLASS, c >> 8, c & 0xff);
- if (e)
- return e->name;
- e = nl_lookup(NL_CLASS, c, 0);
- if (e)
- sprintf(classbuf, "%s [%04x]", e->name, c);
- else
- sprintf(classbuf, "Unknown class [%04x]", c);
- }
- else
- sprintf(classbuf, "Class %04x", c);
- return classbuf;
-}
/*
- * $Id: pciutils.h,v 1.11 1999/01/19 21:24:42 mj Exp $
+ * $Id: pciutils.h,v 1.12 1999/01/22 21:04:59 mj Exp $
*
* Linux PCI Utilities -- Declarations
*
- * Copyright (c) 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ * Copyright (c) 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
-#include <linux/types.h>
+#include "lib/pci.h"
-#ifdef KERNEL_PCI_H
-#include <linux/pci.h>
-#else
-#include "pci.h"
-#endif
-
-#define PCIUTILS_VERSION "1.10"
-
-#define PROC_BUS_PCI "/proc/bus/pci"
-#define ETC_PCI_IDS "/usr/share/pci.ids"
-
-/* Types */
-
-typedef __u8 byte;
-typedef __u16 word;
-typedef __u32 u32;
-
-/* lspci.c */
-
-void *xmalloc(unsigned int);
-
-/* names.c */
-
-extern int show_numeric_ids;
-extern char *pci_ids;
+#define PCIUTILS_VERSION PCILIB_VERSION
-char *lookup_vendor(word);
-char *lookup_device(word, word);
-char *lookup_device_full(word, word);
-char *lookup_class(word);
-char *lookup_subsys_vendor(word);
-char *lookup_subsys_device(word, word);
-char *lookup_subsys_device_full(word, word);
+void __attribute__((noreturn)) die(char *msg, ...);
+void *xmalloc(unsigned int howmuch);
+int parse_generic_option(int i, struct pci_access *pacc, char *optarg);
-/* filter.c */
-
-struct pci_filter {
- int bus, slot, func; /* -1 = ANY */
- int vendor, device;
-};
+#ifdef HAVE_PM_LINUX_PROC
+#define GENOPT_PROC "P:"
+#define GENHELP_PROC "-P <dir>\tUse specified directory instead of " PATH_PROC_BUS_PCI "\n"
+#else
+#define GENOPT_PROC
+#define GENHELP_PROC
+#endif
+#ifdef HAVE_PM_INTEL_CONF
+#define GENOPT_INTEL "H:"
+#define GENHELP_INTEL "-H <mode>\tUse direct hardware access (<mode> = 1 or 2)\n"
+#else
+#define GENOPT_INTEL
+#define GENHELP_INTEL
+#endif
+#ifdef HAVE_PM_SYSCALLS
+#define GENOPT_SYSCALLS "S"
+#define GENHELP_SYSCALLS "-S\t\tUse direct hardware access via syscalls\n"
+#else
+#define GENOPT_SYSCALLS
+#define GENHELP_SYSCALLS
+#endif
+#ifdef HAVE_PM_DUMP
+#define GENOPT_DUMP "F:"
+#define GENHELP_DUMP "-F <file>\tRead configuration data from given file\n"
+#else
+#define GENOPT_DUMP
+#define GENHELP_DUMP
+#endif
-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);
+#define GENERIC_OPTIONS "G" GENOPT_PROC GENOPT_INTEL GENOPT_SYSCALLS GENOPT_DUMP
+#define GENERIC_HELP GENHELP_PROC GENHELP_INTEL GENHELP_SYSCALLS GENHELP_DUMP \
+ "-G\t\tEnable PCI access debugging\n"
+++ /dev/null
-.TH setpci 8 "19 January 1999" "pciutils-1.10" "Linux PCI Utilities"
-.IX setpci
-.SH NAME
-setpci \- configure PCI devices
-.SH SYNOPSIS
-.B setpci
-.RB [ options ]
-.B devices
-.BR operations ...
-
-.SH DESCRIPTION
-.PP
-.B setpci
-is a utility for querying and configuring PCI devices. It requires Linux kernel 2.1.82
-or newer as it uses the /proc/bus/pci interface.
-.PP
-All numbers are entered in hexadecimal notation.
-
-.SH OPTIONS
-.TP
-.B -v
-Tells
-.I setpci
-to be verbose and display detailed information about configuration space accesses.
-.TP
-.B -f
-Tells
-.I lspci
-not to complain when there's nothing to do (when no devices are selected).
-This option is intended for use in widely-distributed configuration scripts
-where it's uncertain whether the device in question is present in the machine
-or not.
-.TP
-.B -D
-`Demo mode' -- simulate configuration space accesses instead of really doing them.
-It's useful to try
-.B setpci -vD
-to see what your complex sequence of
-.B setpci
-operations does before you actually execute it.
-
-.SH DEVICE SELECTION
-.PP
-Before each sequence of operations you need to select which devices you wish that
-operation to affect.
-.TP
-.B -s [[<bus>]:][<slot>][.[<func>]]
-Select 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" selects only
-fourth function of each device.
-.TP
-.B -d [<vendor>]:[<device>]
-Select devices with specified vendor and device ID. Both ID's are given in
-hexadecimal and may be omitted or given as "*" meaning "any value".
-
-.SH OPERATIONS
-.PP
-To query value of a configuration register, just name it (either by typing its name or
-by typing register address with optional
-.BR .B ,
-.B .W
-or
-.B .L
-suffix specifying register width as byte, word or longword).
-.PP
-To set a register, write
-.BR reg = values
-where
-.B reg
-is the same you would use to query the register and
-.B values
-is a comma-separated list of values you want to write starting with the given
-address.
-
-.SH REGISTER NAMES
-.PP
-.B setpci
-knows the following configuration register names. See PCI bus specs for their precise
-meaning or consult
-.B /usr/include/linux/pci.h
-for few comments.
-.PP
-.nf
-VENDOR_ID
-DEVICE_ID
-COMMAND
-STATUS
-REVISION
-CLASS_PROG
-CLASS_DEVICE
-CACHE_LINE_SIZE
-LATENCY_TIMER
-HEADER_TYPE
-BIST
-BASE_ADDRESS_0
-BASE_ADDRESS_1
-BASE_ADDRESS_2
-BASE_ADDRESS_3
-BASE_ADDRESS_4
-BASE_ADDRESS_5
-CARDBUS_CIS
-SUBSYSTEM_VENDOR_ID
-SUBSYSTEM_ID
-ROM_ADDRESS
-INTERRUPT_LINE
-INTERRUPT_PIN
-MIN_GNT
-MAX_LAT
-PRIMARY_BUS
-SECONDARY_BUS
-SUBORDINATE_BUS
-SEC_LATENCY_TIMER
-IO_BASE
-IO_LIMIT
-SEC_STATUS
-MEMORY_BASE
-MEMORY_LIMIT
-PREF_MEMORY_BASE
-PREF_MEMORY_LIMIT
-PREF_BASE_UPPER32
-PREF_LIMIT_UPPER32
-IO_BASE_UPPER16
-IO_LIMIT_UPPER16
-BRIDGE_ROM_ADDRESS
-BRIDGE_CONTROL
-CB_CARDBUS_BASE
-CB_CAPABILITIES
-CB_SEC_STATUS
-CB_BUS_NUMBER
-CB_CARDBUS_NUMBER
-CB_SUBORDINATE_BUS
-CB_CARDBUS_LATENCY
-CB_MEMORY_BASE_0
-CB_MEMORY_LIMIT_0
-CB_MEMORY_BASE_1
-CB_MEMORY_LIMIT_1
-CB_IO_BASE_0
-CB_IO_BASE_0_HI
-CB_IO_LIMIT_0
-CB_IO_LIMIT_0_HI
-CB_IO_BASE_1
-CB_IO_BASE_1_HI
-CB_IO_LIMIT_1
-CB_IO_LIMIT_1_HI
-CB_SUBSYSTEM_VENDOR_ID
-CB_SUBSYSTEM_ID
-CB_LEGACY_MODE_BASE
-
-.SH EXAMPLES
-.PP
-`setpci -d *:* latency_timer=40' sets the latency timer to 64 (40 hexadecimal).
-.PP
-`setpci -s 0 device_id vendor_id' lists ID's of devices in slot 0 in all busses.
-.PP
-`setpci -s 12:3.4 34.l=1,2,3' writes longword 1 to register 34, 2 to register 35
-and 3 to register 35 of device at bus 12, slot 3, function 4.
-
-.SH AUTHOR
-The Linux PCI Utilities are maintained by Martin Mares <mj@atrey.karlin.mff.cuni.cz>.
/*
- * $Id: setpci.c,v 1.8 1998/10/24 13:39:20 mj Exp $
+ * $Id: setpci.c,v 1.9 1999/01/22 21:05:02 mj Exp $
*
* Linux PCI Utilities -- Manipulate PCI Configuration Registers
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
-#define _GNU_SOURCE
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <fcntl.h>
+#include <stdarg.h>
#include <unistd.h>
-#include <errno.h>
-#include <asm/byteorder.h>
-
-#include <asm/unistd.h>
-#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
-#include <syscall-list.h>
-#endif
#include "pciutils.h"
static int verbose; /* Verbosity level */
static int demo_mode; /* Only show */
-struct device {
- struct device *next;
- byte bus, devfn, mark;
- word vendid, devid;
- int fd, need_write;
-};
-
-static struct device *first_dev;
+static struct pci_access *pacc;
struct op {
struct op *next;
- struct device **dev_vector;
+ struct pci_dev **dev_vector;
unsigned int addr;
unsigned int width; /* Byte width of the access */
int num_values; /* Number of values to write; <0=read */
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;
-}
-
-/*
- * As libc doesn't support pread/pwrite yet, we have to call them directly
- * or use lseek/read/write instead.
- */
-#if !(defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0)
-
-#if defined(__GLIBC__) && !(defined(__powerpc__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
-#ifndef SYS_pread
-#define SYS_pread __NR_pread
-#endif
-static int
-pread(unsigned int fd, void *buf, size_t size, loff_t where)
-{
- return syscall(SYS_pread, fd, buf, size, where);
-}
-
-#ifndef SYS_pwrite
-#define SYS_pwrite __NR_pwrite
-#endif
-static int
-pwrite(unsigned int fd, void *buf, size_t size, loff_t where)
-{
- return syscall(SYS_pwrite, fd, buf, size, where);
-}
-#else
-static _syscall4(int, pread, unsigned int, fd, void *, buf, size_t, size, loff_t, where);
-static _syscall4(int, pwrite, unsigned int, fd, void *, buf, size_t, size, loff_t, where);
-#endif
-
-#endif
-
-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 **
+static struct pci_dev **
select_devices(struct pci_filter *filt)
{
- struct device *z, **a, **b;
+ struct pci_dev *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))
+ for(z=pacc->devices; z; z=z->next)
+ if (pci_filter_match(filt, z))
cnt++;
a = b = xmalloc(sizeof(struct device *) * cnt);
- for(z=first_dev; z; z=z->next)
- if (z->mark)
+ for(z=pacc->devices; z; z=z->next)
+ if (pci_filter_match(filt, z))
*a++ = z;
*a = NULL;
return b;
}
static void
-exec_op(struct op *op, struct device *dev)
+exec_op(struct op *op, struct pci_dev *dev)
{
char *mm[] = { NULL, "%02x", "%04x", NULL, "%08x" };
char *m = mm[op->width];
unsigned int x;
int i;
- __u32 x32;
- __u16 x16;
- __u8 x8;
-
- if (!demo_mode && dev->fd < 0)
- {
- char name[64];
- sprintf(name, PROC_BUS_PCI "/%02x/%02x.%x", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- if ((dev->fd = open(name, dev->need_write ? O_RDWR : O_RDONLY)) < 0)
- {
- perror(name);
- exit(1);
- }
- }
if (verbose)
- printf("%02x:%02x.%x:%02x", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), op->addr);
+ printf("%02x:%02x.%x:%02x", dev->bus, dev->dev, dev->func, op->addr);
if (op->num_values >= 0)
for(i=0; i<op->num_values; i++)
{
switch (op->width)
{
case 1:
- x8 = op->values[i];
- i = pwrite(dev->fd, &x8, 1, op->addr);
+ pci_write_byte(dev, op->addr, op->values[i]);
break;
case 2:
- x16 = __cpu_to_le16(op->values[i]);
- i = pwrite(dev->fd, &x16, 2, op->addr);
+ pci_write_word(dev, op->addr, op->values[i]);
break;
default:
- x32 = __cpu_to_le32(op->values[i]);
- i = pwrite(dev->fd, &x32, 4, op->addr);
+ pci_write_long(dev, op->addr, op->values[i]);
break;
}
- if (i != (int) op->width)
- {
- fprintf(stderr, "Error writing to %02x:%02x.%d: %m\n", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- exit(1);
- }
}
else
{
switch (op->width)
{
case 1:
- i = pread(dev->fd, &x8, 1, op->addr);
- x = x8;
+ x = pci_read_byte(dev, op->addr);
break;
case 2:
- i = pread(dev->fd, &x16, 2, op->addr);
- x = __le16_to_cpu(x16);
+ x = pci_read_word(dev, op->addr);
break;
default:
- i = pread(dev->fd, &x32, 4, op->addr);
- x = __le32_to_cpu(x32);
+ x = pci_read_long(dev, op->addr);
break;
}
- if (i != (int) op->width)
- {
- fprintf(stderr, "Error reading from %02x:%02x.%d: %m\n", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- exit(1);
- }
printf(m, x);
}
else
static void
execute(struct op *op)
{
- struct device **vec = NULL;
- struct device **pdev, *dev;
+ struct pci_dev **vec = NULL;
+ struct pci_dev **pdev, *dev;
struct op *oops;
while (op)
static void
scan_ops(struct op *op)
{
- struct device **pdev, *dev;
-
while (op)
{
if (op->num_values >= 0)
- {
- pdev = op->dev_vector;
- while (dev = *pdev++)
- dev->need_write = 1;
- }
+ pacc->writeable = 1;
op = op->next;
}
}
usage(void)
{
fprintf(stderr,
-"Usage: setpci [-fvD] (<device>+ <reg>[=<values>]*)*\n\
+"Usage: setpci [<options>] (<device>+ <reg>[=<values>]*)*\n\
-f\t\tDon't complain if there's nothing to do\n\
-v\t\tBe verbose\n\
--D\t\tList changes, don't commit them\n\
-<device>:\t-s [[<bus>]:][<slot>][.[<func>]]\n\
+-D\t\tList changes, don't commit them\n"
+GENERIC_HELP
+"<device>:\t-s [[<bus>]:][<slot>][.[<func>]]\n\
\t|\t-d [<vendor>]:[<device>]\n\
<reg>:\t\t<number>[.(B|W|L)]\n\
|\t\t<name>\n\
{
enum { STATE_INIT, STATE_GOT_FILTER, STATE_GOT_OP } state = STATE_INIT;
struct pci_filter filter;
- struct device **selected_devices = NULL;
+ struct pci_dev **selected_devices = NULL;
+ char *opts = GENERIC_OPTIONS ;
if (argc == 2 && !strcmp(argv[1], "--version"))
{
}
argc--;
argv++;
+
+ pacc = pci_alloc();
+ pacc->error = die;
+
while (argc && argv[0][0] == '-')
{
char *c = argv[0]+1;
char *d = c;
+ char *e;
while (*c)
switch (*c)
{
case 0:
break;
default:
- if (c != d)
- usage();
- goto next;
+ if (e = strchr(opts, *c))
+ {
+ char *arg;
+ c++;
+ if (e[1] == ':')
+ {
+ if (*c)
+ arg = c;
+ else if (argc > 1)
+ {
+ arg = argv[1];
+ argc--; argv++;
+ }
+ else
+ usage();
+ c = "";
+ }
+ else
+ arg = NULL;
+ if (!parse_generic_option(*e, pacc, arg))
+ usage();
+ }
+ else
+ {
+ if (c != d)
+ usage();
+ goto next;
+ }
}
argc--;
argv++;
}
next:
- scan_devices();
+ pci_init(pacc);
+ pci_scan_bus(pacc);
while (argc)
{
usage();
if (state != STATE_GOT_FILTER)
{
- filter_init(&filter);
+ pci_filter_init(pacc, &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;
- }
+ if (d = pci_filter_parse_slot(&filter, d))
+ die("-s: %s", d);
break;
case 'd':
- if (d = filter_parse_id(&filter, d))
- {
- fprintf(stderr, "setpci: -d: %s\n", d);
- return 1;
- }
+ if (d = pci_filter_parse_id(&filter, d))
+ die("-d: %s", d);
break;
default:
usage();
op->width = r->width;
}
if (ll > 0x100 || ll + op->width*((n < 0) ? 1 : n) > 0x100)
- {
- fprintf(stderr, "setpci: Register number out of range!\n");
- return 1;
- }
+ die("Register number out of range!");
if (ll & (op->width - 1))
- {
- fprintf(stderr, "setpci: Unaligned register address!\n");
- return 1;
- }
+ die("Unaligned register address!");
op->addr = ll;
for(i=0; i<n; i++)
{
--- /dev/null
+.TH setpci 8 "@TODAY@" "@VERSION@" "Linux PCI Utilities"
+.IX setpci
+.SH NAME
+setpci \- configure PCI devices
+.SH SYNOPSIS
+.B setpci
+.RB [ options ]
+.B devices
+.BR operations ...
+
+.SH DESCRIPTION
+.PP
+.B setpci
+is a utility for querying and configuring PCI devices.
+
+To make use of all the features of this program, you need to have Linux kernel
+2.1.82 or newer which supports the /proc/bus/pci interface. With older kernels,
+the PCI utilities have to use direct hardware access which is available
+only to root and it suffers from numerous race conditions and other problems.
+
+All numbers are entered in hexadecimal notation.
+
+.SH OPTIONS
+.TP
+.B -v
+Tells
+.I setpci
+to be verbose and display detailed information about configuration space accesses.
+.TP
+.B -f
+Tells
+.I setpci
+not to complain when there's nothing to do (when no devices are selected).
+This option is intended for use in widely-distributed configuration scripts
+where it's uncertain whether the device in question is present in the machine
+or not.
+.TP
+.B -D
+`Demo mode' -- simulate configuration space accesses instead of really doing them.
+It's useful to try
+.B setpci -vD
+to see what your complex sequence of
+.B setpci
+operations does before you actually execute it.
+
+.SH DEVICE SELECTION
+.PP
+Before each sequence of operations you need to select which devices you wish that
+operation to affect.
+.TP
+.B -s [[<bus>]:][<slot>][.[<func>]]
+Select 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" selects only
+fourth function of each device.
+.TP
+.B -d [<vendor>]:[<device>]
+Select devices with specified vendor and device ID. Both ID's are given in
+hexadecimal and may be omitted or given as "*" meaning "any value".
+
+.SH OPERATIONS
+.PP
+To query value of a configuration register, just name it (either by typing its name or
+by typing register address with optional
+.BR .B ,
+.B .W
+or
+.B .L
+suffix specifying register width as byte, word or longword).
+.PP
+To set a register, write
+.BR reg = values
+where
+.B reg
+is the same you would use to query the register and
+.B values
+is a comma-separated list of values you want to write starting with the given
+address.
+
+.SH REGISTER NAMES
+.PP
+.B setpci
+knows the following configuration register names. See PCI bus specs for their precise
+meaning or consult
+.B /usr/include/linux/pci.h
+for few comments.
+.PP
+.nf
+VENDOR_ID
+DEVICE_ID
+COMMAND
+STATUS
+REVISION
+CLASS_PROG
+CLASS_DEVICE
+CACHE_LINE_SIZE
+LATENCY_TIMER
+HEADER_TYPE
+BIST
+BASE_ADDRESS_0
+BASE_ADDRESS_1
+BASE_ADDRESS_2
+BASE_ADDRESS_3
+BASE_ADDRESS_4
+BASE_ADDRESS_5
+CARDBUS_CIS
+SUBSYSTEM_VENDOR_ID
+SUBSYSTEM_ID
+ROM_ADDRESS
+INTERRUPT_LINE
+INTERRUPT_PIN
+MIN_GNT
+MAX_LAT
+PRIMARY_BUS
+SECONDARY_BUS
+SUBORDINATE_BUS
+SEC_LATENCY_TIMER
+IO_BASE
+IO_LIMIT
+SEC_STATUS
+MEMORY_BASE
+MEMORY_LIMIT
+PREF_MEMORY_BASE
+PREF_MEMORY_LIMIT
+PREF_BASE_UPPER32
+PREF_LIMIT_UPPER32
+IO_BASE_UPPER16
+IO_LIMIT_UPPER16
+BRIDGE_ROM_ADDRESS
+BRIDGE_CONTROL
+CB_CARDBUS_BASE
+CB_CAPABILITIES
+CB_SEC_STATUS
+CB_BUS_NUMBER
+CB_CARDBUS_NUMBER
+CB_SUBORDINATE_BUS
+CB_CARDBUS_LATENCY
+CB_MEMORY_BASE_0
+CB_MEMORY_LIMIT_0
+CB_MEMORY_BASE_1
+CB_MEMORY_LIMIT_1
+CB_IO_BASE_0
+CB_IO_BASE_0_HI
+CB_IO_LIMIT_0
+CB_IO_LIMIT_0_HI
+CB_IO_BASE_1
+CB_IO_BASE_1_HI
+CB_IO_LIMIT_1
+CB_IO_LIMIT_1_HI
+CB_SUBSYSTEM_VENDOR_ID
+CB_SUBSYSTEM_ID
+CB_LEGACY_MODE_BASE
+
+.SH PCILIB OPTIONS
+The PCI utilities use PCILIB (a portable library providing platform-independent
+functions for PCI configuration space access) to talk to the PCI cards. The following
+options control parameters of the library, especially what access method it uses.
+By default, PCILIB uses the first available access method and displays no debugging
+messages. Each switch is accompanied by a list of hardware/software configurations
+it's supported in.
+
+.TP
+.B -P <dir>
+Use Linux 2.1 style configuration access to directory
+.B <dir>
+instead of /proc/bus/pci. (Linux 2.1 or newer only)
+.TP
+.B -H1
+Use direct hardware access via Intel configuration mechanism 1. (i386 and compatible only)
+.TP
+.B -H2
+Use direct hardware access via Intel configuration mechanism 2. Warning: This method
+is able to address only first 16 devices on any bus and it seems to be very
+unrealiable in many cases. (i386 and compatible only)
+.TP
+.B -S
+Use PCI access syscalls. (Linux on Alpha and UltraSparc only)
+.TP
+.B -F <file>
+Extract all information from given file containing output of lspci -x. This is very
+useful for analysis of user-supplied bug reports, because you can display the
+hardware configuration in any way you want without disturbing the user with
+requests for more dumps. (All systems)
+.TP
+.B -G
+Increase debug level of the library. (All systems)
+
+.SH EXAMPLES
+.PP
+`setpci -d *:* latency_timer=40' sets the latency timer to 64 (40 hexadecimal).
+.PP
+`setpci -s 0 device_id vendor_id' lists ID's of devices in slot 0 in all busses.
+.PP
+`setpci -s 12:3.4 34.l=1,2,3' writes longword 1 to register 34, 2 to register 35
+and 3 to register 35 of device at bus 12, slot 3, function 4.
+
+.SH SEE ALSO
+.BR lspci (8)
+
+.SH AUTHOR
+The Linux PCI Utilities are maintained by Martin Mares <mj@atrey.karlin.mff.cuni.cz>.