OSDN Git Service

Initial import of libpciaccess.
authorIan Romanick <idr@us.ibm.com>
Sat, 18 Mar 2006 00:12:48 +0000 (00:12 +0000)
committerIan Romanick <idr@us.ibm.com>
Sat, 18 Mar 2006 00:12:48 +0000 (00:12 +0000)
27 files changed:
.cvsignore [new file with mode: 0644]
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
include/pciaccess.h [new file with mode: 0644]
pciaccess.pc.in [new file with mode: 0644]
src/.cvsignore [new file with mode: 0644]
src/.gitignore [new file with mode: 0644]
src/Doxyfile [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/Makefile.foo [new file with mode: 0644]
src/Makefile.in [new file with mode: 0644]
src/common_capability.c [new file with mode: 0644]
src/common_device_name.c [new file with mode: 0644]
src/common_init.c [new file with mode: 0644]
src/common_interface.c [new file with mode: 0644]
src/common_iterator.c [new file with mode: 0644]
src/linux_sysfs.c [new file with mode: 0644]
src/pciaccess_private.h [new file with mode: 0644]
src/scanpci.c [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..5eb8ffa
--- /dev/null
@@ -0,0 +1,19 @@
+aclocal.m4
+autom4te.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+pciaccess.pc
+install-sh
+libtool
+ltmain.sh
+Makefile
+Makefile.in
+missing
+mkinstalldirs
+stamp-h1
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..5eb8ffa
--- /dev/null
@@ -0,0 +1,19 @@
+aclocal.m4
+autom4te.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+pciaccess.pc
+install-sh
+libtool
+ltmain.sh
+Makefile
+Makefile.in
+missing
+mkinstalldirs
+stamp-h1
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..3fc0435
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Ian Romanick of IBM
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..2f825cb
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,21 @@
+(C) Copyright IBM Corporation 2006
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation on
+the rights to use, copy, modify, merge, publish, distribute, sub license,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..8691ae9
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,32 @@
+2006-03-17  Ian D. Romanick  <idr@us.ibm.com>
+
+       * configure.ac, src/common_device_name.c
+       Added configure option (--with-pciids-path) to set the default
+       place to look for the pci.ids file.
+
+2006-03-16  Ian D. Romanick  <idr@us.ibm.com>
+
+       * src/pcils.c, src/scanpci.c, src/Makefile.foo
+       Made pcils more like XFree86's scanpci utility than lspci.  Changed
+       the name of the source file from pcils.c to scanpci.c.  Eventually
+       this will be it's own project somewhere else (or it will whither and
+       die).
+
+2006-03-15  Ian D. Romanick  <idr@us.ibm.com>
+
+       * First round of autotools madness.
+
+2006-02-24  Ian D. Romanick  <idr@us.ibm.com>
+
+       * common_device_name.c, pciaccess.h, pcils.c:
+       Add interfaces for querying the device, vendor, subdevice, and
+       subvendor name strings from pci.ids.
+
+2006-02-20  Ian D. Romanick  <idr@us.ibm.com>
+
+       * common_agp.c:
+       Removed this file.  It was an old version of what became
+       common_capability.c.
+
+       * common_capability.c:
+       Fixed an issue with AGP rate detection for AGP3 devices.
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..56b077d
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PREFIX', the package will
+use PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).  Here is a another example:
+
+     /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..8a112b4
--- /dev/null
@@ -0,0 +1,30 @@
+# 
+# (C) Copyright IBM Corporation 2006
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+# IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+SUBDIRS = src
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = pciaccess.pc
+
+EXTRA_DIST = pciaccess.pc.in autogen.sh src/pcils.c src/Makefile.foo
+
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..904cd67
--- /dev/null
@@ -0,0 +1,12 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+autoreconf -v --install || exit 1
+cd $ORIGDIR || exit $?
+
+$srcdir/configure --enable-maintainer-mode "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..a0c2746
--- /dev/null
@@ -0,0 +1,70 @@
+
+dnl (C) Copyright IBM Corporation 2006
+dnl All Rights Reserved.
+dnl
+dnl Permission is hereby granted, free of charge, to any person obtaining a
+dnl copy of this software and associated documentation files (the "Software"),
+dnl to deal in the Software without restriction, including without limitation
+dnl on the rights to use, copy, modify, merge, publish, distribute, sub
+dnl license, and/or sell copies of the Software, and to permit persons to whom
+dnl the Software is furnished to do so, subject to the following conditions:
+dnl
+dnl The above copyright notice and this permission notice (including the next
+dnl paragraph) shall be included in all copies or substantial portions of the
+dnl Software.
+dnl
+dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+dnl IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+dnl FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+dnl IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+dnl LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+dnl FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+dnl DEALINGS IN THE SOFTWARE.
+dnl
+dnl Process this file with autoconf to create configure.
+
+# AC_DEFINE_DIR macro from autoconf-archive.cryp.to
+AC_DEFUN([AC_DEFINE_DIR], [
+  prefix_NONE=
+  exec_prefix_NONE=
+  test "x$prefix" = xNONE && prefix_NONE=yes && prefix=$ac_default_prefix
+  test "x$exec_prefix" = xNONE && exec_prefix_NONE=yes && exec_prefix=$prefix
+dnl In Autoconf 2.60, ${datadir} refers to ${datarootdir}, which in turn
+dnl refers to ${prefix}.  Thus we have to use `eval' twice.
+  eval ac_define_dir="\"[$]$2\""
+  eval ac_define_dir="\"$ac_define_dir\""
+  AC_SUBST($1, "$ac_define_dir")
+  AC_DEFINE_UNQUOTED($1, "$ac_define_dir", [$3])
+  test "$prefix_NONE" && prefix=NONE
+  test "$exec_prefix_NONE" && exec_prefix=NONE
+])
+
+AC_PREREQ([2.57])
+
+AC_INIT(libpciaccess, 0.2, [none yet], libpciaccess)
+AM_INIT_AUTOMAKE([dist-bzip2])
+AM_MAINTAINER_MODE
+
+AM_CONFIG_HEADER(config.h)
+
+# Check for progs
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+m4_ifdef([AS_HELP_STRING], , [m4_define([AS_HELP_STRING], m4_defn([AC_HELP_STRING]))])
+
+DEFAULT_PCIIDS_PATH=/usr/share/hwdata
+AC_ARG_WITH(pciids-path,
+       AS_HELP_STRING([--with-pciids-path=PCIIDS_PATH], [Path to pci.ids file]),
+       [PCIIDS_PATH="$withval"],
+       [PCIIDS_PATH="$DEFAULT_PCIIDS_PATH"])
+AC_DEFINE_DIR(PCIIDS_PATH, PCIIDS_PATH, [Path to pci.ids])
+
+AC_SUBST(PCIACCESS_CFLAGS)
+AC_SUBST(PCIACCESS_LIBS)
+                 
+XORG_RELEASE_VERSION
+
+AC_OUTPUT([Makefile
+          src/Makefile
+           pciaccess.pc])
diff --git a/include/pciaccess.h b/include/pciaccess.h
new file mode 100644 (file)
index 0000000..fec8271
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file pciaccess.h
+ * 
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <inttypes.h>
+
+typedef uint64_t pciaddr_t;
+
+struct pci_device;
+struct pci_device_iterator;
+struct pci_id_match;
+
+int pci_device_read_rom( struct pci_device * dev, void * buffer );
+
+int pci_device_map_region( struct pci_device * dev, unsigned region,
+    int write_enable );
+
+int pci_device_unmap_region( struct pci_device * dev, unsigned region );
+
+int pci_device_probe( struct pci_device * dev );
+
+const struct pci_agp_info * pci_device_get_agp_info( struct pci_device * dev );
+
+int pci_system_init( void );
+
+void pci_system_cleanup( void );
+
+struct pci_device_iterator * pci_iterator_create( const char *regex );
+
+void pci_iterator_destroy( struct pci_device_iterator * iter );
+
+struct pci_device * pci_device_next( struct pci_device_iterator * iter );
+
+const char * pci_get_name( const struct pci_id_match * m );
+const char * pci_device_get_device_name( const struct pci_device * dev );
+const char * pci_device_get_subdevice_name( const struct pci_device * dev );
+const char * pci_device_get_vendor_name( const struct pci_device * dev );
+const char * pci_device_get_subvendor_name( const struct pci_device * dev );
+
+int pci_device_cfg_read    ( struct pci_device * dev, void * data,
+    pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_read );
+int pci_device_cfg_read_u8 ( struct pci_device * dev, uint8_t  * data,
+    pciaddr_t offset );
+int pci_device_cfg_read_u16( struct pci_device * dev, uint16_t * data,
+    pciaddr_t offset );
+int pci_device_cfg_read_u32( struct pci_device * dev, uint32_t * data,
+    pciaddr_t offset );
+
+int pci_device_cfg_write    ( struct pci_device * dev, const void * data,
+    pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_written );
+int pci_device_cfg_write_u8 ( struct pci_device * dev, const uint8_t  * data,
+    pciaddr_t offset );
+int pci_device_cfg_write_u16( struct pci_device * dev, const uint16_t * data,
+    pciaddr_t offset );
+int pci_device_cfg_write_u32( struct pci_device * dev, const uint32_t * data,
+    pciaddr_t offset );
+
+
+#define PCI_MATCH_ANY  (~0)
+
+/**
+ */
+struct pci_id_match {
+    /**
+     * \name Device / vendor matching controls
+     * 
+     * Control the search based on the device, vendor, subdevice, or subvendor
+     * IDs.  Setting any of these fields to \c PCI_MATCH_ANY will cause the
+     * field to not be used in the comparison.
+     */
+    /*@{*/
+    uint32_t    vendor_id;
+    uint32_t    device_id;
+    uint32_t    subvendor_id;
+    uint32_t    subdevice_id;
+    /*@}*/
+
+    
+    /**
+     * \name Device class matching controls
+     * 
+     */
+    /*@{*/
+    uint32_t    device_class;
+    uint32_t    device_class_mask;
+    /*@}*/
+    
+    intptr_t    match_data;
+};
+
+
+/**
+ * BAR descriptor for a PCI device.
+ */
+struct pci_mem_region {
+    /**
+     * When the region is mapped, this is the pointer to the memory.
+     */
+    void * memory;
+
+    pciaddr_t bus_addr;
+    pciaddr_t base_addr;
+
+
+    /**
+     * Size, in bytes, of the region.
+     */
+    pciaddr_t size;
+    
+
+    /**
+     * Is the region I/O ports or memory?
+     */
+    unsigned is_IO:1;
+    
+    /**
+     * Is the memory region prefetchable?
+     *
+     * \note
+     * This can only be set if \c is_IO is not set.
+     */
+    unsigned is_prefetchable:1;
+
+
+    /**
+     * Is the memory at a 64-bit address?
+     *
+     * \note
+     * This can only be set if \c is_IO is not set.
+     */
+    unsigned is_64:1;
+};
+
+
+/**
+ * PCI device.
+ * 
+ * Contains all of the information about a particular PCI device.
+ */
+struct pci_device {
+    /**
+     * \name Device bus identification.
+     *
+     * Complete bus identification, including domain, of the device.  On
+     * platforms that do not support PCI domains (e.g., 32-bit x86 hardware),
+     * the domain will always be zero.
+     */
+    /*@{*/
+    uint16_t    domain;
+    uint8_t     bus;
+    uint8_t     dev;
+    uint8_t     func;
+    /*@}*/
+
+
+    /**
+     * \name Vendor / device ID
+     * 
+     * The vendor ID, device ID, and sub-IDs for the device.
+     */
+    /*@{*/
+    uint16_t    vendor_id;
+    uint16_t    device_id;
+    uint16_t    subvendor_id;
+    uint16_t    subdevice_id;
+    /*@}*/
+
+    /**
+     * Device's class and subclass packed into a single 32-bit value.
+     */
+    uint32_t    device_class;
+
+
+    /**
+     * Device revision number, as read from the configuration header.
+     */
+    uint8_t     revision;
+
+
+    /**
+     * BAR descriptors for the device.
+     */
+    struct pci_mem_region regions[6];
+
+
+    /**
+     * Size, in bytes, of the device's expansion ROM.
+     */
+    pciaddr_t   rom_size;
+
+
+    /**
+     * IRQ associated with the device.  If there is no IRQ, this value will
+     * be -1.
+     */
+    int irq;
+
+
+    /**
+     * Storage for user data.  Users of the library can store arbitrary
+     * data in this pointer.  The library will not use it for any purpose.
+     * It is the user's responsability to free this memory before destroying
+     * the \c pci_device structure.
+     */
+    void * user_data;
+};
+
+
+/**
+ * Description of the AGP capability of the device.
+ * 
+ * \sa pci_device_get_agp_info
+ */
+struct pci_agp_info {
+    /**
+     * Offset of the AGP registers in the devices configuration register
+     * space.  This is generally used so that the offset of the AGP command
+     * register can be determined.
+     */
+    unsigned    config_offset;
+
+   
+    /**
+     * \name AGP major / minor version.
+     */
+    /*@{*/
+    uint8_t    major_version;
+    uint8_t     minor_version;
+    /*@}*/
+
+    /**
+     * Logical OR of the supported AGP rates.  For example, a value of 0x07
+     * means that the device can support 1x, 2x, and 4x.  A value of 0x0c
+     * means that the device can support 8x and 4x.
+     */
+    uint8_t    rates;
+
+    uint8_t    fast_writes:1;       /**< Are fast-writes supported? */
+    uint8_t    addr64:1;
+    uint8_t    htrans:1;
+    uint8_t    gart64:1;
+    uint8_t    coherent:1;
+    uint8_t    sideband:1;          /**< Is side-band addressing supported? */
+    uint8_t    isochronus:1;
+
+    uint8_t    async_req_size;
+    uint8_t    calibration_cycle_timing;
+    uint8_t    max_requests;
+};
diff --git a/pciaccess.pc.in b/pciaccess.pc.in
new file mode 100644 (file)
index 0000000..706c5f7
--- /dev/null
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: pciaccess
+Description: Library providing generic access to the PCI bus and devices.
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lpciaccess
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644 (file)
index 0000000..7a5734c
--- /dev/null
@@ -0,0 +1,6 @@
+.deps
+.libs
+*.lo
+libpciaccess.la
+Makefile
+Makefile.in
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644 (file)
index 0000000..7a5734c
--- /dev/null
@@ -0,0 +1,6 @@
+.deps
+.libs
+*.lo
+libpciaccess.la
+Makefile
+Makefile.in
diff --git a/src/Doxyfile b/src/Doxyfile
new file mode 100644 (file)
index 0000000..87a4123
--- /dev/null
@@ -0,0 +1,1228 @@
+# Doxyfile 1.4.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = libpciaccess
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = 
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, 
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, 
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, 
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, 
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is YES.
+
+SHOW_DIRECTORIES       = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from the 
+# version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the progam writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = 
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that a graph may be further truncated if the graph's 
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH 
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), 
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, which results in a white background. 
+# Warning: Depending on the platform used, enabling this option may lead to 
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to 
+# read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..6bdf5ad
--- /dev/null
@@ -0,0 +1,42 @@
+# 
+# (C) Copyright IBM Corporation 2006
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+# IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+lib_LTLIBRARIES = libpciaccess.la
+
+libpciaccess_la_SOURCES = common_iterator.c \
+       common_init.c \
+       common_interface.c \
+       common_capability.c \
+       common_device_name.c \
+       linux_sysfs.c
+
+INCLUDES = -I$(top_srcdir)/include
+
+libpciaccess_la_LIBADD = @PCIACCESS_LIBS@
+
+libpciaccess_la_LDFLAGS = -version-number 0:2:0 -no-undefined
+
+libpciaccessincludedir = $(includedir)
+libpciaccessinclude_HEADERS = \
+    $(top_srcdir)/include/pciaccess.h
+
diff --git a/src/Makefile.foo b/src/Makefile.foo
new file mode 100644 (file)
index 0000000..b577dbc
--- /dev/null
@@ -0,0 +1,26 @@
+SOURCES = common_iterator.c \
+       common_init.c \
+       common_interface.c \
+       common_capability.c \
+       common_device_name.c \
+       linux_sysfs.c
+
+OBJECTS = $(SOURCES:.c=.o)
+
+CFLAGS = -ggdb3 -Wall -O0 -I$(VPATH)../include
+
+.PHONY: docs
+
+scanpci: scanpci.o
+       $(CC) $(CFLAGS) $(LDFLAGS) scanpci.o -o scanpci -L.libs -lpciaccess
+
+scanpci.o : scanpci.c ../include/pciaccess.h
+
+$(OBJECTS) : pciaccess.h pciaccess_private.h
+
+docs:
+       doxygen Doxyfile | grep Warning: ; echo
+
+clean:
+       rm -f $(OBJECTS) libpciaccess.a *~
+       rm -f scanpci scanpci.o
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644 (file)
index 0000000..e265207
--- /dev/null
@@ -0,0 +1,523 @@
+# Makefile.in generated by automake 1.9.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# 
+# (C) Copyright IBM Corporation 2006
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+# IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+
+SOURCES = $(libpciaccess_la_SOURCES)
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+DIST_COMMON = $(libpciaccessinclude_HEADERS) $(srcdir)/Makefile.am \
+       $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" \
+       "$(DESTDIR)$(libpciaccessincludedir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libpciaccess_la_DEPENDENCIES =
+am_libpciaccess_la_OBJECTS = common_iterator.lo common_init.lo \
+       common_interface.lo common_capability.lo common_device_name.lo \
+       linux_sysfs.lo
+libpciaccess_la_OBJECTS = $(am_libpciaccess_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libpciaccess_la_SOURCES)
+DIST_SOURCES = $(libpciaccess_la_SOURCES)
+libpciaccessincludeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(libpciaccessinclude_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@
+PCIACCESS_LIBS = @PCIACCESS_LIBS@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+lib_LTLIBRARIES = libpciaccess.la
+libpciaccess_la_SOURCES = common_iterator.c \
+       common_init.c \
+       common_interface.c \
+       common_capability.c \
+       common_device_name.c \
+       linux_sysfs.c
+
+INCLUDES = -I$(top_srcdir)/include
+libpciaccess_la_LIBADD = @PCIACCESS_LIBS@
+libpciaccess_la_LDFLAGS = -version-number 0:2:0 -no-undefined
+libpciaccessincludedir = $(includedir)
+libpciaccessinclude_HEADERS = \
+    $(top_srcdir)/include/pciaccess.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  src/Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --gnu  src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
+       @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-libLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+       done
+
+clean-libLTLIBRARIES:
+       -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+       @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+libpciaccess.la: $(libpciaccess_la_OBJECTS) $(libpciaccess_la_DEPENDENCIES) 
+       $(LINK) -rpath $(libdir) $(libpciaccess_la_LDFLAGS) $(libpciaccess_la_OBJECTS) $(libpciaccess_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_capability.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_device_name.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_init.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_iterator.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux_sysfs.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+       -rm -f libtool
+uninstall-info-am:
+install-libpciaccessincludeHEADERS: $(libpciaccessinclude_HEADERS)
+       @$(NORMAL_INSTALL)
+       test -z "$(libpciaccessincludedir)" || $(mkdir_p) "$(DESTDIR)$(libpciaccessincludedir)"
+       @list='$(libpciaccessinclude_HEADERS)'; for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         f=$(am__strip_dir) \
+         echo " $(libpciaccessincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(libpciaccessincludedir)/$$f'"; \
+         $(libpciaccessincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(libpciaccessincludedir)/$$f"; \
+       done
+
+uninstall-libpciaccessincludeHEADERS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(libpciaccessinclude_HEADERS)'; for p in $$list; do \
+         f=$(am__strip_dir) \
+         echo " rm -f '$(DESTDIR)$(libpciaccessincludedir)/$$f'"; \
+         rm -f "$(DESTDIR)$(libpciaccessincludedir)/$$f"; \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+           $$tags $$unique; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$tags $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && cd $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       $(mkdir_p) $(distdir)/../include
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+           $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+         esac; \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+         if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+           dir="/$$dir"; \
+           $(mkdir_p) "$(distdir)$$dir"; \
+         else \
+           dir=''; \
+         fi; \
+         if test -d $$d/$$file; then \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+       for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libpciaccessincludedir)"; do \
+         test -z "$$dir" || $(mkdir_p) "$$dir"; \
+       done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+       mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-libpciaccessincludeHEADERS
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES \
+       uninstall-libpciaccessincludeHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-libLTLIBRARIES clean-libtool ctags distclean \
+       distclean-compile distclean-generic distclean-libtool \
+       distclean-tags distdir dvi dvi-am html html-am info info-am \
+       install install-am install-data install-data-am install-exec \
+       install-exec-am install-info install-info-am \
+       install-libLTLIBRARIES install-libpciaccessincludeHEADERS \
+       install-man install-strip installcheck installcheck-am \
+       installdirs maintainer-clean maintainer-clean-generic \
+       mostlyclean mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+       uninstall-am uninstall-info-am uninstall-libLTLIBRARIES \
+       uninstall-libpciaccessincludeHEADERS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/common_capability.c b/src/common_capability.c
new file mode 100644 (file)
index 0000000..48f6ed4
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file common_capability.c
+ * Platform independent PCI capability related routines.
+ * 
+ * In addition to including the interface glue for \c pci_device_get_agp_info,
+ * this file also contains a generic implementation of that function.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+/**
+ * Generic implementation of \c pci_system_methods::fill_capabilities.
+ *
+ * \param dev   Device whose capability information is to be processed.
+ *
+ * \return
+ * Zero on success or an errno value on failure.
+ *
+ * \todo
+ * Once more than just the AGP capability is supported, the body of each of
+ * the cases in the capability processing loop should probably be broken out
+ * into its own function.
+ * 
+ * \todo
+ * Once more than just the AGP capability is supported, some care will need
+ * to be taken in partial failure cases.  If, say, the first capability is
+ * correctly processed but the second fails, the function would be re-called
+ * later to try again for the second capability.  This could lead to memory
+ * leaks or other quirky behavior.
+ */
+int
+pci_fill_capabilities_generic( struct pci_device * dev )
+{
+    struct pci_device_private * const dev_priv =
+      (struct pci_device_private *) dev;
+    int       err;
+    uint16_t  status;
+    uint8_t   cap_offset;
+
+
+    err = pci_device_cfg_read_u16( dev, & status, 6 );
+    if ( err ) {
+       return err;
+    }
+
+    /* Are PCI capabilities supported by this device?
+     */
+    if ( (status & 0x0010) == 0 ) {
+       return ENOSYS;
+    }
+    
+    err = pci_device_cfg_read_u8( dev, & cap_offset, 52 );
+    if ( err ) {
+       return err;
+    }
+
+
+    /* Process each of the capabilities list in the PCI header.
+     */
+    while ( cap_offset != 0 ) {
+       uint8_t cap_id;
+       uint8_t next_cap;
+
+       err = pci_device_cfg_read_u8( dev, & cap_id, cap_offset );
+       if ( err ) {
+           return err;
+       }
+
+       err = pci_device_cfg_read_u8( dev, & next_cap, cap_offset + 1 );
+       if ( err ) {
+           return err;
+       }
+       
+       switch ( cap_id ) {
+       case 2: {
+           struct pci_agp_info * agp_info = calloc( 1, sizeof( struct pci_agp_info ) );
+           uint32_t agp_status;
+           uint8_t agp_ver;
+
+
+           if ( agp_info == NULL ) {
+               return ENOMEM;
+           }
+
+
+           err = pci_device_cfg_read_u8( dev, & agp_ver, cap_offset + 2 );
+           if ( err ) {
+               return err;
+           }
+
+           err = pci_device_cfg_read_u32( dev, & agp_status, cap_offset + 4 );
+           if ( err ) {
+               return err;
+           }
+
+           agp_info->config_offset = cap_offset;
+
+           agp_info->major_version = (agp_ver & 0x0f0) >> 4;
+           agp_info->minor_version = (agp_ver & 0x00f);
+
+           agp_info->rates = (agp_status & 0x07);
+
+           /* If AGP3 is supported, then the meaning of the rates values
+            * changes.
+            */
+           if ( (agp_status & 0x08) != 0 ) {
+               agp_info->rates <<= 2;
+           }
+
+           /* Some devices, notably motherboard chipsets, have the AGP3
+            * capability set and the 4x bit set.  This results in an
+            * impossible 16x mode being listed as available.  I'm not 100%
+            * sure this is the right solution.
+            */
+           agp_info->rates &= 0x0f;
+
+
+           agp_info->fast_writes = (agp_status & 0x0010) != 0;
+           agp_info->addr64 =      (agp_status & 0x0020) != 0;
+           agp_info->htrans =      (agp_status & 0x0040) == 0;
+           agp_info->gart64 =      (agp_status & 0x0080) != 0;
+           agp_info->coherent =    (agp_status & 0x0100) != 0;
+           agp_info->sideband =    (agp_status & 0x0200) != 0;
+           agp_info->isochronus =  (agp_status & 0x10000) != 0;
+
+           agp_info->async_req_size = 4 + (1 << ((agp_status & 0xe000) >> 13));
+           agp_info->calibration_cycle_timing = ((agp_status & 0x1c00) >> 10);
+           agp_info->max_requests = 1 + ((agp_status & 0xff000000) >> 24);
+
+           dev_priv->agp = agp_info;
+           break;
+       }
+
+       /* No other capabilities are currently handled.
+        */
+       default:
+           printf( "Unknown cap 0x%02x @ 0x%02x\n", cap_id, cap_offset );
+           break;
+       }
+
+       cap_offset = next_cap;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Get AGP capability data for a device.
+ */
+const struct pci_agp_info *
+pci_device_get_agp_info( struct pci_device * dev )
+{
+    struct pci_device_private * dev_priv = (struct pci_device_private *) dev;
+
+    if ( dev == NULL ) {
+       return NULL;
+    }
+    
+    if ( dev_priv->agp == NULL ) {
+       (void) (*pci_sys->methods->fill_capabilities)( dev );
+    }
+
+    return dev_priv->agp;
+}
diff --git a/src/common_device_name.c b/src/common_device_name.c
new file mode 100644 (file)
index 0000000..2a0d5bf
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file common_device_name.c
+ * Support routines used to determine the vendor or device names associated
+ * with a particular device or vendor.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#if defined(HAVE_STRING_H)
+# include <string.h>
+#elif defined(HAVE_STRINGS_H)
+# include <strings.h>
+#endif
+
+#if defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+# include <stdint.h>
+#endif
+
+#include "pciaccess.h"
+
+#ifndef PCIIDS_PATH
+# define PCIIDS_PATH "/usr/share/hwdata"
+#endif
+
+#define DO_MATCH(a,b)  (((a) == PCI_MATCH_ANY) || ((a) == (b)))
+
+/**
+ * Node for sorting vendor IDs.
+ * 
+ * Each structure forms an internal node of an n-way tree.  Each node selects
+ * \c pci_id_node::bits number of bits from the vendor ID.  Starting from the
+ * root of the tree, a slice of the low-order bits of the vendor ID are
+ * selected and used as an index into the \c pci_id_node::children array.
+ *
+ * At the leaf nodes (i.e., the node entered when all 16 bits of the vendor ID
+ * have been used), the \c pci_id_node::children is actually an array of
+ * pointers to \c pci_id_leaf structures.
+ * 
+ * \todo
+ * Determine if there is a cleaner way (in the source code) to have the
+ * \c children array change type based on whether the node is internal or
+ * a leaf.
+ *
+ * \todo
+ * Currently \c bits is always 4.  Decide if this value can ever change
+ * (i.e., to pull-up levels of the n-way tree when all the children's children
+ * are full).  If it can, rip it out and hard-code it to 4 everywhere.
+ */
+struct pci_id_node {
+    unsigned bits;
+    struct pci_id_node * children[16];
+};
+
+struct pci_id_leaf {
+    uint16_t     vendor;
+    const char * vendor_name;
+    
+    size_t num_devices;
+    struct pci_device_leaf * devices;
+};
+
+struct pci_device_leaf {
+    struct pci_id_match   id;
+    const char * device_name;
+};
+
+/**
+ * Root of the PCI vendor ID search tree.
+ */
+struct pci_id_node * tree = NULL;
+
+/**
+ * Name of the file containing the PCI ID information.
+ */
+static const char pci_id_file[] = PCIIDS_PATH "/pci.ids";
+
+
+/**
+ * Get a pointer to the leaf node for a vendor ID.
+ * 
+ * If the vendor ID does not exist in the tree, it is added.
+ */
+static struct pci_id_leaf *
+insert( uint16_t vendor )
+{
+    struct pci_id_node * n;
+    unsigned bits = 0;
+
+    if ( tree == NULL ) {
+       tree = calloc( 1, sizeof( struct pci_id_node ) );
+       tree->bits = 4;
+    }
+
+    n = tree;
+    while ( n != NULL ) {
+       const unsigned used_bits = n->bits;
+       const unsigned mask = (1 << used_bits) - 1;
+       const unsigned idx = (vendor & (mask << bits)) >> bits;
+
+
+       if ( bits >= 16 ) {
+           break;
+       }
+
+       bits += used_bits;
+
+       if ( n->children[ idx ] == NULL ) {
+           if ( bits < 16 ) {
+               struct pci_id_node * child =
+                   calloc( 1, sizeof( struct pci_id_node ) );
+
+               child->bits = 4;
+
+               n->children[ idx ] = child;
+           }
+           else {
+               struct pci_id_leaf * leaf = 
+                   calloc( 1, sizeof( struct pci_id_leaf ) );
+
+               leaf->vendor = vendor;
+
+               n->children[ idx ] = (struct pci_id_node *) leaf;
+           }
+       }
+
+       n = n->children[ idx ];
+    }
+
+    return (struct pci_id_leaf *) n;
+}
+
+
+/**
+ * Populate a vendor node with all the devices associated with that vendor
+ * 
+ * \param vend  Vendor node that is to be filled from the pci.ids file.
+ * 
+ * \todo
+ * The parsing in this function should be more rhobust.  There are some error
+ * cases (i.e., a 0-tab line followed by a 2-tab line) that aren't handled
+ * correctly.  I don't think there are any security problems with the code,
+ * but it's not impossible.
+ */
+static void
+populate_vendor( struct pci_id_leaf * vend, int fill_device_data )
+{
+    FILE * f = fopen( pci_id_file, "r" );
+    char buf[128];
+    unsigned vendor = PCI_MATCH_ANY;
+
+
+    while( fgets( buf, sizeof( buf ), f ) != NULL ) {
+       unsigned num_tabs;
+       char * new_line;
+       size_t length;
+
+       /* Each line either starts with zero, one, or two tabs followed by
+        * a series of 4 hex digits.  Any lines not matching that are ignored.
+        */
+
+       for ( num_tabs = 0 ; num_tabs < 3 ; num_tabs++ ) {
+           if ( buf[ num_tabs ] != '\t' ) {
+               break;
+           }
+       }
+       
+       if ( !isxdigit( buf[ num_tabs + 0 ] )
+            || !isxdigit( buf[ num_tabs + 1 ] )
+            || !isxdigit( buf[ num_tabs + 2 ] )
+            || !isxdigit( buf[ num_tabs + 3 ] ) ) {
+           continue;
+       }
+       
+       new_line = strchr( buf, '\n' );
+       if ( new_line != NULL ) {
+           *new_line = '\0';
+       }
+
+       length = strlen( buf );
+       (void) memset( buf + length, 0, sizeof( buf ) - length );
+
+
+       if ( num_tabs == 0 ) {
+           vendor = (unsigned) strtoul( & buf[ num_tabs ], NULL, 16 );
+           if ( vend->vendor == vendor ) {
+               vend->vendor_name = strdup( & buf[ num_tabs + 6 ] );
+
+               /* If we're not going to fill in all of the device data as
+                * well, then bail out now.  We have all the information that
+                * we need.
+                */
+               if ( ! fill_device_data ) {
+                   break;
+               }
+           }
+       }
+       else if ( vendor == vend->vendor ) {
+           struct pci_device_leaf * d;
+           struct pci_device_leaf * dev;
+           struct pci_device_leaf * last_dev;
+           
+
+
+           d = realloc( vend->devices, (vend->num_devices + 1)
+                        * sizeof( struct pci_device_leaf ) );
+           if ( d == NULL ) {
+               return;
+           }
+
+           last_dev = & d[ vend->num_devices - 1 ];
+           dev = & d[ vend->num_devices ];
+           vend->num_devices++;
+           vend->devices = d;
+
+           if ( num_tabs == 1 ) {
+               dev->id.vendor_id = vend->vendor;
+               dev->id.device_id = (unsigned) strtoul( & buf[ num_tabs ], 
+                                                       NULL, 16 );
+               dev->id.subvendor_id = PCI_MATCH_ANY;
+               dev->id.subdevice_id = PCI_MATCH_ANY;
+
+               dev->id.device_class = 0;
+               dev->id.device_class_mask = 0;
+               dev->id.match_data = 0;
+
+               dev->device_name = strdup( & buf[ num_tabs + 6 ] );
+           }
+           else {
+               dev->id = last_dev->id;
+
+               dev->id.subvendor_id= (unsigned) strtoul( & buf[ num_tabs ],
+                                                         NULL, 16 );
+               dev->id.subdevice_id = (unsigned) strtoul( & buf[ num_tabs + 5 ], 
+                                                          NULL, 16 );
+               dev->device_name = strdup( & buf[ num_tabs + 5 + 6 ] );
+           }
+       }
+    }
+    
+    fclose( f );
+}
+
+
+static const char *
+find_device_name( const struct pci_id_match * m )
+{
+    struct pci_id_leaf * vend;
+    unsigned i;
+
+
+    if ( m->vendor_id == PCI_MATCH_ANY ) {
+       return NULL;
+    }
+
+
+    vend = insert( m->vendor_id );
+    if ( vend == NULL ) {
+       return NULL;
+    }
+
+    if ( vend->num_devices == 0 ) {
+       populate_vendor( vend, 1 );
+    }
+
+
+    for ( i = 0 ; i < vend->num_devices ; i++ ) {
+       struct pci_device_leaf * d = & vend->devices[ i ];
+
+       if ( DO_MATCH( m->vendor_id, d->id.vendor_id )
+            && DO_MATCH( m->device_id, d->id.device_id )
+            && DO_MATCH( m->subvendor_id, d->id.subvendor_id )
+            && DO_MATCH( m->subdevice_id, d->id.subdevice_id ) ) {
+           return d->device_name;
+       }
+    }
+
+    return NULL;
+}
+
+
+static const char *
+find_vendor_name( const struct pci_id_match * m )
+{
+    struct pci_id_leaf * vend;
+
+
+    if ( m->vendor_id == PCI_MATCH_ANY ) {
+       return NULL;
+    }
+
+
+    vend = insert( m->vendor_id );
+    if ( vend == NULL ) {
+       return NULL;
+    }
+
+    if ( vend->vendor_name == NULL ) {
+       populate_vendor( vend, 0 );
+    }
+
+
+    return vend->vendor_name;
+}
+
+
+/**
+ * Get a name based on an arbitrary PCI search structure.
+ */
+const char *
+pci_get_name( const struct pci_id_match * m )
+{
+    return find_device_name( m );
+}
+
+
+/**
+ * Get the name associated with the device's primary device ID.
+ */
+const char *
+pci_device_get_device_name( const struct pci_device * dev )
+{
+    struct pci_id_match m;
+
+
+    m.vendor_id = dev->vendor_id;
+    m.device_id = dev->device_id;
+    m.subvendor_id = PCI_MATCH_ANY;
+    m.subdevice_id = PCI_MATCH_ANY;
+    m.device_class = 0;
+    m.device_class_mask = 0;
+    m.match_data = 0;
+
+    return find_device_name( & m );
+}
+
+
+/**
+ * Get the name associated with the device's subdevice ID.
+ */
+const char *
+pci_device_get_subdevice_name( const struct pci_device * dev )
+{
+    struct pci_id_match m;
+
+
+    if ( (dev->subvendor_id == 0) || (dev->subdevice_id == 0) ) {
+       return NULL;
+    }
+
+    m.vendor_id = dev->vendor_id;
+    m.device_id = dev->device_id;
+    m.subvendor_id = dev->subvendor_id;
+    m.subdevice_id = dev->subdevice_id;
+    m.device_class = 0;
+    m.device_class_mask = 0;
+    m.match_data = 0;
+
+    return find_device_name( & m );
+}
+
+
+/**
+ * Get the name associated with the device's primary vendor ID.
+ */
+const char *
+pci_device_get_vendor_name( const struct pci_device * dev )
+{
+    struct pci_id_match m;
+
+
+    m.vendor_id = dev->vendor_id;
+    m.device_id = PCI_MATCH_ANY;
+    m.subvendor_id = PCI_MATCH_ANY;
+    m.subdevice_id = PCI_MATCH_ANY;
+    m.device_class = 0;
+    m.device_class_mask = 0;
+    m.match_data = 0;
+
+    return find_vendor_name( & m );
+}
+
+
+/**
+ * Get the name associated with the device's subvendor ID.
+ */
+const char *
+pci_device_get_subvendor_name( const struct pci_device * dev )
+{
+    struct pci_id_match m;
+
+
+    if ( dev->subvendor_id == 0 ) {
+       return NULL;
+    }
+
+
+    m.vendor_id = dev->subvendor_id;
+    m.device_id = PCI_MATCH_ANY;
+    m.subvendor_id = PCI_MATCH_ANY;
+    m.subdevice_id = PCI_MATCH_ANY;
+    m.device_class = 0;
+    m.device_class_mask = 0;
+    m.match_data = 0;
+
+    return find_vendor_name( & m );
+}
diff --git a/src/common_init.c b/src/common_init.c
new file mode 100644 (file)
index 0000000..cabda5e
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file common_init.c
+ * Platform independent routines for initializing access to the PCI system.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+extern int pci_system_linux_sysfs_create( void );
+
+struct pci_system * pci_sys;
+
+/**
+ * Initialize the PCI subsystem for access.
+ * 
+ * \return
+ * Zero on success or an errno value on failure.  In particular, if no
+ * platform-specific initializers are available, \c ENOSYS will be returned.
+ *
+ * \sa pci_system_cleanup
+ */
+
+int
+pci_system_init( void )
+{
+    int err = ENOSYS;
+    
+#ifdef linux
+    err = pci_system_linux_sysfs_create();
+#endif
+
+    return err;
+}
+
+
+/**
+ * Shutdown all access to the PCI subsystem.
+ * 
+ * \sa pci_system_init
+ */
+void
+pci_system_cleanup( void )
+{
+    unsigned i;
+    unsigned j;
+
+
+    if ( pci_sys == NULL ) {
+       return;
+    }
+
+
+    if ( pci_sys->devices ) {
+       for ( i = 0 ; i < pci_sys->num_devices ; i++ ) {
+           for ( j = 0 ; j < 6 ; j++ ) {
+               (void) pci_device_unmap_region( & pci_sys->devices[i].base, j );
+           }
+
+           free( (char *) pci_sys->devices[i].device_string );
+           free( (char *) pci_sys->devices[i].agp );
+           
+           pci_sys->devices[i].device_string = NULL;
+           pci_sys->devices[i].agp = NULL;
+
+           if ( pci_sys->methods->destroy_device != NULL ) {
+               (*pci_sys->methods->destroy_device)( & pci_sys->devices[i].base );
+           }
+       }
+       
+       free( pci_sys->devices );
+       pci_sys->devices = NULL;
+       pci_sys->num_devices = 0;
+    }
+
+
+    if ( pci_sys->methods->destroy != NULL ) {
+       (*pci_sys->methods->destroy)();
+    }
+    
+    free( pci_sys );
+    pci_sys = NULL;
+}
diff --git a/src/common_interface.c b/src/common_interface.c
new file mode 100644 (file)
index 0000000..811d9a1
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file common_interface.c
+ * Platform independent interface glue.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+#include <byteswap.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define LETOH_16(x)   bswap_16(x)
+# define HTOLE_16(x)   bswap_16(x)
+# define LETOH_32(x)   bswap_32(x)
+# define HTOLE_32(x)   bswap_32(x)
+#else
+# define LETOH_16(x)   (x)
+# define HTOLE_16(x)   (x)
+# define LETOH_32(x)   (x)
+# define HTOLE_32(x)   (x)
+#endif
+
+/**
+ * Read a device's expansion ROM.
+ * 
+ * Reads the device's expansion ROM and stores the data in the memory pointed
+ * to by \c buffer.  The buffer must be at least \c pci_device::rom_size
+ * bytes.
+ *
+ * \param dev    Device whose expansion ROM is to be read.
+ * \param buffer Memory in which to store the ROM.
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ */
+int
+pci_device_read_rom( struct pci_device * dev, void * buffer )
+{
+    if ( (dev == NULL) || (buffer == NULL) ) {
+       return EFAULT;
+    }
+
+
+    return (pci_sys->methods->read_rom)( dev, buffer );
+}
+
+
+/**
+ * Probe a PCI device to learn information about the device.
+ * 
+ * Probes a PCI device to learn various information about the device.  Before
+ * calling this function, the only public fields in the \c pci_device
+ * structure that have valid values are \c pci_device::domain,
+ * \c pci_device::bus, \c pci_device::dev, and \c pci_device::func.
+ * 
+ * \param dev  Device to be probed.
+ * 
+ * \return
+ * Zero on succes or an \c errno value on failure.
+ */
+int
+pci_device_probe( struct pci_device * dev )
+{
+    if ( dev == NULL ) {
+       return EFAULT;
+    }
+
+
+    return (pci_sys->methods->probe)( dev );
+}
+
+
+/**
+ * Map the specified BAR so that it can be accessed by the CPU.
+ *
+ * Maps the specified BAR for acces by the processor.  The pointer to the
+ * mapped region is stored in the \c pci_mem_region::memory pointer for the
+ * BAR.
+ *
+ * \param dev          Device whose memory region is to be mapped.
+ * \param region       Region, on the range [0, 5], that is to be mapped.
+ * \param write_enable Map for writing (non-zero).
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_unmap_region
+ */
+int
+pci_device_map_region( struct pci_device * dev, unsigned region,
+                      int write_enable )
+{
+    if ( dev == NULL ) {
+       return EFAULT;
+    }
+
+    if ( (region > 5) || (dev->regions[ region ].size == 0) ) {
+       return ENOENT;
+    }
+
+    if ( dev->regions[ region ].memory != NULL ) {
+       return 0;
+    }
+    
+    return (pci_sys->methods->map)( dev, region, write_enable );
+}
+
+
+/**
+ * Unmap the specified BAR so that it can no longer be accessed by the CPU.
+ *
+ * Unmaps the specified BAR that was previously mapped via
+ * \c pci_device_map_region.
+ *
+ * \param dev          Device whose memory region is to be mapped.
+ * \param region       Region, on the range [0, 5], that is to be mapped.
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_map_region
+ */
+int
+pci_device_unmap_region( struct pci_device * dev, unsigned region )
+{
+    if ( dev == NULL ) {
+       return EFAULT;
+    }
+
+    if ( (region > 5) || (dev->regions[ region ].size == 0) ) {
+       return ENOENT;
+    }
+
+    if ( dev->regions[ region ].memory == NULL ) {
+       return 0;
+    }
+    
+    return (pci_sys->methods->unmap)( dev, region );
+}
+
+
+/**
+ * Read arbitrary bytes from device's PCI config space
+ *
+ * Reads data from the device's PCI configuration space.  As with the system
+ * read command, less data may be returned, without an error, than was
+ * requested.  This is particuarly the case if a non-root user tries to read
+ * beyond the first 64-bytes of configuration space.
+ *
+ * \param dev         Device whose PCI configuration data is to be read.
+ * \param data        Location to store the data
+ * \param offset      Initial byte offset to read
+ * \param size        Total number of bytes to read
+ * \param bytes_read  Location to store the actual number of bytes read.  This
+ *                    pointer may be \c NULL.
+ *
+ * \returns
+ * Zero on success or an errno value on failure.
+ *
+ * \note
+ * Data read from PCI configuartion space using this routine is \b not
+ * byte-swapped to the host's byte order.  PCI configuration data is always
+ * stored in little-endian order, and that is what this routine returns.
+ */
+int
+pci_device_cfg_read( struct pci_device * dev, void * data,
+                    pciaddr_t offset, pciaddr_t size, 
+                    pciaddr_t * bytes_read )
+{
+    pciaddr_t  scratch;
+
+    if ( (dev == NULL) || (data == NULL) ) {
+       return EFAULT;
+    }
+
+    return pci_sys->methods->read( dev, data, offset, size,
+                                  (bytes_read == NULL) 
+                                  ? & scratch : bytes_read );
+}
+
+
+int
+pci_device_cfg_read_u8( struct pci_device * dev, uint8_t * data,
+                       pciaddr_t offset )
+{
+    pciaddr_t bytes;
+    int err = pci_device_cfg_read( dev, data, offset, 1, & bytes );
+    
+    if ( (err == 0) && (bytes != 1) ) {
+       err = ENODATA;
+    }
+
+    return err;
+}
+
+
+int
+pci_device_cfg_read_u16( struct pci_device * dev, uint16_t * data,
+                        pciaddr_t offset )
+{
+    pciaddr_t bytes;
+    int err = pci_device_cfg_read( dev, data, offset, 2, & bytes );
+    
+    if ( (err == 0) && (bytes != 2) ) {
+       err = ENODATA;
+    }
+
+    *data = LETOH_16( *data );
+    return err;
+}
+
+
+int
+pci_device_cfg_read_u32( struct pci_device * dev, uint32_t * data,
+                        pciaddr_t offset )
+{
+    pciaddr_t bytes;
+    int err = pci_device_cfg_read( dev, data, offset, 4, & bytes );
+
+    if ( (err == 0) && (bytes != 4) ) {
+       err = ENODATA;
+    }
+
+    *data = LETOH_32( *data );
+    return err;
+}
+
+
+/**
+ * Write arbitrary bytes to device's PCI config space
+ *
+ * Writess data to the device's PCI configuration space.  As with the system
+ * write command, less data may be written, without an error, than was
+ * requested.
+ *
+ * \param dev         Device whose PCI configuration data is to be written.
+ * \param data        Location of the source data
+ * \param offset      Initial byte offset to write
+ * \param size        Total number of bytes to write
+ * \param bytes_read  Location to store the actual number of bytes written.
+ *                    This pointer may be \c NULL.
+ *
+ * \returns
+ * Zero on success or an errno value on failure.
+ *
+ * \note
+ * Data written to PCI configuartion space using this routine is \b not
+ * byte-swapped from the host's byte order.  PCI configuration data is always
+ * stored in little-endian order, so data written with this routine should be
+ * put in that order in advance.
+ */
+int
+pci_device_cfg_write( struct pci_device * dev, const void * data,
+                     pciaddr_t offset, pciaddr_t size, 
+                     pciaddr_t * bytes_written )
+{
+    pciaddr_t  scratch;
+
+    if ( (dev == NULL) || (data == NULL) ) {
+       return EFAULT;
+    }
+
+    return pci_sys->methods->write( dev, data, offset, size,
+                                   (bytes_written == NULL) 
+                                   ? & scratch : bytes_written );
+}
+
+
+int
+pci_device_cfg_write_u8( struct pci_device * dev, const uint8_t * data,
+                        pciaddr_t offset )
+{
+    pciaddr_t bytes;
+    int err = pci_device_cfg_write( dev, data, offset, 1, & bytes );
+
+    if ( (err == 0) && (bytes != 1) ) {
+       err = ENOSPC;
+    }
+
+
+    return err;
+}
+  
+
+int
+pci_device_cfg_write_u16( struct pci_device * dev, const uint16_t * data,
+                         pciaddr_t offset )
+{
+    pciaddr_t bytes;
+    const uint16_t temp = HTOLE_16( *data );
+    int err = pci_device_cfg_write( dev, & temp, offset, 2, & bytes );
+
+    if ( (err == 0) && (bytes != 2) ) {
+       err = ENOSPC;
+    }
+
+
+    return err;
+}
+
+
+int
+pci_device_cfg_write_u32( struct pci_device * dev, const uint32_t * data,
+                         pciaddr_t offset )
+{
+    pciaddr_t bytes;
+    const uint32_t temp = HTOLE_32( *data );
+    int err = pci_device_cfg_write( dev, & temp, offset, 4, & bytes );
+
+    if ( (err == 0) && (bytes != 4) ) {
+       err = ENOSPC;
+    }
+
+
+    return err;
+}
diff --git a/src/common_iterator.c b/src/common_iterator.c
new file mode 100644 (file)
index 0000000..ffff041
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file common_iterator.c
+ * Platform independent iterator support routines.
+ * 
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <regex.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+/**
+ * Track device iteration state
+ * 
+ * \private
+ */
+struct pci_device_iterator {
+    unsigned next_index;
+    regex_t   reg;
+    int no_regex;
+};
+
+
+
+/**
+ * Create an iterator based on a regular expression.
+ * 
+ * The set of devices to be iterated is selected by the regular expression
+ * passed in \c regex.  The expression matches against an extended PCI bus
+ * identifier string. The format of this string is
+ * "domain:bus:slot.function:vendor:device_id:subvendor:subdevice_id:class".
+ * Unlike classic X bus IDs, all values in the extened bus identifier string
+ * are in hexadecimal.  To simplify the required regular expressions, all hex
+ * digits greater than 9 will be lower-case. 
+ *
+ * To match all devices in domain 0, the expression "0:.+" would be used.  To
+ * match all devices by ATI, the expression ".+:1002:.+". To match all devices
+ * with a class of display, a class of multimedia and a subclass of video, or
+ * a class of processor and a subclass of coprocessor, the expression
+ * ".+:(03[[:hex:]]2|0400|0b40|0001)$" would be used.  Since this is a fully
+ * function regular expression, arbitrarilly complex matches can be requested.
+ * 
+ * \param pci_sys  Handle for the PCI subsystem.
+ * \param regex    Pointer to the regular expression to match against.  If
+ *                 \c NULL is passed, all devices will be matched.
+ * 
+ * \return
+ * A pointer to a fully initialized \c pci_device_iterator structure on
+ * success, or \c NULL on failure.
+ * 
+ * \sa pci_device_next, pci_iterator_destroy
+ */
+struct pci_device_iterator *
+pci_iterator_create( const char * re )
+{
+    struct pci_device_iterator * iter;
+    
+    if ( pci_sys == NULL ) {
+       return NULL;
+    }
+
+    iter = malloc( sizeof( *iter ) );
+    if ( iter != NULL ) {
+       iter->next_index = 0;
+
+       /* If the caller passed a NULL or empty expression, then we don't try
+        * to compile the expression.  Instead we set a flag that tells the
+        * iterator routine to iterate every device in the list.
+        */
+       if ( (re != NULL) && (strlen( re ) > 0) ) {
+           int err = regcomp( & iter->reg, re, REG_EXTENDED | REG_NOSUB );
+           if ( err != 0 ) {
+               free( iter );
+               iter = NULL;
+           }
+
+           iter->no_regex = 0;
+       }
+       else {
+           iter->no_regex = 1;
+       }
+    }
+
+    return iter;
+}
+
+
+/**
+ * Destroy an iterator previously created with \c pci_iterator_create.
+ * 
+ * \param iter  Iterator to be destroyed.
+ * 
+ * \sa pci_device_next, pci_iterator_create
+ */
+void
+pci_iterator_destroy( struct pci_device_iterator * iter )
+{
+    if ( iter != NULL ) {
+       if ( ! iter->no_regex ) {
+           regfree( & iter->reg );
+       }
+
+       free( iter );
+    }
+}
+
+
+static void
+fill_device_string( struct pci_device_private * d )
+{
+
+    if ( d->device_string == NULL ) {
+       char * const string = malloc( 40 );
+       if ( string != NULL ) {
+           pci_device_probe( (struct pci_device *) d );
+           sprintf( string, "%04x:%02x:%02x.%u:%04x:%04x:%04x:%04x:%06x",
+                    d->base.domain,
+                    d->base.bus,
+                    d->base.dev,
+                    d->base.func,
+                    d->base.vendor_id,
+                    d->base.device_id,
+                    d->base.subvendor_id,
+                    d->base.subdevice_id,
+                    d->base.device_class );
+
+           d->device_string = string;
+       }
+    }
+}
+
+
+/**
+ * Iterate to the next PCI device.
+ * 
+ * \param iter  Device iterator returned by \c pci_device_iterate.
+ * 
+ * \return
+ * A pointer to a \c pci_device, or \c NULL when all devices have been
+ * iterated.
+ *
+ * \bug
+ * The only time this routine should be able to return \c NULL is when the
+ * end of the list is hit.  However, there is a memory allocation (via
+ * \c fill_device_string) that can fail.  If this allocation fails, \c NULL
+ * will be erroneously returned.  What should be done here?  Pre-fill the
+ * device strings in \c pci_iterator_create?
+ */
+struct pci_device *
+pci_device_next( struct pci_device_iterator * iter )
+{
+    struct pci_device_private * d = NULL;
+
+    if ( iter->no_regex ) {
+       if ( iter->next_index < pci_sys->num_devices ) {
+           d = & pci_sys->devices[ iter->next_index ];
+           iter->next_index++;
+       }
+    }
+    else {
+       while ( iter->next_index < pci_sys->num_devices ) {
+           struct pci_device_private * const temp = 
+             & pci_sys->devices[ iter->next_index ];
+
+           if ( temp->device_string == NULL ) {
+               fill_device_string( temp );             
+               if ( temp->device_string == NULL ) {
+                   break;
+               }
+           }
+
+           iter->next_index++;
+
+           if ( regexec( & iter->reg, temp->device_string, 0, NULL, 0 ) == 0 ) {
+               d = temp;
+               break;
+           }
+       }
+    }
+    
+    return (struct pci_device *) d;
+}
diff --git a/src/linux_sysfs.c b/src/linux_sysfs.c
new file mode 100644 (file)
index 0000000..d6d6b10
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file linux_sysfs.c
+ * Access PCI subsystem using Linux's sysfs interface.  This interface is
+ * available starting somewhere in the late 2.5.x kernel phase, and is the
+ * prefered method on all 2.6.x kernels.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+static int pci_device_linux_sysfs_read_rom( struct pci_device * dev,
+    void * buffer );
+
+static int pci_device_linux_sysfs_probe( struct pci_device * dev );
+
+static int pci_device_linux_sysfs_map_region( struct pci_device * dev,
+    unsigned region, int write_enable );
+
+static int pci_device_linux_sysfs_unmap_region( struct pci_device * dev,
+    unsigned region );
+
+static int pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
+    pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_read );
+
+static int pci_device_linux_sysfs_write( struct pci_device * dev,
+    const void * data, pciaddr_t offset, pciaddr_t size,
+    pciaddr_t * bytes_wrtten );
+
+static const struct pci_system_methods linux_sysfs_methods = {
+    .destroy = NULL,
+    .destroy_device = NULL,
+    .read_rom = pci_device_linux_sysfs_read_rom,
+    .probe = pci_device_linux_sysfs_probe,
+    .map = pci_device_linux_sysfs_map_region,
+    .unmap = pci_device_linux_sysfs_unmap_region,
+
+    .read = pci_device_linux_sysfs_read,
+    .write = pci_device_linux_sysfs_write,
+
+    .fill_capabilities = pci_fill_capabilities_generic
+};
+
+#define SYS_BUS_PCI "/sys/bus/pci/devices"
+
+
+static void populate_entries( struct pci_system * pci_sys );
+
+
+/**
+ * Attempt to access PCI subsystem using Linux's sysfs interface.
+ */
+int
+pci_system_linux_sysfs_create( void )
+{
+    int err = 0;
+    struct stat st;
+
+
+    /* If the directory "/sys/bus/pci/devices" exists, then the PCI subsystem
+     * can be accessed using this interface.
+     */
+    
+    if ( stat( SYS_BUS_PCI, & st ) == 0 ) {
+       pci_sys = calloc( 1, sizeof( struct pci_system ) );
+       if ( pci_sys != NULL ) {
+           pci_sys->methods = & linux_sysfs_methods;
+           populate_entries( pci_sys );
+       }
+       else {
+           err = ENOMEM;
+       }
+    }
+    else {
+       err = errno;
+    }
+
+    return err;
+}
+
+
+/**
+ * Filter out the names "." and ".." from the scanned sysfs entries.
+ *
+ * \param d  Directory entry being processed by \c scandir.
+ *
+ * \return
+ * Zero if the entry name matches either "." or "..", non-zero otherwise.
+ *
+ * \sa scandir, populate_entries
+ */
+static int
+scan_sys_pci_filter( const struct dirent * d )
+{
+    return !((strcmp( d->d_name, "." ) == 0) 
+            || (strcmp( d->d_name, ".." ) == 0));
+}
+
+
+void
+populate_entries( struct pci_system * p )
+{
+    struct dirent ** devices;
+    int n;
+    int i;
+
+
+    n = scandir( SYS_BUS_PCI, & devices, scan_sys_pci_filter, alphasort );
+    if ( n > 0 ) {
+       p->num_devices = n;
+       p->devices = calloc( n, sizeof( struct pci_device_private ) );
+
+
+       for ( i = 0 ; i < n ; i++ ) {
+           unsigned dom, bus, dev, func;
+
+
+           sscanf( devices[ i ]->d_name, "%04x:%02x:%02x.%1u",
+                   & dom, & bus, & dev, & func );
+
+           p->devices[ i ].base.domain = dom;
+           p->devices[ i ].base.bus = bus;
+           p->devices[ i ].base.dev = dev;
+           p->devices[ i ].base.func = func;
+       }
+    }
+}
+
+
+static int
+pci_device_linux_sysfs_probe( struct pci_device * dev )
+{
+    char     name[256];
+    uint8_t  config[256];
+    char     resource[512];
+    int fd;
+    pciaddr_t bytes;
+    unsigned i;
+    int err;
+
+
+    err = pci_device_linux_sysfs_read( dev, config, 0, 256, & bytes );
+    if ( bytes >= 64 ) {
+       dev->vendor_id = ((uint16_t *) config)[0];
+       dev->device_id = ((uint16_t *) config)[1];
+       dev->device_class = (((uint32_t *) config)[2]) >> 8;
+       dev->revision = config[8];
+       dev->subvendor_id = ((uint16_t *) config)[22];
+       dev->subdevice_id = ((uint16_t *) config)[23];
+       dev->irq = config[60];
+
+
+       /* The PCI config registers can be used to obtain information
+        * about the memory and I/O regions for the device.  However,
+        * doing so requires some tricky parsing (to correctly handle
+        * 64-bit memory regions) and requires writing to the config
+        * registers.  Since we'd like to avoid having to deal with the
+        * parsing issues and non-root users can write to PCI config
+        * registers, we use a different file in the device's sysfs
+        * directory called "resource".
+        * 
+        * The resource file contains all of the needed information in
+        * a format that is consistent across all platforms.  Each BAR
+        * and the expansion ROM have a single line of data containing
+        * 3, 64-bit hex values:  the first address in the region,
+        * the last address in the region, and the region's flags.
+        */
+       snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/resource",
+                 SYS_BUS_PCI,
+                 dev->domain,
+                 dev->bus,
+                 dev->dev,
+                 dev->func );
+       fd = open( name, O_RDONLY );
+       if ( fd != -1 ) {
+           char * next;
+           pciaddr_t  low_addr;
+           pciaddr_t  high_addr;
+           pciaddr_t  flags;
+
+
+           bytes = read( fd, resource, 512 );
+           resource[511] = '\0';
+
+           close( fd );
+
+           next = resource;
+           for ( i = 0 ; i < 6 ; i++ ) {
+
+               dev->regions[i].base_addr = strtoull( next, & next, 16 );
+               high_addr = strtoull( next, & next, 16 );
+               flags = strtoull( next, & next, 16 );
+                   
+               if ( dev->regions[i].base_addr != 0 ) {
+                   dev->regions[i].size = (high_addr 
+                                           - dev->regions[i].base_addr) + 1;
+
+                   dev->regions[i].is_IO = (flags & 0x01);
+                   dev->regions[i].is_64 = (flags & 0x04);
+                   dev->regions[i].is_prefetchable = (flags & 0x08);
+               }
+           }
+
+           low_addr = strtoull( next, & next, 16 );
+           high_addr = strtoull( next, & next, 16 );
+           flags = strtoull( next, & next, 16 );
+           if ( low_addr != 0 ) {
+               dev->rom_size = (high_addr - low_addr) + 1;
+           }
+       }
+    }
+
+    return err;
+}
+
+
+static int
+pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer )
+{
+    char name[256];
+    int fd;
+    struct stat  st;
+    int err = 0;
+
+
+    snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/rom",
+             SYS_BUS_PCI,
+             dev->domain,
+             dev->bus,
+             dev->dev,
+             dev->func );
+    
+    fd = open( name, O_RDWR );
+    if ( fd == -1 ) {
+       return errno;
+    }
+
+
+    if ( fstat( fd, & st ) == -1 ) {
+       close( fd );
+       return errno;
+    }
+
+
+    /* This is a quirky thing on Linux.  Even though the ROM and the file
+     * for the ROM in sysfs are read-only, the string "1" must be written to
+     * the file to enable the ROM.  After the data has been read, "0" must be
+     * written to the file to disable the ROM.
+     */
+    write( fd, "1", 1 );
+    lseek( fd, 0, SEEK_SET );
+
+    if ( read( fd, buffer, st.st_size ) == -1 ) {
+       err = errno;
+    }
+
+    lseek( fd, 0, SEEK_SET );
+    write( fd, "0", 1 );
+
+    close( fd );
+    return err;
+}
+
+
+static int
+pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
+                            pciaddr_t offset, pciaddr_t size,
+                            pciaddr_t * bytes_read )
+{
+    char name[256];
+    pciaddr_t temp_size = size;
+    int err = 0;
+    int fd;
+
+
+    if ( bytes_read != NULL ) {
+       *bytes_read = 0;
+    }
+
+    /* Each device has a directory under sysfs.  Within that directory there
+     * is a file named "config".  This file used to access the PCI config
+     * space.  It is used here to obtain most of the information about the
+     * device.
+     */
+    snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/config",
+             SYS_BUS_PCI,
+             dev->domain,
+             dev->bus,
+             dev->dev,
+             dev->func );
+
+    fd = open( name, O_RDONLY );
+    if ( fd == -1 ) {
+       return errno;
+    }
+
+
+    while ( temp_size > 0 ) {
+       const ssize_t bytes = pread64( fd, data, temp_size, offset );
+
+       /* If zero bytes were read, then we assume it's the end of the
+        * config file.
+        */
+       if ( bytes <= 0 ) {
+           err = errno;
+           break;
+       }
+
+       temp_size -= bytes;
+       offset += bytes;
+       data += bytes;
+    }
+    
+    if ( bytes_read != NULL ) {
+       *bytes_read = size - temp_size;
+    }
+
+    close( fd );
+    return err;
+}
+
+
+static int
+pci_device_linux_sysfs_write( struct pci_device * dev, const void * data,
+                            pciaddr_t offset, pciaddr_t size,
+                            pciaddr_t * bytes_written )
+{
+    char name[256];
+    pciaddr_t temp_size = size;
+    int err = 0;
+    int fd;
+
+
+    if ( bytes_written != NULL ) {
+       *bytes_written = 0;
+    }
+
+    /* Each device has a directory under sysfs.  Within that directory there
+     * is a file named "config".  This file used to access the PCI config
+     * space.  It is used here to obtain most of the information about the
+     * device.
+     */
+    snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/config",
+             SYS_BUS_PCI,
+             dev->domain,
+             dev->bus,
+             dev->dev,
+             dev->func );
+
+    fd = open( name, O_WRONLY );
+    if ( fd == -1 ) {
+       return errno;
+    }
+
+
+    while ( temp_size > 0 ) {
+       const ssize_t bytes = pwrite64( fd, data, temp_size, offset );
+
+       /* If zero bytes were written, then we assume it's the end of the
+        * config file.
+        */
+       if ( bytes <= 0 ) {
+           err = errno;
+           break;
+       }
+
+       temp_size -= bytes;
+       offset += bytes;
+       data += bytes;
+    }
+    
+    if ( bytes_written != NULL ) {
+       *bytes_written = size - temp_size;
+    }
+
+    close( fd );
+    return err;
+}
+
+
+/**
+ * Map a memory region for a device using the Linux sysfs interface.
+ * 
+ * \param dev          Device whose memory region is to be mapped.
+ * \param region       Region, on the range [0, 5], that is to be mapped.
+ * \param write_enable Map for writing (non-zero).
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_map_region, pci_device_linux_sysfs_unmap_region
+ *
+ * \todo
+ * Some older 2.6.x kernels don't implement the resourceN files.  On those
+ * systems /dev/mem must be used.  On these systems it is also possible that
+ * \c mmap64 may need to be used.
+ */
+static int
+pci_device_linux_sysfs_map_region( struct pci_device * dev, unsigned region,
+                                  int write_enable )
+{
+    char name[256];
+    int fd;
+    int err = 0;
+    int prot = (write_enable) ? (PROT_READ | PROT_WRITE) : PROT_READ;
+
+
+    snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/resource%u",
+             SYS_BUS_PCI,
+             dev->domain,
+             dev->bus,
+             dev->dev,
+             dev->func,
+             region );
+
+    fd = open( name, (write_enable) ? O_RDWR : O_RDONLY );
+    if ( fd == -1 ) {
+       return errno;
+    }
+
+
+    dev->regions[ region ].memory = mmap( NULL, dev->regions[ region ].size,
+                                         prot, MAP_SHARED, fd, 0 );
+    if ( dev->regions[ region ].memory == MAP_FAILED ) {
+       err = errno;
+       dev->regions[ region ].memory = NULL;
+    }
+
+    close( fd );
+    return err;
+}
+
+
+/**
+ * Unmap the specified region using the Linux sysfs interface.
+ *
+ * \param dev          Device whose memory region is to be mapped.
+ * \param region       Region, on the range [0, 5], that is to be mapped.
+ *
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_unmap_region, pci_device_linux_sysfs_map_region
+ *
+ * \todo
+ * Some older 2.6.x kernels don't implement the resourceN files.  On those
+ * systems /dev/mem must be used.  On these systems it is also possible that
+ * \c mmap64 may need to be used.
+ */
+static int
+pci_device_linux_sysfs_unmap_region( struct pci_device * dev, unsigned region )
+{
+    return munmap( dev->regions[ region ].memory,
+                  dev->regions[ region ].size );
+}
diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h
new file mode 100644 (file)
index 0000000..bc35f7f
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file pciaccess_private.h
+ * Functions and datastructures that are private to the pciaccess library.
+ * 
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+
+int pci_fill_capabilities_generic( struct pci_device * dev );
+
+struct pci_system_methods {
+    void (*destroy)( void );
+    void (*destroy_device)( struct pci_device * dev );
+    int (*read_rom)( struct pci_device * dev, void * buffer );    
+    int (*probe)( struct pci_device * dev );
+    int (*map)( struct pci_device * dev, unsigned region, int write_enable );
+    int (*unmap)( struct pci_device * dev, unsigned region );
+    
+    int (*read)(struct pci_device * dev, void * data, pciaddr_t offset,
+               pciaddr_t size, pciaddr_t * bytes_read );
+
+    int (*write)(struct pci_device * dev, const void * data, pciaddr_t offset,
+               pciaddr_t size, pciaddr_t * bytes_written );
+
+    int (*fill_capabilities)( struct pci_device * dev );
+};
+
+struct pci_device_private {
+    struct pci_device  base;
+    const char * device_string;
+    
+    /**
+     * \name PCI Capabilities
+     */
+    /*@{*/
+    const struct pci_agp_info * agp;   /**< AGP capability information. */
+    /*@}*/
+};
+
+
+/**
+ * Base type for tracking PCI subsystem information.
+ */
+struct pci_system {
+    /**
+     * Platform dependent implementations of specific API routines.
+     */
+    const struct pci_system_methods * methods;
+
+    /**
+     * Number of known devices in the system.
+     */
+    size_t num_devices;
+
+    /**
+     * Array of known devices.
+     */
+    struct pci_device_private * devices;
+};
+
+extern struct pci_system * pci_sys;
diff --git a/src/scanpci.c b/src/scanpci.c
new file mode 100644 (file)
index 0000000..1c4622f
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "pciaccess.h"
+
+
+void
+print_pci_device( struct pci_device * dev, int verbose )
+{
+    const char * dev_name;
+    const char * vend_name;
+
+    vend_name = pci_device_get_vendor_name( dev );
+    dev_name = pci_device_get_device_name( dev );
+    if ( dev_name == NULL ) {
+       dev_name = "Device unknown";
+    }
+
+    printf("\npci bus 0x%04x cardnum 0x%02x function 0x%02x:"
+          " vendor 0x%04x device 0x%04x\n",
+          dev->bus, 
+          dev->dev,
+          dev->func,
+          dev->vendor_id,
+          dev->device_id );
+    if ( vend_name != NULL ) {
+       printf( " %s %s\n", vend_name, dev_name );
+    }
+    else {
+       printf( " %s\n", dev_name );
+    }
+    
+    if ( verbose ) {
+       unsigned   i;
+       uint16_t  command, status;
+       uint8_t   bist;
+       uint8_t   header_type;
+       uint8_t   latency_timer;
+       uint8_t   cache_line_size;
+       uint8_t   max_latency;
+       uint8_t   min_grant;
+       uint8_t   int_pin;
+
+
+       vend_name = pci_device_get_subvendor_name( dev );
+       dev_name = pci_device_get_subdevice_name( dev );
+       if ( dev_name == NULL ) {
+           dev_name = "Card unknown";
+       }
+
+       printf( " CardVendor 0x%04x card 0x%04x (",
+               dev->subvendor_id,
+               dev->subdevice_id );
+       if ( vend_name != NULL ) {
+           printf( "%s, %s)\n", vend_name, dev_name );
+       }
+       else {
+           printf( "%s)\n", dev_name );
+       }
+
+       pci_device_cfg_read_u16( dev, & command, 4 );
+       pci_device_cfg_read_u16( dev, & status,  6 );
+       printf( "  STATUS    0x%04x  COMMAND 0x%04x\n", 
+               status,
+               command );
+       printf( "  CLASS     0x%02x 0x%02x 0x%02x  REVISION 0x%02x\n",
+               (dev->device_class >> 16) & 0x0ff,
+               (dev->device_class >>  8) & 0x0ff,
+               (dev->device_class >>  0) & 0x0ff,
+               dev->revision );
+
+       pci_device_cfg_read_u8( dev, & cache_line_size, 8 );
+       pci_device_cfg_read_u8( dev, & latency_timer, 9 );
+       pci_device_cfg_read_u8( dev, & header_type, 10 );
+       pci_device_cfg_read_u8( dev, & bist, 11 );
+
+       printf( "  BIST      0x%02x  HEADER 0x%02x  LATENCY 0x%02x  CACHE 0x%02x\n",
+               bist,
+               header_type,
+               latency_timer,
+               cache_line_size );
+       
+       for ( i = 0 ; i < 6 ; i++ ) {
+           if ( dev->regions[i].base_addr != 0 ) {
+               printf( "  BASE%u     0x%08x  addr 0x%08x  %s",
+                       i,
+                       0,
+                       (intptr_t) dev->regions[i].base_addr,
+                       (dev->regions[i].is_IO) ? "I/O" : "MEM" );
+
+               if ( ! dev->regions[i].is_IO ) {
+                   if ( dev->regions[i].is_prefetchable ) {
+                       printf( " PREFETCHABLE" );
+                   }
+               }
+               
+               printf( "\n" );
+           }
+       }
+
+       if ( dev->rom_size ) {
+           printf( "  BASEROM   0x%08x  addr 0x%08x\n",
+                   0, 0 );
+       }
+
+       pci_device_cfg_read_u8( dev, & int_pin, 61 );
+       pci_device_cfg_read_u8( dev, & min_grant, 62 );
+       pci_device_cfg_read_u8( dev, & max_latency, 63 );
+
+       printf( "  MAX_LAT   0x%02x  MIN_GNT 0x%02x  INT_PIN 0x%02x  INT_LINE 0x%02x\n",
+               max_latency,
+               min_grant,
+               int_pin,
+               dev->irq );
+    }
+}
+
+
+int main( int argc, char ** argv )
+{
+    struct pci_device_iterator * iter;
+    struct pci_device * dev;
+
+    pci_system_init();
+
+    iter = pci_iterator_create( (argc > 1) ? argv[1] : NULL );
+
+    while ( (dev = pci_device_next( iter )) != NULL ) {
+       pci_device_probe( dev );
+       print_pci_device( dev, 1 );
+    }
+
+    pci_system_cleanup();
+    return 0;
+}