Git init
authorKibum Kim <kb0929.kim@samsung.com>
Fri, 6 Jan 2012 15:48:30 +0000 (00:48 +0900)
committerKibum Kim <kb0929.kim@samsung.com>
Fri, 6 Jan 2012 15:48:30 +0000 (00:48 +0900)
46 files changed:
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0644]
configure.ac [new file with mode: 0644]
debian/README.source [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0755]
debian/copyright [new file with mode: 0644]
debian/libpciaccess-dev.install [new file with mode: 0644]
debian/libpciaccess0-udeb.install [new file with mode: 0644]
debian/libpciaccess0.install [new file with mode: 0644]
debian/libpciaccess0.symbols [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/watch [new file with mode: 0644]
include/pciaccess.h [new file with mode: 0644]
m4/ac_define_dir.m4 [new file with mode: 0644]
packaging/libpciaccess.spec [new file with mode: 0644]
pciaccess.pc.in [new file with mode: 0644]
src/Doxyfile [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/common_bridge.c [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_io.c [new file with mode: 0644]
src/common_iterator.c [new file with mode: 0644]
src/common_map.c [new file with mode: 0644]
src/common_vgaarb.c [new file with mode: 0644]
src/common_vgaarb_stub.c [new file with mode: 0644]
src/freebsd_pci.c [new file with mode: 0644]
src/linux_devmem.c [new file with mode: 0644]
src/linux_devmem.h [new file with mode: 0644]
src/linux_sysfs.c [new file with mode: 0644]
src/netbsd_pci.c [new file with mode: 0644]
src/openbsd_pci.c [new file with mode: 0644]
src/pci_tools.h [new file with mode: 0644]
src/pciaccess_private.h [new file with mode: 0644]
src/scanpci.c [new file with mode: 0644]
src/scanpci.man [new file with mode: 0644]
src/solx_devfs.c [new file with mode: 0644]
src/x86_pci.c [new file with mode: 0644]

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..05c5941
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,67 @@
+(C) Copyright IBM Corporation 2006, 2007
+(C) Copyright Eric Anholt 2006
+Copyright 2007, 2008, 2009 Sun Microsystems, Inc.
+Copyright 2009 Red Hat, Inc.
+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.
+
+------------------------------------------------------------------------------
+
+Copyright (c) 2008 Juan Romero Pardines
+Copyright (c) 2008 Mark Kettenis
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+------------------------------------------------------------------------------
+
+Copyright (C) 2000 The XFree86 Project, Inc.  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 the
+rights to use, copy, modify, merge, publish, distribute, sublicense, 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL THE
+XFREE86 PROJECT 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.
+
+Except as contained in this notice, the name of the XFree86 Project shall
+not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from the
+XFree86 Project.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..f263fae
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,1556 @@
+commit fa3f1c1ea8ce4b45976e11520856cfa164f8b92d
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Wed Jul 21 09:39:26 2010 +1000
+
+    libpciaccess 0.12.0 - bump version for release
+
+commit 2f98724d1e603268360d704b3c8823b93d5fecb4
+Author: Thomas Hellstrom <thellstrom@vmware.com>
+Date:   Tue Jul 20 22:14:22 2010 +0200
+
+    Fix long standing MTRR bug.
+    
+    Add an include that makes the file common_vgaarb.c see the same
+    struct pci_system as the file linux_sysfs.c.
+    
+    Without this fix, on a MTRR system, the vgaarb_fd member
+    would overwrite the mtrr_fd member and cause the MTRR_IOC_ADD_ENTRY call
+    to be issued to the incorrect device causing the infamous
+    "Inappropriate ioctl for device (25)" error.
+    
+    This error would cause MTRR setup to fail on all systems relying on it
+    and is severe enough to warrant a new release.
+    
+    Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
+    Signed-off-by: Dave Airlie <airlied@redhat.com>
+
+commit e5159771bd0a013201dcef760e9320071c6df59e
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Mon Jul 12 13:09:33 2010 +1000
+
+    pciaccess: fix use after free.
+    
+    Using the pointer passed to realloc earlier isn't a recipe for success.
+    
+    Signed-off-by: Dave Airlie <airlied@redhat.com>
+
+commit 3f59728ddc6f7d2cb17d434e81ac76c9288d0aef
+Author: Alan Coopersmith <alan.coopersmith@oracle.com>
+Date:   Sat Jun 19 10:36:24 2010 -0700
+
+    Let libtool handle library flags for scanpci on Solaris
+    
+    Stop hardcoding -ldevinfo since configure/libtool already know to add it
+    for static linking, and ELF dependencies handle it for dynamic linking
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
+
+commit e0ae5251cd030b201c14f5888a539aa40f17abfb
+Author: Tiago Vignatti <tiago.vignatti@nokia.com>
+Date:   Sat May 22 18:23:33 2010 +0300
+
+    vgaarb: read back vga count when setting new decoding
+    
+    Decode kernel operation can also change vga refcount, so we need to read back
+    the information when calling it.
+    
+    Signed-off-by: Tiago Vignatti <tiago.vignatti@nokia.com>
+
+commit 0f153de858032c95ea5844aa6e0f1c8dad7531da
+Author: Tiago Vignatti <tiago.vignatti@nokia.com>
+Date:   Wed May 12 13:12:47 2010 +0300
+
+    vgaarb: decode should send new information to the kernel
+    
+    This was introduced in e360c11c.
+    
+    Signed-off-by: Tiago Vignatti <tiago.vignatti@nokia.com>
+
+commit fa7cca617583eb93a862c5ebbb5a56843210e5a8
+Author: Alan Coopersmith <alan.coopersmith@oracle.com>
+Date:   Fri Jun 4 16:58:56 2010 -0700
+
+    Delay allocation of agp_info so we don't leak it on prior errors
+    
+       Memory leak of pointer 'agp_info'
+            at line 119 of src/common_capability.c in function 'pci_fill_capabilities_generic'.
+              'agp_info' allocated at line 107 with calloc(1, 12).
+              'agp_info' leaks when err != 0 at line 118.
+            at line 124 of src/common_capability.c in function 'pci_fill_capabilities_generic'.
+              'agp_info' allocated at line 107 with calloc(1, 12).
+              'agp_info' leaks when err != 0 at line 123.
+    
+    [ This bug was found by the Parfait bug checking tool.
+      For more information see http://research.sun.com/projects/parfait ]
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
+
+commit b8295f4776912d4c3cef836eb0f158e07b432a25
+Author: Gaetan Nadon <memsize@videotron.ca>
+Date:   Mon Mar 29 16:50:34 2010 -0400
+
+    config: update AC_PREREQ statement to 2.60
+    
+    Unrelated to the previous patches, the new value simply reflects
+    the reality that the minimum level for autoconf to configure
+    all x.org modules is 2.60 dated June 2006.
+    
+    ftp://ftp.gnu.org/gnu/autoconf/autoconf-2.60.tar.gz
+    
+    Signed-off-by: Gaetan Nadon <memsize@videotron.ca>
+
+commit a624de7af1d4c0956ecd485e3ae193f93bd78c57
+Author: Gaetan Nadon <memsize@videotron.ca>
+Date:   Mon Mar 29 14:53:49 2010 -0400
+
+    config: remove the pkgconfig pc.in file from EXTRA_DIST
+    
+    Automake always includes it in the tarball.
+    
+    Signed-off-by: Gaetan Nadon <memsize@videotron.ca>
+
+commit af2be74979aeab9a2fc4c933462e97ce70f816b6
+Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
+Date:   Tue Jan 19 18:37:43 2010 +0100
+
+    libpciaccess x86 backend
+    
+    This adds support on x86 for OSes that do not have a PCI interface,
+    tinkering with I/O ports, and makes use of it on GNU/Hurd.
+    
+    Signed-off-by: Julien Cristau <jcristau@debian.org>
+
+commit ebb3c6b69f4e8a844ff95d4e880dde9ede3de347
+Author: Julien Cristau <jcristau@debian.org>
+Date:   Sun Jan 17 14:33:13 2010 +0000
+
+    COPYING: add Red Hat's copyright notice
+
+commit b775e6fa006d78cac21bbfe52f1f721947ddc6ca
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Thu Jan 14 20:48:20 2010 -0800
+
+    Update Sun license notices to current X.Org standard form
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
+
+commit fac83b8116e19d4efbf8438d1cc485656cca5c60
+Author: Adam Jackson <ajax@redhat.com>
+Date:   Mon Dec 14 17:27:12 2009 -0500
+
+    libpciaccess 0.11.0
+    
+    Signed-off-by: Adam Jackson <ajax@redhat.com>
+
+commit 947ab16f2938e8883503ef679a40684dfe2a90e5
+Author: Adam Jackson <ajax@redhat.com>
+Date:   Mon Dec 14 16:26:31 2009 -0500
+
+    Fix I/O handle array allocator to work for devices past the first
+    
+    Signed-off-by: Adam Jackson <ajax@redhat.com>
+
+commit d4e008eeb9af7773edadd259cf55da43411f1a7f
+Author: Adam Jackson <ajax@redhat.com>
+Date:   Mon Dec 14 16:19:35 2009 -0500
+
+    Fix pci_device_open_io() to actually return something useful
+    
+    Remember, code review just means we're all inept.
+    
+    Signed-off-by: Adam Jackson <ajax@redhat.com>
+
+commit 5e8d4c19b4f618e22b6e8e1ad3294d8708067474
+Author: Adam Jackson <ajax@redhat.com>
+Date:   Wed Nov 18 13:53:49 2009 -0500
+
+    I/O port access routines
+    
+    Acked-by: Tiago Vignatti <tiago.vignatti@nokia.com>
+    Acked-by: Matt Turner <mattst88@gmail.com>
+    Signed-off-by: Adam Jackson <ajax@redhat.com>
+
+commit b2fbe63bdf3522c5d3df5eda2ca3c3b8770c02c9
+Author: Adam Jackson <ajax@redhat.com>
+Date:   Wed Nov 18 14:12:57 2009 -0500
+
+    Add pci_device_get_parent_bridge()
+    
+    Copied from linuxPci.c in the X server.
+    
+    Acked-by: Tiago Vignatti <tiago.vignatti@nokia.com>
+    Signed-off-by: Adam Jackson <ajax@redhat.com>
+
+commit b2b3c3bfdac23c1c8e33f47b28f22c1d4a78cc71
+Author: Gaetan Nadon <memsize@videotron.ca>
+Date:   Fri Nov 27 20:56:05 2009 -0500
+
+    Makefile.am: add ChangeLog and INSTALL on MAINTAINERCLEANFILES
+    
+    Now that the INSTALL file is generated.
+    Allows running make maintainer-clean.
+
+commit 57f4d11fef7021e77549a70cbf40ca43e60ea55f
+Author: Gaetan Nadon <memsize@videotron.ca>
+Date:   Wed Oct 28 14:09:10 2009 -0400
+
+    INSTALL, NEWS, README or AUTHORS files are missing/incorrect #24206
+    
+    Add missing INSTALL file. Use standard GNU file on building tarball
+    README may have been updated
+    Remove AUTHORS file as it is empty and no content available yet.
+    Remove NEWS file as it is empty and no content available yet.
+
+commit caa398b5305cb4c5299e283b9833ed2251698893
+Author: Gaetan Nadon <memsize@videotron.ca>
+Date:   Tue Oct 27 15:07:25 2009 -0400
+
+    Deploy the new XORG_DEFAULT_OPTIONS #24242
+    
+    This macro aggregate a number of existing macros that sets commmon
+    X.Org components configuration options. It shields the configuration file from
+    future changes.
+
+commit b8284cb2097601d5934773ab75db388b9fa5a9db
+Author: Gaetan Nadon <memsize@videotron.ca>
+Date:   Mon Oct 26 22:08:43 2009 -0400
+
+    Makefile.am: ChangeLog not required: EXTRA_DIST or *CLEANFILES #24432
+    
+    ChangeLog filename is known to Automake and requires no further
+    coding in the makefile.
+
+commit 28830993636cc5820842345b511d301af33d9c49
+Author: Gaetan Nadon <memsize@videotron.ca>
+Date:   Thu Oct 22 12:34:20 2009 -0400
+
+    .gitignore: use common defaults with custom section # 24239
+    
+    Using common defaults will reduce errors and maintenance.
+    Only the very small or inexistent custom section need periodic maintenance
+    when the structure of the component changes. Do not edit defaults.
+
+commit 97d677746cd70ec9eb1f33483cc829a0063953bc
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Sep 25 10:25:56 2009 +1000
+
+    shutup stupid gcc warning, strtok_r ignores the first parameter
+
+commit 2a10d510d24c7c0aebb03914dd887f9e92cfa754
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Sep 25 10:19:07 2009 +1000
+
+    libpciaccess 0.10.9
+
+commit 1714046ef08ef685bcf1d6c154e64809b12e8d7f
+Author: Tiago Vignatti <tiago.vignatti@nokia.com>
+Date:   Fri Sep 18 15:21:19 2009 +0300
+
+    vgaarb: fix newbie typo
+    
+    Eh, we don't need to check for the fd anyway. Kudos jcristau for reporting.
+    
+    Signed-off-by: Tiago Vignatti <tiago.vignatti@nokia.com>
+
+commit 13c7e6c8f100882718f995f5bf1d478a012cdbdd
+Author: Tiago Vignatti <tiago.vignatti@nokia.com>
+Date:   Wed Sep 16 12:56:53 2009 +0300
+
+    vgaarb: check for fd before close it
+    
+    Signed-off-by: Tiago Vignatti <tiago.vignatti@nokia.com>
+
+commit cdbdfaf61c05d0d18eae6815b10666f93162148f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 17 17:38:56 2009 -0700
+
+    Free return value from scandir instead of leaking it.
+    
+    Scandir is defined to return pointers to malloc'd storage, so make
+    sure that memory is nicely freed.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 42b879a203c1c16daa9d0c610c6a217ead7a5829
+Author: Dave Airlie <airlied@linux.ie>
+Date:   Wed Sep 2 19:03:11 2009 +1000
+
+    vgaarb: check pci_sys exists before initing vga arb
+
+commit 312cde3c2f3530b031134cfb53a8a54731f02b1b
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Mon Aug 31 09:14:16 2009 +1000
+
+    pciaccess: bump to 0.10.8
+
+commit 566a67767e9fea463c24421d99dc12db590a7b5f
+Author: Thomas Klausner <wiz@netbsd.org>
+Date:   Mon Aug 31 09:13:27 2009 +1000
+
+    pciaccess: fix vga arb stubs
+
+commit d062dd78baeb28ef2cc59f4fb4a7d82ecd5adf60
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Aug 28 11:29:00 2009 +1000
+
+    libpciaccess: bump to 0.10.7 for vga arb interface addition
+
+commit 81b4705525bdf82d75f5b3c740c53fa4a866d9c3
+Merge: f514852 2f997f9
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Aug 28 11:25:15 2009 +1000
+
+    Merge branch 'vga'
+
+commit 2f997f90c8d0b54baab85285703550e8df28325e
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Aug 28 11:24:53 2009 +1000
+
+    vgaarb: update stub interface
+
+commit b229acdfd10fd61f46d8e711910b5c1bdb727857
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Aug 28 11:21:11 2009 +1000
+
+    Revert "vgaarb: delete stub functions"
+    
+    This reverts commit b7fd4d06890d801aae93fe1a1af7ab110fd388fd.
+
+commit e70767cb2e574f8544a04903eea3afee33345eea
+Author: Tiago Vignatti <tiago.vignatti@nokia.com>
+Date:   Wed Aug 26 11:14:03 2009 +0300
+
+    Revert "vgaarb: fix pci_device_vgaarb_get_info() return value."
+    
+    This reverts commit ef8aca5da46155e9ea0d1227215921ad9ce59150.
+
+commit f5148525d546015c12b703a768b5e6c3726446a3
+Merge: 7636348 ef8aca5
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Aug 21 13:27:11 2009 +1000
+
+    Merge remote branch 'origin/vga-arbiter'
+
+commit ef8aca5da46155e9ea0d1227215921ad9ce59150
+Author: Tiago Vignatti <tiago.vignatti@nokia.com>
+Date:   Sun Aug 16 19:11:15 2009 +0300
+
+    vgaarb: fix pci_device_vgaarb_get_info() return value.
+    
+    Signed-off-by: Tiago Vignatti <tiago.vignatti@nokia.com>
+
+commit 25be96885671d22ee3f932769d72cf3a31f355ee
+Author: Tiago Vignatti <tiago.vignatti@nokia.com>
+Date:   Sun Aug 16 19:09:35 2009 +0300
+
+    vgaarb: fix indentation and remove trailing white spaces
+    
+    Signed-off-by: Tiago Vignatti <tiago.vignatti@nokia.com>
+
+commit b7fd4d06890d801aae93fe1a1af7ab110fd388fd
+Author: Tiago Vignatti <tiago.vignatti@nokia.com>
+Date:   Sun Aug 16 18:59:21 2009 +0300
+
+    vgaarb: delete stub functions
+    
+    Such stub functions is already with API outdated. Moreover, if some operating
+    system doesn't have arbiter's implementation then the app can set some
+    autoconf tricks like "ifdef HAVE_PCI_DEVICE_VGAARB_INIT".
+    
+    Signed-off-by: Tiago Vignatti <tiago.vignatti@nokia.com>
+
+commit 76363486864b325b8f156ece35736ddb64c4e697
+Author: Julien Cristau <jcristau@debian.org>
+Date:   Sun Aug 9 11:28:38 2009 +0200
+
+    Silence compiler warning about pci_id_file_open definition
+    
+    src/common_device_name.c:59: warning: function declaration isn't a prototype
+    src/common_device_name.c: In function 'pci_id_file_open':
+    src/common_device_name.c:59: warning: old-style function definition
+
+commit 4eac0173588ab9ef67fcadb47b531abb114aa0a7
+Author: Julien Cristau <jcristau@debian.org>
+Date:   Sat Aug 8 18:12:08 2009 +0200
+
+    configure.ac: fix help text for the linux-rom-fallback option
+    
+    LINUX_ROM defaults to no, fix the help text to reflect that
+    
+    Signed-off-by: Julien Cristau <jcristau@debian.org>
+
+commit e9f2db8b867cba8d91a040a0db9be56099fba680
+Merge: 706201e dedd31b
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Thu Aug 6 09:43:08 2009 +1000
+
+    Merge branch 'master' into vga-arbiter
+
+commit dedd31b3bcdeea12955bf565b8e3f2a9d3c66057
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Thu Aug 6 09:39:01 2009 +1000
+
+    pciaccess: make linux rom reading fallback optional
+    
+    On kernels which have ROM files, the boot VGA rom file
+    will contain the 0xc0000 file anyways. If another card
+    is missing a rom file there is no need for this.
+    
+    This is fallback is disabled by default, on the premise
+    that distro shipping this new a pciaccess will be running
+    on kernels with working rom support which is been upstream
+    for a long time
+
+commit 706201e900b5664ea35ec498784590275b98c23a
+Merge: 57cf6f1 8aa06cf
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Thu Aug 6 09:42:06 2009 +1000
+
+    Merge branch 'master' into vga-arbiter
+
+commit 8aa06cf7ef5e88c53bf6778336ba1a6036b16cc0
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Thu Aug 6 09:39:01 2009 +1000
+
+    pciaccess: make linux rom reading fallback optional
+    
+    On kernels which have ROM files, the boot VGA rom file
+    will contain the 0xc0000 file anyways. If another card
+    is missing a rom file there is no need for this.
+    
+    This is fallback is disabled by default, on the premise
+    that distro shipping this new a pciaccess will be running
+    on kernels with working rom support which is been upstream
+    for a long time
+
+commit 57cf6f1f428ab73fb2a88c39c694e7d14c2c96c6
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Thu Aug 6 09:39:01 2009 +1000
+
+    pciaccess: make linux rom reading fallback optional
+    
+    On kernels which have ROM files, the boot VGA rom file
+    will contain the 0xc0000 file anyways. If another card
+    is missing a rom file there is no need for this.
+    
+    This is fallback is disabled by default, on the premise
+    that distro shipping this new a pciaccess will be running
+    on kernels with working rom support which is been upstream
+    for a long time
+
+commit 7b7999a302c70f1ad9a5c8fc7517e24ab95c3a95
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Mon Aug 3 12:43:26 2009 +1000
+
+    vgaarb: add vga count + resource accessor
+
+commit 3a6c1be79c05517cfddbce88157bb352237058ab
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Mon Aug 3 09:39:22 2009 +1000
+
+    vgaarb: more api changes + cleanup
+    
+    add a comma for ease of parsing,
+    use hex on the interface in both directions instead of hex on one
+    and decimal on the other
+
+commit e5127339c6c48ae6f63f9dc841a94fe960d11496
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Jul 31 16:15:55 2009 +1000
+
+    vgaarb: change API to target taking a device + lock/unlock not taking one
+    
+    working on the target device - a target device of NULL
+    reselects the target that existed when we started.
+    
+    this is mainly to allow a udev posting tool to return to the
+    state of what happened before it ran.
+
+commit 0596c559af5ca277a069b04a6402d21724464cda
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Jul 31 15:34:32 2009 +1000
+
+    vgaarb: add support for targetting default device
+
+commit 453928b8485bc7beff69996abe12628efc09405f
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Jul 31 11:17:21 2009 +1000
+
+    vgaarb: clean up debug output
+
+commit d22d7c0d5e48d130c89282514e378819e0b98636
+Merge: e360c11 2bda5b7
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Jul 31 11:16:16 2009 +1000
+
+    Merge remote branch 'main/master' into vga-arbiter
+
+commit e360c11c37a219534bfd7266caf163870dddced0
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Mon Jul 20 13:26:41 2009 +1000
+
+    vgaarb: fixup api for new count reporting + decodes interface was wrong.
+    
+    decodes is a information setting interface so it takes new decodes
+    and sends them to the kernel
+
+commit 5d1bdf0cb51c19efd6e2b2c0a463ace9443c48d9
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Thu Jul 16 15:36:30 2009 +1000
+
+    add support for finding if something has a kernel driver
+
+commit 2bda5b733bb12854760750c08138db95e77aea0c
+Author: Jesse Barnes <jbarnes@virtuousgeek.org>
+Date:   Tue Jun 30 15:24:45 2009 -0700
+
+    Don't try to use bogus bridge data
+    
+    If, for whatever reason, we weren't able to read bridge data (therefore
+    leaving bridge.pci or bridge.pcmcia empty), we shouldn't try to look at
+    the bus data inside the pci/pcmcia struct.
+
+commit 9ae22c87743c624bda593a1ef4bd4eca01c65655
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Fri Jun 5 09:32:10 2009 +1000
+
+    vgaarb: fixup api and decode rsrc.
+    
+    This fixes up the API and stores the vga arb fd in the sys_pci structure,
+    instead of hiding it in a random dev struct.
+    
+    It also reads back after setting the target and works out the decodes.
+    
+    Signed-off-by: Dave Airlie <airlied@redhat.com>
+
+commit 9ae66143550a6aee25d9a9620c5bebf93fa196e5
+Author: Tiago Vignatti <vignatti@freedesktop.org>
+Date:   Thu May 14 17:30:17 2009 -0300
+
+    Comment typo.
+
+commit 6ae00a992714639fd725efd8817dca69b28276c8
+Author: Tiago Vignatti <vignatti@freedesktop.org>
+Date:   Thu May 14 17:28:05 2009 -0300
+
+    Reorganize the code.
+
+commit 6ef4e7aebfd2b83e2346e9f8f4ef3c890a6ea73d
+Author: Tiago Vignatti <vignatti@freedesktop.org>
+Date:   Thu May 14 03:42:56 2009 -0300
+
+    Fix typo in vgaarb stubs.
+
+commit 18a186804bc4e496a392cb31003cef25798f6c7b
+Author: Tiago Vignatti <vignatti@freedesktop.org>
+Date:   Thu May 14 03:40:25 2009 -0300
+
+    Delete vga_arb_rec.
+
+commit 812ad80018d49f6e4f1be8256d86488690c3ba52
+Author: Tiago Vignatti <vignatti@freedesktop.org>
+Date:   Wed May 13 18:31:09 2009 -0300
+
+    vgaarb: a bunch of clean ups to fit in libpciaccess style.
+
+commit b77b0fc3fbacc46d55998889f09326d1233339fc
+Author: Tiago Vignatti <vignatti@freedesktop.org>
+Date:   Wed May 13 17:55:31 2009 -0300
+
+    vgaarb: make it compile.
+
+commit 67af888bcc5667eadf1e9e9bf15305f742416daf
+Author: Tiago Vignatti <vignatti@freedesktop.org>
+Date:   Wed May 13 17:44:46 2009 -0300
+
+    Import libvgaaccess (VGA Arbiter) implementation from C3SL repository:
+        http://git.c3sl.ufpr.br/
+
+commit 8ba6b02ecfa5b03bbf2807e8262bb1253a026493
+Author: Aaron Plattner <aplattner@nvidia.com>
+Date:   Fri May 1 15:04:19 2009 -0700
+
+    Don't try to write boot_vga since that fails with EACCES
+
+commit b2838fb61c3542f107014b285cbda097acae1e12
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Wed Mar 4 15:55:11 2009 +1000
+
+    pciaccess: provide a method to detect if a device is boot VGA
+    
+    When the linux kernel exposes this information, we can use this interface
+    in the X server to detect whether the kernel believes the device we
+    are looking at is the boot VGA device.
+    
+    Signed-off-by: Dave Airlie <airlied@redhat.com>
+
+commit f14c6cd626273bd2f8b102ff661d11926619a99b
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri Apr 24 16:32:12 2009 -0700
+
+    Version bump: 0.10.6
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
+
+commit 6df3387173c3ab25e8a618d9ccf628682d8336d5
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri Apr 24 16:19:34 2009 -0700
+
+    Resync COPYING file with code copyright notices
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
+
+commit 7f08a1e19b49c9ffdc62e1dff340b392ac7c42d1
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri Apr 17 22:05:03 2009 -0700
+
+    Fix unused variable warnings in Solaris code
+    
+    solx_devfs.c: In function `find_target_node':
+    solx_devfs.c:672: warning: unused variable `prop'
+    solx_devfs.c:673: warning: unused variable `i'
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
+
+commit 0edb2392ede59cadd75915873b52baa188bfa273
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri Apr 17 21:59:25 2009 -0700
+
+    Fix $CWARNFLAGS addition
+    
+    Original addition to configure.ac had typo (missing N) - moving to
+    Makefile.am allows easier override at build time
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
+
+commit 146dc2f4ac232bb9d63225c8e72b214dc3120ea6
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri Apr 17 21:56:31 2009 -0700
+
+    Move included m4 to a subdir so we can more easily update from upstream
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
+
+commit a7f8e58d44716a01f4a8dc9826996a0fa78e4196
+Author: Owain Ainsworth <zerooa@googlemail.com>
+Date:   Sat Apr 18 06:38:46 2009 +0200
+
+    openbsd_pci.c: use the correct size when mapping the legacy vga rom.
+    
+    fixes errors (and probably bugs) on intel hardware (at the least).
+    
+    Signed-off-by: Matthieu Herrb <matthieu.herrb@laas.fr>
+
+commit be748a7b512bf5597e162694a3b1769132938fe1
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Wed Apr 15 10:06:49 2009 -0700
+
+    Sun bug 6811468: pci_device_solx_devfs_probe accesses freed memory
+    
+    di_fini() is being called in pci_device_solx_devfs_probe()
+    The di_fini (3DEVINFO) man page says "All  handles associated with this
+    snapshot become invalid after the  call to di_fini()".  But after that,
+    eight lines down, the subroutine was calling di_prop_lookup_ints with
+    a handle args.node which was stored from walking the device tree, and
+    then using the pointers that returned even further down.
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
+
+commit c56da48ee806f73c8ed81afb4a251b24de304620
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Tue Apr 14 17:29:10 2009 -0700
+
+    Fix const mismatch compiler warnings in Solaris backend
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
+
+commit f6084593c275c5dc1d6154f292991b20bffd68c2
+Author: edward shu <edward.shu@sun.com>
+Date:   Tue Apr 14 17:19:09 2009 -0700
+
+    Sun bug 6785726: libpciaccess needs to use the correct BAR index on solaris
+    
+    <http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6785726>
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
+
+commit 2355e720ef3c285a44c88f914ebdc163a1c591a7
+Author: Mark Kettenis <mark.kettenis@xs4all.nl>
+Date:   Tue Apr 14 21:53:26 2009 +0200
+
+    Make libpciaccess on OpenBSD domain-aware.
+    
+    Makes X capable of discovering PCI devices
+    in other domains (on macppc or sparc64 for example).
+
+commit 9ba94caf57e3a8c3e9c6f3f5f068f4a7a7b3ff9d
+Author: Darren Smith <darren.smith@juno.com>
+Date:   Tue Apr 14 10:46:26 2009 -0400
+
+    Be more paranoid about reading bridge info (#20786)
+
+commit 72e75b00e4f3f7df3badb10c916126253204ae45
+Author: Robert Noland <rnoland@2hip.net>
+Date:   Fri Feb 27 00:34:28 2009 -0600
+
+    FreeBSD: Incorporate several fixes that have accumulated.
+    
+       -Don't frob the BARs while they are enabled
+       -Find proper pci bios address / length
+       -Use the new PCIOCGETBAR ioctl if it exists
+         rather than frob the BARs ourself
+       -Write must also be a power of two
+
+commit 5855cf5a2cc7ee920b42052372ab734003799d00
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Mon Feb 2 20:34:38 2009 -0800
+
+    Add README with pointers to mailing list, bugzilla & git repos
+    
+    Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
+
+commit 42b493490e90e1c5461d36beb3f2dc2580c7d25e
+Author: Paulo Cesar Pereira de Andrade <pcpa@mandriva.com.br>
+Date:   Wed Jan 28 18:03:21 2009 -0200
+
+    Janitor: Correct make distcheck and compiler warnings.
+
+commit 5bf4b32c2b3844c50e720be5820f2ce657ddea12
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Thu Jan 22 16:14:22 2009 -0800
+
+    Solaris: Use bus-range properties to limit busses scanned on each node
+    
+    Based on code provided by Dan.Mick@sun.com
+
+commit 0488a2830a6a0d27d9be032607eda954a8c99801
+Author: Matthieu Herrb <matthieu.herrb@laas.fr>
+Date:   Sun Dec 7 19:18:29 2008 +0100
+
+    Fix a logic error in pci_device_netbsd_write()
+    
+    This is the same error as in pci_device_openbsd_write() that actually
+    prevented it to write anything.
+
+commit 565c8fcbf39a56319cee4f77f689dfc79e0c6614
+Author: Matthieu Herrb <matthieu.herrb@laas.fr>
+Date:   Sun Dec 7 19:00:22 2008 +0100
+
+    Sync with OpenBSD code.
+    
+    - implement pci_read_rom()
+    - only set MTRR on x86 cpus
+    - failure to set non-cacheable attributes is not fatal
+    - fix a logic error in pci_write()
+
+commit 8222fb8534cf09e433f0f3d68c35d6c390fbba5e
+Author: Matthieu Herrb <matthieu.herrb@laas.fr>
+Date:   Tue Nov 25 12:42:15 2008 +0100
+
+    Fix a logic error in pci_device_openbsd_write().
+
+commit 613c1e6d09930bab47f2c6983f220df002c2e2ce
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Wed Nov 19 09:37:49 2008 -0800
+
+    Add AC_SYS_LARGEFILE to configure.ac
+
+commit 0821f3b4eae5428cf1af5c4c056240f8991758f6
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Wed Nov 19 08:22:22 2008 -0800
+
+    Don't open/gzopen pci.ids if we're not going to read it
+
+commit ccbfd4cf2a7d203344bd1ffcb9d0024536a0eefa
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Tue Nov 18 19:54:42 2008 -0800
+
+    Fill in byte swapping routines for big-endian Solaris machines
+
+commit 7aca9465a61934d57781352f4fcc42b779392cd0
+Author: Julien Cristau <jcristau@debian.org>
+Date:   Fri Oct 31 18:07:52 2008 +0100
+
+    Bump to 0.10.5
+
+commit 8b0be8751279f9bc8f15ced4e5384fa2b0f78711
+Author: Julien Cristau <jcristau@debian.org>
+Date:   Fri Oct 31 17:33:50 2008 +0100
+
+    Make --without-zlib work
+
+commit 7a5ed759f13c3fc5f379cce2ca02c9ebfae5eae9
+Author: Robert Noland <rnoland@2hip.net>
+Date:   Wed Oct 29 22:20:35 2008 -0400
+
+    Fix FreeBSD systems which support pci domains.
+    
+    Support for FreeBSD based systems which support pci domains was broken
+    in the commit to support kFreeBSD.  Include config.h so that things are
+    happy again.
+
+commit 067f979cbd410ddb82aee702d8434552e35c7154
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri Oct 17 14:09:52 2008 -0700
+
+    Version 0.10.4
+
+commit 714fef70e66b651e9a535d3d3cb20d055595a12d
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri Oct 17 14:09:43 2008 -0700
+
+    Add scanpci.man to EXTRA_DIST
+
+commit 77f274b6386301cb31c074061a8c947a78b49da9
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri Oct 17 13:51:28 2008 -0700
+
+    Update COPYING with the rest of the copyright/license notices from the code
+
+commit 482d1da02498a6a31a6d829a5be41727f6333f94
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri Oct 17 13:48:46 2008 -0700
+
+    Add scanpci man page from Xorg
+
+commit f537fc50e014063d1a1297bfd82680ae3f170281
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Thu Oct 16 21:17:24 2008 -0700
+
+    More minor Solaris cleanups
+
+commit 9a5565c72c13aa107167c9c4a4469dd11ac13714
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Thu Oct 16 18:18:09 2008 -0700
+
+    Clean up formatting of solx_devfs.c
+
+commit de97e7e4c63146032c0badb9e0f0b1899dc8debf
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Thu Oct 16 16:55:27 2008 -0700
+
+    Fix bus probing on Solaris/SPARC
+
+commit 110cdac97ca1bca3ec811ce0a71b2b24c1f80525
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Thu Oct 16 13:33:01 2008 -0700
+
+    Correct Sun license notice
+
+commit 4c0d050c72a38e66a7b4ccb134e7e872eb0bf557
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Wed Oct 15 18:23:03 2008 -0700
+
+    scanpci: add -v flag to enable verbose mode like old scanpci
+
+commit 64d0c836d547847b752da6539792b94c803f206b
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Wed Oct 15 16:14:18 2008 -0700
+
+    Correct comment about devices used on Solaris
+
+commit d43d21c8cb0f917b65228852a03a7d501636f227
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Wed Oct 15 15:35:25 2008 -0700
+
+    Fix various typos (mostly in comments)
+
+commit 4c1c607c602e5e8d9277b9c01edfa7a8d10333cd
+Author: Juan RP <xtraeme@gmail.com>
+Date:   Sat Oct 11 20:28:03 2008 +0200
+
+    Add NetBSD support
+    
+    It's based in the OpenBSD code, but with differences because on NetBSD,
+    to set MTRRs we have to use i386/x86_64_set_mtrr() and link to libi386
+    or libx86_64.
+    
+    X.Org bug#17931 <http://bugs.freedesktop.org/show_bug.cgi?id=17931>
+
+commit 6ae378611bb4caaf57311734d3adcb7e10ac3622
+Author: Petr Salinger <petr.salinger@seznam.cz>
+Date:   Sat Oct 11 20:22:28 2008 +0200
+
+    Add support for GNU/kFreeBSD
+    
+    We need to initialize the FreeBSD backend on GNU/kFreeBSD and detect
+    whether pci_io.pi_sel.pc_domain member exists.
+    
+    X.Org bug#17882 <http://bugs.freedesktop.org/show_bug.cgi?id=17882>
+
+commit 968289fc3137ac0863c62d3c343153fa3e4aeb10
+Author: John Tapsell <johnflux@gmail.com>
+Date:   Tue Sep 23 17:26:09 2008 +0300
+
+    configure.ac: Make mtrr.h test more portable
+    
+    Use the standard AC_CHECK_HEADERS, which works for cross-compiling as
+    well as in various other locations.
+
+commit 79ed41882fd721a15c8b0bea7efeb98864d85dfb
+Author: Matthieu Herrb <matthieu.herrb@laas.fr>
+Date:   Sat Sep 20 18:28:59 2008 +0200
+
+    OpenBSD: allow 2 successives calls to pci_system_init().
+    
+    And fix pci_system_cleanup() to make it possible to call pci_system_init()
+    again.
+    ok kettenis at openbsd.
+
+commit 45015ab30b36bdaefd3f3aeab73d287023928826
+Author: Kel Modderman <kel@otaku42.de>
+Date:   Tue Jul 8 13:09:52 2008 +0200
+
+    Handle compressed pci.ids
+    
+    Add an option to build with zlib support so we can find
+    vendor/device information if the pci.ids file is gzipped.
+    
+    Signed-off-by: Julien Cristau <jcristau@debian.org>
+
+commit 32c64bb2386c55d5c7a3878ae9e3f95577f00875
+Author: Julien Cristau <jcristau@debian.org>
+Date:   Wed Mar 12 15:00:26 2008 +0100
+
+    Hide one more private symbol
+
+commit 7282b53c47c2435c1ea23948272c9ccf1798178a
+Author: Jesse Barnes <jbarnes@hobbes.(none)>
+Date:   Mon Jun 23 11:24:04 2008 -0700
+
+    Support write combine resource files in Linux sysfs
+    
+    Starting with version 2.6.26, Linux will support resourceN_wc files which
+    export write combining mappings of PCI resource ranges, so support them if
+    present in libpciaccess.
+
+commit f49f66710b6c3cc5edfd0681cf7b69063cb4b893
+Author: Stefan Dirsch <sndirsch@suse.de>
+Date:   Mon Jun 23 10:50:30 2008 +0200
+
+    Fixed typo in output ("performace" --> "performance").
+
+commit ed0555e4225aec26aaaa40f4f3c15fd914390817
+Author: Adam Jackson <ajax@redhat.com>
+Date:   Tue Jun 10 15:24:56 2008 -0400
+
+    libpciaccess 0.10.3
+
+commit 07577a875bc9996437cfe30e5a87ca6b1a0f7e4a
+Author: Adam Jackson <ajax@redhat.com>
+Date:   Tue Jun 10 15:23:06 2008 -0400
+
+    libpciaccess 0.10.2
+
+commit e3adc06b8b8214478aa1d3e85fd5f83b79d039b4
+Author: Eric Anholt <eric@anholt.net>
+Date:   Thu Jun 5 11:39:06 2008 -0700
+
+    Catch and recover from yet another linux kernel bug in mprotect.
+
+commit 4586bb6766983d040bff38b43dc458c47e0ca21f
+Author: Adam Jackson <ajax@redhat.com>
+Date:   Wed May 21 13:44:38 2008 -0400
+
+    Linux: Fail gracefully on machines without PCI.
+
+commit 26400575a2a2d10b1014eaf0bfca6cfbf5d9b93b
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Wed May 21 16:10:37 2008 +1000
+
+    pciaccess: bump to 0.10.1
+
+commit 4bc9292ff9338e759eb9a73f12edfa5ca87353e0
+Author: Dave Airlie <airlied@redhat.com>
+Date:   Wed May 21 16:10:24 2008 +1000
+
+    linux: add pci_device_enable entrypoint and sysfs support for it
+
+commit ded8326f2adadc773b34889474a0d4fc20ef387a
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri May 9 15:15:42 2008 -0700
+
+    Fix lint warnings in solx_devfs.c
+
+commit 74c976a7bcee3102993cf788850d0b803cf15afd
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri May 9 15:05:46 2008 -0700
+
+    Add pci_system_solx_devfs_create prototype to pciaccess_private.h
+
+commit 2ac461b2eca788fa0559312d45efd3caf6eea9bb
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Fri May 9 14:49:32 2008 -0700
+
+    Initialize err to 0 in pci_device_solx_devfs_map_range
+    
+    Prevents returning errors when mapping actually succeeds
+
+commit b30d458202bc0304c705eb081b12ead860584bea
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 16 12:10:52 2008 -0700
+
+    Kludge around linux bug and turn off write-through and cache-disable bits
+    
+    When mmaping the PCI device, the kernel turns on the write-through and
+    cache-disable bits in the allocated PTEs. This disables write-combining mode
+    and dramatically reduces write bandwidth to the frame buffer. While that
+    should be fixed in the kernel, we'll kludge around it here by using mprotect
+    to rewrite the PTEs and get those bits turned off.
+
+commit a3b63c43b960e3b37e1b303214e63c5155192a5d
+Author: Hasso Tepper <hasso@estpak.ee>
+Date:   Mon Apr 7 15:28:44 2008 +0300
+
+    Add DragonFly BSD support
+    
+    DragonFly behaves exactly like FreeBSD, so no problem here.
+
+commit ec53d6ef2bdf0e7a087ffd45fe112290f2181656
+Author: Danny van Dyk <danny.dyk@uni-dortmund.de>
+Date:   Fri Mar 28 17:01:29 2008 -0700
+
+    Fix function prototypes for C++
+
+commit a5c862029846ddd5cecf44819f2a967e2a1672a9
+Author: Stuart Bennett <sb476@cam.ac.uk>
+Date:   Fri Mar 14 11:58:33 2008 -0400
+
+    Bug #13988: Fix reads from "0"-sized ROMs.
+
+commit d898072e28ac35f5b3569f48f2e90a9ef8eee2ca
+Author: Mark Kettenis <mark.kettenis@xs4all.nl>
+Date:   Wed Mar 12 21:29:58 2008 +0100
+
+    OpenBSD support for libpciaccess.
+    
+    xserver and libpciaccess both need to open /dev/xf86, which can only
+    be opened once.  I implemented pci_system_init_dev_mem() like Ian
+    suggested.  This requires some minor changes to the BSD-specific
+    os-support code.  Since pci_system_init_dev_mem() is a no-op on
+    FreeBSD this should be no problem.
+
+commit 4224ff23794500e1455f28fd5689bd0549b72367
+Author: Julien Cristau <jcristau@debian.org>
+Date:   Fri Mar 7 14:41:47 2008 +0100
+
+    solaris: add pci_tools.h to OS_SUPPORT
+    
+    pci_tools.h was missing from the tarball, but is needed by solx_devfs.c
+
+commit ac119e0b1d5fdbb6bd447b6cef1ddca59840fe40
+Author: Adam Jackson <ajax@redhat.com>
+Date:   Thu Mar 6 15:31:51 2008 -0500
+
+    libpciaccess 0.10
+
+commit 0ac748d0da1361075efa48a6238f2328d24ba1a8
+Author: Doug Chapman <doug.chapman@hp.com>
+Date:   Thu Mar 6 14:22:17 2008 -0500
+
+    Bug #14818: Actually return the PCI vendor name, instead of NULL.
+
+commit adc46f65d7a097ea0e8427a2496586a420c99d55
+Author: Julien Cristau <jcristau@debian.org>
+Date:   Tue Feb 19 14:45:40 2008 +0100
+
+    Don't export private symbols.
+
+commit 25de45d250811474e86cb9a09caf258aef699196
+Author: Julien Cristau <jcristau@debian.org>
+Date:   Tue Feb 19 14:26:54 2008 +0100
+
+    Use <byteswap.h> when using glibc, not just on linux
+    
+    This fixes the build on GNU/kFreeBSD.
+
+commit ceda00d33fbf3d491e3f7e53302acd2b8b74a305
+Author: James Cloos <cloos@jhcloos.com>
+Date:   Thu Dec 6 16:38:51 2007 -0500
+
+    Replace static ChangeLog with dist-hook to generate from git log
+
+commit e392082abb5696c8837224da86cc0af4f21d7010
+Author: Matthias Hopf <mhopf@suse.de>
+Date:   Tue Oct 23 15:19:36 2007 +0200
+
+    Bit-fields have to have type _Bool, signed int, or unsigned int.
+    
+    ISO/IEC 9899:1999 (E), 6.7.2.1 Structure and union specifiers, (4).
+    _Bool is only supported for C99 and up, and 1-bit signed types don't make
+    sense -> unsigned int.
+
+commit 5b9ca552a17de37bbac84f0cf5b4430d108e576c
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Thu Oct 18 15:59:14 2007 -0700
+
+    Update bug reporting link.
+
+commit 57a942b3cca314a56735e0a4198cac2f25b653dd
+Author: Eric Anholt <eric@anholt.net>
+Date:   Wed Oct 10 15:20:51 2007 -0700
+
+    FreeBSD: for 64-bit BARs, skip the resource slot used for the upper 32 bits.
+    
+    This gets us the same resource numbering as on Linux.
+
+commit 127ae628a2090bb00df81adce831b8b031d3b4a8
+Author: Eric Anholt <eric@anholt.net>
+Date:   Wed Oct 10 14:55:45 2007 -0700
+
+    FreeBSD: Don't try to unset an MTRR if we didn't set it.
+
+commit 28fea32f987a74d365d01bc5870a8bce1c393d59
+Author: Eric Anholt <eric@anholt.net>
+Date:   Wed Oct 10 14:32:38 2007 -0700
+
+    Add domain output to scanpci.
+
+commit 393145db90578d7d598fccf949b249217066a67c
+Author: Eric Anholt <eric@anholt.net>
+Date:   Wed Oct 10 14:32:09 2007 -0700
+
+    FreeBSD: Add support for multiple PCI domains.
+
+commit 7d809e149b59f22e24723db7360a4c38a9145b45
+Author: Eric Anholt <eric@anholt.net>
+Date:   Tue Oct 9 12:13:49 2007 -0700
+
+    FreeBSD: Fix unmap_range to return an error value.
+
+commit 042735df2aa5846fcabfd74c5f73877132728b25
+Author: Eric Anholt <eric@anholt.net>
+Date:   Tue Oct 9 12:12:34 2007 -0700
+
+    FreeBSD: don't set the MTRR if it's the default mode (uncacheable).
+
+commit 4bdaca5295eeacdaeb80f2e7d0fa17674dcbc77a
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Thu Sep 27 15:22:51 2007 -0700
+
+    Need to link with -ldevinfo on Solaris
+
+commit 63983e2397d813246b851771c13397ff700e239e
+Author: Alan Coopersmith <alan.coopersmith@sun.com>
+Date:   Wed Sep 26 17:26:47 2007 -0700
+
+    Fix Solaris build: missing static prototype & typo in variable name
+
+commit 8c77862e70eac7f61cd402e9ef33a5b0ca1c6426
+Author: Eric Anholt <eric@anholt.net>
+Date:   Tue Sep 11 15:07:55 2007 +0000
+
+    Add FreeBSD MTRR setting support.
+
+commit 82a2ff0bb091e097bacb66273f55a287afb15abf
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Tue Sep 4 16:13:24 2007 -0700
+
+    Add stub version of pci_device_map_memory_range
+    
+    This stub version of pci_device_map_memory_range allows the vesa driver and
+    other users of this interface to continue functioning with current
+    libpciaccess bits.  That said, users of this interface should convert over
+    to pci_device_map_range as soon as possible.
+
+commit 9d1596cba90c8fd273e9d1d5488747cc0f34fdc7
+Merge: b1e9117 5cf29b0
+Author: James Cloos <cloos@jhcloos.com>
+Date:   Mon Sep 3 06:15:58 2007 -0400
+
+    Merge branch 'master' of ssh://git.freedesktop.org/git/xorg/lib/libpciaccess
+
+commit b1e911784d314fdbd8d938e5fe3671bec128fb61
+Author: James Cloos <cloos@jhcloos.com>
+Date:   Mon Sep 3 05:53:57 2007 -0400
+
+    Add *~ to .gitignore to skip patch/emacs droppings
+
+commit 5cf29b06b9b5806056a0b04160b2286eb4158748
+Author: Keith Packard <keithp@koto.keithp.com>
+Date:   Fri Aug 31 13:43:18 2007 -0700
+
+    Don't add MTRR for uncached regions. Remove MTRR on unmap.
+    
+    MTRR regions aren't needed for uncached mappings, so don't add them. Also,
+    when unmapping memory, remove the MTRR entry.
+
+commit ebc618e7508847307713a59aeeed337a9277629d
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Fri Aug 31 12:40:03 2007 -0700
+
+    Update / add comments in struct pci_mem_region.
+
+commit 08ff9f7fbd26dd2d0e30351b556c71c272f6be6c
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Thu Aug 30 17:52:02 2007 -0700
+
+    New interfaces to map memory with MTRR (or similar) support.
+    
+    Added new functions pci_device_map_range and pci_device_unmap_range to
+    handle mapping of PCI device BARs.  These new interfaces allow the
+    possiblity of MTRRs on platforms that support them.
+    
+    These additional APIs necessitated changing some internal interfaces.  The
+    code for FreeBSD and Solaris has been updated but has not been compiled or
+    tested.
+    
+    Old interfaces are marked deprecated and will eventually be removed.
+
+commit c87273e8e20c8bff892ded31295dba103f27dd35
+Author: Eric Anholt <eric@anholt.net>
+Date:   Tue Aug 28 16:02:46 2007 -0700
+
+    Make the base address printout of scanpci more usable.
+
+commit 47d625ccea7dbcd6b69009aa1ec64a96e97513f6
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Mon Aug 27 16:41:52 2007 -0700
+
+    Bump version to 0.9.1 (sigh).
+
+commit 73197e09c924dabc18b8839180508584b97e03df
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Mon Aug 27 16:41:21 2007 -0700
+
+    Add linux_devmem.h to file list.
+
+commit 5e595d09e7011b82a90f74b149a97bea23ddfbf0
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Mon Aug 27 16:39:00 2007 -0700
+
+    Bump version to 0.9.0.
+
+commit b0c9558c97ee861af240a948c364807e628e49de
+Author: James Cloos <cloos@jhcloos.com>
+Date:   Thu Aug 23 21:31:50 2007 -0400
+
+    Remove deprecated .cvsignore files
+
+commit 4e6be0466ad973ee6f63e0cbed466a974908dce8
+Author: Eric Anholt <eric@anholt.net>
+Date:   Fri Aug 3 16:47:09 2007 -0700
+
+    FreeBSD: Add VGA rom reading through /dev/mem.
+
+commit ae4aed2821161028dabd8381273f3803a24340ad
+Author: Eric Anholt <eric@anholt.net>
+Date:   Fri Aug 3 10:46:55 2007 -0700
+
+    FreeBSD: Fill in the subdevice ID.
+
+commit 14e62c77bd1ae6ef1d4048df2da96eeff8f7538f
+Author: Eric Anholt <eric@anholt.net>
+Date:   Fri Aug 3 10:40:53 2007 -0700
+
+    Make scanpci exit cleanly if pci_system_init() fails.
+
+commit a7faac3d2dc49a2130906fbeea3298f32bb9349f
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Mon Jun 18 12:56:40 2007 -0700
+
+    Initial support for reading expansion ROM via VGA BIOS address.
+
+commit 206e29213f92dd639fb4814ed2f3b6ec27e6f985
+Author: edward shu <edward.shu@sun.com>
+Date:   Wed Jun 6 23:05:56 2007 +0800
+
+    Libpciaccess on Solaris Initial integration
+    
+    Libpciaccess on Solaris Initial integration. It depends on devfs to access
+    pci configuration space, also xsvc is used for memory map.
+
+commit db56c640028d2f8072274f3eb603caa481103f4f
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Tue Mar 27 08:01:39 2007 -0700
+
+    Whitespace police.
+
+commit c6e72deddb3055167fff8007bf039be61e45849e
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Tue Mar 27 07:57:35 2007 -0700
+
+    Don't pci_device_probe until absolutely necessary.
+
+commit 28dc34c2a6045ab95183d708500009bd1eea1659
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Tue Mar 27 07:57:00 2007 -0700
+
+    Make sure header_type is available in read_bridge_info.
+
+commit 061a011ceffc13db3b147dd105d8b7c2edcc3bc8
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Tue Mar 27 07:56:16 2007 -0700
+
+    Populate device and vendor ID fields at device list creation.
+
+commit b36d737d92dbeee7951aded990fa52bac39b2a79
+Author: Eric Anholt <eric@anholt.net>
+Date:   Tue Mar 6 10:48:51 2007 -0800
+
+    FreeBSD: Fix a couple of minor issues in cleanup paths.
+
+commit 09be109c223b93d74ea3cc7a12d9a22b44990a14
+Author: Eric Anholt <eric@anholt.net>
+Date:   Thu Mar 1 10:49:13 2007 -0800
+
+    FreeBSD: Add system cleanup function.
+
+commit f6502eee20205ec14ce6499251a28962cc36fdd6
+Author: Eric Anholt <eric@anholt.net>
+Date:   Wed Feb 28 16:25:07 2007 -0800
+
+    FreeBSD: When mapping regions, use the region's base address, not 0.
+
+commit a4ec2f35ea5b4f74cf455be24f8ad25d4096ab98
+Author: Eric Anholt <eric@anholt.net>
+Date:   Wed Feb 28 16:13:44 2007 -0800
+
+    Fix inverted protection typo for mmap in region mapping.
+
+commit 9819ae0c376db57a9de5fcbb2f1d4c3ee1ed2ea8
+Author: Eric Anholt <eric@anholt.net>
+Date:   Wed Feb 28 15:42:24 2007 -0800
+
+    scanpci prototype warning fix
+
+commit e70b710133cc552df266d5046a53f7a241a569eb
+Author: Eric Anholt <eric@anholt.net>
+Date:   Wed Feb 28 15:39:38 2007 -0800
+
+    Update freebsd code for pci_device_cfg_write API change.
+
+commit d86245be3bd57b29e5b7561b3facecb3298fea3b
+Author: George Sapountzis <gsap7@yahoo.gr>
+Date:   Wed Nov 15 02:49:50 2006 +0200
+
+    scanpci: BIST line offsets were off by 4.
+
+commit cc1d08f113140010f49503adc4e7afe5db892a02
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Tue Jan 16 21:24:12 2007 -0800
+
+    Fix bad parameter to pci_device_cfg_write in pci_device_cfg_write_u8.
+    
+    When changing the interface of the pci_device_cfg_write_u* functions
+    in commit 37ce43c1804bad9c52b8316eaefd3a57b670ee29, I forgot to modify
+    pci_device_cfg_write_u8 to pass a pointer to data to
+    pci_device_cfg_write instead of just passing data.
+
+commit 54d40b528ab769c4e89aaca87d1728a6194e4378
+Merge: 37ce43c 335d42f
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Mon Jan 15 11:18:29 2007 -0800
+
+    Merge branch 'master' of git+ssh://git.freedesktop.org/git/xorg/lib/libpciaccess
+
+commit 37ce43c1804bad9c52b8316eaefd3a57b670ee29
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Mon Jan 15 11:18:19 2007 -0800
+
+    Convert pci_device_write_u* funtions to take a value instead of a pointer.
+    
+    At anholt's request, the pci_device_write_u* functions have been
+    converted to take the value to be written as a parameter instead of a
+    pointer to the value.
+    
+    Bump the version to 0.8.0.
+
+commit 335d42f637dd44461bc20ba599ca5dc4971b6eaa
+Author: Eric Anholt <eric@anholt.net>
+Date:   Fri Jan 12 16:32:51 2007 -0800
+
+    Add support for getting region information on FreeBSD.
+    
+    This could stand a lot more testing -- all it has received is visual inspection
+    of scanpci output on one machine, with some differing results from XFree86
+    scanpci output.
+
+commit 94355b6f49a61e7424ddc7ddfc70a9b344233a47
+Author: Eric Anholt <eric@anholt.net>
+Date:   Fri Jan 12 14:15:29 2007 -0800
+
+    Open the pci device read-write so we can read and write config regs.
+    
+    With this, we can hook up the IRQ line information.  It would probably be nice
+    to have an unpriveleged mode, but for now, write access is required.
+
+commit 253e7f672b8b311b18cf827cd12c9147bba8eb4c
+Author: Eric Anholt <eric@anholt.net>
+Date:   Fri Jan 12 13:33:51 2007 -0800
+
+    Remove extra fallback definition of PCIIDS_PATH.
+    
+    PCIIDS_PATH should always be provided by configure.ac and config.h.
+
+commit 87ec7de307ab5bd395d01cdb4f8fdf231d9e769e
+Author: Eric Anholt <eric@anholt.net>
+Date:   Fri Jan 12 13:13:27 2007 -0800
+
+    Fix many warnings and bugs in the freebsd implementation.
+    
+    With this, scanpci gives partially-sane results.
+
+commit 4f6e1a61fc0abe1865e147509af5f7f2bfcaf8f7
+Author: Eric Anholt <eric@anholt.net>
+Date:   Fri Jan 12 13:11:21 2007 -0800
+
+    Enable more warnings when the compiler is GCC.
+
+commit c7ce8ee140b01931994030900c0e8238fbb0caa2
+Author: Eric Anholt <eric@anholt.net>
+Date:   Fri Jan 12 13:06:50 2007 -0800
+
+    Add pciaccess_private.h to _SOURCES so it gets included in the dist.
+
+commit c65aa7630802c8dfcc06a20e515ace31ab0d0e48
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Thu Jan 11 21:40:57 2007 -0800
+
+    Add interfaces to map / unmap specific memory ranges, bump lib version to 0.7.0.
+    
+    Add pci_device_map_memory_range and pci_device_unmap_memory_range to
+    map and unmap specific memory ranges.  The unmap bit is still a bit
+    hinkey (unmaps the whole BAR).  Works so far for initial conversion of
+    VESA driver.  Will need to be revisited.
+
+commit db4a12d09fba381f39af024418e913fb99c34935
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Thu Jan 11 21:39:15 2007 -0800
+
+    Fix bad cast that caused bit truncation.
+
+commit 8948a6c3593d92a50a09baf568b69f164d7e7f59
+Author: Eric Anholt <eric@anholt.net>
+Date:   Tue Nov 14 14:38:48 2006 -0800
+
+    Update .gitignores.
+
+commit 1d227d67d35aba4601c4ffd6a2947ee746d5dc47
+Author: Eric Anholt <eric@anholt.net>
+Date:   Tue Nov 14 14:37:53 2006 -0800
+
+    Add missing newline at the end of the file.
+
+commit e29843d3b0ff5d32d8ab4bc84c58300782d189d3
+Merge: 07b09d9 d05da65
+Author: Eric Anholt <eric@anholt.net>
+Date:   Tue Nov 14 14:37:46 2006 -0800
+
+    Merge branch 'origin'
+    
+    Conflicts:
+    
+       src/Makefile.am
+
+commit 07b09d930ed2b7eae299ae036ec30099374b95aa
+Author: Eric Anholt <anholt@FreeBSD.org>
+Date:   Sun Jul 30 16:19:50 2006 -0700
+
+    Add the beginnings of a FreeBSD port.
+
+commit d05da6520a273ee4c2f0e11b5a9bac65b51835fe
+Author: Ian Romanick <idr@localhost.localdomain>
+Date:   Thu Aug 10 09:46:07 2006 -0700
+
+    Fix a segfault in populate_vendor that was triggered when the pci.ids file
+    could not be opened.  Thanks to Aaron Plattner for reporting this.  Fix a
+    couple possible memory leaks in the same function.
+
+commit 27f0ffca71277371a0b6c0cd1a720a9ce9519da5
+Author: Ian Romanick <idr@localhost.localdomain>
+Date:   Sun Jul 30 15:35:41 2006 -0700
+
+    Added some function preamble comments.
+
+commit cf1b4d3ddfcdbaeddefc42b6eb19eb85a0a1e454
+Author: Eric Anholt <anholt@FreeBSD.org>
+Date:   Sun Jul 30 14:29:58 2006 -0700
+
+    Add endian macros for BSD.
+
+commit edf3908958eacc20162563b68aa45964f0e38b2c
+Author: Eric Anholt <anholt@FreeBSD.org>
+Date:   Sun Jul 30 14:26:38 2006 -0700
+
+    Use ENXIO instead of ENODATA for pci reads returning less than desired.
+
+commit c0e31708e0446b33240d3e1ba3e36c26a618544c
+Author: Ian Romanick <idr@umwelt.(none)>
+Date:   Tue Jul 25 15:36:52 2006 -0700
+
+    Add pci_device_get_bridge_buses, bump API version to 0.5.0.
+
+commit 2ba1a0e42928f82e678987c84598e1b9d8ba1ef9
+Author: Ian Romanick <idr@umwelt.(none)>
+Date:   Thu Jul 6 17:18:14 2006 -0700
+
+    Files missed (for reasons I still don't understand) on the previous
+    commit.  REALLY add support for querying bridge information.  Bump to
+    version 0.5.0.
+
+commit c0ff6e6141ee6ebb1f628931ae62f0fa8ef87061
+Author: Ian Romanick <idr@umwelt.(none)>
+Date:   Thu Jul 6 17:09:47 2006 -0700
+
+    Add support for querying bridge information.  Bump to version 0.5.0.
+
+commit 2467b3c509c7e5b771ca21ee6317b2d72d481439
+Author: Ian Romanick <idr@umwelt.(none)>
+Date:   Thu Jul 6 17:07:18 2006 -0700
+
+    Fix byte ordering of the PCI class.
+
+commit 70a66689fc2e44e7cd693947ed5f3f2acb4b6587
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Mon May 22 16:10:37 2006 +0000
+
+    Fix foolish endianess bug. Bump to version 0.4.1.
+
+commit 64af050c3803ed61837d9e9109c7a4e239a5c0b8
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Wed Apr 12 22:56:50 2006 +0000
+
+    Bump to version 0.4.0.
+    Add multiple-inclusion protection.
+    Add new function to write masked bits to PCI config space. This mirrors
+        functionality currently available in X.org that is slated to be
+        removed.
+    Gut old regex based search mechanism with a new mechanism that is modeled
+        after the Linux kernel. In addition to searching for devices by device
+        / vendor ID, it is possible to search for devices by their domain / bus
+        / slot / function.
+    Fix serious bus in the reading of ROMs and in the unmapping of regions. The
+        main point is that the map routine depens on the pci_mem_region::memory
+        pointer being non-NULL only when the region is mapped. Therefore, the
+        unmap routine should set it to NULL after unmapping.
+    Update to use new search API.
+
+commit 5b4db5c392c123f71a7933bd94c789b5e23dd69a
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Mon Mar 27 18:08:42 2006 +0000
+
+    Remove src/pcils.c and src/Makefile.foo. Add src/scanpci.c.
+    Bump version to 0.3.0.
+    Replace pci_get_name with pci_get_strings. This function matches the
+        functionality provided by the Xorg scanpci module almost identically.
+
+commit 6b1e9fae2ab9979b2a3bb3137c5db4d92d2905c8
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Fri Mar 24 16:57:17 2006 +0000
+
+    Remove src/Makefile.foo from CVS since the generated Makefile can do
+        everything now.
+
+commit d890ded5312dc88455fd332e03a4f212ba587e9d
+Author: Kristian Høgsberg <krh@redhat.com>
+Date:   Mon Mar 20 20:13:34 2006 +0000
+
+    Add scanpci as a noinst target.
+    Drop from CVS.
+
+commit 5a04522a921cd8737ef921dfd49b750a8c64dfc9
+Author: Ian Romanick <idr@us.ibm.com>
+Date:   Sat Mar 18 00:12:48 2006 +0000
+
+    Initial import of libpciaccess.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..ff8db2f
--- /dev/null
@@ -0,0 +1,43 @@
+# 
+# (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 autoconf macros from m4 subdir
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = src
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = pciaccess.pc
+
+MAINTAINERCLEANFILES = ChangeLog INSTALL
+EXTRA_DIST = src/scanpci.c src/scanpci.man 
+
+.PHONY: ChangeLog INSTALL
+
+INSTALL:
+       $(INSTALL_CMD)
+
+ChangeLog:
+       $(CHANGELOG_CMD)
+
+dist-hook: ChangeLog INSTALL
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..8b64261
--- /dev/null
+++ b/README
@@ -0,0 +1,35 @@
+xorg/lib/libpciaccess - Generic PCI access library
+
+Documentation of the libpciaccess API's can be generated from the
+sources via the doxygen command.    Information about porting Xorg
+drivers to libpciaccess is located at:
+
+       http://www.x.org/wiki/PciReworkHowto
+
+For historical reference, the original proposal for this work is at:
+
+       http://www.x.org/wiki/PciReworkProposal
+
+All questions regarding this software should be directed at the
+Xorg mailing list:
+
+        http://lists.freedesktop.org/mailman/listinfo/xorg
+
+Please submit bug reports to the Xorg bugzilla:
+
+        https://bugs.freedesktop.org/enter_bug.cgi?product=xorg
+
+The master development code repository can be found at:
+
+        git://anongit.freedesktop.org/git/xorg/lib/libpciaccess
+
+        http://cgit.freedesktop.org/xorg/lib/libpciaccess
+
+For patch submission instructions, see:
+
+       http://www.x.org/wiki/Development/Documentation/SubmittingPatches
+
+For more information on the git code manager, see:
+
+        http://wiki.x.org/wiki/GitPage
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100644 (file)
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..bba0cff
--- /dev/null
@@ -0,0 +1,127 @@
+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_PREREQ([2.60])
+
+AC_INIT(libpciaccess, 0.12.0, [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg&component=libpciaccess], libpciaccess)
+AM_INIT_AUTOMAKE([foreign dist-bzip2])
+AM_MAINTAINER_MODE
+
+# Require xorg-macros: XORG_DEFAULT_OPTIONS
+m4_ifndef([XORG_MACROS_VERSION],
+          [m4_fatal([must install xorg-macros 1.3 or later before running autoconf/autogen])])
+XORG_MACROS_VERSION(1.3)
+XORG_DEFAULT_OPTIONS
+AM_CONFIG_HEADER(config.h)
+
+# Check for progs
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+pciids_path=/usr/share/hwdata
+AC_ARG_WITH(pciids-path, AC_HELP_STRING([--with-pciids-path=PCIIDS_PATH],
+       [Path to pci.ids file]), [pciids_path="$withval"])
+AC_DEFINE_DIR(PCIIDS_PATH, pciids_path, [Path to pci.ids])
+
+AC_ARG_ENABLE(linux-rom-fallback, AS_HELP_STRING([--enable-linux-rom-fallback],
+               [Enable support for falling back to /dev/mem for roms (default: disabled)]),
+               [LINUX_ROM=$enableval],[LINUX_ROM=no])
+
+if test "x$LINUX_ROM" = xyes; then
+       AC_DEFINE(LINUX_ROM, 1, [Linux ROM read fallback])
+fi
+
+use_zlib=no
+AC_ARG_WITH(zlib, AC_HELP_STRING([--with-zlib],
+       [Enable zlib support to read gzip compressed pci.ids]),
+       [use_zlib="$withval"])
+if test "x$use_zlib" = xyes; then
+       AC_CHECK_LIB(z, gzopen,
+       [PCIACCESS_LIBS="$PCIACCESS_LIBS -lz"],
+       [AC_MSG_ERROR(Check for zlib library failed)])
+       AC_CHECK_HEADER([zlib.h],
+       [AC_DEFINE(HAVE_ZLIB, 1, [Use zlib to read gzip compressed pci.ids])],
+       [AC_MSG_ERROR(Check for zlib.h header file failed)])
+fi
+
+case $host_os in
+       *freebsd* | *dragonfly*)
+               freebsd=yes
+               ;;
+       *linux*)
+               linux=yes
+               ;;
+       *netbsd*)
+               case $host in
+               *i386*)
+                       PCIACCESS_LIBS="-li386"
+                       ;;
+               *x86_64*|*amd64*)
+                       PCIACCESS_LIBS="-lx86_64"
+                       ;;
+               esac
+               netbsd=yes
+               ;;
+       *openbsd*)
+               openbsd=yes
+               ;;
+       *solaris*)
+               solaris=yes
+               PCIACCESS_LIBS="$PCIACCESS_LIBS -ldevinfo"
+               ;;
+       gnu*)
+               gnu=yes
+               ;;
+esac
+
+AM_CONDITIONAL(LINUX, [test "x$linux" = xyes])
+AM_CONDITIONAL(FREEBSD, [test "x$freebsd" = xyes])
+AM_CONDITIONAL(NETBSD, [test "x$netbsd" = xyes])
+AM_CONDITIONAL(OPENBSD, [test "x$openbsd" = xyes])
+AM_CONDITIONAL(SOLARIS, [test "x$solaris" = xyes])
+AM_CONDITIONAL(GNU, [test "x$gnu" = xyes])
+
+AC_SYS_LARGEFILE
+
+AC_CHECK_HEADER([asm/mtrr.h], [have_mtrr_h="yes"], [have_mtrr_h="no"])
+
+if test "x$have_mtrr_h" = xyes; then
+    AC_DEFINE(HAVE_MTRR, 1, [Use MTRRs on mappings])
+fi
+
+dnl check for the pci_io.pi_sel.pc_domain
+AC_CHECK_MEMBER([struct pci_io.pi_sel.pc_domain],
+               [AC_DEFINE(HAVE_PCI_IO_PC_DOMAIN,1,[Have the pci_io.pi_sel.pc_domain member.])],
+               [],
+               [ #include <sys/types.h>
+                 #include <sys/pciio.h>
+               ])
+
+AC_SUBST(PCIACCESS_CFLAGS)
+AC_SUBST(PCIACCESS_LIBS)
+                 
+
+AC_OUTPUT([Makefile
+          src/Makefile
+           pciaccess.pc])
diff --git a/debian/README.source b/debian/README.source
new file mode 100644 (file)
index 0000000..446d386
--- /dev/null
@@ -0,0 +1,7 @@
+This package uses quilt to manage modifications to the upstream source.
+Changes are stored in the source package as diffs in debian/patches and
+applied during the build.
+
+See /usr/share/doc/quilt/README.source in the quilt package for details.
+
+ -- Julien Cristau <jcristau@debian.org>  Sat, 08 Aug 2009 18:42:21 +0200
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..adad22a
--- /dev/null
@@ -0,0 +1,150 @@
+libpciaccess (0.12.0-2slp2) unstable; urgency=low
+
+  * [X11R7.6] upgrade package
+  * Git: 165.213.180.234:slp/pkgs/xorg/lib/libpciaccess
+  * Tag: libpciaccess_0.12.0-2slp2
+
+ -- SooChan Lim <sc1.lim@samsung.com>  Mon, 03 Jan 2011 22:02:39 +0900
+
+libpciaccess (0.12.0-1) unstable; urgency=low
+
+  * New upstream release:
+    - x86 backend for hurd
+    - various fixes for vgaarb, leak, use after free
+    - fix long standing MTRR bug
+  * Drop pciaccess-hurd-hack.diff and patch system.
+  * Update debian/copyright from upstream COPYING.
+  * Bump Standards-Version to 3.9.0.
+
+ -- Julien Cristau <jcristau@debian.org>  Sat, 24 Jul 2010 11:20:30 +0200
+
+libpciaccess (0.11.0-2) unstable; urgency=low
+
+  [ Julien Cristau ]
+  * Remove myself from Uploaders
+
+  [ Cyril Brulebois ]
+  * Add udeb needed for the graphical installer: libpciaccess0-udeb.
+  * Add myself to Uploaders.
+  * Bump Standards-Version from 3.7.3 to 3.8.4 (no changes needed).
+
+ -- Cyril Brulebois <kibi@debian.org>  Tue, 09 Mar 2010 02:05:55 +0100
+
+libpciaccess (0.11.0-1) unstable; urgency=low
+
+  * New upstream release.
+  * Bump xutils-dev build-dep for util-macros 1.4.
+  * Rename the build directory to not include DEB_BUILD_GNU_TYPE for no
+    good reason.  Thanks, Colin Watson!
+  * Refresh pciaccess-hurd-hack.diff.
+  * Update libpciaccess0.symbols and bump shlibs.
+  * Add build-dep on pkg-config.
+  * Bump Standards-Version to 3.8.3.
+
+ -- Julien Cristau <jcristau@debian.org>  Sun, 17 Jan 2010 14:36:38 +0000
+
+libpciaccess (0.10.9-1) unstable; urgency=low
+
+  * New upstream release.
+  * Refresh pciaccess-hurd-hack.diff.
+  * Update shlibs and symbols file.
+
+ -- Julien Cristau <jcristau@debian.org>  Mon, 28 Sep 2009 18:29:27 +0200
+
+libpciaccess (0.10.6-2) unstable; urgency=low
+
+  * Apply patch from Samuel Thibault to tinker with I/O ports on systems
+    without a PCI interface, such as GNU/Hurd (closes: #524111).
+  * debian/rules: clean out libtool m4 files.
+  * Make glob in debian/libpciaccess0.install more strict.
+  * Add README.source pointing at the quilt package.
+  * Bump Standards-Version to 3.8.2.
+  * Version debhelper build-dep to silence lintian.
+
+ -- Julien Cristau <jcristau@debian.org>  Sat, 08 Aug 2009 18:49:40 +0200
+
+libpciaccess (0.10.6-1) unstable; urgency=low
+
+  * New upstream release
+    + Update debian/copyright with new information from COPYING
+    + Add versioned xutils-dev to build-dep, as the macros are now required
+  * Update standards version to 3.8.1.0. No changes necessary.
+
+ -- David Nusinow <dnusinow@debian.org>  Mon, 27 Apr 2009 21:16:01 -0400
+
+libpciaccess (0.10.5-3) unstable; urgency=low
+
+  * Upload to unstable, for real this time.
+
+ -- Julien Cristau <jcristau@debian.org>  Mon, 16 Feb 2009 15:52:10 +0100
+
+libpciaccess (0.10.5-2) experimental; urgency=low
+
+  * Upload to unstable.
+
+ -- Julien Cristau <jcristau@debian.org>  Mon, 16 Feb 2009 01:12:29 +0100
+
+libpciaccess (0.10.5-1) experimental; urgency=low
+
+  * New upstream release
+    + Fixes PCI domain support on kfreebsd (closes: #501333)
+  * Run autoreconf at build time, cleanup generated files in clean.
+  * Allow reading compressed pci.ids file (closes: #478696).
+
+ -- Julien Cristau <jcristau@debian.org>  Wed, 12 Nov 2008 20:13:13 +0100
+
+libpciaccess (0.10.3-1) unstable; urgency=low
+
+  [ Julien Cristau ]
+  * Add watch file.
+  * New upstream release.
+  * Bump shlibs and update symbols file.
+  * Suggest pciutils, which provides the pci.ids list.
+
+  [ Brice Goglin ]
+  * Update upstream URL in debian/copyright.
+  * Drop the XS- prefix from Vcs-Git and Vcs-Browser fields in debian/control.
+
+ -- Julien Cristau <jcristau@debian.org>  Sun, 13 Jul 2008 14:58:51 +0200
+
+libpciaccess (0.10-1) unstable; urgency=low
+
+  * New upstream release.
+  * Install the upstream changelog.
+
+ -- Julien Cristau <jcristau@debian.org>  Fri, 07 Mar 2008 14:43:39 +0100
+
+libpciaccess (0.9.1+git20080219-1) unstable; urgency=low
+
+  * Add a symbols file for libpciaccess.so.0.
+  * Bump shlibs to >= 0.8.0+git20071002 (this version added the
+    pci_device_{un,}map_range functions)
+  * Bump Standards-Version to 3.7.3.
+  * New upstream snapshot.
+  * Fix build on non-linux glibc architectures.
+
+ -- Julien Cristau <jcristau@debian.org>  Tue, 19 Feb 2008 16:13:05 +0100
+
+libpciaccess (0.8.0+git20071002-1) experimental; urgency=low
+
+  * Debian stores its pci.ids list in /usr/share/misc. Use that for the
+    --with-pciids-path configure option so the library can fill in certain
+    values correctly
+  * New upstream git pull
+  * Add myself to uploaders
+
+ -- David Nusinow <dnusinow@debian.org>  Tue, 02 Oct 2007 21:40:38 -0400
+
+libpciaccess (0.8.0+git20070628-1) experimental; urgency=low
+
+  * New upstream snapshot.
+  * Make configure executable in debian/rules clean (closes: #430932); thanks,
+    Frank Lichtenheld!
+
+ -- Julien Cristau <jcristau@debian.org>  Fri, 29 Jun 2007 01:02:18 +0100
+
+libpciaccess (0.8.0+git20070613-1) experimental; urgency=low
+
+  * Initial upload (closes: #428776).
+
+ -- Julien Cristau <jcristau@debian.org>  Thu, 14 Jun 2007 23:09:50 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7ed6ff8
--- /dev/null
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100755 (executable)
index 0000000..79f014d
--- /dev/null
@@ -0,0 +1,41 @@
+Source: libpciaccess
+Section: devel
+Priority: optional
+Maintainer: Sung-Jin Park <sj76.park@samsung.com>, Sangjin Lee <lsj119@samsung.com>, Debian X Strike Force <debian-x@lists.debian.org>
+Uploaders: Sung-Jin Park <sj76.park@samsung.com>, SooChan Lim <sc1.lim@samsung.com>, David Nusinow <dnusinow@debian.org>, Cyril Brulebois <kibi@debian.org>
+Build-Depends: debhelper (>= 5), libtool, automake, zlib1g-dev, xutils-dev (>= 1:7.5), pkg-config,
+Standards-Version: 3.9.0
+
+Package: libpciaccess0
+Section: libs
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Suggests: pciutils
+Description: Generic PCI access library for X
+ Provides functionality for X to access the PCI bus and devices
+ in a platform-independant way.
+
+#Package: libpciaccess0-udeb
+#XC-Package-Type: udeb
+#Section: debian-installer
+#Architecture: any
+#Depends: ${shlibs:Depends}, ${misc:Depends}
+#Suggests: pciutils
+#Description: Generic PCI access library for X
+# This is a udeb, or a microdeb, for the debian-installer.
+
+Package: libpciaccess-dev
+Section: libdevel
+Architecture: any
+Depends: libpciaccess0 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends}
+Description: Generic PCI access library for X - development files
+ Provides functionality for X to access the PCI bus and devices
+ in a platform-independant way.
+ .
+ This package contains the development files for libpciaccess.
+
+Package: libpciaccess0-dbg
+Section: debug
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, libpciaccess0 (=${Source-Version})
+Description: Debug package os libpciaccess0
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..e2321bb
--- /dev/null
@@ -0,0 +1,87 @@
+This package was downloaded from
+http://xorg.freedesktop.org/releases/individual/lib/
+
+It was debianized by Julien Cristau <jcristau@debian.org> on
+Wed, 13 Jun 2007, with package descriptions taken from a package by
+Matthew Garrett <mjg59@srcf.ucam.org>.
+
+The Debian packaging is (C) 2007, Matthew Garrett <mjg59@srcf.ucam.org> and
+Julien Cristau <jcristau@debian.org>, and is licensed under the GPL, see
+`/usr/share/common-licenses/GPL'.
+
+Upstream authors:
+
+    Ian Romanick <idr@us.ibm.com>
+    Eric Anholt <eric@anholt.com>
+    edward shu <edward.shu@sun.com>
+
+Copyright:
+
+(C) Copyright IBM Corporation 2006, 2007
+(C) Copyright Eric Anholt 2006
+Copyright 2007, 2008, 2009 Sun Microsystems, Inc.
+Copyright 2009 Red Hat, Inc.
+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.
+
+------------------------------------------------------------------------------
+
+Copyright (c) 2008 Juan Romero Pardines
+Copyright (c) 2008 Mark Kettenis
+Copyright (c) 2009 Samuel Thibault
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+------------------------------------------------------------------------------
+
+Copyright (C) 2000 The XFree86 Project, Inc.  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 the
+rights to use, copy, modify, merge, publish, distribute, sublicense, 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL THE
+XFREE86 PROJECT 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.
+
+Except as contained in this notice, the name of the XFree86 Project shall
+not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from the
+XFree86 Project.
diff --git a/debian/libpciaccess-dev.install b/debian/libpciaccess-dev.install
new file mode 100644 (file)
index 0000000..4797855
--- /dev/null
@@ -0,0 +1,4 @@
+usr/lib/pkgconfig
+usr/lib/lib*.a
+usr/lib/lib*.so
+usr/include
diff --git a/debian/libpciaccess0-udeb.install b/debian/libpciaccess0-udeb.install
new file mode 100644 (file)
index 0000000..413fe77
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/libpciaccess.so.0*
diff --git a/debian/libpciaccess0.install b/debian/libpciaccess0.install
new file mode 100644 (file)
index 0000000..413fe77
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/libpciaccess.so.0*
diff --git a/debian/libpciaccess0.symbols b/debian/libpciaccess0.symbols
new file mode 100644 (file)
index 0000000..5411b6c
--- /dev/null
@@ -0,0 +1,56 @@
+libpciaccess.so.0 libpciaccess0 #MINVER#
+ pci_device_next@Base 0
+ pci_device_map_region@Base 0
+ pci_device_cfg_read_u32@Base 0
+ pci_system_init@Base 0
+ pci_system_init_dev_mem@Base 0.10.2
+ pci_device_cfg_write_u16@Base 0
+ pci_device_enable@Base 0.10.2
+ pci_get_strings@Base 0
+ pci_device_map_memory_range@Base 0
+ pci_device_get_subvendor_name@Base 0
+ pci_device_probe@Base 0
+ pci_device_cfg_write@Base 0
+ pci_device_unmap_region@Base 0
+ pci_device_vgaarb_decodes@Base 0.10.7
+ pci_device_vgaarb_fini@Base 0.10.7
+ pci_device_vgaarb_get_info@Base 0.10.7
+ pci_device_vgaarb_init@Base 0.10.7
+ pci_device_vgaarb_lock@Base 0.10.7
+ pci_device_vgaarb_set_target@Base 0.10.7
+ pci_device_vgaarb_trylock@Base 0.10.7
+ pci_device_vgaarb_unlock@Base 0.10.7
+ pci_device_cfg_read_u16@Base 0
+ pci_device_get_device_name@Base 0
+ pci_device_find_by_slot@Base 0
+ pci_id_match_iterator_create@Base 0
+ pci_device_cfg_write_u8@Base 0
+ pci_device_get_subdevice_name@Base 0
+ pci_device_unmap_range@Base 0.8.0+git20071002
+ pci_device_get_bridge_info@Base 0
+ pci_system_cleanup@Base 0
+ pci_device_cfg_read_u8@Base 0
+ pci_iterator_destroy@Base 0
+ pci_device_read_rom@Base 0
+ pci_device_map_range@Base 0.8.0+git20071002
+ pci_slot_match_iterator_create@Base 0
+ pci_device_cfg_write_u32@Base 0
+ pci_device_unmap_memory_range@Base 0
+ pci_device_get_agp_info@Base 0
+ pci_device_get_pcmcia_bridge_info@Base 0
+ pci_device_get_bridge_buses@Base 0
+ pci_device_cfg_write_bits@Base 0
+ pci_device_get_vendor_name@Base 0
+ pci_device_has_kernel_driver@Base 0.10.7
+ pci_device_is_boot_vga@Base 0.10.7
+ pci_device_cfg_read@Base 0
+ pci_device_get_parent_bridge@Base 0.11.0
+ pci_device_open_io@Base 0.11.0
+ pci_device_close_io@Base 0.11.0
+ pci_legacy_open_io@Base 0.11.0
+ pci_io_read8@Base 0.11.0
+ pci_io_read16@Base 0.11.0
+ pci_io_read32@Base 0.11.0
+ pci_io_write8@Base 0.11.0
+ pci_io_write16@Base 0.11.0
+ pci_io_write32@Base 0.11.0
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..b703b74
--- /dev/null
@@ -0,0 +1,97 @@
+#!/usr/bin/make -f
+
+PACKAGE = libpciaccess0
+
+CFLAGS = -Wall -g
+ifneq (,$(filter noopt,$(DEB_BUILD_OPTIONS)))
+       CFLAGS += -O0
+else
+       CFLAGS += -O2
+endif
+ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+       NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+       MAKEFLAGS += -j$(NUMJOBS)
+endif
+
+DEB_HOST_ARCH      ?= $(shell dpkg-architecture -qDEB_HOST_ARCH)
+DEB_HOST_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE))
+       confflags += --build=$(DEB_HOST_GNU_TYPE)
+else
+       confflags += --build=$(DEB_HOST_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE)
+#      confflags += --build=$(DEB_BUILD_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE)
+endif
+
+configure:
+       autoreconf -vfi
+
+obj-$(DEB_BUILD_GNU_TYPE)/config.status: configure
+       mkdir -p obj-$(DEB_BUILD_GNU_TYPE)
+       cd obj-$(DEB_BUILD_GNU_TYPE) && \
+       ../configure \
+         --prefix=/usr \
+         --mandir=\$${prefix}/share/man \
+         --infodir=\$${prefix}/share/info \
+         --with-pciids-path=\$${prefix}/share/misc \
+         --with-zlib \
+         $(confflags) \
+         CFLAGS="$(CFLAGS)" 
+
+build: build-stamp
+build-stamp: obj-$(DEB_BUILD_GNU_TYPE)/config.status
+       dh_testdir
+       cd obj-$(DEB_BUILD_GNU_TYPE) && $(MAKE)
+       
+       touch build-stamp
+
+clean: 
+       dh_testdir
+       dh_testroot
+       rm -f build-stamp
+       
+       rm -f config.cache config.log config.status
+       rm -f */config.cache */config.log */config.status
+       rm -f conftest* */conftest*
+#      rm -rf autom4te.cache */autom4te.cache
+       rm -rf obj-*
+       rm -f $$(find -name Makefile.in)
+       rm -f compile config.guess config.sub configure depcomp install-sh
+       rm -f ltmain.sh missing INSTALL aclocal.m4 mkinstalldirs config.h.in
+       rm -f m4/libtool.m4 m4/lt*.m4
+       
+       dh_clean
+
+install: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs
+
+       cd obj-$(DEB_BUILD_GNU_TYPE) && $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
+
+# Install architecture-dependent files here.
+binary-arch: build install
+       dh_testdir
+       dh_testroot
+
+#      dh_installdocs
+       dh_install --sourcedir=debian/tmp --list-missing
+#      dh_installchangelogs ChangeLog
+       dh_link
+       dh_strip --dbg-package=$(PACKAGE)-dbg
+       dh_compress
+       dh_fixperms
+       dh_makeshlibs -V'libpciaccess0 (>= 0.11.0)'
+#      dh_makeshlibs -V'libpciaccess0 (>= 0.11.0)' --add-udeb=$(PACKAGE)-udeb
+       dh_shlibdeps
+       dh_installdeb
+       dh_gencontrol
+       dh_md5sums
+       dh_builddeb
+
+binary-indep: build install
+# Nothing to do
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/debian/watch b/debian/watch
new file mode 100644 (file)
index 0000000..afa5008
--- /dev/null
@@ -0,0 +1,2 @@
+version=3
+http://xorg.freedesktop.org/releases/individual/lib/ libpciaccess-(.*)\.tar\.gz
diff --git a/include/pciaccess.h b/include/pciaccess.h
new file mode 100644 (file)
index 0000000..88515e2
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * Copyright 2009 Red Hat, Inc.
+ * 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.
+ */
+/*
+ * Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti
+ *
+ * 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 the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, 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 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
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS 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>
+ */
+
+#ifndef PCIACCESS_H
+#define PCIACCESS_H
+
+#include <inttypes.h>
+
+#if __GNUC__ >= 3
+#define __deprecated __attribute__((deprecated))
+#else
+#define __deprecated 
+#endif
+
+typedef uint64_t pciaddr_t;
+
+struct pci_device;
+struct pci_device_iterator;
+struct pci_id_match;
+struct pci_slot_match;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int pci_device_has_kernel_driver(struct pci_device *dev);
+
+int pci_device_is_boot_vga(struct pci_device *dev);
+
+int pci_device_read_rom(struct pci_device *dev, void *buffer);
+
+int  __deprecated pci_device_map_region(struct pci_device *dev,
+    unsigned region, int write_enable);
+
+int __deprecated pci_device_unmap_region(struct pci_device *dev,
+    unsigned region);
+
+int pci_device_map_range(struct pci_device *dev, pciaddr_t base,
+    pciaddr_t size, unsigned map_flags, void **addr);
+
+int pci_device_unmap_range(struct pci_device *dev, void *memory,
+    pciaddr_t size);
+
+int __deprecated pci_device_map_memory_range(struct pci_device *dev,
+    pciaddr_t base, pciaddr_t size, int write_enable, void **addr);
+
+int __deprecated pci_device_unmap_memory_range(struct pci_device *dev,
+    void *memory, pciaddr_t size);
+
+int pci_device_probe(struct pci_device *dev);
+
+const struct pci_agp_info *pci_device_get_agp_info(struct pci_device *dev);
+
+const struct pci_bridge_info *pci_device_get_bridge_info(
+    struct pci_device *dev);
+
+const struct pci_pcmcia_bridge_info *pci_device_get_pcmcia_bridge_info(
+    struct pci_device *dev);
+
+int pci_device_get_bridge_buses(struct pci_device *dev, int *primary_bus,
+    int *secondary_bus, int *subordinate_bus);
+
+int pci_system_init(void);
+
+void pci_system_init_dev_mem(int fd);
+
+void pci_system_cleanup(void);
+
+struct pci_device_iterator *pci_slot_match_iterator_create(
+    const struct pci_slot_match *match);
+
+struct pci_device_iterator *pci_id_match_iterator_create(
+    const struct pci_id_match *match);
+
+void pci_iterator_destroy(struct pci_device_iterator *iter);
+
+struct pci_device *pci_device_next(struct pci_device_iterator *iter);
+
+struct pci_device *pci_device_find_by_slot(uint32_t domain, uint32_t bus,
+    uint32_t dev, uint32_t func);
+
+struct pci_device *pci_device_get_parent_bridge(struct pci_device *dev);
+
+void pci_get_strings(const struct pci_id_match *m,
+    const char **device_name, const char **vendor_name,
+    const char **subdevice_name, const char **subvendor_name);
+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);
+
+void pci_device_enable(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, uint8_t  data,
+    pciaddr_t offset);
+int pci_device_cfg_write_u16(struct pci_device *dev, uint16_t data,
+    pciaddr_t offset);
+int pci_device_cfg_write_u32(struct pci_device *dev, uint32_t data,
+    pciaddr_t offset);
+int pci_device_cfg_write_bits(struct pci_device *dev, uint32_t mask,
+    uint32_t data, pciaddr_t offset);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * \name Mapping flags passed to \c pci_device_map_range
+ */
+/*@{*/
+#define PCI_DEV_MAP_FLAG_WRITABLE       (1U<<0)
+#define PCI_DEV_MAP_FLAG_WRITE_COMBINE  (1U<<1)
+#define PCI_DEV_MAP_FLAG_CACHABLE       (1U<<2)
+/*@}*/
+
+
+#define PCI_MATCH_ANY  (~0)
+
+/**
+ * Compare two PCI ID values (either vendor or device).  This is used
+ * internally to compare the fields of \c pci_id_match to the fields of
+ * \c pci_device.
+ */
+#define PCI_ID_COMPARE(a, b) \
+    (((a) == PCI_MATCH_ANY) || ((a) == (b)))
+
+/**
+ */
+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;
+};
+
+
+/**
+ */
+struct pci_slot_match {
+    /**
+     * \name Device slot matching controls
+     *
+     * Control the search based on the domain, bus, slot, and function of
+     * the device.  Setting any of these fields to \c PCI_MATCH_ANY will cause
+     * the field to not be used in the comparison.
+     */
+    /*@{*/
+    uint32_t    domain;
+    uint32_t    bus;
+    uint32_t    dev;
+    uint32_t    func;
+    /*@}*/
+
+    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.
+     *
+     * This field is \b only set when the deprecated \c pci_device_map_region
+     * interface is used.  Use \c pci_device_map_range instead.
+     *
+     * \deprecated
+     */
+    void *memory;
+
+
+    /**
+     * Base physical address of the region within its bus / domain.
+     *
+     * \warning
+     * This address is really only useful to other devices in the same
+     * domain.  It's probably \b not the address applications will ever
+     * use.
+     * 
+     * \warning
+     * Most (all?) platform back-ends leave this field unset.
+     */
+    pciaddr_t bus_addr;
+
+
+    /**
+     * Base physical address of the region from the CPU's point of view.
+     * 
+     * This address is typically passed to \c pci_device_map_range to create
+     * a mapping of the region to the CPU's virtual address space.
+     */
+    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, subclass, and programming interface packed into a
+     * single 32-bit value.  The class is at bits [23:16], subclass is at
+     * bits [15:8], and programming interface is at [7:0].
+     */
+    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.
+     */
+    intptr_t user_data;
+
+    /**
+      * Used by the VGA arbiter. Type of resource decoded by the device and
+      * the file descriptor (/dev/vga_arbiter). */
+    int vgaarb_rsrc;
+};
+
+
+/**
+ * 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;
+
+    unsigned int    fast_writes:1;  /**< Are fast-writes supported? */
+    unsigned int    addr64:1;
+    unsigned int    htrans:1;
+    unsigned int    gart64:1;
+    unsigned int    coherent:1;
+    unsigned int    sideband:1;     /**< Is side-band addressing supported? */
+    unsigned int    isochronus:1;
+
+    uint8_t    async_req_size;
+    uint8_t    calibration_cycle_timing;
+    uint8_t    max_requests;
+};
+
+/**
+ * Description of a PCI-to-PCI bridge device.
+ *
+ * \sa pci_device_get_bridge_info
+ */
+struct pci_bridge_info {
+    uint8_t    primary_bus;
+    uint8_t    secondary_bus;
+    uint8_t    subordinate_bus;
+    uint8_t    secondary_latency_timer;
+
+    uint8_t     io_type;
+    uint8_t     mem_type;
+    uint8_t     prefetch_mem_type;
+
+    uint16_t    secondary_status;
+    uint16_t    bridge_control;
+
+    uint32_t    io_base;
+    uint32_t    io_limit;
+
+    uint32_t    mem_base;
+    uint32_t    mem_limit;
+
+    uint64_t    prefetch_mem_base;
+    uint64_t    prefetch_mem_limit;
+};
+
+/**
+ * Description of a PCI-to-PCMCIA bridge device.
+ *
+ * \sa pci_device_get_pcmcia_bridge_info
+ */
+struct pci_pcmcia_bridge_info {
+    uint8_t    primary_bus;
+    uint8_t    card_bus;
+    uint8_t    subordinate_bus;
+    uint8_t    cardbus_latency_timer;
+    
+    uint16_t    secondary_status;
+    uint16_t    bridge_control;
+
+    struct {
+       uint32_t    base;
+       uint32_t    limit;
+    } io[2];
+
+    struct {
+       uint32_t    base;
+       uint32_t    limit;
+    } mem[2];
+
+};
+
+
+/**
+ * VGA Arbiter definitions, functions and related.
+ */
+
+/* Legacy VGA regions */
+#define VGA_ARB_RSRC_NONE       0x00
+#define VGA_ARB_RSRC_LEGACY_IO  0x01
+#define VGA_ARB_RSRC_LEGACY_MEM 0x02
+/* Non-legacy access */
+#define VGA_ARB_RSRC_NORMAL_IO  0x04
+#define VGA_ARB_RSRC_NORMAL_MEM 0x08
+
+int  pci_device_vgaarb_init         (void);
+void pci_device_vgaarb_fini         (void);
+int  pci_device_vgaarb_set_target   (struct pci_device *dev);
+/* use the targetted device */
+int  pci_device_vgaarb_decodes      (int new_vga_rsrc);
+int  pci_device_vgaarb_lock         (void);
+int  pci_device_vgaarb_trylock      (void);
+int  pci_device_vgaarb_unlock       (void);
+/* return the current device count + resource decodes for the device */
+int pci_device_vgaarb_get_info     (struct pci_device *dev, int *vga_count, int *rsrc_decodes);
+
+/*
+ * I/O space access.
+ */
+
+struct pci_io_handle;
+
+struct pci_io_handle *pci_device_open_io(struct pci_device *dev, pciaddr_t base,
+                                        pciaddr_t size);
+struct pci_io_handle *pci_legacy_open_io(struct pci_device *dev, pciaddr_t base,
+                                        pciaddr_t size);
+void pci_device_close_io(struct pci_device *dev, struct pci_io_handle *handle);
+uint32_t pci_io_read32(struct pci_io_handle *handle, uint32_t reg);
+uint16_t pci_io_read16(struct pci_io_handle *handle, uint32_t reg);
+uint8_t pci_io_read8(struct pci_io_handle *handle, uint32_t reg);
+void pci_io_write32(struct pci_io_handle *handle, uint32_t reg, uint32_t data);
+void pci_io_write16(struct pci_io_handle *handle, uint32_t reg, uint16_t data);
+void pci_io_write8(struct pci_io_handle *handle, uint32_t reg, uint8_t data);
+
+#endif /* PCIACCESS_H */
diff --git a/m4/ac_define_dir.m4 b/m4/ac_define_dir.m4
new file mode 100644 (file)
index 0000000..db42d3e
--- /dev/null
@@ -0,0 +1,49 @@
+# ===========================================================================
+#             http://autoconf-archive.cryp.to/ac_define_dir.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AC_DEFINE_DIR(VARNAME, DIR [, DESCRIPTION])
+#
+# DESCRIPTION
+#
+#   This macro sets VARNAME to the expansion of the DIR variable, taking
+#   care of fixing up ${prefix} and such.
+#
+#   VARNAME is then offered as both an output variable and a C preprocessor
+#   symbol.
+#
+#   Example:
+#
+#      AC_DEFINE_DIR([DATADIR], [datadir], [Where data are placed to.])
+#
+# LAST MODIFICATION
+#
+#   2008-04-12
+#
+# COPYLEFT
+#
+#   Copyright (c) 2008 Stepan Kasal <kasal@ucw.cz>
+#   Copyright (c) 2008 Andreas Schwab <schwab@suse.de>
+#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+#   Copyright (c) 2008 Alexandre Oliva
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.
+
+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
+])
diff --git a/packaging/libpciaccess.spec b/packaging/libpciaccess.spec
new file mode 100644 (file)
index 0000000..900bd0d
--- /dev/null
@@ -0,0 +1,65 @@
+
+Name:       libpciaccess
+Summary:    PCI access library
+Version:    0.12.0
+Release:    0
+Group:      System/Libraries
+License:    MIT
+URL:        http://www.x.org/
+Source0:    http://xorg.freedesktop.org/archive/individual/lib/%{name}-%{version}.tar.bz2
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+BuildRequires:  zlib-devel
+
+
+%description
+Generic PCI access library
+
+
+%package devel
+Summary:    PCI access library development package
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+Generic PCI access library development package
+
+
+%prep
+%setup -q -n %{name}-%{version}
+
+
+%build
+
+%configure --disable-static \
+    --with-pciids-path=%{_prefix}/share/misc --with-zlib \
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+
+
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+
+
+
+
+%files
+%defattr(-,root,root,-)
+%{_libdir}/libpciaccess.so.0
+%{_libdir}/libpciaccess.so.0.10.8
+
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/pciaccess.h
+%{_libdir}/libpciaccess.so
+%{_libdir}/pkgconfig/pciaccess.pc
+
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/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..0ee8449
--- /dev/null
@@ -0,0 +1,83 @@
+# 
+# (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.
+
+AM_CFLAGS = $(CWARNFLAGS) @PCIACCESS_CFLAGS@
+
+lib_LTLIBRARIES = libpciaccess.la
+
+if LINUX
+OS_SUPPORT = linux_sysfs.c linux_devmem.c linux_devmem.h
+endif
+
+if FREEBSD
+OS_SUPPORT = freebsd_pci.c
+endif
+
+if NETBSD
+OS_SUPPORT = netbsd_pci.c
+endif
+
+if OPENBSD
+OS_SUPPORT = openbsd_pci.c
+endif
+
+if SOLARIS
+OS_SUPPORT = solx_devfs.c pci_tools.h
+endif
+
+if LINUX
+VGA_ARBITER = common_vgaarb.c
+else
+VGA_ARBITER = common_vgaarb_stub.c
+endif
+
+if GNU
+OS_SUPPORT = x86_pci.c
+endif
+
+libpciaccess_la_SOURCES = common_bridge.c \
+       common_iterator.c \
+       common_init.c \
+       common_interface.c \
+       common_io.c \
+       common_capability.c \
+       common_device_name.c \
+       common_map.c \
+       pciaccess_private.h \
+       $(VGA_ARBITER) \
+       $(OS_SUPPORT)
+
+INCLUDES = -I$(top_srcdir)/include
+
+libpciaccess_la_LIBADD = $(PCIACCESS_LIBS)
+
+libpciaccess_la_LDFLAGS = -version-number 0:10:8 -no-undefined
+
+libpciaccessincludedir = $(includedir)
+libpciaccessinclude_HEADERS = \
+    $(top_srcdir)/include/pciaccess.h
+
+noinst_PROGRAMS = scanpci
+
+scanpci_SOURCES = scanpci.c
+scanpci_LDADD = libpciaccess.la
diff --git a/src/common_bridge.c b/src/common_bridge.c
new file mode 100644 (file)
index 0000000..f37420f
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * (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_bridge.c
+ * Support routines used to process PCI header information for bridges.
+ * 
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.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"
+#include "pciaccess_private.h"
+
+static int
+read_bridge_info( struct pci_device_private * priv )
+{
+    uint8_t  buf[0x40];
+    pciaddr_t bytes;
+    int err;
+
+
+    /* Make sure the device has been probed.  If not, header_type won't be
+     * set and the rest of this function will fail.
+     */
+    err = pci_device_probe(& priv->base);
+    if (err) {
+       return err;
+    }
+
+    switch ( priv->header_type & 0x7f ) {
+    case 0x00:
+       break;
+
+    case 0x01: {
+       struct pci_bridge_info *info;
+
+       info = malloc(sizeof(*info));
+       if (info != NULL) {
+           pci_device_cfg_read( (struct pci_device *) priv, buf + 0x18, 0x18, 
+                                0x40 - 0x18, & bytes );
+
+           info->primary_bus = buf[0x18];
+           info->secondary_bus = buf[0x19];
+           info->subordinate_bus = buf[0x1a];
+           info->secondary_latency_timer = buf[0x1b];
+
+           info->io_type = buf[0x1c] & 0x0f;
+           info->io_base = (((uint32_t) (buf[0x1c] & 0x0f0)) << 8)
+             + (((uint32_t) buf[0x30]) << 16)
+             + (((uint32_t) buf[0x31]) << 24);
+
+           info->io_limit = 0x00000fff
+             + (((uint32_t) (buf[0x1d] & 0x0f0)) << 8)
+             + (((uint32_t) buf[0x32]) << 16)
+             + (((uint32_t) buf[0x33]) << 24);
+
+           info->mem_type = buf[0x20] & 0x0f;
+           info->mem_base = (((uint32_t) (buf[0x20] & 0x0f0)) << 16)
+             + (((uint32_t) buf[0x21]) << 24);
+
+           info->mem_limit = 0x0000ffff
+             + (((uint32_t) (buf[0x22] & 0x0f0)) << 16)
+             + (((uint32_t) buf[0x23]) << 24);
+
+           info->prefetch_mem_type = buf[0x24] & 0x0f;
+           info->prefetch_mem_base = (((uint64_t) (buf[0x24] & 0x0f0)) << 16)
+             + (((uint64_t) buf[0x25]) << 24)
+             + (((uint64_t) buf[0x28]) << 32)
+             + (((uint64_t) buf[0x29]) << 40)
+             + (((uint64_t) buf[0x2a]) << 48)
+             + (((uint64_t) buf[0x2b]) << 56);
+
+           info->prefetch_mem_limit = 0x0000ffff
+             + (((uint64_t) (buf[0x26] & 0x0f0)) << 16)
+             + (((uint64_t) buf[0x27]) << 24)
+             + (((uint64_t) buf[0x2c]) << 32)
+             + (((uint64_t) buf[0x2d]) << 40)
+             + (((uint64_t) buf[0x2e]) << 48)
+             + (((uint64_t) buf[0x2f]) << 56);
+
+           info->bridge_control = ((uint16_t) buf[0x3e])
+             + (((uint16_t) buf[0x3f]) << 8);
+
+           info->secondary_status = ((uint16_t) buf[0x1e])
+             + (((uint16_t) buf[0x1f]) << 8);
+       }
+
+       priv->bridge.pci = info;
+       break;
+    }
+
+    case 0x02: {
+       struct pci_pcmcia_bridge_info *info;
+
+       info = malloc(sizeof(*info));
+       if (info != NULL) {
+           pci_device_cfg_read( (struct pci_device *) priv, buf + 0x16, 0x16,
+                                0x40 - 0x16, & bytes );
+
+           info->primary_bus = buf[0x18];
+           info->card_bus = buf[0x19];
+           info->subordinate_bus = buf[0x1a];
+           info->cardbus_latency_timer = buf[0x1b];
+
+           info->mem[0].base = (((uint32_t) buf[0x1c]))
+             + (((uint32_t) buf[0x1d]) << 8)
+             + (((uint32_t) buf[0x1e]) << 16)
+             + (((uint32_t) buf[0x1f]) << 24);
+
+           info->mem[0].limit = (((uint32_t) buf[0x20]))
+             + (((uint32_t) buf[0x21]) << 8)
+             + (((uint32_t) buf[0x22]) << 16)
+             + (((uint32_t) buf[0x23]) << 24);
+
+           info->mem[1].base = (((uint32_t) buf[0x24]))
+             + (((uint32_t) buf[0x25]) << 8)
+             + (((uint32_t) buf[0x26]) << 16)
+             + (((uint32_t) buf[0x27]) << 24);
+
+           info->mem[1].limit = (((uint32_t) buf[0x28]))
+             + (((uint32_t) buf[0x29]) << 8)
+             + (((uint32_t) buf[0x2a]) << 16)
+             + (((uint32_t) buf[0x2b]) << 24);
+
+           info->io[0].base = (((uint32_t) buf[0x2c]))
+             + (((uint32_t) buf[0x2d]) << 8)
+             + (((uint32_t) buf[0x2e]) << 16)
+             + (((uint32_t) buf[0x2f]) << 24);
+
+           info->io[0].limit = (((uint32_t) buf[0x30]))
+             + (((uint32_t) buf[0x31]) << 8)
+             + (((uint32_t) buf[0x32]) << 16)
+             + (((uint32_t) buf[0x33]) << 24);
+
+           info->io[1].base = (((uint32_t) buf[0x34]))
+             + (((uint32_t) buf[0x35]) << 8)
+             + (((uint32_t) buf[0x36]) << 16)
+             + (((uint32_t) buf[0x37]) << 24);
+
+           info->io[1].limit = (((uint32_t) buf[0x38]))
+             + (((uint32_t) buf[0x39]) << 8)
+             + (((uint32_t) buf[0x3a]) << 16)
+             + (((uint32_t) buf[0x3b]) << 24);
+
+           info->secondary_status = ((uint16_t) buf[0x16])
+             + (((uint16_t) buf[0x17]) << 8);
+
+           info->bridge_control = ((uint16_t) buf[0x3e])
+             + (((uint16_t) buf[0x3f]) << 8);
+       }
+
+       priv->bridge.pcmcia = info;
+       break;
+    }
+    }
+
+    return 0;
+}
+
+
+/**
+ * Get the PCI bridge information for a device
+ *
+ * \returns
+ * If \c dev is a PCI-to-PCI bridge, a pointer to a \c pci_bridge_info
+ * structure.  Otherwise, \c NULL is returned.
+ */
+const struct pci_bridge_info *
+pci_device_get_bridge_info( struct pci_device * dev )
+{
+    struct pci_device_private * priv = (struct pci_device_private *) dev;
+
+    if (priv->bridge.pci == NULL) {
+       read_bridge_info(priv);
+    }
+
+    return (priv->header_type == 1) ? priv->bridge.pci : NULL;
+}
+
+
+/**
+ * Get the PCMCIA bridge information for a device
+ *
+ * \returns
+ * If \c dev is a PCI-to-PCMCIA bridge, a pointer to a
+ * \c pci_pcmcia_bridge_info structure.  Otherwise, \c NULL is returned.
+ */
+const struct pci_pcmcia_bridge_info *
+pci_device_get_pcmcia_bridge_info( struct pci_device * dev )
+{
+    struct pci_device_private * priv = (struct pci_device_private *) dev;
+
+    if (priv->bridge.pcmcia == NULL) {
+       read_bridge_info(priv);
+    }
+
+    return (priv->header_type == 2) ? priv->bridge.pcmcia : NULL;
+}
+
+
+/**
+ * Determine the primary, secondary, and subordinate buses for a bridge
+ * 
+ * Determines the IDs of the primary, secondary, and subordinate buses for
+ * a specified bridge.  Not all bridges directly store this information
+ * (e.g., PCI-to-ISA bridges).  For those bridges, no error is returned, but
+ * -1 is stored in the bus IDs that don't make sense.
+ *
+ * For example, for a PCI-to-ISA bridge, \c primary_bus will be set to the ID
+ * of the bus containing the device and both \c secondary_bus and
+ * \c subordinate_bus will be set to -1.
+ *
+ * \return
+ * On success, zero is returned.  If \c dev is not a bridge, \c ENODEV is
+ * returned.
+ * 
+ * \bug
+ * Host bridges are handled the same way as PCI-to-ISA bridges.  This is
+ * almost certainly not correct.
+ */
+int
+pci_device_get_bridge_buses(struct pci_device * dev, int *primary_bus,
+                           int *secondary_bus, int *subordinate_bus)
+{
+    struct pci_device_private * priv = (struct pci_device_private *) dev;
+
+    /* If the device isn't a bridge, return an error.
+     */
+    
+    if (((dev->device_class >> 16) & 0x0ff) != 0x06) {
+       return ENODEV;
+    }
+
+    if (!priv->bridge.pci) {
+       return ENODEV;
+    }
+
+    switch ((dev->device_class >> 8) & 0x0ff) {
+    case 0x00:
+       /* What to do for host bridges?  I'm pretty sure this isn't right.
+        */
+       *primary_bus = dev->bus;
+       *secondary_bus = -1;
+       *subordinate_bus = -1;
+       break;
+
+    case 0x01:
+    case 0x02:
+    case 0x03:
+       *primary_bus = dev->bus;
+       *secondary_bus = -1;
+       *subordinate_bus = -1;
+       break;
+
+    case 0x04:
+    if (priv->bridge.pci == NULL)
+        read_bridge_info(priv);
+    if (priv->header_type == 0x01) {
+       *primary_bus = priv->bridge.pci->primary_bus;
+       *secondary_bus = priv->bridge.pci->secondary_bus;
+       *subordinate_bus = priv->bridge.pci->subordinate_bus;
+    } else {
+       *primary_bus = dev->bus;
+       *secondary_bus = -1;
+       *subordinate_bus = -1;
+    }
+       break;
+
+    case 0x07:
+    if (priv->bridge.pcmcia == NULL)
+        read_bridge_info(priv);
+    if (priv->header_type == 0x02) {
+       *primary_bus = priv->bridge.pcmcia->primary_bus;
+       *secondary_bus = priv->bridge.pcmcia->card_bus;
+       *subordinate_bus = priv->bridge.pcmcia->subordinate_bus;
+    } else {
+       *primary_bus = dev->bus;
+       *secondary_bus = -1;
+       *subordinate_bus = -1;
+    }
+       break;
+    }
+
+    return 0;
+}
+
+#define PCI_CLASS_BRIDGE 0x06
+#define PCI_SUBCLASS_BRIDGE_PCI 0x04
+
+struct pci_device *
+pci_device_get_parent_bridge(struct pci_device *dev)
+{
+    struct pci_id_match bridge_match = {
+        PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY,
+        (PCI_CLASS_BRIDGE << 16) | (PCI_SUBCLASS_BRIDGE_PCI << 8),
+        0
+    };
+
+    struct pci_device *bridge;
+    struct pci_device_iterator *iter;
+
+    if (dev == NULL)
+        return NULL;
+
+    iter = pci_id_match_iterator_create(& bridge_match);
+    if (iter == NULL)
+        return NULL;
+
+    while ((bridge = pci_device_next(iter)) != NULL) {
+        if (bridge->domain == dev->domain) {
+            const struct pci_bridge_info *info =
+                pci_device_get_bridge_info(bridge);
+
+            if (info != NULL) {
+                if (info->secondary_bus == dev->bus) {
+                    break;
+                }
+            }
+        }
+    }
+
+    pci_iterator_destroy(iter);
+
+    return bridge;
+}
diff --git a/src/common_capability.c b/src/common_capability.c
new file mode 100644 (file)
index 0000000..3963db1
--- /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.
+ */
+_pci_hidden 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;
+           uint32_t agp_status;
+           uint8_t agp_ver;
+
+
+           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 = calloc( 1, sizeof( struct pci_agp_info ) );
+           if ( agp_info == NULL ) {
+               return ENOMEM;
+           }
+
+           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..896a8a3
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * (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"
+#include "pciaccess_private.h"
+
+#define DO_MATCH(a,b)  (((a) == PCI_MATCH_ANY) || ((a) == (b)))
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+typedef gzFile pci_id_file;
+
+static pci_id_file
+pci_id_file_open(void)
+{
+    pci_id_file result;
+
+    result = gzopen(PCIIDS_PATH "/pci.ids.gz", "rb");
+    if (result)
+        return result;
+
+    return gzopen(PCIIDS_PATH "/pci.ids", "rb");
+}
+
+#define pci_id_file_gets(l, s, f)      gzgets(f, l, s)
+#define pci_id_file_close(f)           gzclose(f)
+#else
+typedef FILE pci_id_file;
+#define pci_id_file_open()             fopen(PCIIDS_PATH "/pci.ids", "r")
+#define pci_id_file_gets(l, s, f)      fgets(l, s, f)
+#define pci_id_file_close(f)           fclose(f)
+#endif
+
+/**
+ * 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.
+ */
+_pci_hidden struct pci_id_node * tree = NULL;
+
+/**
+ * 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 )
+{
+    pci_id_file * f;
+    char buf[128];
+    unsigned vendor = PCI_MATCH_ANY;
+
+
+    /* If the device tree for this vendor is already populated, don't do
+     * anything.  This avoids wasted processing and potential memory leaks.
+     */
+    if (vend->num_devices != 0) {
+       return;
+    }
+
+    f = pci_id_file_open();
+    
+    /* If the pci.ids file could not be opened, there's nothing we can do.
+     */
+    if (f == NULL) {
+       return;
+    }
+
+    while( pci_id_file_gets( 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 ) {
+               /* vendor_name may already be set from a previous invocation
+                * of this function with fill_device_data = 0.
+                */
+               if (vend->vendor_name == NULL) {
+                   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 ] );
+           }
+       }
+    }
+    
+    pci_id_file_close( f );
+}
+
+
+/**
+ * Find the name of the specified device.
+ *
+ * Finds the actual product name of the specified device.  If a subvendor ID
+ * and subdevice ID are specified in \c m, the returned name will be the name
+ * of the subdevice.
+ */
+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;
+}
+
+
+/**
+ * Find the vendor name of the specified device.
+ *
+ * Finds the actual vendor name of the specified device.  If a subvendor ID
+ * and subdevice ID are specified in \c m, the returned name will be the name
+ * associated with the subvendor.
+ */
+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.
+ */
+void
+pci_get_strings( const struct pci_id_match * m,
+                const char ** device_name,
+                const char ** vendor_name,
+                const char ** subdevice_name,
+                const char ** subvendor_name )
+{
+    struct pci_id_match  temp;
+
+
+    temp = *m;
+    temp.subvendor_id = PCI_MATCH_ANY;
+    temp.subdevice_id = PCI_MATCH_ANY;
+
+    if ( device_name != NULL ) {
+       *device_name = find_device_name( & temp );
+    }
+
+    if ( vendor_name != NULL ) {
+       *vendor_name = find_vendor_name( & temp );
+    }
+
+    if ( subdevice_name != NULL ) {
+       *subdevice_name = find_device_name( m );
+    }
+
+    if ( subvendor_name != NULL ) {
+       *subvendor_name = find_vendor_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..89c56ad
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * (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"
+
+_pci_hidden 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();
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+    err = pci_system_freebsd_create();
+#elif defined(__NetBSD__)
+    err = pci_system_netbsd_create();
+#elif defined(__OpenBSD__)
+    err = pci_system_openbsd_create();
+#elif defined(__sun)
+    err = pci_system_solx_devfs_create();
+#elif defined(__GNU__)
+    err = pci_system_x86_create();
+#endif
+
+    return err;
+}
+
+void
+pci_system_init_dev_mem(int fd)
+{
+#ifdef __OpenBSD__
+    pci_system_openbsd_init_dev_mem(fd);
+#endif
+}
+
+/**
+ * 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;
+    }
+
+    pci_io_cleanup();
+
+    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..4af772a
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * (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 <string.h>
+#include <errno.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+#if defined(__linux__) || defined(__GLIBC__)
+#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 /* linux */
+
+#elif defined(__sun)
+
+#include <sys/byteorder.h>
+
+#ifdef _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 /* Solaris */
+
+#else
+
+#include <sys/endian.h>
+
+#define HTOLE_16(x)    htole16(x)
+#define HTOLE_32(x)    htole32(x)
+
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
+#define LETOH_16(x)    le16toh(x)
+#define LETOH_32(x)    le32toh(x)
+#else
+#define LETOH_16(x)    letoh16(x)
+#define LETOH_32(x)    letoh32(x)
+#endif
+
+#endif /* others */
+
+/**
+ * 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 (VGA) device to determine if its the boot VGA device
+ *
+ * \param dev    Device whose VGA status to query
+ * \return
+ * Zero if not the boot VGA, 1 if the boot VGA.
+ */
+int
+pci_device_is_boot_vga( struct pci_device * dev )
+{
+       if (!pci_sys->methods->boot_vga)
+               return 0;
+       return pci_sys->methods->boot_vga( dev );
+}
+
+/**
+ * Probe a PCI device to determine if a kernel driver is attached.
+ * 
+ * \param dev Device to query
+ * \return
+ * Zero if no driver attached, 1 if attached kernel drviver
+ */
+int
+pci_device_has_kernel_driver( struct pci_device * dev )
+{
+       if (!pci_sys->methods->has_kernel_driver)
+               return 0;
+       return pci_sys->methods->has_kernel_driver( dev );
+}
+
+/**
+ * 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 success 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 access 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_map_range, pci_device_unmap_range
+ * \deprecated
+ */
+int
+pci_device_map_region(struct pci_device * dev, unsigned region,
+                      int write_enable)
+{
+    const unsigned map_flags =
+        (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE : 0;
+
+    if ((region > 5) || (dev->regions[region].size == 0))  {
+        return ENOENT;
+    }
+
+    if (dev->regions[region].memory != NULL) {
+        return 0;
+    }
+    
+    return pci_device_map_range(dev, dev->regions[region].base_addr,
+                                dev->regions[region].size, map_flags,
+                                &dev->regions[region].memory);
+}
+
+
+/**
+ * Map the specified memory range so that it can be accessed by the CPU.
+ *
+ * Maps the specified memory range for access by the processor.  The pointer
+ * to the mapped region is stored in \c addr.  In addition, the
+ * \c pci_mem_region::memory pointer for the BAR will be updated.
+ *
+ * \param dev          Device whose memory region is to be mapped.
+ * \param base         Base address of the range to be mapped.
+ * \param size         Size of the range to be mapped.
+ * \param write_enable Map for writing (non-zero).
+ * \param addr         Location to store the mapped address.
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_map_range
+ */
+int pci_device_map_memory_range(struct pci_device *dev,
+                               pciaddr_t base, pciaddr_t size,
+                               int write_enable, void **addr)
+{
+    return pci_device_map_range(dev, base, size,
+                               (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE : 0,
+                               addr);
+}
+
+
+/**
+ * Map the specified memory range so that it can be accessed by the CPU.
+ *
+ * Maps the specified memory range for access by the processor.  The pointer
+ * to the mapped region is stored in \c addr.  In addition, the
+ * \c pci_mem_region::memory pointer for the BAR will be updated.
+ *
+ * \param dev          Device whose memory region is to be mapped.
+ * \param base         Base address of the range to be mapped.
+ * \param size         Size of the range to be mapped.
+ * \param map_flags    Flag bits controlling how the mapping is accessed.
+ * \param addr         Location to store the mapped address.
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_unmap_range
+ */
+int
+pci_device_map_range(struct pci_device *dev, pciaddr_t base,
+                     pciaddr_t size, unsigned map_flags,
+                     void **addr)
+{
+    struct pci_device_private *const devp =
+        (struct pci_device_private *) dev;
+    struct pci_device_mapping *mappings;
+    unsigned region;
+    unsigned i;
+    int err = 0;
+
+
+    *addr = NULL;
+
+    if (dev == NULL) {
+        return EFAULT;
+    }
+
+
+    for (region = 0; region < 6; region++) {
+        const struct pci_mem_region const* r = &dev->regions[region];
+
+        if (r->size != 0) {
+            if ((r->base_addr <= base) && ((r->base_addr + r->size) > base)) {
+                if ((base + size) > (r->base_addr + r->size)) {
+                    return E2BIG;
+                }
+
+                break;
+            }
+        }
+    }
+
+    if (region > 5) {
+        return ENOENT;
+    }
+
+    /* Make sure that there isn't already a mapping with the same base and
+     * size.
+     */
+    for (i = 0; i < devp->num_mappings; i++) {
+        if ((devp->mappings[i].base == base)
+            && (devp->mappings[i].size == size)) {
+            return EINVAL;
+        }
+    }
+
+
+    mappings = realloc(devp->mappings,
+                       (sizeof(devp->mappings[0]) * (devp->num_mappings + 1)));
+    if (mappings == NULL) {
+        return ENOMEM;
+    }
+
+    mappings[devp->num_mappings].base = base;
+    mappings[devp->num_mappings].size = size;
+    mappings[devp->num_mappings].region = region;
+    mappings[devp->num_mappings].flags = map_flags;
+    mappings[devp->num_mappings].memory = NULL;
+
+    if (dev->regions[region].memory == NULL) {
+        err = (*pci_sys->methods->map_range)(dev,
+                                             &mappings[devp->num_mappings]);
+    }
+
+    if (err == 0) {
+        *addr =  mappings[devp->num_mappings].memory;
+        devp->num_mappings++;
+    } else {
+        mappings = realloc(mappings,
+                           (sizeof(mappings[0]) * devp->num_mappings));
+    }
+
+    devp->mappings = mappings;
+
+    return err;
+}
+
+
+/**
+ * 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_range, pci_device_unmap_range
+ * \deprecated
+ */
+int
+pci_device_unmap_region( struct pci_device * dev, unsigned region )
+{
+    int err;
+
+    if (dev == NULL) {
+        return EFAULT;
+    }
+
+    if ((region > 5) || (dev->regions[region].size == 0)) {
+        return ENOENT;
+    }
+
+    err = pci_device_unmap_range(dev, dev->regions[region].memory,
+                                 dev->regions[region].size);
+    if (!err) {
+        dev->regions[region].memory = NULL;
+    }
+
+    return err;
+}
+
+
+/**
+ * Unmap the specified memory range so that it can no longer be accessed by the CPU.
+ *
+ * Unmaps the specified memory range that was previously mapped via
+ * \c pci_device_map_memory_range.
+ *
+ * \param dev          Device whose memory is to be unmapped.
+ * \param memory       Pointer to the base of the mapped range.
+ * \param size         Size, in bytes, of the range to be unmapped.
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_map_range, pci_device_unmap_range
+ * \deprecated
+ */
+int
+pci_device_unmap_memory_range(struct pci_device *dev, void *memory,
+                              pciaddr_t size)
+{
+    return pci_device_unmap_range(dev, memory, size);
+}
+
+
+/**
+ * Unmap the specified memory range so that it can no longer be accessed by the CPU.
+ *
+ * Unmaps the specified memory range that was previously mapped via
+ * \c pci_device_map_memory_range.
+ *
+ * \param dev          Device whose memory is to be unmapped.
+ * \param memory       Pointer to the base of the mapped range.
+ * \param size         Size, in bytes, of the range to be unmapped.
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_map_range
+ */
+int
+pci_device_unmap_range(struct pci_device *dev, void *memory,
+                       pciaddr_t size)
+{
+    struct pci_device_private *const devp =
+        (struct pci_device_private *) dev;
+    unsigned i;
+    int err;
+
+
+    if (dev == NULL) {
+        return EFAULT;
+    }
+
+    for (i = 0; i < devp->num_mappings; i++) {
+        if ((devp->mappings[i].memory == memory)
+            && (devp->mappings[i].size == size)) {
+            break;
+        }
+    }
+
+    if (i == devp->num_mappings) {
+        return ENOENT;
+    }
+
+    
+    err = (*pci_sys->methods->unmap_range)(dev, &devp->mappings[i]);
+    if (!err) {
+        const unsigned entries_to_move = (devp->num_mappings - i) - 1;
+        
+        if (entries_to_move > 0) {
+            (void) memmove(&devp->mappings[i],
+                           &devp->mappings[i + 1],
+                           entries_to_move * sizeof(devp->mappings[0]));
+        }
+        
+        devp->num_mappings--;
+        devp->mappings = realloc(devp->mappings,
+                                 (sizeof(devp->mappings[0]) * devp->num_mappings));
+    }
+
+    return err;
+}
+
+
+/**
+ * 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 particularly 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 configuration 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 = ENXIO;
+    }
+
+    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 = ENXIO;
+    }
+
+    *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 = ENXIO;
+    }
+
+    *data = LETOH_32( *data );
+    return err;
+}
+
+
+/**
+ * Write arbitrary bytes to device's PCI config space
+ *
+ * Writes 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 configuration 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, 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, 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, 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;
+}
+
+
+int
+pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask, 
+                          uint32_t data, pciaddr_t offset )
+{
+    uint32_t  temp;
+    int err;
+
+    err = pci_device_cfg_read_u32( dev, & temp, offset );
+    if ( ! err ) {
+       temp &= ~mask;
+       temp |= data;
+
+       err = pci_device_cfg_write_u32(dev, temp, offset);
+    }
+
+    return err;
+}
+
+void
+pci_device_enable(struct pci_device *dev)
+{
+    if (dev == NULL) {
+       return;
+    }
+
+    if (pci_sys->methods->enable)
+       pci_sys->methods->enable(dev);
+}
diff --git a/src/common_io.c b/src/common_io.c
new file mode 100644 (file)
index 0000000..58628b4
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * 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
+ * them 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 MERCHANTIBILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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.
+ *
+ * Author:
+ *     Adam Jackson <ajax@redhat.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+static struct pci_io_handle *ios;
+static unsigned int num_ios;
+
+static struct pci_io_handle *
+new_io_handle(void)
+{
+    struct pci_io_handle *new;
+
+    new = realloc(ios, sizeof(struct pci_io_handle) * (num_ios + 1));
+    if (!new)
+       return NULL;
+
+    ios = new;
+    num_ios++;
+
+    return ios + num_ios - 1;
+}
+
+static void
+delete_io_handle(struct pci_io_handle *handle)
+{
+    struct pci_io_handle *new;
+    int i = 0;
+
+    if (!handle || !num_ios || (void *)handle < (void *)ios ||
+        (void *)handle > (void *)(ios + num_ios - 1))
+        return;
+
+    for (i = 0; i < num_ios; i++) {
+        if (ios + i == handle) {
+            memmove(&ios[i], &ios[i+1], sizeof(struct pci_io_handle) *
+                                        (num_ios - i - 1));
+            break;
+        }
+    }
+
+    new = realloc(ios, sizeof(struct pci_io_handle) * (num_ios - 1));
+    if (new)
+        ios = new;
+    num_ios--;
+}
+
+_pci_hidden void
+pci_io_cleanup(void)
+{
+    free(ios);
+    ios = NULL;
+    num_ios = 0;
+}
+
+/**
+ * Open a handle to a PCI device I/O range.  The \c base and \c size
+ * requested must fit entirely within a single I/O BAR on the device.
+ * \c size is in bytes.
+ *
+ * \returns
+ * An opaque handle to the I/O BAR, or \c NULL on error.
+ */
+struct pci_io_handle *
+pci_device_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
+{
+    struct pci_io_handle *ret;
+    int bar;
+
+    if (!pci_sys->methods->open_device_io)
+       return NULL;
+
+    for (bar = 0; bar < 6; bar++) {
+       struct pci_mem_region *region = &(dev->regions[bar]);
+       if (!region->is_IO)
+           continue;
+
+       if (base < region->base_addr || base > (region->base_addr+region->size))
+           continue;
+
+       if ((base + size) > (region->base_addr + region->size))
+           continue;
+
+       ret = new_io_handle();
+       if (!ret)
+           return NULL;
+       
+       if (!pci_sys->methods->open_device_io(ret, dev, bar, base, size)) {
+           delete_io_handle(ret);
+           return NULL;
+       }
+
+        return ret;
+    }
+
+    return NULL;
+}
+
+/**
+ * Open a handle to the legacy I/O space for the PCI domain containing
+ * \c dev. \c size is in bytes.
+ *
+ * \returns
+ * An opaque handle to the requested range, or \c NULL on error.
+ */
+struct pci_io_handle *
+pci_legacy_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
+{
+    struct pci_io_handle *ret;
+
+    if (!pci_sys->methods->open_legacy_io)
+       return NULL;
+
+    ret = new_io_handle();
+    if (!ret)
+       return NULL;
+
+    if (!pci_sys->methods->open_legacy_io(ret, dev, base, size)) {
+       delete_io_handle(ret);
+       return NULL;
+    }
+
+    return ret;
+}
+
+/**
+ * Close an I/O handle.
+ */
+void
+pci_device_close_io(struct pci_device *dev, struct pci_io_handle *handle)
+{
+    if (dev && handle && pci_sys->methods->close_io)
+       pci_sys->methods->close_io(dev, handle);
+
+    delete_io_handle(handle);
+}
+
+/**
+ * Read a 32-bit value from the I/O space.  \c reg is relative to the
+ * \c base specified when the handle was opened.  Some platforms may
+ * require that \c reg be 32-bit-aligned.
+ *
+ * \returns
+ * The value read from the I/O port, or undefined on any error.
+ */
+uint32_t
+pci_io_read32(struct pci_io_handle *handle, uint32_t reg)
+{
+    if (reg + 4 > handle->size)
+       return UINT32_MAX;
+
+    return pci_sys->methods->read32(handle, reg);
+}
+
+/**
+ * Read a 16-bit value from the I/O space.  \c reg is relative to the
+ * \c base specified when the handle was opened.  Some platforms may
+ * require that \c reg be 16-bit-aligned.
+ *
+ * \returns
+ * The value read from the I/O port, or undefined on any error.
+ */
+uint16_t
+pci_io_read16(struct pci_io_handle *handle, uint32_t reg)
+{
+    if (reg + 2 > handle->size)
+       return UINT16_MAX;
+
+    return pci_sys->methods->read16(handle, reg);
+}
+
+/**
+ * Read a 8-bit value from the I/O space.  \c reg is relative to the
+ * \c base specified when the handle was opened.
+ *
+ * \returns
+ * The value read from the I/O port, or undefined on any error.
+ */
+uint8_t
+pci_io_read8(struct pci_io_handle *handle, uint32_t reg)
+{
+    if (reg + 1 > handle->size)
+       return UINT8_MAX;
+
+    return pci_sys->methods->read8(handle, reg);
+}
+
+/**
+ * Write a 32-bit value to the I/O space.  \c reg is relative to the
+ * \c base specified when the handle was opened.  Some platforms may
+ * require that \c reg be 32-bit-aligned.
+ */
+void
+pci_io_write32(struct pci_io_handle *handle, uint32_t reg, uint32_t data)
+{
+    if (reg + 4 > handle->size)
+       return;
+
+    pci_sys->methods->write32(handle, reg, data);
+}
+
+/**
+ * Write a 16-bit value to the I/O space.  \c reg is relative to the
+ * \c base specified when the handle was opened.  Some platforms may
+ * require that \c reg be 16-bit-aligned.
+ */
+void
+pci_io_write16(struct pci_io_handle *handle, uint32_t reg, uint16_t data)
+{
+    if (reg + 2 > handle->size)
+       return;
+
+    pci_sys->methods->write16(handle, reg, data);
+}
+
+/**
+ * Write a 8-bit value to the I/O space.  \c reg is relative to the
+ * \c base specified when the handle was opened.
+ */
+void
+pci_io_write8(struct pci_io_handle *handle, uint32_t reg, uint8_t data)
+{
+    if (reg + 1 > handle->size)
+       return;
+
+    pci_sys->methods->write8(handle, reg, data);
+}
diff --git a/src/common_iterator.c b/src/common_iterator.c
new file mode 100644 (file)
index 0000000..83cade3
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * (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 <string.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+/**
+ * Track device iteration state
+ * 
+ * \private
+ */
+struct pci_device_iterator {
+    unsigned next_index;
+
+    enum {
+       match_any,
+       match_slot,
+       match_id
+    } mode;
+
+    union {
+       struct pci_slot_match   slot;
+       struct pci_id_match     id;
+    } match;
+};
+
+
+/**
+ * Create an iterator based on a regular expression.
+ *
+ * \return
+ * A pointer to a fully initialized \c pci_device_iterator structure on
+ * success, or \c NULL on failure.
+ *
+ * \sa pci_id_match_iterator_create, pci_device_next, pci_iterator_destroy
+ */
+struct pci_device_iterator *
+pci_slot_match_iterator_create( const struct pci_slot_match * match )
+{
+    struct pci_device_iterator * iter;
+    
+    if ( pci_sys == NULL ) {
+       return NULL;
+    }
+
+    iter = malloc( sizeof( *iter ) );
+    if ( iter != NULL ) {
+       iter->next_index = 0;
+
+       if ( match != NULL ) {
+           iter->mode = match_slot;
+
+           (void) memcpy( & iter->match.slot, match, sizeof( *match ) );
+       }
+       else {
+           iter->mode = match_any;
+       }
+    }
+
+    return iter;
+}
+
+
+/**
+ * Create an iterator based on a regular expression.
+ *
+ * \return
+ * A pointer to a fully initialized \c pci_device_iterator structure on
+ * success, or \c NULL on failure.
+ *
+ * \sa pci_slot_match_iterator_create, pci_device_next, pci_iterator_destroy
+ */
+struct pci_device_iterator *
+pci_id_match_iterator_create( const struct pci_id_match * match )
+{
+    struct pci_device_iterator * iter;
+    
+    if ( pci_sys == NULL ) {
+       return NULL;
+    }
+
+    iter = malloc( sizeof( *iter ) );
+    if ( iter != NULL ) {
+       iter->next_index = 0;
+
+       if ( match != NULL ) {
+           iter->mode = match_id;
+
+           (void) memcpy( & iter->match.id, match, sizeof( *match ) );
+       }
+       else {
+           iter->mode = match_any;
+       }
+    }
+
+    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 ) {
+       free( iter );
+    }
+}
+
+
+/**
+ * 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.
+ */
+struct pci_device *
+pci_device_next( struct pci_device_iterator * iter )
+{
+    struct pci_device_private * d = NULL;
+
+    if (!iter)
+       return NULL;
+
+    switch( iter->mode ) {
+    case match_any:
+       if ( iter->next_index < pci_sys->num_devices ) {
+           d = & pci_sys->devices[ iter->next_index ];
+           iter->next_index++;
+       }
+
+       break;
+
+    case match_slot: {
+       while ( iter->next_index < pci_sys->num_devices ) {
+           struct pci_device_private * const temp = 
+             & pci_sys->devices[ iter->next_index ];
+
+           iter->next_index++;
+           if ( PCI_ID_COMPARE( iter->match.slot.domain, temp->base.domain )
+                && PCI_ID_COMPARE( iter->match.slot.bus, temp->base.bus )
+                && PCI_ID_COMPARE( iter->match.slot.dev, temp->base.dev )
+                && PCI_ID_COMPARE( iter->match.slot.func, temp->base.func ) ) {
+               d = temp;
+               break;
+           }
+       }
+       
+       break;
+    }
+
+    case match_id: {
+       while ( iter->next_index < pci_sys->num_devices ) {
+           struct pci_device_private * const temp = 
+             & pci_sys->devices[ iter->next_index ];
+
+           iter->next_index++;
+           if ( PCI_ID_COMPARE( iter->match.id.vendor_id, temp->base.vendor_id )
+                && PCI_ID_COMPARE( iter->match.id.device_id, temp->base.device_id )
+                && PCI_ID_COMPARE( iter->match.id.subvendor_id, temp->base.subvendor_id )
+                && PCI_ID_COMPARE( iter->match.id.subdevice_id, temp->base.subdevice_id )
+                && ((temp->base.device_class & iter->match.id.device_class_mask) 
+                    == iter->match.id.device_class) ) {
+               d = temp;
+               break;
+           }
+       }
+       
+       break;
+    }
+    }
+
+    return (struct pci_device *) d;
+}
+
+
+struct pci_device *
+pci_device_find_by_slot( uint32_t domain, uint32_t bus, uint32_t dev,
+                        uint32_t func )
+{
+    struct pci_device_iterator  iter;
+    
+    
+    iter.next_index = 0;
+    iter.mode = match_slot;
+    iter.match.slot.domain = domain;
+    iter.match.slot.bus = bus;
+    iter.match.slot.dev = dev;
+    iter.match.slot.func = func;
+
+    return pci_device_next( & iter );
+}
diff --git a/src/common_map.c b/src/common_map.c
new file mode 100644 (file)
index 0000000..8757151
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright IBM Corporation 2007
+ * 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 <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+/**
+ * \file common_map.c
+ * Platform independent memory map routines.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+/**
+ * Unmap the specified region using the munmap.
+ *
+ * \param dev    Device whose memory region is to be mapped.
+ * \param map    Memory mapping that is to be undone.
+ *
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_unmap_range
+ */
+_pci_hidden int
+pci_device_generic_unmap_range(struct pci_device *dev,
+                              struct pci_device_mapping *map)
+{
+    return (munmap(map->memory, map->size) == -1) ? errno : 0;
+}
diff --git a/src/common_vgaarb.c b/src/common_vgaarb.c
new file mode 100644 (file)
index 0000000..86eceb5
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti
+ *               2009 Tiago Vignatti
+ *
+ * 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 the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, 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 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
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS 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 <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "config.h"
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+#define BUFSIZE 64
+
+static int
+parse_string_to_decodes_rsrc(char *input, int *vga_count, struct pci_slot_match *match)
+{
+    char *tok;
+    char *input_sp = NULL, *count_sp, *pci_sp;
+    char tmp[32];
+
+    tok = strtok_r(input,",",&input_sp);
+    if (!tok)
+        goto fail;
+
+    strncpy(tmp, input, 15);
+    tmp[15] = 0;
+
+    tok = strtok_r(tmp,":",&count_sp);
+    if (!tok)
+        goto fail;
+    tok = strtok_r(NULL, ":",&count_sp);
+    if (!tok)
+        goto fail;
+
+    *vga_count = strtoul(tok, NULL, 10);
+    if (*vga_count == LONG_MAX)
+        goto fail;
+
+#ifdef DEBUG
+    fprintf(stderr,"vga count is %d\n", *vga_count);
+#endif
+
+    tok = strtok_r(NULL, ",",&input_sp);
+    if (!tok)
+        goto fail;
+
+    if (match) {
+        strncpy(tmp, tok, 32);
+        tmp[31] = 0;
+        tok = strtok_r(tmp, ":", &pci_sp);
+        if (!tok)
+            goto fail;
+        tok = strtok_r(NULL, ":", &pci_sp);
+        if (!tok)
+            goto fail;
+        match->domain = strtoul(tok, NULL, 16);
+
+        tok = strtok_r(NULL, ":", &pci_sp);
+        if (!tok)
+            goto fail;
+        match->bus = strtoul(tok, NULL, 16);
+
+        tok = strtok_r(NULL, ".", &pci_sp);
+        if (!tok)
+            goto fail;
+        match->dev = strtoul(tok, NULL, 16);
+
+        tok = strtok_r(NULL, ".", &pci_sp);
+        if (!tok)
+            goto fail;
+        match->func = strtoul(tok, NULL, 16);
+    }
+
+    tok = strtok_r(NULL, ",",&input_sp);
+    if (!tok)
+        goto fail;
+    tok = strtok_r(tok, "=", &input_sp);
+    if (!tok)
+        goto fail;
+    tok = strtok_r(NULL, "=", &input_sp);
+    if (!tok)
+        goto fail;
+
+    if (!strncmp(tok, "io+mem", 6))
+        return VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM;
+    if (!strncmp(tok, "io", 2))
+        return VGA_ARB_RSRC_LEGACY_IO;
+    if (!strncmp(tok, "mem", 3))
+        return VGA_ARB_RSRC_LEGACY_MEM;
+fail:
+    return VGA_ARB_RSRC_NONE;
+}
+
+int
+pci_device_vgaarb_init(void)
+{
+    struct pci_slot_match match;
+    char buf[BUFSIZE];
+    int ret, rsrc;
+
+    if (!pci_sys)
+        return -1;
+
+    if ((pci_sys->vgaarb_fd = open ("/dev/vga_arbiter", O_RDWR)) < 0) {
+        return errno;
+    }
+
+    ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
+    if (ret <= 0)
+        return -1;
+
+    memset(&match, 0xff, sizeof(match));
+    /* need to find the device to go back to and what it was decoding */
+    rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, &match);
+
+    pci_sys->vga_default_dev = pci_device_find_by_slot(match.domain, match.bus, match.dev, match.func);
+
+    if (pci_sys->vga_default_dev)
+        pci_sys->vga_default_dev->vgaarb_rsrc = rsrc;
+    return 0;
+}
+
+void
+pci_device_vgaarb_fini(void)
+{
+    if (!pci_sys)
+        return;
+
+    close(pci_sys->vgaarb_fd);
+}
+
+/**
+ * Writes message on vga device. The messages are defined by the kernel
+ * implementation.
+ *
+ * \param fd    vga arbiter device.
+ * \param buf   message itself.
+ * \param len   message length.
+ *
+ * \return
+ * Zero on success, 1 if something gets wrong and 2 if fd is busy (only for
+ * 'trylock')
+ */
+static int
+vgaarb_write(int fd, char *buf, int len)
+{
+    int ret;
+
+
+    buf[len] = '\0';
+
+    ret = write(fd, buf, len);
+    if (ret == -1) {
+        /* the user may have called "trylock" and didn't get the lock */
+        if (errno == EBUSY)
+            return 2;
+
+#ifdef DEBUG
+        fprintf(stderr, "write error");
+#endif
+        return 1;
+    }
+    else if (ret != len) {
+        /* it's need to receive the exactly amount required. */
+#ifdef DEBUG
+        fprintf(stderr, "write error: wrote different than expected\n");
+#endif
+        return 1;
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf);
+#endif
+
+    return 0;
+}
+
+
+static const char *
+rsrc_to_str(int iostate)
+{
+    switch (iostate) {
+    case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM:
+        return "io+mem";
+    case VGA_ARB_RSRC_LEGACY_IO:
+        return "io";
+    case VGA_ARB_RSRC_LEGACY_MEM:
+        return "mem";
+    }
+
+    return "none";
+}
+
+int
+pci_device_vgaarb_set_target(struct pci_device *dev)
+{
+    int len;
+    char buf[BUFSIZE];
+    int ret;
+
+    if (!dev)
+        dev = pci_sys->vga_default_dev;
+    if (!dev)
+        return -1;
+
+    len = snprintf(buf, BUFSIZE, "target PCI:%04x:%02x:%02x.%x",
+                   dev->domain, dev->bus, dev->dev, dev->func);
+
+    ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
+    if (ret)
+        return ret;
+
+    ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
+    if (ret <= 0)
+        return -1;
+
+    dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL);
+    pci_sys->vga_target = dev;
+    return 0;
+}
+
+int
+pci_device_vgaarb_decodes(int new_vgaarb_rsrc)
+{
+    int len;
+    char buf[BUFSIZE];
+    int ret;
+    struct pci_device *dev = pci_sys->vga_target;
+
+    if (!dev)
+        return -1;
+    if (dev->vgaarb_rsrc == new_vgaarb_rsrc)
+        return 0;
+
+    len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(new_vgaarb_rsrc));
+    ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
+    if (ret == 0)
+        dev->vgaarb_rsrc = new_vgaarb_rsrc;
+
+    ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
+    if (ret <= 0)
+        return -1;
+
+    parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL);
+
+    return ret;
+}
+
+int
+pci_device_vgaarb_lock(void)
+{
+    int len;
+    char buf[BUFSIZE];
+    struct pci_device *dev = pci_sys->vga_target;
+
+    if (!dev)
+       return -1;
+
+    if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
+        return 0;
+
+    len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc));
+
+    return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
+}
+
+int
+pci_device_vgaarb_trylock(void)
+{
+    int len;
+    char buf[BUFSIZE];
+    struct pci_device *dev = pci_sys->vga_target;
+
+    if (!dev)
+        return -1;
+
+    if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
+        return 0;
+
+    len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc));
+
+    return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
+}
+
+int
+pci_device_vgaarb_unlock(void)
+{
+    int len;
+    char buf[BUFSIZE];
+    struct pci_device *dev = pci_sys->vga_target;
+
+    if (!dev)
+        return -1;
+
+    if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
+        return 0;
+
+    len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc));
+
+    return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
+}
+
+int pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count, int *rsrc_decodes)
+{
+    *vga_count = pci_sys->vga_count;
+    if (!dev)
+        return 0;
+
+    *rsrc_decodes = dev->vgaarb_rsrc;
+        return 0;
+}
diff --git a/src/common_vgaarb_stub.c b/src/common_vgaarb_stub.c
new file mode 100644 (file)
index 0000000..9394273
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2009 Tiago Vignatti
+ *
+ * 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 the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, 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 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
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS 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 <stdio.h>
+#include "pciaccess.h"
+
+int
+pci_device_vgaarb_init(void)
+{
+#ifdef DEBUG
+    fprintf(stderr, "%s: You're using VGA arbiter stub functions!\n",
+                                                            __FUNCTION__);
+#endif
+    return -1;
+}
+
+void
+pci_device_vgaarb_fini(void)
+{
+}
+
+int
+pci_device_vgaarb_set_target(struct pci_device *dev)
+{
+    return -1;
+}
+
+int
+pci_device_vgaarb_decodes(int new_vga_rsrc)
+{
+    return -1;
+}
+
+int
+pci_device_vgaarb_lock(void)
+{
+    return -1;
+}
+
+int
+pci_device_vgaarb_trylock(void)
+{
+    return -1;
+}
+
+int
+pci_device_vgaarb_unlock(void)
+{
+    return 0;
+}
+
+int pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count,
+                              int *rsrc_decodes)
+{
+    return -1;
+}
diff --git a/src/freebsd_pci.c b/src/freebsd_pci.c
new file mode 100644 (file)
index 0000000..4a2dcf1
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * (C) Copyright Eric Anholt 2006
+ * (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 freebsd_pci.c
+ *
+ * Access the kernel PCI support using /dev/pci's ioctl and mmap interface.
+ *
+ * \author Eric Anholt <eric@anholt.net>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/pciio.h>
+#include <sys/mman.h>
+#include <sys/memrange.h>
+
+#include "config.h"
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+#define        PCIC_DISPLAY    0x03
+#define        PCIS_DISPLAY_VGA        0x00
+#define        PCIS_DISPLAY_XGA        0x01
+#define        PCIS_DISPLAY_3D         0x02
+#define        PCIS_DISPLAY_OTHER      0x80
+
+/* Registers taken from pcireg.h */
+#define PCIR_COMMAND    0x04
+#define PCIM_CMD_PORTEN         0x0001
+#define PCIM_CMD_MEMEN          0x0002
+#define PCIR_BIOS      0x30
+#define PCIM_BIOS_ENABLE       0x01
+#define PCIM_BIOS_ADDR_MASK    0xfffff800
+
+#define PCIR_BARS       0x10
+#define PCIR_BAR(x)             (PCIR_BARS + (x) * 4)
+#define PCI_BAR_IO(x)           (((x) & PCIM_BAR_SPACE) == PCIM_BAR_IO_SPACE)
+#define PCI_BAR_MEM(x)          (((x) & PCIM_BAR_SPACE) == PCIM_BAR_MEM_SPACE)
+#define PCIM_BAR_MEM_TYPE       0x00000006
+#define PCIM_BAR_MEM_64         4
+#define PCIM_BAR_MEM_PREFETCH   0x00000008
+#define PCIM_BAR_SPACE          0x00000001
+#define PCIM_BAR_MEM_SPACE      0
+#define PCIM_BAR_IO_SPACE       1
+
+/**
+ * FreeBSD private pci_system structure that extends the base pci_system
+ * structure.
+ *
+ * It is initialized once and used as a global, just as pci_system is used.
+ */
+_pci_hidden
+struct freebsd_pci_system {
+    /* This must be the first entry in the structure, as pci_system_cleanup()
+     * frees pci_sys.
+     */
+    struct pci_system pci_sys;
+
+    int pcidev; /**< fd for /dev/pci */
+} *freebsd_pci_sys;
+
+/**
+ * Map a memory region for a device using /dev/mem.
+ * 
+ * \param dev   Device whose memory region is to be mapped.
+ * \param map   Parameters of the mapping that is to be created.
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ */
+static int
+pci_device_freebsd_map_range(struct pci_device *dev,
+                            struct pci_device_mapping *map)
+{
+    const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 
+        ? (PROT_READ | PROT_WRITE) : PROT_READ;
+    struct mem_range_desc mrd;
+    struct mem_range_op mro;
+
+    int fd, err = 0;
+
+    fd = open("/dev/mem", O_RDWR);
+    if (fd == -1)
+       return errno;
+
+    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, map->base);
+
+    if (map->memory == MAP_FAILED) {
+       err = errno;
+    }
+
+    mrd.mr_base = map->base;
+    mrd.mr_len = map->size;
+    strncpy(mrd.mr_owner, "pciaccess", sizeof(mrd.mr_owner));
+    if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE)
+       mrd.mr_flags = MDF_WRITEBACK;
+    else if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)
+       mrd.mr_flags = MDF_WRITECOMBINE;
+    else
+       mrd.mr_flags = MDF_UNCACHEABLE;
+    mro.mo_desc = &mrd;
+    mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
+
+    /* No need to set an MTRR if it's the default mode. */
+    if (mrd.mr_flags != MDF_UNCACHEABLE) {
+       if (ioctl(fd, MEMRANGE_SET, &mro)) {
+           fprintf(stderr, "failed to set mtrr: %s\n", strerror(errno));
+       }
+    }
+
+    close(fd);
+
+    return err;
+}
+
+static int
+pci_device_freebsd_unmap_range( struct pci_device *dev,
+                               struct pci_device_mapping *map )
+{
+    struct mem_range_desc mrd;
+    struct mem_range_op mro;
+    int fd;
+
+    if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
+       (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE))
+    {
+       fd = open("/dev/mem", O_RDWR);
+       if (fd != -1) {
+           mrd.mr_base = map->base;
+           mrd.mr_len = map->size;
+           strncpy(mrd.mr_owner, "pciaccess", sizeof(mrd.mr_owner));
+           mrd.mr_flags = MDF_UNCACHEABLE;
+           mro.mo_desc = &mrd;
+           mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
+
+           if (ioctl(fd, MEMRANGE_SET, &mro)) {
+               fprintf(stderr, "failed to unset mtrr: %s\n", strerror(errno));
+           }
+
+           close(fd);
+       } else {
+           fprintf(stderr, "Failed to open /dev/mem\n");
+       }
+    }
+
+    return pci_device_generic_unmap_range(dev, map);
+}
+
+static int
+pci_device_freebsd_read( struct pci_device * dev, void * data,
+                        pciaddr_t offset, pciaddr_t size,
+                        pciaddr_t * bytes_read )
+{
+    struct pci_io io;
+
+#if HAVE_PCI_IO_PC_DOMAIN
+    io.pi_sel.pc_domain = dev->domain;
+#endif
+    io.pi_sel.pc_bus = dev->bus;
+    io.pi_sel.pc_dev = dev->dev;
+    io.pi_sel.pc_func = dev->func;
+
+    *bytes_read = 0;
+    while ( size > 0 ) {
+       int toread = (size < 4) ? size : 4;
+
+       /* Only power of two allowed. */
+       if (toread == 3)
+           toread = 2;
+
+       io.pi_reg = offset;
+       io.pi_width = toread;
+
+       if ( ioctl( freebsd_pci_sys->pcidev, PCIOCREAD, &io ) < 0 ) 
+           return errno;
+
+       memcpy(data, &io.pi_data, toread );
+
+       offset += toread;
+       data = (char *)data + toread;
+       size -= toread;
+       *bytes_read += toread;
+    }
+
+    return 0;
+}
+
+
+static int
+pci_device_freebsd_write( struct pci_device * dev, const void * data,
+                         pciaddr_t offset, pciaddr_t size,
+                         pciaddr_t * bytes_written )
+{
+    struct pci_io io;
+
+#if HAVE_PCI_IO_PC_DOMAIN
+    io.pi_sel.pc_domain = dev->domain;
+#endif
+    io.pi_sel.pc_bus = dev->bus;
+    io.pi_sel.pc_dev = dev->dev;
+    io.pi_sel.pc_func = dev->func;
+
+    *bytes_written = 0;
+    while ( size > 0 ) {
+       int towrite = (size < 4 ? size : 4);
+
+       /* Only power of two allowed. */
+       if (towrite == 3)
+           towrite = 2;
+
+       io.pi_reg = offset;
+       io.pi_width = towrite;
+       memcpy( &io.pi_data, data, towrite );
+
+       if ( ioctl( freebsd_pci_sys->pcidev, PCIOCWRITE, &io ) < 0 ) 
+           return errno;
+
+       offset += towrite;
+       data = (char *)data + towrite;
+       size -= towrite;
+       *bytes_written += towrite;
+    }
+
+    return 0;
+}
+
+/**
+ * Read a VGA rom using the 0xc0000 mapping.
+ *
+ * This function should be extended to handle access through PCI resources,
+ * which should be more reliable when available.
+ */
+static int
+pci_device_freebsd_read_rom( struct pci_device * dev, void * buffer )
+{
+    struct pci_device_private *priv = (struct pci_device_private *) dev;
+    void *bios;
+    pciaddr_t rom_base;
+    uint32_t rom;
+    uint16_t reg;
+    int pci_rom, memfd;
+
+    if ( ( dev->device_class & 0x00ffff00 ) !=
+        ( ( PCIC_DISPLAY << 16 ) | ( PCIS_DISPLAY_VGA << 8 ) ) )
+    {
+       return ENOSYS;
+    }
+
+    if (priv->rom_base == 0) {
+#if defined(__amd64__) || defined(__i386__)
+       rom_base = 0xc0000;
+       pci_rom = 0;
+#else
+       return ENOSYS;
+#endif
+    } else {
+       rom_base = priv->rom_base;
+       pci_rom = 1;
+
+       pci_device_cfg_read_u16( dev, &reg, PCIR_COMMAND );
+       pci_device_cfg_write_u16( dev, reg | PCIM_CMD_MEMEN, PCIR_COMMAND );
+       pci_device_cfg_read_u32( dev, &rom, PCIR_BIOS );
+       pci_device_cfg_write_u32( dev, rom | PCIM_BIOS_ENABLE, PCIR_BIOS );
+    }
+
+    printf("Using rom_base = 0x%lx\n", (long)rom_base);
+    memfd = open( "/dev/mem", O_RDONLY );
+    if ( memfd == -1 )
+       return errno;
+
+    bios = mmap( NULL, dev->rom_size, PROT_READ, 0, memfd, rom_base );
+    if ( bios == MAP_FAILED ) {
+       close( memfd );
+       return errno;
+    }
+
+    memcpy( buffer, bios, dev->rom_size );
+
+    munmap( bios, dev->rom_size );
+    close( memfd );
+
+    if (pci_rom) {
+       pci_device_cfg_write_u32( dev, PCIR_BIOS, rom );
+       pci_device_cfg_write_u16( dev, PCIR_COMMAND, reg );
+    }
+
+    return 0;
+}
+
+/** Returns the number of regions (base address registers) the device has */
+
+static int
+pci_device_freebsd_get_num_regions( struct pci_device * dev )
+{
+    struct pci_device_private *priv = (struct pci_device_private *) dev;
+
+    switch (priv->header_type) {
+    case 0:
+       return 6;
+    case 1:
+       return 2;
+    case 2:
+       return 1;
+    default:
+       printf("unknown header type %02x\n", priv->header_type);
+       return 0;
+    }
+}
+
+#ifdef PCIOCGETBAR
+
+static int
+pci_device_freebsd_probe( struct pci_device * dev )
+{
+    struct pci_device_private *priv = (struct pci_device_private *) dev;
+    struct pci_bar_io bar;
+    uint8_t irq;
+    int err, i;
+
+#if HAVE_PCI_IO_PC_DOMAIN
+    bar.pbi_sel.pc_domain = dev->domain;
+#endif
+    bar.pbi_sel.pc_bus = dev->bus;
+    bar.pbi_sel.pc_dev = dev->dev;
+    bar.pbi_sel.pc_func = dev->func;
+
+
+    /* Many of the fields were filled in during initial device enumeration.
+     * At this point, we need to fill in regions, rom_size, and irq.
+     */
+
+    err = pci_device_cfg_read_u8( dev, &irq, 60 );
+    if (err)
+       return errno;
+    dev->irq = irq;
+
+    for (i = 0; i < pci_device_freebsd_get_num_regions( dev ); i++) {
+       bar.pbi_reg = PCIR_BAR(i);
+       if ( ioctl( freebsd_pci_sys->pcidev, PCIOCGETBAR, &bar ) < 0 ) 
+           continue;
+
+       if (PCI_BAR_IO(bar.pbi_base))
+           dev->regions[i].is_IO = 1;
+
+       if ((bar.pbi_base & PCIM_BAR_MEM_TYPE) == PCIM_BAR_MEM_64)
+           dev->regions[i].is_64 = 1;
+
+       if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH)
+           dev->regions[i].is_prefetchable = 1;
+
+       dev->regions[i].base_addr = bar.pbi_base & ~((uint64_t)0xf);
+       dev->regions[i].size = bar.pbi_length;
+    }
+
+    /* If it's a VGA device, set up the rom size for read_rom using the
+     * 0xc0000 mapping.
+     */
+     if ((dev->device_class & 0x00ffff00) ==
+       ((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8))) {
+            dev->rom_size = 64 * 1024;
+     }
+
+     return 0;
+}
+
+#else
+
+/** Masks out the flag bigs of the base address register value */
+static uint32_t
+get_map_base( uint32_t val )
+{
+    if (val & 0x01)
+       return val & ~0x03;
+    else
+       return val & ~0x0f;
+}
+
+/** Returns the size of a region based on the all-ones test value */
+static int
+get_test_val_size( uint32_t testval )
+{
+    if (testval == 0)
+       return 0;
+
+    /* Mask out the flag bits */
+    testval = get_map_base( testval );
+
+    return 1 << (ffs(testval) - 1);
+}
+
+/**
+ * Sets the address and size information for the region from config space
+ * registers.
+ *
+ * This would be much better provided by a kernel interface.
+ *
+ * \return 0 on success, or an errno value.
+ */
+static int
+pci_device_freebsd_get_region_info( struct pci_device * dev, int region,
+                                   int bar )
+{
+    uint32_t addr, testval;
+    uint16_t cmd;
+    int err;
+
+    /* Get the base address */
+    err = pci_device_cfg_read_u32( dev, &addr, bar );
+    if (err != 0)
+       return err;
+
+    /*
+     * We are going to be doing evil things to the registers here
+     * so disable them via the command register first. 
+     */
+    err = pci_device_cfg_read_u16( dev, &cmd, PCIR_COMMAND );
+    if (err != 0)
+       return err;
+
+    err = pci_device_cfg_write_u16( dev,
+       cmd & ~(PCI_BAR_MEM(addr) ? PCIM_CMD_MEMEN : PCIM_CMD_PORTEN),
+       PCIR_COMMAND );
+    if (err != 0)
+       return err;
+
+    /* Test write all ones to the register, then restore it. */
+    err = pci_device_cfg_write_u32( dev, 0xffffffff, bar );
+    if (err != 0)
+       return err;
+    err = pci_device_cfg_read_u32( dev, &testval, bar );
+    if (err != 0)
+       return err;
+    err = pci_device_cfg_write_u32( dev, addr, bar );
+    if (err != 0)
+       return err;
+
+    /* Restore the command register */
+    err = pci_device_cfg_write_u16( dev, cmd, PCIR_COMMAND );
+    if (err != 0)
+       return err;
+
+    if (addr & 0x01)
+       dev->regions[region].is_IO = 1;
+    if (addr & 0x04)
+       dev->regions[region].is_64 = 1;
+    if (addr & 0x08)
+       dev->regions[region].is_prefetchable = 1;
+
+    /* Set the size */
+    dev->regions[region].size = get_test_val_size( testval );
+       printf("size = 0x%lx\n", (long)dev->regions[region].size);
+
+    /* Set the base address value */
+    if (dev->regions[region].is_64) {
+       uint32_t top;
+
+       err = pci_device_cfg_read_u32( dev, &top, bar + 4 );
+       if (err != 0)
+           return err;
+
+       dev->regions[region].base_addr = ((uint64_t)top << 32) |
+                                         get_map_base(addr);
+    } else {
+       dev->regions[region].base_addr = get_map_base(addr);
+    }
+
+    return 0;
+}
+
+static int
+pci_device_freebsd_probe( struct pci_device * dev )
+{
+    struct pci_device_private *priv = (struct pci_device_private *) dev;
+    uint32_t reg, size;
+    uint8_t irq;
+    int err, i, bar;
+
+    /* Many of the fields were filled in during initial device enumeration.
+     * At this point, we need to fill in regions, rom_size, and irq.
+     */
+
+    err = pci_device_cfg_read_u8( dev, &irq, 60 );
+    if (err)
+       return errno;
+    dev->irq = irq;
+
+    bar = 0x10;
+    for (i = 0; i < pci_device_freebsd_get_num_regions( dev ); i++) {
+       pci_device_freebsd_get_region_info( dev, i, bar );
+       if (dev->regions[i].is_64) {
+           bar += 0x08;
+           i++;
+       } else
+           bar += 0x04;
+    }
+
+    /* If it's a VGA device, set up the rom size for read_rom */
+    if ((dev->device_class & 0x00ffff00) ==
+       ((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8)))
+    {
+       err = pci_device_cfg_read_u32( dev, &reg, PCIR_BIOS );
+       if (err)
+           return errno;
+
+       if (reg == 0) {
+           dev->rom_size = 0x10000;
+           return 0;
+       }
+
+       err = pci_device_cfg_write_u32( dev, ~PCIM_BIOS_ENABLE, PCIR_BIOS );
+       if (err)
+           return errno;
+       pci_device_cfg_read_u32( dev, &size, PCIR_BIOS );
+       pci_device_cfg_write_u32( dev, reg, PCIR_BIOS );
+
+       if ((reg & PCIM_BIOS_ADDR_MASK) != 0) {
+           priv->rom_base = (reg & PCIM_BIOS_ADDR_MASK);
+           dev->rom_size = -(size & PCIM_BIOS_ADDR_MASK);
+       }
+    }
+
+    return 0;
+}
+
+#endif
+
+static void
+pci_system_freebsd_destroy(void)
+{
+    close(freebsd_pci_sys->pcidev);
+    free(freebsd_pci_sys->pci_sys.devices);
+    freebsd_pci_sys = NULL;
+}
+
+static const struct pci_system_methods freebsd_pci_methods = {
+    .destroy = pci_system_freebsd_destroy,
+    .destroy_device = NULL, /* nothing to do for this */
+    .read_rom = pci_device_freebsd_read_rom,
+    .probe = pci_device_freebsd_probe,
+    .map_range = pci_device_freebsd_map_range,
+    .unmap_range = pci_device_freebsd_unmap_range,
+    .read = pci_device_freebsd_read,
+    .write = pci_device_freebsd_write,
+    .fill_capabilities = pci_fill_capabilities_generic,
+};
+
+/**
+ * Attempt to access the FreeBSD PCI interface.
+ */
+_pci_hidden int
+pci_system_freebsd_create( void )
+{
+    struct pci_conf_io pciconfio;
+    struct pci_conf pciconf[255];
+    int pcidev;
+    int i;
+
+    /* Try to open the PCI device */
+    pcidev = open( "/dev/pci", O_RDWR );
+    if ( pcidev == -1 )
+       return ENXIO;
+
+    freebsd_pci_sys = calloc( 1, sizeof( struct freebsd_pci_system ) );
+    if ( freebsd_pci_sys == NULL ) {
+       close( pcidev );
+       return ENOMEM;
+    }
+    pci_sys = &freebsd_pci_sys->pci_sys;
+
+    pci_sys->methods = & freebsd_pci_methods;
+    freebsd_pci_sys->pcidev = pcidev;
+
+    /* Probe the list of devices known by the system */
+    bzero( &pciconfio, sizeof( struct pci_conf_io ) );
+    pciconfio.match_buf_len = sizeof(pciconf);
+    pciconfio.matches = pciconf;
+
+    if ( ioctl( pcidev, PCIOCGETCONF, &pciconfio ) == -1) {
+       free( pci_sys );
+       close( pcidev );
+       return errno;
+    }
+
+    if (pciconfio.status == PCI_GETCONF_ERROR ) {
+       free( pci_sys );
+       close( pcidev );
+       return EINVAL;
+    }
+
+    /* Translate the list of devices into pciaccess's format. */
+    pci_sys->num_devices = pciconfio.num_matches;
+    pci_sys->devices = calloc( pciconfio.num_matches,
+                              sizeof( struct pci_device_private ) );
+
+    for ( i = 0; i < pciconfio.num_matches; i++ ) {
+       struct pci_conf *p = &pciconf[ i ];
+
+#if HAVE_PCI_IO_PC_DOMAIN
+       pci_sys->devices[ i ].base.domain = p->pc_sel.pc_domain;
+#else
+       pci_sys->devices[ i ].base.domain = 0;
+#endif
+       pci_sys->devices[ i ].base.bus = p->pc_sel.pc_bus;
+       pci_sys->devices[ i ].base.dev = p->pc_sel.pc_dev;
+       pci_sys->devices[ i ].base.func = p->pc_sel.pc_func;
+       pci_sys->devices[ i ].base.vendor_id = p->pc_vendor;
+       pci_sys->devices[ i ].base.device_id = p->pc_device;
+       pci_sys->devices[ i ].base.subvendor_id = p->pc_subvendor;
+       pci_sys->devices[ i ].base.subdevice_id = p->pc_subdevice;
+       pci_sys->devices[ i ].base.revision = p->pc_revid;
+       pci_sys->devices[ i ].base.device_class = (uint32_t)p->pc_class << 16 |
+           (uint32_t)p->pc_subclass << 8 | (uint32_t)p->pc_progif;
+       pci_sys->devices[ i ].header_type = p->pc_hdr & 0x7f;
+    }
+
+    return 0;
+}
diff --git a/src/linux_devmem.c b/src/linux_devmem.c
new file mode 100644 (file)
index 0000000..271e53f
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * (C) Copyright IBM Corporation 2007
+ * 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_devmem.c
+ * Access PCI subsystem using Linux's the old /dev/mem interface.
+ * 
+ * \note
+ * This is currently just a skeleton.  It only includes the /dev/mem based
+ * function for reading the device ROM.
+ *
+ * \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"
+#include "linux_devmem.h"
+
+/**
+ * Read a device's expansion ROM using /dev/mem.
+ * 
+ * \note
+ * This function could probably be used, as-is, on other platforms that have
+ * a /dev/mem interface.
+ * 
+ * \bugs
+ * Before using the VGA special case code, this function should check that
+ * VGA access are routed to the device.  Right?
+ */
+_pci_hidden int
+pci_device_linux_devmem_read_rom(struct pci_device *dev, void *buffer)
+{
+    struct pci_device_private *priv = (struct pci_device_private *) dev;
+    int fd;
+    int err = 0;
+    uint32_t rom_base_tmp;
+    pciaddr_t rom_base;
+    pciaddr_t rom_size;
+    int PCI_ROM;
+
+
+    /* Handle some special cases of legacy devices.
+     */
+    if (priv->base.rom_size == 0) {
+       /* VGA ROMs are supposed to be at 0xC0000.
+        */
+       if ((priv->base.device_class & 0x00ffff00) == 0x000030000) {
+           rom_base = 0x000C0000;
+           rom_size = 0x00010000;
+           PCI_ROM = 0;
+       }
+       else {
+           /* "Function not implemented."
+            */
+           return ENOSYS;
+       }
+    }
+    else {
+       rom_base = priv->rom_base;
+       rom_size = priv->base.rom_size;
+       PCI_ROM = 1;
+    }
+    
+
+
+    /* Enable the device's ROM.
+     */
+    if (PCI_ROM) {
+       err = pci_device_cfg_read_u32(& priv->base, & rom_base_tmp, 48);
+       if (err) {
+           return err;
+       }
+
+       if ((rom_base_tmp & 0x000000001) == 0) {
+           err = pci_device_cfg_write_u32(& priv->base, 
+                                          rom_base_tmp | 1, 48);
+           if (err) {
+               return err;
+           }
+       }
+    }
+    
+    
+    /* Read the portion of /dev/mem that corresponds to the device's ROM.
+     */
+    fd = open("/dev/mem", O_RDONLY, 0);
+    if (fd < 0) {
+       err = errno;
+    }
+    else {
+       size_t bytes;
+
+       for (bytes = 0; bytes < rom_size; /* empty */) {
+           const ssize_t got = pread(fd, buffer, rom_size - bytes, 
+                                     rom_base + bytes);
+           if (got == -1) {
+               err = errno;
+               break;
+           }
+
+           bytes += got;
+       }
+
+       close(fd);
+    }
+
+    
+    /* Disable the device's ROM.
+     */
+    if (PCI_ROM && ((rom_base_tmp & 0x000000001) == 0)) {
+       const int tmp_err = pci_device_cfg_write_u32(& priv->base,
+                                                    rom_base_tmp, 48);
+
+       /* Prefer to return the first error that occurred.
+        */
+       if (err == 0) {
+           err = tmp_err;
+       }
+    }
+
+    return err;
+}
diff --git a/src/linux_devmem.h b/src/linux_devmem.h
new file mode 100644 (file)
index 0000000..2337f30
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * (C) Copyright IBM Corporation 2007
+ * 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_devmem.h
+ * Functions and datastructures that are private to the /dev/mem based
+ * back-end for pciaccess.
+ * 
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+extern int pci_device_linux_devmem_read_rom(struct pci_device *dev,
+                                           void *buffer);
diff --git a/src/linux_sysfs.c b/src/linux_sysfs.c
new file mode 100644 (file)
index 0000000..1832ee7
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+ * (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
+ * preferred 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 "config.h"
+
+#ifdef HAVE_MTRR
+#include <asm/mtrr.h>
+#include <sys/ioctl.h>
+#endif
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+#include "linux_devmem.h"
+
+static const struct pci_system_methods linux_sysfs_methods;
+
+#define SYS_BUS_PCI "/sys/bus/pci/devices"
+
+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 populate_entries(struct pci_system * pci_sys);
+
+/**
+ * Attempt to access PCI subsystem using Linux's sysfs interface.
+ */
+_pci_hidden 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;
+#ifdef HAVE_MTRR
+           pci_sys->mtrr_fd = open("/proc/mtrr", O_WRONLY);
+#endif
+           err = 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));
+}
+
+
+int
+populate_entries( struct pci_system * p )
+{
+    struct dirent ** devices;
+    int n;
+    int i;
+    int err = 0;
+
+
+    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 ) );
+
+       if (p->devices != NULL) {
+           for (i = 0 ; i < n ; i++) {
+               uint8_t config[48];
+               pciaddr_t bytes;
+               unsigned dom, bus, dev, func;
+               struct pci_device_private *device =
+                       (struct pci_device_private *) &p->devices[i];
+
+
+               sscanf(devices[i]->d_name, "%04x:%02x:%02x.%1u",
+                      & dom, & bus, & dev, & func);
+
+               device->base.domain = dom;
+               device->base.bus = bus;
+               device->base.dev = dev;
+               device->base.func = func;
+
+
+               err = pci_device_linux_sysfs_read(& device->base, config, 0,
+                                                 48, & bytes);
+               if ((bytes == 48) && !err) {
+                   device->base.vendor_id = (uint16_t)config[0]
+                       + ((uint16_t)config[1] << 8);
+                   device->base.device_id = (uint16_t)config[2]
+                       + ((uint16_t)config[3] << 8);
+                   device->base.device_class = (uint32_t)config[9]
+                       + ((uint32_t)config[10] << 8)
+                       + ((uint32_t)config[11] << 16);
+                   device->base.revision = config[8];
+                   device->base.subvendor_id = (uint16_t)config[44]
+                       + ((uint16_t)config[45] << 8);
+                   device->base.subdevice_id = (uint16_t)config[46]
+                       + ((uint16_t)config[47] << 8);
+               }
+
+               if (err) {
+                   break;
+               }
+           }
+       }
+       else {
+           err = ENOMEM;
+       }
+    }
+
+    for (i = 0; i < n; i++)
+       free(devices[i]);
+    free(devices);
+
+    if (err) {
+       free(p->devices);
+       p->devices = NULL;
+    }
+
+    return err;
+}
+
+
+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 ) {
+       struct pci_device_private *priv = (struct pci_device_private *) dev;
+
+       dev->irq = config[60];
+       priv->header_type = config[14];
+
+
+       /* 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 ) {
+               priv->rom_base = low_addr;
+               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;
+    size_t rom_size;
+    size_t total_bytes;
+
+
+    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 ) {
+#ifdef LINUX_ROM
+       /* If reading the ROM using sysfs fails, fall back to the old
+        * /dev/mem based interface.
+        * disable this for newer kernels using configure
+        */
+       return pci_device_linux_devmem_read_rom(dev, buffer);
+#else
+       return errno;
+#endif
+    }
+
+
+    if ( fstat( fd, & st ) == -1 ) {
+       close( fd );
+       return errno;
+    }
+
+    rom_size = st.st_size;
+    if ( rom_size == 0 )
+       rom_size = 0x10000;
+
+    /* 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 );
+
+    for ( total_bytes = 0 ; total_bytes < rom_size ; /* empty */ ) {
+       const int bytes = read( fd, (char *) buffer + total_bytes,
+                               rom_size - total_bytes );
+       if ( bytes == -1 ) {
+           err = errno;
+           break;
+       }
+       else if ( bytes == 0 ) {
+           break;
+       }
+
+       total_bytes += bytes;
+    }
+       
+
+    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;
+    char *data_bytes = data;
+
+    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_bytes, 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 += 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;
+    const char *data_bytes = data;
+
+    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_bytes, 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 += bytes;
+    }
+    
+    if ( bytes_written != NULL ) {
+       *bytes_written = size - temp_size;
+    }
+
+    close( fd );
+    return err;
+}
+
+static int
+pci_device_linux_sysfs_map_range_wc(struct pci_device *dev,
+                                   struct pci_device_mapping *map)
+{
+    char name[256];
+    int fd;
+    const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 
+        ? (PROT_READ | PROT_WRITE) : PROT_READ;
+    const int open_flags = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 
+        ? O_RDWR : O_RDONLY;
+    const off_t offset = map->base - dev->regions[map->region].base_addr;
+
+    snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u_wc",
+            SYS_BUS_PCI,
+            dev->domain,
+            dev->bus,
+            dev->dev,
+            dev->func,
+            map->region);
+    fd = open(name, open_flags);
+    if (fd == -1)
+           return errno;
+
+    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset);
+    if (map->memory == MAP_FAILED) {
+        map->memory = NULL;
+       close(fd);
+       return errno;
+    }
+
+    close(fd);
+
+    return 0;
+}
+
+/**
+ * Map a memory region for a device using the Linux sysfs interface.
+ * 
+ * \param dev   Device whose memory region is to be mapped.
+ * \param map   Parameters of the mapping that is to be created.
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_map_rrange, pci_device_linux_sysfs_unmap_range
+ *
+ * \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_range(struct pci_device *dev,
+                                 struct pci_device_mapping *map)
+{
+    char name[256];
+    int fd;
+    int err = 0;
+    const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 
+        ? (PROT_READ | PROT_WRITE) : PROT_READ;
+    const int open_flags = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 
+        ? O_RDWR : O_RDONLY;
+    const off_t offset = map->base - dev->regions[map->region].base_addr;
+#ifdef HAVE_MTRR
+    struct mtrr_sentry sentry = {
+       .base = map->base,
+        .size = map->size,
+       .type = MTRR_TYPE_UNCACHABLE
+    };
+#endif
+
+    /* For WC mappings, try sysfs resourceN_wc file first */
+    if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) &&
+       !pci_device_linux_sysfs_map_range_wc(dev, map))
+           return 0;
+
+    snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u",
+             SYS_BUS_PCI,
+             dev->domain,
+             dev->bus,
+             dev->dev,
+             dev->func,
+             map->region);
+
+    fd = open(name, open_flags);
+    if (fd == -1) {
+        return errno;
+    }
+
+
+    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset);
+    if (map->memory == MAP_FAILED) {
+        map->memory = NULL;
+       close(fd);
+       return errno;
+    }
+
+#ifdef HAVE_MTRR
+    if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) != 0) {
+        sentry.type = MTRR_TYPE_WRBACK;
+    } else if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) != 0) {
+        sentry.type = MTRR_TYPE_WRCOMB;
+    }
+
+    if (pci_sys->mtrr_fd != -1 && sentry.type != MTRR_TYPE_UNCACHABLE) {
+       if (ioctl(pci_sys->mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) < 0) {
+           /* FIXME: Should we report an error in this case?
+            */
+           fprintf(stderr, "error setting MTRR "
+                   "(base = 0x%08lx, size = 0x%08x, type = %u) %s (%d)\n",
+                   sentry.base, sentry.size, sentry.type,
+                   strerror(errno), errno);
+/*            err = errno;*/
+       }
+       /* KLUDGE ALERT -- rewrite the PTEs to turn off the CD and WT bits */
+       mprotect (map->memory, map->size, PROT_NONE);
+       err = mprotect (map->memory, map->size, PROT_READ|PROT_WRITE);
+
+       if (err != 0) {
+           fprintf(stderr, "mprotect(PROT_READ | PROT_WRITE) failed: %s\n",
+                   strerror(errno));
+           fprintf(stderr, "remapping without mprotect performance kludge.\n");
+
+           munmap(map->memory, map->size);
+           map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset);
+           if (map->memory == MAP_FAILED) {
+               map->memory = NULL;
+               close(fd);
+               return errno;
+           }
+       }
+    }
+#endif
+
+    close(fd);
+
+    return 0;
+}
+
+/**
+ * Unmap a memory region for a device using the Linux sysfs interface.
+ * 
+ * \param dev   Device whose memory region is to be unmapped.
+ * \param map   Parameters of the mapping that is to be destroyed.
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_map_rrange, pci_device_linux_sysfs_map_range
+ *
+ * \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_range(struct pci_device *dev,
+                                  struct pci_device_mapping *map)
+{
+    int err = 0;
+#ifdef HAVE_MTRR
+    struct mtrr_sentry sentry = {
+       .base = map->base,
+        .size = map->size,
+       .type = MTRR_TYPE_UNCACHABLE
+    };
+#endif
+
+    err = pci_device_generic_unmap_range (dev, map);
+    if (err)
+       return err;
+    
+#ifdef HAVE_MTRR
+    if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) != 0) {
+        sentry.type = MTRR_TYPE_WRBACK;
+    } else if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) != 0) {
+        sentry.type = MTRR_TYPE_WRCOMB;
+    }
+
+    if (pci_sys->mtrr_fd != -1 && sentry.type != MTRR_TYPE_UNCACHABLE) {
+       if (ioctl(pci_sys->mtrr_fd, MTRRIOC_DEL_ENTRY, &sentry) < 0) {
+           /* FIXME: Should we report an error in this case?
+            */
+           fprintf(stderr, "error setting MTRR "
+                   "(base = 0x%08lx, size = 0x%08x, type = %u) %s (%d)\n",
+                   sentry.base, sentry.size, sentry.type,
+                   strerror(errno), errno);
+/*            err = errno;*/
+       }
+    }
+#endif
+
+    return err;
+}
+
+static void pci_device_linux_sysfs_enable(struct pci_device *dev)
+{
+    char name[256];
+    int fd;
+
+    snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/enable",
+             SYS_BUS_PCI,
+             dev->domain,
+             dev->bus,
+             dev->dev,
+             dev->func );
+    
+    fd = open( name, O_RDWR );
+    if (fd == -1)
+       return;
+
+    write( fd, "1", 1 );
+    close(fd);
+}
+
+static int pci_device_linux_sysfs_boot_vga(struct pci_device *dev)
+{
+    char name[256];
+    char reply[3];
+    int fd, bytes_read;
+    int ret = 0;
+
+    snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/boot_vga",
+             SYS_BUS_PCI,
+             dev->domain,
+             dev->bus,
+             dev->dev,
+             dev->func );
+    
+    fd = open( name, O_RDONLY );
+    if (fd == -1)
+       return 0;
+
+    bytes_read = read(fd, reply, 1);
+    if (bytes_read != 1)
+       goto out;
+    if (reply[0] == '1')
+       ret = 1;
+out:
+    close(fd);
+    return ret;
+}
+
+static int pci_device_linux_sysfs_has_kernel_driver(struct pci_device *dev)
+{
+    char name[256];
+    struct stat dummy;
+    int ret;
+
+    snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/driver",
+             SYS_BUS_PCI,
+             dev->domain,
+             dev->bus,
+             dev->dev,
+             dev->func );
+    
+    ret = stat(name, &dummy);
+    if (ret < 0)
+       return 0;
+    return 1;
+}
+
+static struct pci_io_handle *
+pci_device_linux_sysfs_open_device_io(struct pci_io_handle *ret,
+                                     struct pci_device *dev, int bar,
+                                     pciaddr_t base, pciaddr_t size)
+{
+    char name[PATH_MAX];
+
+    snprintf(name, PATH_MAX, "%s/%04x:%02x:%02x.%1u/resource%d",
+            SYS_BUS_PCI, dev->domain, dev->bus, dev->dev, dev->func, bar);
+
+    ret->fd = open(name, O_RDWR);
+
+    if (ret->fd < 0)
+       return NULL;
+
+    ret->base = base;
+    ret->size = size;
+
+    return ret;
+}
+
+static struct pci_io_handle *
+pci_device_linux_sysfs_open_legacy_io(struct pci_io_handle *ret,
+                                     struct pci_device *dev, pciaddr_t base,
+                                     pciaddr_t size)
+{
+    char name[PATH_MAX];
+
+    /* First check if there's a legacy io method for the device */
+    while (dev) {
+       snprintf(name, PATH_MAX, "/sys/class/pci_bus/%04x:%02x/legacy_io",
+                dev->domain, dev->bus);
+
+       ret->fd = open(name, O_RDWR);
+       if (ret->fd >= 0)
+           break;
+
+       dev = pci_device_get_parent_bridge(dev);
+    }
+
+    /* If not, /dev/port is the best we can do */
+    if (!dev)
+       ret->fd = open("/dev/port", O_RDWR);
+
+    if (ret->fd < 0)
+       return NULL;
+
+    ret->base = base;
+    ret->size = size;
+
+    return ret;
+}
+
+static void
+pci_device_linux_sysfs_close_io(struct pci_device *dev,
+                               struct pci_io_handle *handle)
+{
+    close(handle->fd);
+}
+
+static uint32_t
+pci_device_linux_sysfs_read32(struct pci_io_handle *handle, uint32_t port)
+{
+    uint32_t ret;
+
+    pread(handle->fd, &ret, 4, port + handle->base);
+
+    return ret;
+}
+
+static uint16_t
+pci_device_linux_sysfs_read16(struct pci_io_handle *handle, uint32_t port)
+{
+    uint16_t ret;
+
+    pread(handle->fd, &ret, 2, port + handle->base);
+
+    return ret;
+}
+
+static uint8_t
+pci_device_linux_sysfs_read8(struct pci_io_handle *handle, uint32_t port)
+{
+    uint8_t ret;
+
+    pread(handle->fd, &ret, 1, port + handle->base);
+
+    return ret;
+}
+
+static void
+pci_device_linux_sysfs_write32(struct pci_io_handle *handle, uint32_t port,
+                              uint32_t data)
+{
+    pwrite(handle->fd, &data, 4, port + handle->base);
+}
+
+static void
+pci_device_linux_sysfs_write16(struct pci_io_handle *handle, uint32_t port,
+                              uint16_t data)
+{
+    pwrite(handle->fd, &data, 2, port + handle->base);
+}
+
+static void
+pci_device_linux_sysfs_write8(struct pci_io_handle *handle, uint32_t port,
+                             uint8_t data)
+{
+    pwrite(handle->fd, &data, 1, port + handle->base);
+}
+
+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_range = pci_device_linux_sysfs_map_range,
+    .unmap_range = pci_device_linux_sysfs_unmap_range,
+
+    .read = pci_device_linux_sysfs_read,
+    .write = pci_device_linux_sysfs_write,
+
+    .fill_capabilities = pci_fill_capabilities_generic,
+    .enable = pci_device_linux_sysfs_enable,
+    .boot_vga = pci_device_linux_sysfs_boot_vga,
+    .has_kernel_driver = pci_device_linux_sysfs_has_kernel_driver,
+
+    .open_device_io = pci_device_linux_sysfs_open_device_io,
+    .open_legacy_io = pci_device_linux_sysfs_open_legacy_io,
+    .close_io = pci_device_linux_sysfs_close_io,
+    .read32 = pci_device_linux_sysfs_read32,
+    .read16 = pci_device_linux_sysfs_read16,
+    .read8 = pci_device_linux_sysfs_read8,
+    .write32 = pci_device_linux_sysfs_write32,
+    .write16 = pci_device_linux_sysfs_write16,
+    .write8 = pci_device_linux_sysfs_write8,
+};
diff --git a/src/netbsd_pci.c b/src/netbsd_pci.c
new file mode 100644 (file)
index 0000000..f33b3eb
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2008 Juan Romero Pardines
+ * Copyright (c) 2008 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <machine/sysarch.h>
+#include <machine/mtrr.h>
+
+#include <dev/pci/pciio.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+static int pcifd;
+
+static int
+pci_read(int bus, int dev, int func, uint32_t reg, uint32_t *val)
+{
+       struct pciio_bdf_cfgreg io;
+       int err;
+
+       bzero(&io, sizeof(io));
+       io.bus = bus;
+       io.device = dev;
+       io.function = func;
+       io.cfgreg.reg = reg;
+
+       err = ioctl(pcifd, PCI_IOC_BDF_CFGREAD, &io);
+       if (err)
+               return (err);
+
+       *val = io.cfgreg.val;
+
+       return 0;
+}
+
+static int
+pci_write(int bus, int dev, int func, uint32_t reg, uint32_t val)
+{
+       struct pciio_bdf_cfgreg io;
+
+       bzero(&io, sizeof(io));
+       io.bus = bus;
+       io.device = dev;
+       io.function = func;
+       io.cfgreg.reg = reg;
+       io.cfgreg.val = val;
+
+       return ioctl(pcifd, PCI_IOC_BDF_CFGWRITE, &io);
+}
+
+static int
+pci_nfuncs(int bus, int dev)
+{
+       uint32_t hdr;
+
+       if (pci_read(bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
+               return -1;
+
+       return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
+}
+
+static int
+pci_device_netbsd_map_range(struct pci_device *dev,
+    struct pci_device_mapping *map)
+{
+       struct mtrr mtrr;
+       int fd, error, nmtrr, prot = PROT_READ;
+
+       if ((fd = open("/dev/mem", O_RDWR)) == -1)
+               return errno;
+
+       if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
+               prot |= PROT_WRITE;
+
+       map->memory = mmap(NULL, map->size, prot, MAP_SHARED,
+           fd, map->base);
+       if (map->memory == MAP_FAILED)
+               return errno;
+
+       /* No need to set an MTRR if it's the default mode. */
+       if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
+           (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
+               mtrr.base = map->base;
+               mtrr.len = map->size;
+               mtrr.flags = MTRR_VALID;
+
+               if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE)
+                       mtrr.type = MTRR_TYPE_WB;
+               if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)
+                       mtrr.type = MTRR_TYPE_WC;
+#ifdef __i386__
+               error = i386_set_mtrr(&mtrr, &nmtrr);
+#endif
+#ifdef __amd64__
+               error = x86_64_set_mtrr(&mtrr, &nmtrr);
+#endif
+               if (error) {
+                       close(fd);
+                       return errno;
+               }
+       }
+
+       close(fd);
+
+       return 0;
+}
+
+static int
+pci_device_netbsd_unmap_range(struct pci_device *dev,
+    struct pci_device_mapping *map)
+{
+       struct mtrr mtrr;
+       int nmtrr, error;
+
+       if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
+           (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
+               mtrr.base = map->base;
+               mtrr.len = map->size;
+               mtrr.type = MTRR_TYPE_UC;
+               mtrr.flags = 0; /* clear/set MTRR */
+#ifdef __i386__
+               error = i386_set_mtrr(&mtrr, &nmtrr);
+#endif
+#ifdef __amd64__
+               error = x86_64_set_mtrr(&mtrr, &nmtrr);
+#endif
+               if (error)
+                       return errno;
+       }
+
+       return pci_device_generic_unmap_range(dev, map);
+}
+
+static int
+pci_device_netbsd_read(struct pci_device *dev, void *data,
+    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
+{
+       struct pciio_bdf_cfgreg io;
+
+       io.bus = dev->bus;
+       io.device = dev->dev;
+       io.function = dev->func;
+
+       *bytes_read = 0;
+       while (size > 0) {
+               int toread = MIN(size, 4 - (offset & 0x3));
+
+               io.cfgreg.reg = (offset & ~0x3);
+
+               if (ioctl(pcifd, PCI_IOC_BDF_CFGREAD, &io) == -1)
+                       return errno;
+
+               io.cfgreg.val = htole32(io.cfgreg.val);
+               io.cfgreg.val >>= ((offset & 0x3) * 8);
+
+               memcpy(data, &io.cfgreg.val, toread);
+
+               offset += toread;
+               data = (char *)data + toread;
+               size -= toread;
+               *bytes_read += toread;
+       }
+
+       return 0;
+}
+
+static int
+pci_device_netbsd_write(struct pci_device *dev, const void *data,
+    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
+{
+       struct pciio_bdf_cfgreg io;
+
+       if ((offset % 4) != 0 || (size % 4) != 0)
+               return EINVAL;
+
+       io.bus = dev->bus;
+       io.device = dev->dev;
+       io.function = dev->func;
+
+       *bytes_written = 0;
+       while (size > 0) {
+               io.cfgreg.reg = offset;
+               memcpy(&io.cfgreg.val, data, 4);
+
+               if (ioctl(pcifd, PCI_IOC_BDF_CFGWRITE, &io) == -1) 
+                       return errno;
+
+               offset += 4;
+               data = (char *)data + 4;
+               size -= 4;
+               *bytes_written += 4;
+       }
+
+       return 0;
+}
+
+static void
+pci_system_netbsd_destroy(void)
+{
+       close(pcifd);
+       free(pci_sys);
+       pci_sys = NULL;
+}
+
+static int
+pci_device_netbsd_probe(struct pci_device *device)
+{
+       struct pci_device_private *priv = (struct pci_device_private *)device;
+       struct pci_mem_region *region;
+       uint64_t reg64, size64;
+       uint32_t bar, reg, size;
+       int bus, dev, func, err;
+
+       bus = device->bus;
+       dev = device->dev;
+       func = device->func;
+
+       err = pci_read(bus, dev, func, PCI_BHLC_REG, &reg);
+       if (err)
+               return err;
+
+       priv->header_type = PCI_HDRTYPE_TYPE(reg);
+       if (priv->header_type != 0)
+               return 0;
+
+       region = device->regions;
+       for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
+            bar += sizeof(uint32_t), region++) {
+               err = pci_read(bus, dev, func, bar, &reg);
+               if (err)
+                       return err;
+
+               /* Probe the size of the region. */
+               err = pci_write(bus, dev, func, bar, ~0);
+               if (err)
+                       return err;
+               pci_read(bus, dev, func, bar, &size);
+               pci_write(bus, dev, func, bar, reg);
+
+               if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
+                       region->is_IO = 1;
+                       region->base_addr = PCI_MAPREG_IO_ADDR(reg);
+                       region->size = PCI_MAPREG_IO_SIZE(size);
+               } else {
+                       if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
+                               region->is_prefetchable = 1;
+                       switch(PCI_MAPREG_MEM_TYPE(reg)) {
+                       case PCI_MAPREG_MEM_TYPE_32BIT:
+                       case PCI_MAPREG_MEM_TYPE_32BIT_1M:
+                               region->base_addr = PCI_MAPREG_MEM_ADDR(reg);
+                               region->size = PCI_MAPREG_MEM_SIZE(size);
+                               break;
+                       case PCI_MAPREG_MEM_TYPE_64BIT:
+                               region->is_64 = 1;
+
+                               reg64 = reg;
+                               size64 = size;
+
+                               bar += sizeof(uint32_t);
+
+                               err = pci_read(bus, dev, func, bar, &reg);
+                               if (err)
+                                       return err;
+                               reg64 |= (uint64_t)reg << 32;
+
+                               err = pci_write(bus, dev, func, bar, ~0);
+                               if (err)
+                                       return err;
+                               pci_read(bus, dev, func, bar, &size);
+                               pci_write(bus, dev, func, bar, reg64 >> 32);
+                               size64 |= (uint64_t)size << 32;
+
+                               region->base_addr = PCI_MAPREG_MEM64_ADDR(reg64);
+                               region->size = PCI_MAPREG_MEM64_SIZE(size64);
+                               region++;
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static const struct pci_system_methods netbsd_pci_methods = {
+       pci_system_netbsd_destroy,
+       NULL,
+       NULL,
+       pci_device_netbsd_probe,
+       pci_device_netbsd_map_range,
+       pci_device_netbsd_unmap_range,
+       pci_device_netbsd_read,
+       pci_device_netbsd_write,
+       pci_fill_capabilities_generic
+};
+
+int
+pci_system_netbsd_create(void)
+{
+       struct pci_device_private *device;
+       int bus, dev, func, ndevs, nfuncs;
+       uint32_t reg;
+
+       pcifd = open("/dev/pci0", O_RDWR);
+       if (pcifd == -1)
+               return ENXIO;
+
+       pci_sys = calloc(1, sizeof(struct pci_system));
+       if (pci_sys == NULL) {
+               close(pcifd);
+               return ENOMEM;
+       }
+
+       pci_sys->methods = &netbsd_pci_methods;
+
+       ndevs = 0;
+       for (bus = 0; bus < 256; bus++) {
+               for (dev = 0; dev < 32; dev++) {
+                       nfuncs = pci_nfuncs(bus, dev);
+                       for (func = 0; func < nfuncs; func++) {
+                               if (pci_read(bus, dev, func, PCI_ID_REG,
+                                   &reg) != 0)
+                                       continue;
+                               if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
+                                   PCI_VENDOR(reg) == 0)
+                                       continue;
+
+                               ndevs++;
+                       }
+               }
+       }
+
+       pci_sys->num_devices = ndevs;
+       pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
+       if (pci_sys->devices == NULL) {
+               free(pci_sys);
+               close(pcifd);
+               return ENOMEM;
+       }
+
+       device = pci_sys->devices;
+       for (bus = 0; bus < 256; bus++) {
+               for (dev = 0; dev < 32; dev++) {
+                       nfuncs = pci_nfuncs(bus, dev);
+                       for (func = 0; func < nfuncs; func++) {
+                               if (pci_read(bus, dev, func, PCI_ID_REG,
+                                   &reg) != 0)
+                                       continue;
+                               if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
+                                   PCI_VENDOR(reg) == 0)
+                                       continue;
+
+                               device->base.domain = 0;
+                               device->base.bus = bus;
+                               device->base.dev = dev;
+                               device->base.func = func;
+                               device->base.vendor_id = PCI_VENDOR(reg);
+                               device->base.device_id = PCI_PRODUCT(reg);
+
+                               if (pci_read(bus, dev, func, PCI_CLASS_REG,
+                                   &reg) != 0)
+                                       continue;
+
+                               device->base.device_class =
+                                   PCI_INTERFACE(reg) | PCI_CLASS(reg) << 16 |
+                                   PCI_SUBCLASS(reg) << 8;
+                               device->base.revision = PCI_REVISION(reg);
+
+                               if (pci_read(bus, dev, func, PCI_SUBSYS_ID_REG,
+                                   &reg) != 0)
+                                       continue;
+
+                               device->base.subvendor_id = PCI_VENDOR(reg);
+                               device->base.subdevice_id = PCI_PRODUCT(reg);
+
+                               device++;
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/src/openbsd_pci.c b/src/openbsd_pci.c
new file mode 100644 (file)
index 0000000..e954144
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2008 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/memrange.h>
+#include <sys/mman.h>
+#include <sys/pciio.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+/*
+ * This should allow for 16 domains, which should cover everything
+ * except perhaps the really big fridge-sized sparc64 server machines
+ * that are unlikely to have any graphics hardware in them.
+ */
+static int pcifd[16];
+static int ndomains;
+
+static int aperturefd = -1;
+
+static int
+pci_read(int domain, int bus, int dev, int func, uint32_t reg, uint32_t *val)
+{
+       struct pci_io io;
+       int err;
+
+       bzero(&io, sizeof(io));
+       io.pi_sel.pc_bus = bus;
+       io.pi_sel.pc_dev = dev;
+       io.pi_sel.pc_func = func;
+       io.pi_reg = reg;
+       io.pi_width = 4;
+
+       err = ioctl(pcifd[domain], PCIOCREAD, &io);
+       if (err)
+               return (err);
+
+       *val = io.pi_data;
+
+       return 0;
+}
+
+static int
+pci_write(int domain, int bus, int dev, int func, uint32_t reg, uint32_t val)
+{
+       struct pci_io io;
+
+       bzero(&io, sizeof(io));
+       io.pi_sel.pc_bus = bus;
+       io.pi_sel.pc_dev = dev;
+       io.pi_sel.pc_func = func;
+       io.pi_reg = reg;
+       io.pi_width = 4;
+       io.pi_data = val;
+
+       return ioctl(pcifd[domain], PCIOCWRITE, &io);
+}
+
+/**
+ * Read a VGA ROM
+ *
+ */
+static int
+pci_device_openbsd_read_rom(struct pci_device *device, void *buffer)
+{
+       struct pci_device_private *priv = (struct pci_device_private *)device;
+       unsigned char *bios;
+       pciaddr_t rom_base;
+       pciaddr_t rom_size;
+       u_int32_t csr, rom;
+       int pci_rom, domain, bus, dev, func;
+
+       domain = device->domain;
+       if (domain < 0 || domain >= ndomains)
+               return ENXIO;
+
+       bus = device->bus;
+       dev = device->dev;
+       func = device->func;
+
+       if (aperturefd == -1)
+               return ENOSYS;
+
+       if (priv->base.rom_size == 0) {
+#if defined(__alpha__) || defined(__amd64__) || defined(__i386__)
+               if ((device->device_class & 0x00ffff00) ==
+                   ((PCI_CLASS_DISPLAY << 16) |
+                       (PCI_SUBCLASS_DISPLAY_VGA << 8))) {
+                       rom_base = 0xc0000;
+                       rom_size = 0x10000;
+                       pci_rom = 0;
+               } else
+#endif
+                       return ENOSYS;
+       } else {
+               rom_base = priv->rom_base;
+               rom_size = priv->base.rom_size;
+               pci_rom = 1;
+
+               pci_read(domain, bus, dev, func, PCI_COMMAND_STATUS_REG, &csr);
+               pci_write(domain, bus, dev, func, PCI_COMMAND_STATUS_REG,
+                   csr | PCI_COMMAND_MEM_ENABLE);
+               pci_read(domain, bus, dev, func, PCI_ROM_REG, &rom);
+               pci_write(domain, bus, dev, func, PCI_ROM_REG,
+                   rom | PCI_ROM_ENABLE);
+       }
+
+       bios = mmap(NULL, rom_size, PROT_READ, MAP_SHARED,
+           aperturefd, (off_t)rom_base);
+       if (bios == MAP_FAILED)
+               return errno;
+
+       memcpy(buffer, bios, rom_size);
+       munmap(bios, rom_size);
+
+       if (pci_rom) {
+               /* Restore PCI config space */
+               pci_write(domain, bus, dev, func, PCI_ROM_REG, rom);
+               pci_write(domain, bus, dev, func, PCI_COMMAND_STATUS_REG, csr);
+       }
+       return 0;
+}
+
+static int
+pci_nfuncs(int domain, int bus, int dev)
+{
+       uint32_t hdr;
+
+       if (domain < 0 || domain >= ndomains)
+               return ENXIO;
+
+       if (pci_read(domain, bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
+               return -1;
+
+       return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
+}
+
+static int
+pci_device_openbsd_map_range(struct pci_device *dev,
+    struct pci_device_mapping *map)
+{
+       struct mem_range_desc mr;
+       struct mem_range_op mo;
+       int prot = PROT_READ;
+
+       if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
+               prot |= PROT_WRITE;
+
+       map->memory = mmap(NULL, map->size, prot, MAP_SHARED, aperturefd,
+           map->base);
+       if (map->memory == MAP_FAILED)
+               return  errno;
+#if defined(__i386__) || defined(__amd64__)
+       /* No need to set an MTRR if it's the default mode. */
+       if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
+           (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
+               mr.mr_base = map->base;
+               mr.mr_len = map->size;
+               mr.mr_flags = 0;
+               if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE)
+                       mr.mr_flags |= MDF_WRITEBACK;
+               if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)
+                       mr.mr_flags |= MDF_WRITECOMBINE;
+               strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner));
+
+               mo.mo_desc = &mr;
+               mo.mo_arg[0] = MEMRANGE_SET_UPDATE;
+
+               if (ioctl(aperturefd, MEMRANGE_SET, &mo))
+                       (void)fprintf(stderr, "mtrr set failed: %s\n",
+                           strerror(errno));
+       }
+#endif
+       return 0;
+}
+
+static int
+pci_device_openbsd_unmap_range(struct pci_device *dev,
+    struct pci_device_mapping *map)
+{
+#if defined(__i386__) || defined(__amd64__)
+       struct mem_range_desc mr;
+       struct mem_range_op mo;
+
+       if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
+           (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
+               mr.mr_base = map->base;
+               mr.mr_len = map->size;
+               mr.mr_flags = MDF_UNCACHEABLE;
+               strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner));
+
+               mo.mo_desc = &mr;
+               mo.mo_arg[0] = MEMRANGE_SET_REMOVE;
+
+               (void)ioctl(aperturefd, MEMRANGE_SET, &mo);
+       }
+#endif
+       return pci_device_generic_unmap_range(dev, map);
+}
+
+static int
+pci_device_openbsd_read(struct pci_device *dev, void *data,
+    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
+{
+       struct pci_io io;
+
+       io.pi_sel.pc_bus = dev->bus;
+       io.pi_sel.pc_dev = dev->dev;
+       io.pi_sel.pc_func = dev->func;
+
+       *bytes_read = 0;
+       while (size > 0) {
+               int toread = MIN(size, 4 - (offset & 0x3));
+
+               io.pi_reg = (offset & ~0x3);
+               io.pi_width = 4;
+
+               if (ioctl(pcifd[dev->domain], PCIOCREAD, &io) == -1)
+                       return errno;
+
+               io.pi_data = htole32(io.pi_data);
+               io.pi_data >>= ((offset & 0x3) * 8);
+
+               memcpy(data, &io.pi_data, toread);
+
+               offset += toread;
+               data = (char *)data + toread;
+               size -= toread;
+               *bytes_read += toread;
+       }
+
+       return 0;
+}
+
+static int
+pci_device_openbsd_write(struct pci_device *dev, const void *data,
+    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
+{
+       struct pci_io io;
+
+       if ((offset % 4) != 0 || (size % 4) != 0)
+               return EINVAL;
+
+       io.pi_sel.pc_bus = dev->bus;
+       io.pi_sel.pc_dev = dev->dev;
+       io.pi_sel.pc_func = dev->func;
+
+       *bytes_written = 0;
+       while (size > 0) {
+               io.pi_reg = offset;
+               io.pi_width = 4;
+               memcpy(&io.pi_data, data, 4);
+
+               if (ioctl(pcifd[dev->domain], PCIOCWRITE, &io) == -1)
+                       return errno;
+
+               offset += 4;
+               data = (char *)data + 4;
+               size -= 4;
+               *bytes_written += 4;
+       }
+
+       return 0;
+}
+
+static void
+pci_system_openbsd_destroy(void)
+{
+       int domain;
+
+       for (domain = 0; domain < ndomains; domain++)
+               close(pcifd[domain]);
+       ndomains = 0;
+}
+
+static int
+pci_device_openbsd_probe(struct pci_device *device)
+{
+       struct pci_device_private *priv = (struct pci_device_private *)device;
+       struct pci_mem_region *region;
+       uint64_t reg64, size64;
+       uint32_t bar, reg, size;
+       int domain, bus, dev, func, err;
+
+       domain = device->domain;
+       bus = device->bus;
+       dev = device->dev;
+       func = device->func;
+
+       err = pci_read(domain, bus, dev, func, PCI_BHLC_REG, &reg);
+       if (err)
+               return err;
+
+       priv->header_type = PCI_HDRTYPE_TYPE(reg);
+       if (priv->header_type != 0)
+               return 0;
+
+       region = device->regions;
+       for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
+            bar += sizeof(uint32_t), region++) {
+               err = pci_read(domain, bus, dev, func, bar, &reg);
+               if (err)
+                       return err;
+
+               /* Probe the size of the region. */
+               err = pci_write(domain, bus, dev, func, bar, ~0);
+               if (err)
+                       return err;
+               pci_read(domain, bus, dev, func, bar, &size);
+               pci_write(domain, bus, dev, func, bar, reg);
+
+               if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
+                       region->is_IO = 1;
+                       region->base_addr = PCI_MAPREG_IO_ADDR(reg);
+                       region->size = PCI_MAPREG_IO_SIZE(size);
+               } else {
+                       if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
+                               region->is_prefetchable = 1;
+                       switch(PCI_MAPREG_MEM_TYPE(reg)) {
+                       case PCI_MAPREG_MEM_TYPE_32BIT:
+                       case PCI_MAPREG_MEM_TYPE_32BIT_1M:
+                               region->base_addr = PCI_MAPREG_MEM_ADDR(reg);
+                               region->size = PCI_MAPREG_MEM_SIZE(size);
+                               break;
+                       case PCI_MAPREG_MEM_TYPE_64BIT:
+                               region->is_64 = 1;
+
+                               reg64 = reg;
+                               size64 = size;
+
+                               bar += sizeof(uint32_t);
+
+                               err = pci_read(domain, bus, dev, func, bar, &reg);
+                               if (err)
+                                       return err;
+                               reg64 |= (uint64_t)reg << 32;
+
+                               err = pci_write(domain, bus, dev, func, bar, ~0);
+                               if (err)
+                                       return err;
+                               pci_read(domain, bus, dev, func, bar, &size);
+                               pci_write(domain, bus, dev, func, bar, reg64 >> 32);
+                               size64 |= (uint64_t)size << 32;
+
+                               region->base_addr = PCI_MAPREG_MEM64_ADDR(reg64);
+                               region->size = PCI_MAPREG_MEM64_SIZE(size64);
+                               region++;
+                               break;
+                       }
+               }
+       }
+
+       /* Probe expansion ROM if present */
+       err = pci_read(domain, bus, dev, func, PCI_ROM_REG, &reg);
+       if (err)
+               return err;
+       if (reg != 0) {
+               err = pci_write(domain, bus, dev, func, PCI_ROM_REG, ~PCI_ROM_ENABLE);
+               if (err)
+                       return err;
+               pci_read(domain, bus, dev, func, PCI_ROM_REG, &size);
+               pci_write(domain, bus, dev, func, PCI_ROM_REG, reg);
+
+               if (PCI_ROM_ADDR(reg) != 0) {
+                       priv->rom_base = PCI_ROM_ADDR(reg);
+                       device->rom_size = PCI_ROM_SIZE(size);
+               }
+       }
+       return 0;
+}
+
+static const struct pci_system_methods openbsd_pci_methods = {
+       pci_system_openbsd_destroy,
+       NULL,
+       pci_device_openbsd_read_rom,
+       pci_device_openbsd_probe,
+       pci_device_openbsd_map_range,
+       pci_device_openbsd_unmap_range,
+       pci_device_openbsd_read,
+       pci_device_openbsd_write,
+       pci_fill_capabilities_generic
+};
+
+int
+pci_system_openbsd_create(void)
+{
+       struct pci_device_private *device;
+       int domain, bus, dev, func, ndevs, nfuncs;
+       char path[MAXPATHLEN];
+       uint32_t reg;
+
+       if (ndomains > 0)
+               return 0;
+
+       for (domain = 0; domain < sizeof(pcifd) / sizeof(pcifd[0]); domain++) {
+               snprintf(path, sizeof(path), "/dev/pci%d", domain);
+               pcifd[domain] = open(path, O_RDWR);
+               if (pcifd[domain] == -1)
+                       break;
+               ndomains++;
+       }
+
+       if (ndomains == 0)
+               return ENXIO;
+
+       pci_sys = calloc(1, sizeof(struct pci_system));
+       if (pci_sys == NULL) {
+               for (domain = 0; domain < ndomains; domain++)
+                       close(pcifd[domain]);
+               ndomains = 0;
+               return ENOMEM;
+       }
+
+       pci_sys->methods = &openbsd_pci_methods;
+
+       ndevs = 0;
+       for (domain = 0; domain < ndomains; domain++) {
+               for (bus = 0; bus < 256; bus++) {
+                       for (dev = 0; dev < 32; dev++) {
+                               nfuncs = pci_nfuncs(domain, bus, dev);
+                               for (func = 0; func < nfuncs; func++) {
+                                       if (pci_read(domain, bus, dev, func,
+                                           PCI_ID_REG, &reg) != 0)
+                                               continue;
+                                       if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
+                                           PCI_VENDOR(reg) == 0)
+                                               continue;
+
+                                       ndevs++;
+                               }
+                       }
+               }
+       }
+
+       pci_sys->num_devices = ndevs;
+       pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
+       if (pci_sys->devices == NULL) {
+               free(pci_sys);
+               pci_sys = NULL;
+               for (domain = 0; domain < ndomains; domain++)
+                       close(pcifd[domain]);
+               ndomains = 0;
+               return ENOMEM;
+       }
+
+       device = pci_sys->devices;
+       for (domain = 0; domain < ndomains; domain++) {
+               for (bus = 0; bus < 256; bus++) {
+                       for (dev = 0; dev < 32; dev++) {
+                               nfuncs = pci_nfuncs(domain, bus, dev);
+                               for (func = 0; func < nfuncs; func++) {
+                                       if (pci_read(domain, bus, dev, func,
+                                           PCI_ID_REG, &reg) != 0)
+                                               continue;
+                                       if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
+                                           PCI_VENDOR(reg) == 0)
+                                               continue;
+
+                                       device->base.domain = domain;
+                                       device->base.bus = bus;
+                                       device->base.dev = dev;
+                                       device->base.func = func;
+                                       device->base.vendor_id = PCI_VENDOR(reg);
+                                       device->base.device_id = PCI_PRODUCT(reg);
+
+                                       if (pci_read(domain, bus, dev, func,
+                                           PCI_CLASS_REG, &reg) != 0)
+                                               continue;
+
+                                       device->base.device_class =
+                                           PCI_INTERFACE(reg) |
+                                           PCI_CLASS(reg) << 16 |
+                                           PCI_SUBCLASS(reg) << 8;
+                                       device->base.revision = PCI_REVISION(reg);
+
+                                       if (pci_read(domain, bus, dev, func,
+                                           PCI_SUBVEND_0, &reg) != 0)
+                                               continue;
+
+                                       device->base.subvendor_id = PCI_VENDOR(reg);
+                                       device->base.subdevice_id = PCI_PRODUCT(reg);
+
+                                       device++;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+void
+pci_system_openbsd_init_dev_mem(int fd)
+{
+       aperturefd = fd;
+}
diff --git a/src/pci_tools.h b/src/pci_tools.h
new file mode 100644 (file)
index 0000000..b353b31
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright Â© 2007 Sun Microsystems, Inc.  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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+#ifndef _SYS_PCI_TOOLS_H
+#define        _SYS_PCI_TOOLS_H
+
+#pragma ident  "@(#)pci_tools.h        1.4     05/09/28 SMI"
+
+#include <sys/modctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Versioning. Have different versions for userland program and drivers, so
+ * they can all stay in sync with each other.
+ */
+#define        PCITOOL_USER_VERSION    1
+#define        PCITOOL_DRVR_VERSION    1
+
+/* File suffixes for nexus pcitool nodes. */
+#define        PCI_MINOR_REG   "reg"
+#define        PCI_MINOR_INTR  "intr"
+
+/*
+ * Ioctls for PCI tools.
+ */
+#define        PCITOOL_IOC             (('P' << 24) | ('C' << 16) | ('T' << 8))
+
+/* Read/write a device on a PCI bus, in physical space. */
+#define        PCITOOL_DEVICE_GET_REG  (PCITOOL_IOC | 1)
+#define        PCITOOL_DEVICE_SET_REG  (PCITOOL_IOC | 2)
+
+/* Read/write the PCI nexus bridge, in physical space. */
+#define        PCITOOL_NEXUS_GET_REG   (PCITOOL_IOC | 3)
+#define        PCITOOL_NEXUS_SET_REG   (PCITOOL_IOC | 4)
+
+/* Get/set interrupt-CPU mapping for PCI devices. */
+#define        PCITOOL_DEVICE_GET_INTR (PCITOOL_IOC | 5)
+#define        PCITOOL_DEVICE_SET_INTR (PCITOOL_IOC | 6)
+
+/* Return the number of supported interrupts on a PCI bus. */
+#define        PCITOOL_DEVICE_NUM_INTR (PCITOOL_IOC | 7)
+
+
+/*
+ * This file contains data structures for the pci tool.
+ */
+#define        PCITOOL_CONFIG  0
+#define        PCITOOL_BAR0    1
+#define        PCITOOL_BAR1    2
+#define        PCITOOL_BAR2    3
+#define        PCITOOL_BAR3    4
+#define        PCITOOL_BAR4    5
+#define        PCITOOL_BAR5    6
+#define        PCITOOL_ROM     7
+
+/*
+ * Pass this through barnum to signal to use a base addr instead.
+ * This is for platforms which do not have a way to automatically map
+ * a selected bank to a base addr.
+ */
+#define        PCITOOL_BASE    0xFF
+
+/*
+ * BAR corresponding to space desired.
+ */
+typedef enum {
+    config = PCITOOL_CONFIG,
+    bar0 = PCITOOL_BAR0,
+    bar1 = PCITOOL_BAR1,
+    bar2 = PCITOOL_BAR2,
+    bar3 = PCITOOL_BAR3,
+    bar4 = PCITOOL_BAR4,
+    bar5 = PCITOOL_BAR5,
+    rom = PCITOOL_ROM
+} pcitool_bars_t;
+
+
+/*
+ * PCITOOL error numbers.
+ */
+
+typedef enum {
+       PCITOOL_SUCCESS = 0x0,
+       PCITOOL_INVALID_CPUID,
+       PCITOOL_INVALID_INO,
+       PCITOOL_PENDING_INTRTIMEOUT,
+       PCITOOL_REGPROP_NOTWELLFORMED,
+       PCITOOL_INVALID_ADDRESS,
+       PCITOOL_NOT_ALIGNED,
+       PCITOOL_OUT_OF_RANGE,
+       PCITOOL_END_OF_RANGE,
+       PCITOOL_ROM_DISABLED,
+       PCITOOL_ROM_WRITE,
+       PCITOOL_IO_ERROR,
+       PCITOOL_INVALID_SIZE
+} pcitool_errno_t;
+
+
+/*
+ * PCITOOL_DEVICE_SET_INTR ioctl data structure to re-assign the interrupts.
+ */
+typedef struct pcitool_intr_set {
+       uint16_t user_version;  /* Userland program version - to krnl */
+       uint16_t drvr_version;  /* Driver version - from kernel */
+       uint32_t ino;           /* interrupt to set - to kernel */
+       uint32_t cpu_id;        /* to: cpu to set / from: old cpu returned */
+       pcitool_errno_t status; /* from kernel */
+} pcitool_intr_set_t;
+
+
+/*
+ * PCITOOL_DEVICE_GET_INTR ioctl data structure to dump out the
+ * ino mapping information.
+ */
+
+typedef struct pcitool_intr_dev {
+       uint32_t        dev_inst;       /* device instance - from kernel */
+       char            driver_name[MAXMODCONFNAME];    /* from kernel */
+       char            path[MAXPATHLEN]; /* device path - from kernel */
+} pcitool_intr_dev_t;
+
+
+typedef struct pcitool_intr_get {
+       uint16_t user_version;          /* Userland program version - to krnl */
+       uint16_t drvr_version;          /* Driver version - from kernel */
+       uint32_t        ino;            /* interrupt number - to kernel */
+       uint8_t         num_devs_ret;   /* room for this # of devs to be */
+                                       /* returned - to kernel */
+                                       /* # devs returned - from kernel */
+       uint8_t         num_devs;       /* # devs on this ino - from kernel */
+                                       /* intrs enabled for devs if > 0 */
+       uint8_t         ctlr;           /* controller number - from kernel */
+       uint32_t        cpu_id;         /* cpu of interrupt - from kernel */
+       pcitool_errno_t status;         /* returned status - from kernel */
+       pcitool_intr_dev_t      dev[1]; /* start of variable device list */
+                                       /* from kernel */
+} pcitool_intr_get_t;
+
+/*
+ * Get the size needed to return the number of devices wanted.
+ * Can't say num_devs - 1 as num_devs may be unsigned.
+ */
+#define        PCITOOL_IGET_SIZE(num_devs) \
+       (sizeof (pcitool_intr_get_t) - \
+       sizeof (pcitool_intr_dev_t) + \
+       (num_devs * sizeof (pcitool_intr_dev_t)))
+
+/*
+ * Size and endian fields for acc_attr bitmask.
+ */
+#define        PCITOOL_ACC_ATTR_SIZE_MASK      0x3
+#define        PCITOOL_ACC_ATTR_SIZE_1         0x0
+#define        PCITOOL_ACC_ATTR_SIZE_2         0x1
+#define        PCITOOL_ACC_ATTR_SIZE_4         0x2
+#define        PCITOOL_ACC_ATTR_SIZE_8         0x3
+#define        PCITOOL_ACC_ATTR_SIZE(x)        (1 << (x & PCITOOL_ACC_ATTR_SIZE_MASK))
+
+#define        PCITOOL_ACC_ATTR_ENDN_MASK      0x100
+#define        PCITOOL_ACC_ATTR_ENDN_LTL       0x0
+#define        PCITOOL_ACC_ATTR_ENDN_BIG       0x100
+#define        PCITOOL_ACC_IS_BIG_ENDIAN(x)    (x & PCITOOL_ACC_ATTR_ENDN_BIG)
+
+/*
+ * Data structure to read and write to pci device registers.
+ * This is the argument to the following ioctls:
+ *     PCITOOL_DEVICE_SET/GET_REG
+ *     PCITOOL_NEXUS_SET/GET_REG
+ */
+typedef struct pcitool_reg {
+       uint16_t        user_version;   /* Userland program version - to krnl */
+       uint16_t        drvr_version;   /* Driver version - from kernel */
+       uint8_t         bus_no;         /* pci bus - to kernel */
+       uint8_t         dev_no;         /* pci dev - to kernel */
+       uint8_t         func_no;        /* pci function - to kernel */
+       uint8_t         barnum;         /* bank (DEVCTL_NEXUS_SET/GET_REG) or */
+                                       /*   BAR from pcitools_bar_t */
+                                       /*   (DEVCTL_DEVICE_SET/GET_REG) */
+                                       /*   to kernel */
+       uint64_t        offset;         /* to kernel */
+       uint32_t        acc_attr;       /* access attributes - to kernel */
+       uint32_t        padding1;       /* 8-byte align next uint64_t for X86 */
+       uint64_t        data;           /* to/from kernel, 64-bit alignment */
+       uint32_t        status;         /* from kernel */
+       uint32_t        padding2;       /* 8-byte align next uint64_t for X86 */
+       uint64_t        phys_addr;      /* from kernel, 64-bit alignment */
+} pcitool_reg_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_PCI_TOOLS_H */
diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h
new file mode 100644 (file)
index 0000000..1111ef0
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * (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>
+ */
+
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+# define _pci_hidden      __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+# define _pci_hidden      __hidden
+#else /* not gcc >= 4 and not Sun Studio >= 8 */
+# define _pci_hidden
+#endif /* GNUC >= 4 */
+
+struct pci_device_mapping;
+
+int pci_fill_capabilities_generic( struct pci_device * dev );
+int pci_device_generic_unmap_range(struct pci_device *dev,
+    struct pci_device_mapping *map);
+
+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_range)(struct pci_device *dev, struct pci_device_mapping *map);
+    int (*unmap_range)(struct pci_device * dev,
+                      struct pci_device_mapping *map);
+    
+    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 );
+    void (*enable)( struct pci_device *dev );
+    int (*boot_vga)( struct pci_device *dev );
+    int (*has_kernel_driver)( struct pci_device *dev );
+    struct pci_io_handle *(*open_device_io)( struct pci_io_handle *handle,
+                                            struct pci_device *dev, int bar,
+                                            pciaddr_t base, pciaddr_t size );
+    struct pci_io_handle *(*open_legacy_io)( struct pci_io_handle *handle,
+                                            struct pci_device *dev,
+                                            pciaddr_t base, pciaddr_t size );
+    void (*close_io)( struct pci_device *dev, struct pci_io_handle *handle );
+    uint32_t (*read32)( struct pci_io_handle *handle, uint32_t reg );
+    uint16_t (*read16)( struct pci_io_handle *handle, uint32_t reg );
+    uint8_t  (*read8)( struct pci_io_handle *handle, uint32_t reg );
+    void (*write32)( struct pci_io_handle *handle, uint32_t reg,
+                    uint32_t data );
+    void (*write16)( struct pci_io_handle *handle, uint32_t reg,
+                    uint16_t data );
+    void (*write8)( struct pci_io_handle *handle, uint32_t reg, uint8_t data );
+};
+
+struct pci_device_mapping {
+    pciaddr_t base;
+    pciaddr_t size;
+    unsigned region;
+    unsigned flags;
+    void *memory;
+};
+
+struct pci_io_handle {
+    pciaddr_t base;
+    pciaddr_t size;
+    int fd;
+};
+
+struct pci_device_private {
+    struct pci_device  base;
+    const char * device_string;
+    
+    uint8_t header_type;
+
+    /**
+     * \name PCI Capabilities
+     */
+    /*@{*/
+    const struct pci_agp_info * agp;   /**< AGP capability information. */
+    /*@}*/
+    
+    /**
+     * Base address of the device's expansion ROM.
+     */
+    pciaddr_t rom_base;
+
+    /**
+     * \name Bridge information.
+     */
+    /*@{*/
+    union {
+       struct pci_bridge_info * pci;
+       struct pci_pcmcia_bridge_info * pcmcia;
+    } bridge;
+    /*@}*/
+
+    /**
+     * \name Mappings active on this device.
+     */
+    /*@{*/
+    struct pci_device_mapping *mappings;
+    unsigned num_mappings;
+    /*@}*/
+};
+
+
+/**
+ * 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;
+
+#ifdef HAVE_MTRR
+    int mtrr_fd;
+#endif
+    int vgaarb_fd;
+    int vga_count;
+    struct pci_device *vga_target;
+    struct pci_device *vga_default_dev;
+};
+
+extern struct pci_system * pci_sys;
+
+extern int pci_system_linux_sysfs_create( void );
+extern int pci_system_freebsd_create( void );
+extern int pci_system_netbsd_create( void );
+extern int pci_system_openbsd_create( void );
+extern void pci_system_openbsd_init_dev_mem( int );
+extern int pci_system_solx_devfs_create( void );
+extern int pci_system_x86_create( void );
+extern void pci_io_cleanup( void );
diff --git a/src/scanpci.c b/src/scanpci.c
new file mode 100644 (file)
index 0000000..34ec664
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * (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 <err.h>
+#include <unistd.h>
+
+#include "pciaccess.h"
+
+
+static void
+print_pci_bridge( const struct pci_bridge_info * info )
+{
+    printf( "  Bus: primary=%02x, secondary=%02x, subordinate=%02x, "
+           "sec-latency=%u\n",
+           info->primary_bus,
+           info->secondary_bus,
+           info->subordinate_bus,
+           info->secondary_latency_timer );
+    printf( "  I/O behind bridge: %08x-%08x\n",
+           info->io_base,
+           info->io_limit );
+    printf( "  Memory behind bridge: %08x-%08x\n",
+           info->mem_base,
+           info->mem_limit );
+    printf( "  Prefetchable memory behind bridge: %08llx-%08llx\n",
+           info->prefetch_mem_base,
+           info->prefetch_mem_limit );
+}
+
+static 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 ");
+    if (dev->domain != 0)
+       printf("domain 0x%04x ", dev->domain);
+    printf("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, 12 );
+       pci_device_cfg_read_u8( dev, & latency_timer, 13 );
+       pci_device_cfg_read_u8( dev, & header_type, 14 );
+       pci_device_cfg_read_u8( dev, & bist, 15 );
+
+       printf( "  BIST      0x%02x  HEADER 0x%02x  LATENCY 0x%02x  CACHE 0x%02x\n",
+               bist,
+               header_type,
+               latency_timer,
+               cache_line_size );
+       
+       pci_device_probe( dev );
+       for ( i = 0 ; i < 6 ; i++ ) {
+           if ( dev->regions[i].base_addr != 0 ) {
+               printf( "  BASE%u     0x%08x SIZE %d  %s",
+                       i,
+                       (intptr_t) dev->regions[i].base_addr,
+                       (size_t) dev->regions[i].size,
+                       (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 );
+
+       if ( (dev->device_class >> 16) == 0x06 ) {
+           const void * info;
+
+           if ( (info = pci_device_get_bridge_info(dev)) != NULL ) {
+               print_pci_bridge( (const struct pci_bridge_info *) info );
+           }
+           else if ( (info = pci_device_get_pcmcia_bridge_info(dev)) != NULL ) {
+               /* Nothing yet. */
+           }
+       }
+    }
+}
+
+
+int main( int argc, char ** argv )
+{
+    struct pci_device_iterator * iter;
+    struct pci_device * dev;
+    int ret;
+    int verbose = 0;
+    int c;
+    int errors = 0;
+
+    while ((c = getopt(argc, argv, "v")) != -1) {
+       switch (c) {
+       case 'v':
+           verbose = 1;
+           break;
+       case '?':
+           errors++;
+       }
+    }
+    if (errors != 0) {
+       fprintf(stderr, "usage: %s [-v]\n", argv[0]);
+       exit(2);
+    }
+
+    ret = pci_system_init();
+    if (ret != 0)
+       err(1, "Couldn't initialize PCI system");
+
+    iter = pci_slot_match_iterator_create( NULL );
+
+    while ( (dev = pci_device_next( iter )) != NULL ) {
+       print_pci_device( dev, verbose );
+    }
+
+    pci_system_cleanup();
+    return 0;
+}
diff --git a/src/scanpci.man b/src/scanpci.man
new file mode 100644 (file)
index 0000000..aec7b2e
--- /dev/null
@@ -0,0 +1,44 @@
+.\" Copyright (C) 2000 The XFree86 Project, Inc.  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 the
+.\" rights to use, copy, modify, merge, publish, distribute, sublicense, 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL THE
+.\" XFREE86 PROJECT 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.
+.\" 
+.\" Except as contained in this notice, the name of the XFree86 Project shall
+.\" not be used in advertising or otherwise to promote the sale, use or other
+.\" dealings in this Software without prior written authorization from the
+.\" XFree86 Project.
+.\" 
+.TH SCANPCI 1 __xorgversion__
+.SH NAME
+scanpci - scan/probe PCI buses
+.SH SYNOPSIS
+.B scanpci
+.RB [ \-v ]
+.SH DESCRIPTION
+.I Scanpci
+is a utility that can be used to scan PCI buses and report information
+about the configuration space settings for each PCI device.
+On most platforms,
+.I scanpci
+can only be run by the root user.
+.SH OPTIONS
+.TP 8
+.B \-v
+Print the configuration space information for each device in a verbose
+format.  Without this option, only a brief description is printed for
+each device.
+
diff --git a/src/solx_devfs.c b/src/solx_devfs.c
new file mode 100644 (file)
index 0000000..73538b2
--- /dev/null
@@ -0,0 +1,1025 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * Copyright 2007, 2009 Sun Microsystems, Inc.
+ * 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.
+ */
+/*
+ * Solaris devfs interfaces
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <sys/pci.h>
+#include <libdevinfo.h>
+#include "pci_tools.h"
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+/* #define DEBUG */
+
+#define        MAX_DEVICES     256
+#define        CELL_NUMS_1275  (sizeof(pci_regspec_t) / sizeof(uint_t))
+
+typedef union {
+    uint8_t bytes[16 * sizeof (uint32_t)];
+    uint32_t dwords[16];
+} pci_conf_hdr_t;
+
+typedef struct i_devnode {
+    uint8_t bus;
+    uint8_t dev;
+    uint8_t func;
+    di_node_t node;
+} i_devnode_t;
+
+typedef struct nexus {
+    int fd;
+    int first_bus;
+    int last_bus;
+    char *path;                        /* for errors/debugging; fd is all we need */
+    struct nexus *next;
+} nexus_t;
+
+static nexus_t *nexus_list = NULL;
+static int xsvc_fd = -1;
+
+/*
+ * Read config space in native processor endianness.  Endian-neutral
+ * processing can then take place.  On big endian machines, MSB and LSB
+ * of little endian data end up switched if read as little endian.
+ * They are in correct order if read as big endian.
+ */
+#if defined(__sparc)
+# define NATIVE_ENDIAN PCITOOL_ACC_ATTR_ENDN_BIG
+#elif defined(__x86)
+# define NATIVE_ENDIAN PCITOOL_ACC_ATTR_ENDN_LTL
+#else
+# error "ISA is neither __sparc nor __x86"
+#endif
+
+/*
+ * Identify problematic southbridges.  These have device id 0x5249 and
+ * vendor id 0x10b9.  Check for revision ID 0 and class code 060400 as well.
+ * Values are little endian, so they are reversed for SPARC.
+ *
+ * Check for these southbridges on all architectures, as the issue is a
+ * southbridge issue, independent of processor.
+ *
+ * If one of these is found during probing, skip probing other devs/funcs on
+ * the rest of the bus, since the southbridge and all devs underneath will
+ * otherwise disappear.
+ */
+#if (NATIVE_ENDIAN == PCITOOL_ACC_ATTR_ENDN_BIG)
+# define U45_SB_DEVID_VID      0xb9104952
+# define U45_SB_CLASS_RID      0x00000406
+#else
+# define U45_SB_DEVID_VID      0x524910b9
+# define U45_SB_CLASS_RID      0x06040000
+#endif
+
+static int pci_device_solx_devfs_map_range(struct pci_device *dev,
+    struct pci_device_mapping *map);
+
+static int pci_device_solx_devfs_read_rom( struct pci_device * dev,
+    void * buffer );
+
+static int pci_device_solx_devfs_probe( struct pci_device * dev );
+
+static int pci_device_solx_devfs_read( struct pci_device * dev, void * data,
+    pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_read );
+
+static int pci_device_solx_devfs_write( struct pci_device * dev,
+    const void * data, pciaddr_t offset, pciaddr_t size,
+    pciaddr_t * bytes_written );
+
+static int probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p,
+                    struct pci_system *pci_sys);
+
+static int do_probe(nexus_t *nexus, struct pci_system *pci_sys);
+
+static int probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg);
+
+static void pci_system_solx_devfs_destroy( void );
+
+static int get_config_header(int fd, uint8_t bus_no, uint8_t dev_no,
+                            uint8_t func_no, pci_conf_hdr_t *config_hdr_p);
+
+int pci_system_solx_devfs_create( void );
+
+static const struct pci_system_methods solx_devfs_methods = {
+    .destroy = pci_system_solx_devfs_destroy,
+    .destroy_device = NULL,
+    .read_rom = pci_device_solx_devfs_read_rom,
+    .probe = pci_device_solx_devfs_probe,
+    .map_range = pci_device_solx_devfs_map_range,
+    .unmap_range = pci_device_generic_unmap_range,
+
+    .read = pci_device_solx_devfs_read,
+    .write = pci_device_solx_devfs_write,
+
+    .fill_capabilities = pci_fill_capabilities_generic
+};
+
+static nexus_t *
+find_nexus_for_bus( int bus )
+{
+    nexus_t *nexus;
+
+    for (nexus = nexus_list ; nexus != NULL ; nexus = nexus->next) {
+       if ((bus >= nexus->first_bus) && (bus <= nexus->last_bus)) {
+           return nexus;
+       }
+    }
+    return NULL;
+}
+
+#define GET_CONFIG_VAL_8(offset) (config_hdr.bytes[offset])
+#define GET_CONFIG_VAL_16(offset) \
+    (uint16_t) (GET_CONFIG_VAL_8(offset) + (GET_CONFIG_VAL_8(offset+1) << 8))
+#define GET_CONFIG_VAL_32(offset) \
+    (uint32_t) (GET_CONFIG_VAL_8(offset) +             \
+               (GET_CONFIG_VAL_8(offset+1) << 8) +     \
+               (GET_CONFIG_VAL_8(offset+2) << 16) +    \
+               (GET_CONFIG_VAL_8(offset+3) << 24))
+
+/*
+ * Release all the resources
+ * Solaris version
+ */
+static void
+pci_system_solx_devfs_destroy( void )
+{
+    /*
+     * The memory allocated for pci_sys & devices in create routines
+     * will be freed in pci_system_cleanup.
+     * Need to free system-specific allocations here.
+     */
+    nexus_t *nexus, *next;
+
+    for (nexus = nexus_list ; nexus != NULL ; nexus = next) {
+       next = nexus->next;
+       close(nexus->fd);
+       free(nexus->path);
+       free(nexus);
+    }
+    nexus_list = NULL;
+
+    if (xsvc_fd >= 0) {
+       close(xsvc_fd);
+       xsvc_fd = -1;
+    }
+}
+
+/*
+ * Attempt to access PCI subsystem using Solaris's devfs interface.
+ * Solaris version
+ */
+_pci_hidden int
+pci_system_solx_devfs_create( void )
+{
+    int err = 0;
+    di_node_t di_node;
+
+
+    if (nexus_list != NULL) {
+       return 0;
+    }
+
+    /*
+     * Only allow MAX_DEVICES exists
+     * I will fix it later to get
+     * the total devices first
+     */
+    if ((pci_sys = calloc(1, sizeof (struct pci_system))) != NULL) {
+       pci_sys->methods = &solx_devfs_methods;
+
+       if ((pci_sys->devices =
+            calloc(MAX_DEVICES, sizeof (struct pci_device_private)))
+           != NULL) {
+
+           if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
+               err = errno;
+               (void) fprintf(stderr, "di_init() failed: %s\n",
+                              strerror(errno));
+           } else {
+               (void) di_walk_minor(di_node, DDI_NT_REGACC, 0, pci_sys,
+                                    probe_nexus_node);
+               di_fini(di_node);
+           }
+       }
+       else {
+           err = errno;
+       }
+    } else {
+       err = errno;
+    }
+
+    if (err != 0) {
+       if (pci_sys != NULL) {
+           free(pci_sys->devices);
+           free(pci_sys);
+           pci_sys = NULL;
+       }
+    }
+
+    return (err);
+}
+
+/*
+ * Retrieve first 16 dwords of device's config header, except for the first
+ * dword.  First 16 dwords are defined by the PCI specification.
+ */
+static int
+get_config_header(int fd, uint8_t bus_no, uint8_t dev_no, uint8_t func_no,
+                 pci_conf_hdr_t *config_hdr_p)
+{
+    pcitool_reg_t cfg_prg;
+    int i;
+    int rval = 0;
+
+    /* Prepare a local pcitool_reg_t so as to not disturb the caller's. */
+    cfg_prg.offset = 0;
+    cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
+    cfg_prg.bus_no = bus_no;
+    cfg_prg.dev_no = dev_no;
+    cfg_prg.func_no = func_no;
+    cfg_prg.barnum = 0;
+    cfg_prg.user_version = PCITOOL_USER_VERSION;
+
+    /* Get dwords 1-15 of config space. They must be read as uint32_t. */
+    for (i = 1; i < (sizeof (pci_conf_hdr_t) / sizeof (uint32_t)); i++) {
+       cfg_prg.offset += sizeof (uint32_t);
+       if ((rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) {
+           break;
+       }
+       config_hdr_p->dwords[i] = (uint32_t)cfg_prg.data;
+    }
+
+    return (rval);
+}
+
+
+/*
+ * Probe device's functions.  Modifies many fields in the prg_p.
+ */
+static int
+probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, struct pci_system *pci_sys)
+{
+    pci_conf_hdr_t     config_hdr;
+    boolean_t          multi_function_device;
+    int8_t             func;
+    int8_t             first_func = 0;
+    int8_t             last_func = PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT;
+    int                        rval = 0;
+    struct pci_device *        pci_base;
+
+    /*
+     * Loop through at least func=first_func.  Continue looping through
+     * functions if there are no errors and the device is a multi-function
+     * device.
+     *
+     * (Note, if first_func == 0, header will show whether multifunction
+     * device and set multi_function_device.  If first_func != 0, then we
+     * will force the loop as the user wants a specific function to be
+     * checked.
+     */
+    for (func = first_func, multi_function_device = B_FALSE;
+        ((func <= last_func) &&
+         ((func == first_func) || (multi_function_device)));
+        func++) {
+       prg_p->func_no = func;
+
+       /*
+        * Four things can happen here:
+        *
+        * 1) ioctl comes back as EFAULT and prg_p->status is
+        *    PCITOOL_INVALID_ADDRESS.  There is no device at this location.
+        *
+        * 2) ioctl comes back successful and the data comes back as
+        *    zero.  Config space is mapped but no device responded.
+        *
+        * 3) ioctl comes back successful and the data comes back as
+        *    non-zero.  We've found a device.
+        *
+        * 4) Some other error occurs in an ioctl.
+        */
+
+       prg_p->status = PCITOOL_SUCCESS;
+       prg_p->offset = 0;
+       prg_p->data = 0;
+       prg_p->user_version = PCITOOL_USER_VERSION;
+
+       errno = 0;
+       if (((rval = ioctl(nexus->fd, PCITOOL_DEVICE_GET_REG, prg_p)) != 0) ||
+           (prg_p->data == 0xffffffff)) {
+
+           /*
+            * Accept errno == EINVAL along with status of
+            * PCITOOL_OUT_OF_RANGE because some systems
+            * don't implement the full range of config space.
+            * Leave the loop quietly in this case.
+            */
+           if ((errno == EINVAL) ||
+               (prg_p->status == PCITOOL_OUT_OF_RANGE)) {
+               break;
+           }
+
+           /*
+            * Exit silently with ENXIO as this means that there are
+            * no devices under the pci root nexus.
+            */
+           else if ((errno == ENXIO) &&
+                    (prg_p->status == PCITOOL_IO_ERROR)) {
+               break;
+           }
+
+           /*
+            * Expect errno == EFAULT along with status of
+            * PCITOOL_INVALID_ADDRESS because there won't be
+            * devices at each stop.  Quit on any other error.
+            */
+           else if (((errno != EFAULT) ||
+                     (prg_p->status != PCITOOL_INVALID_ADDRESS)) &&
+                    (prg_p->data != 0xffffffff)) {
+               break;
+           }
+
+           /*
+            * If no function at this location,
+            * just advance to the next function.
+            */
+           else {
+               rval = 0;
+           }
+
+           /*
+            * Data came back as 0.
+            * Treat as unresponsive device and check next device.
+            */
+       } else if (prg_p->data == 0) {
+           rval = 0;
+           break;      /* Func loop. */
+
+           /* Found something. */
+       } else {
+           config_hdr.dwords[0] = (uint32_t)prg_p->data;
+
+           /* Get the rest of the PCI header. */
+           if ((rval = get_config_header(nexus->fd, prg_p->bus_no,
+                                         prg_p->dev_no, prg_p->func_no,
+                                         &config_hdr)) != 0) {
+               break;
+           }
+
+           /*
+            * Special case for the type of Southbridge found on
+            * Ultra-45 and other sun4u fire workstations.
+            */
+           if ((config_hdr.dwords[0] == U45_SB_DEVID_VID) &&
+               (config_hdr.dwords[2] == U45_SB_CLASS_RID)) {
+               rval = ECANCELED;
+               break;
+           }
+
+           /*
+            * Found one device with bus number, device number and
+            * function number.
+            */
+
+           pci_base = &pci_sys->devices[pci_sys->num_devices].base;
+
+           /*
+            * Domain is peer bus??
+            */
+           pci_base->domain = 0;
+           pci_base->bus = prg_p->bus_no;
+           pci_base->dev = prg_p->dev_no;
+           pci_base->func = func;
+
+           /*
+            * for the format of device_class, see struct pci_device;
+            */
+
+           pci_base->device_class =
+               (GET_CONFIG_VAL_8(PCI_CONF_BASCLASS) << 16) |
+               (GET_CONFIG_VAL_8(PCI_CONF_SUBCLASS) << 8) |
+               GET_CONFIG_VAL_8(PCI_CONF_PROGCLASS);
+
+           pci_base->revision          = GET_CONFIG_VAL_8(PCI_CONF_REVID);
+           pci_base->vendor_id         = GET_CONFIG_VAL_16(PCI_CONF_VENID);
+           pci_base->device_id         = GET_CONFIG_VAL_16(PCI_CONF_DEVID);
+           pci_base->subvendor_id      = GET_CONFIG_VAL_16(PCI_CONF_SUBVENID);
+           pci_base->subdevice_id      = GET_CONFIG_VAL_16(PCI_CONF_SUBSYSID);
+
+           pci_sys->devices[pci_sys->num_devices].header_type
+                                       = GET_CONFIG_VAL_8(PCI_CONF_HEADER);
+
+#ifdef DEBUG
+           fprintf(stderr,
+                   "nexus = %s, busno = %x, devno = %x, funcno = %x\n",
+                   nexus->path, prg_p->bus_no, prg_p->dev_no, func);
+#endif
+
+           if (pci_sys->num_devices < (MAX_DEVICES - 1)) {
+               pci_sys->num_devices++;
+           } else {
+               (void) fprintf(stderr,
+                              "Maximum number of PCI devices found,"
+                              " discarding additional devices\n");
+           }
+
+
+           /*
+            * Accommodate devices which state their
+            * multi-functionality only in their function 0 config
+            * space.  Note multi-functionality throughout probing
+            * of all of this device's functions.
+            */
+           if (config_hdr.bytes[PCI_CONF_HEADER] & PCI_HEADER_MULTI) {
+               multi_function_device = B_TRUE;
+           }
+       }
+    }
+
+    return (rval);
+}
+
+/*
+ * This function is called from di_walk_minor() when any PROBE is processed
+ */
+static int
+probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg)
+{
+    struct pci_system *pci_sys = (struct pci_system *) arg;
+    char *nexus_name;
+    nexus_t *nexus;
+    int fd;
+    char nexus_path[MAXPATHLEN];
+
+    di_prop_t prop;
+    char *strings;
+    int *ints;
+    int numval;
+    int pci_node = 0;
+    int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M);
+
+#ifdef DEBUG
+    nexus_name = di_devfs_minor_path(minor);
+    fprintf(stderr, "-- device name: %s\n", nexus_name);
+#endif
+
+    for (prop = di_prop_next(di_node, NULL); prop != NULL;
+        prop = di_prop_next(di_node, prop)) {
+
+       const char *prop_name = di_prop_name(prop);
+
+#ifdef DEBUG
+       fprintf(stderr, "   property: %s\n", prop_name);
+#endif
+
+       if (strcmp(prop_name, "device_type") == 0) {
+           numval = di_prop_strings(prop, &strings);
+           if (numval != 1 || strncmp(strings, "pci", 3) != 0) {
+               /* not a PCI node, bail */
+               return (DI_WALK_CONTINUE);
+           }
+           pci_node = 1;
+       }
+       else if (strcmp(prop_name, "class-code") == 0) {
+           /* not a root bus node, bail */
+           return (DI_WALK_CONTINUE);
+       }
+       else if (strcmp(prop_name, "bus-range") == 0) {
+           numval = di_prop_ints(prop, &ints);
+           if (numval == 2) {
+               first_bus = ints[0];
+               last_bus = ints[1];
+           }
+       }
+    }
+
+#ifdef __x86  /* sparc pci nodes don't have the device_type set */
+    if (pci_node != 1)
+       return (DI_WALK_CONTINUE);
+#endif
+
+    /* we have a PCI root bus node. */
+    nexus = calloc(1, sizeof(nexus_t));
+    if (nexus == NULL) {
+       (void) fprintf(stderr, "Error allocating memory for nexus: %s\n",
+                      strerror(errno));
+       return (DI_WALK_TERMINATE);
+    }
+    nexus->first_bus = first_bus;
+    nexus->last_bus = last_bus;
+
+    nexus_name = di_devfs_minor_path(minor);
+    if (nexus_name == NULL) {
+       (void) fprintf(stderr, "Error getting nexus path: %s\n",
+                      strerror(errno));
+       free(nexus);
+       return (DI_WALK_CONTINUE);
+    }
+
+    snprintf(nexus_path, sizeof(nexus_path), "/devices%s", nexus_name);
+    di_devfs_path_free(nexus_name);
+
+#ifdef DEBUG
+    fprintf(stderr, "nexus = %s, bus-range = %d - %d\n",
+           nexus_path, first_bus, last_bus);
+#endif
+
+    if ((fd = open(nexus_path, O_RDWR)) >= 0) {
+       nexus->fd = fd;
+       nexus->path = strdup(nexus_path);
+       if ((do_probe(nexus, pci_sys) != 0) && (errno != ENXIO)) {
+           (void) fprintf(stderr, "Error probing node %s: %s\n",
+                          nexus_path, strerror(errno));
+           (void) close(fd);
+           free(nexus->path);
+           free(nexus);
+       } else {
+           nexus->next = nexus_list;
+           nexus_list = nexus;
+       }
+    } else {
+       (void) fprintf(stderr, "Error opening %s: %s\n",
+                      nexus_path, strerror(errno));
+       free(nexus);
+    }
+
+    return DI_WALK_CONTINUE;
+}
+
+
+/*
+ * Solaris version
+ * Probe a given nexus config space for devices.
+ *
+ * fd is the file descriptor of the nexus.
+ * input_args contains commandline options as specified by the user.
+ */
+static int
+do_probe(nexus_t *nexus, struct pci_system *pci_sys)
+{
+    pcitool_reg_t prg;
+    uint32_t bus;
+    uint8_t dev;
+    uint32_t last_bus = nexus->last_bus;
+    uint8_t last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT;
+    uint8_t first_bus = nexus->first_bus;
+    uint8_t first_dev = 0;
+    int rval = 0;
+
+    prg.barnum = 0;    /* Config space. */
+
+    /* Must read in 4-byte quantities. */
+    prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
+
+    prg.data = 0;
+
+    /*
+     * Loop through all valid bus / dev / func combinations to check for
+     * all devices, with the following exceptions:
+     *
+     * When nothing is found at function 0 of a bus / dev combination, skip
+     * the other functions of that bus / dev combination.
+     *
+     * When a found device's function 0 is probed and it is determined that
+     * it is not a multifunction device, skip probing of that device's
+     * other functions.
+     */
+    for (bus = first_bus; ((bus <= last_bus) && (rval == 0)); bus++) {
+       prg.bus_no = (uint8_t)bus;
+
+       for (dev = first_dev; ((dev <= last_dev) && (rval == 0)); dev++) {
+           prg.dev_no = dev;
+           rval = probe_dev(nexus, &prg, pci_sys);
+       }
+
+       /*
+        * Ultra-45 southbridge workaround:
+        * ECANCELED tells to skip to the next bus.
+        */
+       if (rval == ECANCELED) {
+           rval = 0;
+       }
+    }
+
+    return (rval);
+}
+
+static int
+find_target_node(di_node_t node, void *arg)
+{
+    int *regbuf = NULL;
+    int len = 0;
+    uint32_t busno, funcno, devno;
+    i_devnode_t *devnode = (i_devnode_t *)arg;
+
+    /*
+     * Test the property functions, only for testing
+     */
+    /*
+    void *prop = DI_PROP_NIL;
+
+    (void) fprintf(stderr, "start of node 0x%x\n", node->nodeid);
+    while ((prop = di_prop_hw_next(node, prop)) != DI_PROP_NIL) {
+       int i;
+       (void) fprintf(stderr, "name=%s: ", di_prop_name(prop));
+       len = 0;
+       if (!strcmp(di_prop_name(prop), "reg")) {
+           len = di_prop_ints(prop, &regbuf);
+       }
+       for (i = 0; i < len; i++) {
+           fprintf(stderr, "0x%0x.", regbuf[i]);
+       }
+       fprintf(stderr, "\n");
+    }
+    (void) fprintf(stderr, "end of node 0x%x\n", node->nodeid);
+    */
+
+    len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &regbuf);
+
+    if (len <= 0) {
+#ifdef DEBUG
+       fprintf(stderr, "error = %x\n", errno);
+       fprintf(stderr, "can not find assigned-address\n");
+#endif
+       return (DI_WALK_CONTINUE);
+    }
+
+    busno = PCI_REG_BUS_G(regbuf[0]);
+    devno = PCI_REG_DEV_G(regbuf[0]);
+    funcno = PCI_REG_FUNC_G(regbuf[0]);
+
+    if ((busno == devnode->bus) &&
+       (devno == devnode->dev) &&
+       (funcno == devnode->func)) {
+       devnode->node = node;
+
+       return (DI_WALK_TERMINATE);
+    }
+
+    return (DI_WALK_CONTINUE);
+}
+
+/*
+ * Solaris version
+ */
+static int
+pci_device_solx_devfs_probe( struct pci_device * dev )
+{
+    uint8_t  config[256];
+    int err;
+    di_node_t rnode = DI_NODE_NIL;
+    i_devnode_t args = { 0, 0, 0, DI_NODE_NIL };
+    int *regbuf;
+    pci_regspec_t *reg;
+    int i;
+    pciaddr_t bytes;
+    int len = 0;
+    uint ent = 0;
+
+    err = pci_device_solx_devfs_read( dev, config, 0, 256, & bytes );
+
+    if ( bytes >= 64 ) {
+       struct pci_device_private *priv =
+           (struct pci_device_private *) dev;
+
+       dev->vendor_id = (uint16_t)config[0] + ((uint16_t)config[1] << 8);
+       dev->device_id = (uint16_t)config[2] + ((uint16_t)config[3] << 8);
+       dev->device_class = (uint32_t)config[9] +
+           ((uint32_t)config[10] << 8) +
+           ((uint16_t)config[11] << 16);
+
+       /*
+        * device class code is already there.
+        * see probe_dev function.
+        */
+       dev->revision = config[8];
+       dev->subvendor_id = (uint16_t)config[44] + ((uint16_t)config[45] << 8);
+       dev->subdevice_id = (uint16_t)config[46] + ((uint16_t)config[47] << 8);
+       dev->irq = config[60];
+
+       priv->header_type = config[14];
+       /*
+        * starting to find if it is MEM/MEM64/IO
+        * using libdevinfo
+        */
+       if ((rnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
+           err = errno;
+           (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
+       } else {
+           args.bus = dev->bus;
+           args.dev = dev->dev;
+           args.func = dev->func;
+           (void) di_walk_node(rnode, DI_WALK_CLDFIRST,
+                               (void *)&args, find_target_node);
+       }
+    }
+    if (args.node != DI_NODE_NIL) {
+       /*
+        * It will succeed for sure, because it was
+        * successfully called in find_target_node
+        */
+       len = di_prop_lookup_ints(DDI_DEV_T_ANY, args.node,
+                                 "assigned-addresses",
+                                 &regbuf);
+
+    }
+
+    if (len <= 0)
+       goto cleanup;
+
+
+    /*
+     * how to find the size of rom???
+     * if the device has expansion rom,
+     * it must be listed in the last
+     * cells because solaris find probe
+     * the base address from offset 0x10
+     * to 0x30h. So only check the last
+     * item.
+     */
+    reg = (pci_regspec_t *)&regbuf[len - CELL_NUMS_1275];
+    if (PCI_REG_REG_G(reg->pci_phys_hi) == PCI_CONF_ROM) {
+       /*
+        * rom can only be 32 bits
+        */
+       dev->rom_size = reg->pci_size_low;
+       len = len - CELL_NUMS_1275;
+    }
+    else {
+       /*
+        * size default to 64K and base address
+        * default to 0xC0000
+        */
+       dev->rom_size = 0x10000;
+    }
+
+    /*
+     * Solaris has its own BAR index.
+     * Linux give two region slot for 64 bit address.
+     */
+    for (i = 0; i < len; i = i + CELL_NUMS_1275) {
+
+       reg = (pci_regspec_t *)&regbuf[i];
+       ent = reg->pci_phys_hi & 0xff;
+       /*
+        * G35 broken in BAR0
+        */
+       ent = (ent - PCI_CONF_BASE0) >> 2;
+       if (ent >= 6) {
+           fprintf(stderr, "error ent = %d\n", ent);
+           break;
+       }
+
+       /*
+        * non relocatable resource is excluded
+        * such like 0xa0000, 0x3b0. If it is met,
+        * the loop is broken;
+        */
+       if (!PCI_REG_REG_G(reg->pci_phys_hi))
+           break;
+
+       if (reg->pci_phys_hi & PCI_PREFETCH_B) {
+           dev->regions[ent].is_prefetchable = 1;
+       }
+
+
+       /*
+        * We split the shift count 32 into two 16 to
+        * avoid the complaining of the compiler
+        */
+       dev->regions[ent].base_addr = reg->pci_phys_low +
+           ((reg->pci_phys_mid << 16) << 16);
+       dev->regions[ent].size = reg->pci_size_low +
+           ((reg->pci_size_hi << 16) << 16);
+
+       switch (reg->pci_phys_hi & PCI_REG_ADDR_M) {
+           case PCI_ADDR_IO:
+               dev->regions[ent].is_IO = 1;
+               break;
+           case PCI_ADDR_MEM32:
+               break;
+           case PCI_ADDR_MEM64:
+               dev->regions[ent].is_64 = 1;
+               /*
+                * Skip one slot for 64 bit address
+                */
+               break;
+       }
+    }
+
+  cleanup:
+    if (rnode != DI_NODE_NIL) {
+       di_fini(rnode);
+    }
+    return (err);
+}
+
+/*
+ * Solaris version: read the VGA ROM data
+ */
+static int
+pci_device_solx_devfs_read_rom( struct pci_device * dev, void * buffer )
+{
+    int err;
+    struct pci_device_mapping prom = {
+       .base = 0xC0000,
+       .size = dev->rom_size,
+       .flags = 0
+    };
+
+    err = pci_device_solx_devfs_map_range(dev, &prom);
+    if (err == 0) {
+       (void) bcopy(prom.memory, buffer, dev->rom_size);
+
+       if (munmap(prom.memory, dev->rom_size) == -1) {
+           err = errno;
+       }
+    }
+    return err;
+}
+
+/*
+ * solaris version: Read the configurations space of the devices
+ */
+static int
+pci_device_solx_devfs_read( struct pci_device * dev, void * data,
+                            pciaddr_t offset, pciaddr_t size,
+                            pciaddr_t * bytes_read )
+{
+    pcitool_reg_t cfg_prg;
+    int err = 0;
+    int i = 0;
+    nexus_t *nexus = find_nexus_for_bus(dev->bus);
+
+    *bytes_read = 0;
+
+    if ( nexus == NULL ) {
+       return ENODEV;
+    }
+
+    cfg_prg.offset = offset;
+    cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN;
+    cfg_prg.bus_no = dev->bus;
+    cfg_prg.dev_no = dev->dev;
+    cfg_prg.func_no = dev->func;
+    cfg_prg.barnum = 0;
+    cfg_prg.user_version = PCITOOL_USER_VERSION;
+
+    for (i = 0; i < size; i += PCITOOL_ACC_ATTR_SIZE(PCITOOL_ACC_ATTR_SIZE_1))
+    {
+       cfg_prg.offset = offset + i;
+
+       if ((err = ioctl(nexus->fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) {
+           fprintf(stderr, "read bdf<%s,%x,%x,%x,%llx> config space failure\n",
+                   nexus->path,
+                   cfg_prg.bus_no,
+                   cfg_prg.dev_no,
+                   cfg_prg.func_no,
+                   cfg_prg.offset);
+           fprintf(stderr, "Failure cause = %x\n", err);
+           break;
+       }
+
+       ((uint8_t *)data)[i] = (uint8_t)cfg_prg.data;
+       /*
+        * DWORDS Offset or bytes Offset ??
+        */
+    }
+    *bytes_read = i;
+
+    return (err);
+}
+
+/*
+ * Solaris version
+ */
+static int
+pci_device_solx_devfs_write( struct pci_device * dev, const void * data,
+                            pciaddr_t offset, pciaddr_t size,
+                            pciaddr_t * bytes_written )
+{
+    pcitool_reg_t cfg_prg;
+    int err = 0;
+    int cmd;
+    nexus_t *nexus = find_nexus_for_bus(dev->bus);
+
+    if ( bytes_written != NULL ) {
+       *bytes_written = 0;
+    }
+
+    if ( nexus == NULL ) {
+       return ENODEV;
+    }
+
+    cfg_prg.offset = offset;
+    switch (size) {
+        case 1:
+           cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN;
+           break;
+        case 2:
+           cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 + NATIVE_ENDIAN;
+           break;
+        case 4:
+           cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
+           break;
+        case 8:
+           cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 + NATIVE_ENDIAN;
+           break;
+        default:
+           return EINVAL;
+    }
+    cfg_prg.bus_no = dev->bus;
+    cfg_prg.dev_no = dev->dev;
+    cfg_prg.func_no = dev->func;
+    cfg_prg.barnum = 0;
+    cfg_prg.user_version = PCITOOL_USER_VERSION;
+    cfg_prg.data = *((uint64_t *)data);
+
+    /*
+     * Check if this device is bridge device.
+     * If it is, it is also a nexus node???
+     * It seems that there is no explicit
+     * PCI nexus device for X86, so not applicable
+     * from pcitool_bus_reg_ops in pci_tools.c
+     */
+    cmd = PCITOOL_DEVICE_SET_REG;
+
+    if ((err = ioctl(nexus->fd, cmd, &cfg_prg)) != 0) {
+       return (err);
+    }
+    *bytes_written = size;
+
+    return (err);
+}
+
+
+/**
+ * Map a memory region for a device using /dev/xsvc.
+ *
+ * \param dev   Device whose memory region is to be mapped.
+ * \param map   Parameters of the mapping that is to be created.
+ *
+ * \return
+ * Zero on success or an \c errno value on failure.
+ */
+static int
+pci_device_solx_devfs_map_range(struct pci_device *dev,
+                               struct pci_device_mapping *map)
+{
+    const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0)
+                       ? (PROT_READ | PROT_WRITE) : PROT_READ;
+    int err = 0;
+
+    /*
+     * Still used xsvc to do the user space mapping
+     */
+    if (xsvc_fd < 0) {
+       if ((xsvc_fd = open("/dev/xsvc", O_RDWR)) < 0) {
+           err = errno;
+           (void) fprintf(stderr, "can not open /dev/xsvc: %s\n",
+                          strerror(errno));
+           return err;
+       }
+    }
+
+    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, xsvc_fd, map->base);
+    if (map->memory == MAP_FAILED) {
+       err = errno;
+
+       (void) fprintf(stderr, "map rom region =%llx failed: %s\n",
+                      map->base, strerror(errno));
+    }
+
+    return err;
+}
diff --git a/src/x86_pci.c b/src/x86_pci.c
new file mode 100644 (file)
index 0000000..c42d3e0
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2009 Samuel Thibault
+ * Heavily inspired from the freebsd, netbsd, and openbsd backends
+ * (C) Copyright Eric Anholt 2006
+ * (C) Copyright IBM Corporation 2006
+ * Copyright (c) 2008 Juan Romero Pardines
+ * Copyright (c) 2008 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <strings.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+#if defined(__GNU__)
+
+#include <sys/io.h>
+
+static int
+x86_enable_io(void)
+{
+    if (!ioperm(0, 0xffff, 1))
+        return 0;
+    return errno;
+}
+
+static int
+x86_disable_io(void)
+{
+    if (!ioperm(0, 0xffff, 0))
+        return 0;
+    return errno;
+}
+
+#elif defined(__GLIBC__)
+
+#include <sys/io.h>
+
+static int
+x86_enable_io(void)
+{
+    if (!iopl(3))
+        return 0;
+    return errno;
+}
+
+static int
+x86_disable_io(void)
+{
+    if (!iopl(0))
+        return 0;
+    return errno;
+}
+
+#else
+
+#error How to enable IO ports on this system?
+
+#endif
+
+#define PCI_VENDOR(reg)                ((reg) & 0xFFFF)
+#define PCI_VENDOR_INVALID     0xFFFF
+
+#define PCI_VENDOR_ID          0x00
+#define PCI_SUB_VENDOR_ID      0x2c
+#define PCI_VENDOR_ID_COMPAQ           0x0e11
+#define PCI_VENDOR_ID_INTEL            0x8086
+
+#define PCI_DEVICE(reg)                (((reg) >> 16) & 0xFFFF)
+#define PCI_DEVICE_INVALID     0xFFFF
+
+#define PCI_CLASS              0x08
+#define PCI_CLASS_DEVICE       0x0a
+#define PCI_CLASS_DISPLAY_VGA          0x0300
+#define PCI_CLASS_BRIDGE_HOST          0x0600
+
+#define        PCIC_DISPLAY    0x03
+#define        PCIS_DISPLAY_VGA        0x00
+
+#define PCI_HDRTYPE    0x0E
+#define PCI_IRQ                0x3C
+
+struct pci_system_x86 {
+    struct pci_system system;
+    int (*read)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size);
+    int (*write)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size);
+};
+
+static int
+pci_system_x86_conf1_probe(void)
+{
+    unsigned long sav;
+    int res = ENODEV;
+
+    outb(0x01, 0xCFB);
+    sav = inl(0xCF8);
+    outl(0x80000000, 0xCF8);
+    if (inl(0xCF8) == 0x80000000)
+       res = 0;
+    outl(sav, 0xCF8);
+
+    return res;
+}
+
+static int
+pci_system_x86_conf1_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size)
+{
+    unsigned addr = 0xCFC + (reg & 3);
+    unsigned long sav;
+    int ret = 0;
+
+    if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3)
+       return EIO;
+
+    sav = inl(0xCF8);
+    outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8);
+    /* NOTE: x86 is already LE */
+    switch (size) {
+       case 1: {
+           uint8_t *val = data;
+           *val = inb(addr);
+           break;
+       }
+       case 2: {
+           uint16_t *val = data;
+           *val = inw(addr);
+           break;
+       }
+       case 4: {
+           uint32_t *val = data;
+           *val = inl(addr);
+           break;
+       }
+    }
+    outl(sav, 0xCF8);
+
+    return ret;
+}
+
+static int
+pci_system_x86_conf1_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size)
+{
+    unsigned addr = 0xCFC + (reg & 3);
+    unsigned long sav;
+    int ret = 0;
+
+    if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3)
+       return EIO;
+
+    sav = inl(0xCF8);
+    outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8);
+    /* NOTE: x86 is already LE */
+    switch (size) {
+       case 1: {
+           const uint8_t *val = data;
+           outb(*val, addr);
+           break;
+       }
+       case 2: {
+           const uint16_t *val = data;
+           outw(*val, addr);
+           break;
+       }
+       case 4: {
+           const uint32_t *val = data;
+           outl(*val, addr);
+           break;
+       }
+    }
+    outl(sav, 0xCF8);
+
+    return ret;
+}
+
+static int
+pci_system_x86_conf2_probe(void)
+{
+    outb(0, 0xCFB);
+    outb(0, 0xCF8);
+    outb(0, 0xCFA);
+    if (inb(0xCF8) == 0 && inb(0xCFA) == 0)
+       return 0;
+
+    return ENODEV;
+}
+
+static int
+pci_system_x86_conf2_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size)
+{
+    unsigned addr = 0xC000 | dev << 8 | reg;
+    int ret = 0;
+
+    if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100)
+       return EIO;
+
+    outb((func << 1) | 0xF0, 0xCF8);
+    outb(bus, 0xCFA);
+    /* NOTE: x86 is already LE */
+    switch (size) {
+       case 1: {
+           uint8_t *val = data;
+           *val = inb(addr);
+           break;
+       }
+       case 2: {
+           uint16_t *val = data;
+           *val = inw(addr);
+           break;
+       }
+       case 4: {
+           uint32_t *val = data;
+           *val = inl(addr);
+           break;
+       }
+       default:
+           ret = EIO;
+           break;
+    }
+    outb(0, 0xCF8);
+
+    return ret;
+}
+
+static int
+pci_system_x86_conf2_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size)
+{
+    unsigned addr = 0xC000 | dev << 8 | reg;
+    int ret = 0;
+
+    if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100)
+       return EIO;
+
+    outb((func << 1) | 0xF0, 0xCF8);
+    outb(bus, 0xCFA);
+    /* NOTE: x86 is already LE */
+    switch (size) {
+       case 1: {
+           const uint8_t *val = data;
+           outb(*val, addr);
+           break;
+       }
+       case 2: {
+           const uint16_t *val = data;
+           outw(*val, addr);
+           break;
+       }
+       case 4: {
+           const uint32_t *val = data;
+           outl(*val, addr);
+           break;
+       }
+       default:
+           ret = EIO;
+           break;
+    }
+    outb(0, 0xCF8);
+
+    return ret;
+}
+
+/* Check that this really looks like a PCI configuration. */
+static int
+pci_system_x86_check(struct pci_system_x86 *pci_sys_x86)
+{
+    int dev;
+    uint16_t class, vendor;
+
+    /* Look on bus 0 for a device that is a host bridge, a VGA card,
+     * or an intel or compaq device.  */
+
+    for (dev = 0; dev < 32; dev++) {
+       if (pci_sys_x86->read(0, dev, 0, PCI_CLASS_DEVICE, &class, sizeof(class)))
+           continue;
+       if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA)
+           return 0;
+       if (pci_sys_x86->read(0, dev, 0, PCI_VENDOR_ID, &vendor, sizeof(vendor)))
+           continue;
+       if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ)
+           return 0;
+    }
+
+    return ENODEV;
+}
+
+static int
+pci_nfuncs(struct pci_system_x86 *pci_sys_x86, int bus, int dev)
+{
+    uint8_t hdr;
+    int err;
+
+    err = pci_sys_x86->read(bus, dev, 0, PCI_HDRTYPE, &hdr, sizeof(hdr));
+
+    if (err)
+       return err;
+
+    return hdr & 0x80 ? 8 : 1;
+}
+
+/**
+ * Read a VGA rom using the 0xc0000 mapping.
+ */
+static int
+pci_device_x86_read_rom(struct pci_device *dev, void *buffer)
+{
+    void *bios;
+    int memfd;
+
+    if ((dev->device_class & 0x00ffff00) !=
+        ((PCIC_DISPLAY << 16) | ( PCIS_DISPLAY_VGA << 8))) {
+       return ENOSYS;
+    }
+
+    memfd = open("/dev/mem", O_RDONLY);
+    if (memfd == -1)
+       return errno;
+
+    bios = mmap(NULL, dev->rom_size, PROT_READ, 0, memfd, 0xc0000);
+    if (bios == MAP_FAILED) {
+       close(memfd);
+       return errno;
+    }
+
+    memcpy(buffer, bios, dev->rom_size);
+
+    munmap(bios, dev->rom_size);
+    close(memfd);
+
+    return 0;
+}
+
+/** Returns the number of regions (base address registers) the device has */
+static int
+pci_device_x86_get_num_regions(uint8_t header_type)
+{
+    switch (header_type & 0x7f) {
+       case 0:
+           return 6;
+       case 1:
+           return 2;
+       case 2:
+           return 1;
+       default:
+           fprintf(stderr,"unknown header type %02x\n", header_type);
+           return 0;
+    }
+}
+
+/** Masks out the flag bigs of the base address register value */
+static uint32_t
+get_map_base( uint32_t val )
+{
+    if (val & 0x01)
+       return val & ~0x03;
+    else
+       return val & ~0x0f;
+}
+
+/** Returns the size of a region based on the all-ones test value */
+static unsigned
+get_test_val_size( uint32_t testval )
+{
+    unsigned size = 1;
+
+    if (testval == 0)
+       return 0;
+
+    /* Mask out the flag bits */
+    testval = get_map_base( testval );
+    if (!testval)
+       return 0;
+
+    while ((testval & 1) == 0) {
+       size <<= 1;
+       testval >>= 1;
+    }
+
+    return size;
+}
+
+static int
+pci_device_x86_probe(struct pci_device *dev)
+{
+    uint8_t irq, hdrtype;
+    int err, i, bar;
+
+    /* Many of the fields were filled in during initial device enumeration.
+     * At this point, we need to fill in regions, rom_size, and irq.
+     */
+
+    err = pci_device_cfg_read_u8(dev, &irq, PCI_IRQ);
+    if (err)
+       return err;
+    dev->irq = irq;
+
+    err = pci_device_cfg_read_u8(dev, &hdrtype, PCI_HDRTYPE);
+    if (err)
+       return err;
+
+    bar = 0x10;
+    for (i = 0; i < pci_device_x86_get_num_regions(hdrtype); i++, bar += 4) {
+       uint32_t addr, testval;
+
+       /* Get the base address */
+       err = pci_device_cfg_read_u32(dev, &addr, bar);
+       if (err != 0)
+           continue;
+
+       /* Test write all ones to the register, then restore it. */
+       err = pci_device_cfg_write_u32(dev, 0xffffffff, bar);
+       if (err != 0)
+           continue;
+       pci_device_cfg_read_u32(dev, &testval, bar);
+       err = pci_device_cfg_write_u32(dev, addr, bar);
+
+       if (addr & 0x01)
+           dev->regions[i].is_IO = 1;
+       if (addr & 0x04)
+           dev->regions[i].is_64 = 1;
+       if (addr & 0x08)
+           dev->regions[i].is_prefetchable = 1;
+
+       /* Set the size */
+       dev->regions[i].size = get_test_val_size(testval);
+
+       /* Set the base address value */
+       if (dev->regions[i].is_64) {
+           uint32_t top;
+
+           err = pci_device_cfg_read_u32(dev, &top, bar + 4);
+           if (err != 0)
+               continue;
+
+           dev->regions[i].base_addr = ((uint64_t)top << 32) |
+                                       get_map_base(addr);
+           bar += 4;
+           i++;
+       } else {
+           dev->regions[i].base_addr = get_map_base(addr);
+       }
+    }
+
+    /* If it's a VGA device, set up the rom size for read_rom using the
+     * 0xc0000 mapping.
+     */
+    if ((dev->device_class & 0x00ffff00) ==
+       ((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8)))
+    {
+       dev->rom_size = 64 * 1024;
+    }
+
+    return 0;
+}
+
+static int
+pci_device_x86_map_range(struct pci_device *dev,
+    struct pci_device_mapping *map)
+{
+    int memfd = open("/dev/mem", O_RDWR);
+    int prot = PROT_READ;
+
+    if (memfd == -1)
+       return errno;
+
+    if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
+       prot |= PROT_WRITE;
+
+    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, memfd, map->base);
+    close(memfd);
+    if (map->memory == MAP_FAILED)
+       return errno;
+
+    return 0;
+}
+
+static int
+pci_device_x86_read(struct pci_device *dev, void *data,
+    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
+{
+    struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys;
+    int err;
+
+    *bytes_read = 0;
+    while (size > 0) {
+       int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1);
+       if (toread > size)
+           toread = size;
+
+       err = pci_sys_x86->read(dev->bus, dev->dev, dev->func, offset, data, toread);
+       if (err)
+           return err;
+
+       offset += toread;
+       data = (char*)data + toread;
+       size -= toread;
+       *bytes_read += toread;
+    }
+    return 0;
+}
+
+static int
+pci_device_x86_write(struct pci_device *dev, const void *data,
+    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
+{
+    struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys;
+    int err;
+
+    *bytes_written = 0;
+    while (size > 0) {
+       int towrite = 4;
+       if (towrite > size)
+           towrite = size;
+       if (towrite > 4 - (offset & 0x3))
+           towrite = 4 - (offset & 0x3);
+
+       err = pci_sys_x86->write(dev->bus, dev->dev, dev->func, offset, data, towrite);
+       if (err)
+           return err;
+
+       offset += towrite;
+       data = (const char*)data + towrite;
+       size -= towrite;
+       *bytes_written += towrite;
+    }
+    return 0;
+}
+
+static void
+pci_system_x86_destroy(void)
+{
+    x86_disable_io();
+}
+
+static const struct pci_system_methods x86_pci_methods = {
+    .destroy = pci_system_x86_destroy,
+    .read_rom = pci_device_x86_read_rom,
+    .probe = pci_device_x86_probe,
+    .map_range = pci_device_x86_map_range,
+    .unmap_range = pci_device_generic_unmap_range,
+    .read = pci_device_x86_read,
+    .write = pci_device_x86_write,
+    .fill_capabilities = pci_fill_capabilities_generic,
+};
+
+static int pci_probe(struct pci_system_x86 *pci_sys_x86)
+{
+    if (pci_system_x86_conf1_probe() == 0) {
+       pci_sys_x86->read = pci_system_x86_conf1_read;
+       pci_sys_x86->write = pci_system_x86_conf1_write;
+       if (pci_system_x86_check(pci_sys_x86) == 0)
+           return 0;
+    }
+
+    if (pci_system_x86_conf2_probe() == 0) {
+       pci_sys_x86->read = pci_system_x86_conf2_read;
+       pci_sys_x86->write = pci_system_x86_conf2_write;
+       if (pci_system_x86_check(pci_sys_x86) == 0)
+           return 0;
+    }
+
+    return ENODEV;
+}
+
+_pci_hidden int
+pci_system_x86_create(void)
+{
+    struct pci_device_private *device;
+    int ret, bus, dev, ndevs, func, nfuncs;
+    struct pci_system_x86 *pci_sys_x86;
+    uint32_t reg;
+
+    ret = x86_enable_io();
+    if (ret)
+       return ret;
+
+    pci_sys_x86 = calloc(1, sizeof(struct pci_system_x86));
+    if (pci_sys_x86 == NULL) {
+       x86_disable_io();
+       return ENOMEM;
+    }
+    pci_sys = &pci_sys_x86->system;
+
+    ret = pci_probe(pci_sys_x86);
+    if (ret) {
+       x86_disable_io();
+       free(pci_sys_x86);
+       pci_sys = NULL;
+       return ret;
+    }
+
+    pci_sys->methods = &x86_pci_methods;
+
+    ndevs = 0;
+    for (bus = 0; bus < 256; bus++) {
+       for (dev = 0; dev < 32; dev++) {
+           nfuncs = pci_nfuncs(pci_sys_x86, bus, dev);
+           for (func = 0; func < nfuncs; func++) {
+               if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, &reg, sizeof(reg)) != 0)
+                   continue;
+               if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
+                   PCI_VENDOR(reg) == 0)
+                   continue;
+               ndevs++;
+           }
+       }
+    }
+
+    pci_sys->num_devices = ndevs;
+    pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
+    if (pci_sys->devices == NULL) {
+       x86_disable_io();
+       free(pci_sys_x86);
+       pci_sys = NULL;
+       return ENOMEM;
+    }
+
+    device = pci_sys->devices;
+    for (bus = 0; bus < 256; bus++) {
+       for (dev = 0; dev < 32; dev++) {
+           nfuncs = pci_nfuncs(pci_sys_x86, bus, dev);
+           for (func = 0; func < nfuncs; func++) {
+               if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, &reg, sizeof(reg)) != 0)
+                   continue;
+               if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
+                   PCI_VENDOR(reg) == 0)
+                   continue;
+               device->base.domain = 0;
+               device->base.bus = bus;
+               device->base.dev = dev;
+               device->base.func = func;
+               device->base.vendor_id = PCI_VENDOR(reg);
+               device->base.device_id = PCI_DEVICE(reg);
+
+               if (pci_sys_x86->read(bus, dev, func, PCI_CLASS, &reg, sizeof(reg)) != 0)
+                   continue;
+               device->base.device_class = reg >> 8;
+               device->base.revision = reg & 0xFF;
+
+               if (pci_sys_x86->read(bus, dev, func, PCI_SUB_VENDOR_ID, &reg, sizeof(reg)) != 0)
+                   continue;
+               device->base.subvendor_id = PCI_VENDOR(reg);
+               device->base.subdevice_id = PCI_DEVICE(reg);
+
+               device++;
+           }
+       }
+    }
+
+    return 0;
+}