[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

libpciaccess: Changes to 'upstream-unstable'



 .gitignore              |   74 +++++++++++---
 INSTALL                 |  236 --------------------------------------------
 Makefile.am             |   11 +-
 configure.ac            |   15 +-
 include/pciaccess.h     |   21 ++++
 src/.gitignore          |    8 -
 src/Makefile.am         |    1 
 src/common_bridge.c     |   40 +++++++
 src/common_init.c       |    1 
 src/common_io.c         |  252 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/linux_sysfs.c       |  183 +++++++++++++++++++++++++++-------
 src/pciaccess_private.h |   22 ++++
 12 files changed, 556 insertions(+), 308 deletions(-)

New commits:
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>

diff --git a/configure.ac b/configure.ac
index 12847ca..ffc1c8d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,7 +24,7 @@ dnl Process this file with autoconf to create configure.
 
 AC_PREREQ([2.57])
 
-AC_INIT(libpciaccess, 0.10.9, [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg&component=libpciaccess], libpciaccess)
+AC_INIT(libpciaccess, 0.11.0, [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg&component=libpciaccess], libpciaccess)
 AM_INIT_AUTOMAKE([foreign dist-bzip2])
 AM_MAINTAINER_MODE
 

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>

diff --git a/src/common_io.c b/src/common_io.c
index b4aa360..58628b4 100644
--- a/src/common_io.c
+++ b/src/common_io.c
@@ -28,13 +28,13 @@
 #include "pciaccess.h"
 #include "pciaccess_private.h"
 
-static struct pci_io_handle **ios;
+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;
+    struct pci_io_handle *new;
 
     new = realloc(ios, sizeof(struct pci_io_handle) * (num_ios + 1));
     if (!new)
@@ -43,13 +43,13 @@ new_io_handle(void)
     ios = new;
     num_ios++;
 
-    return ios[num_ios - 1];
+    return ios + num_ios - 1;
 }
 
 static void
 delete_io_handle(struct pci_io_handle *handle)
 {
-    struct pci_io_handle **new;
+    struct pci_io_handle *new;
     int i = 0;
 
     if (!handle || !num_ios || (void *)handle < (void *)ios ||
@@ -57,7 +57,7 @@ delete_io_handle(struct pci_io_handle *handle)
         return;
 
     for (i = 0; i < num_ios; i++) {
-        if (ios[i] == handle) {
+        if (ios + i == handle) {
             memmove(&ios[i], &ios[i+1], sizeof(struct pci_io_handle) *
                                         (num_ios - i - 1));
             break;

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>

diff --git a/src/common_io.c b/src/common_io.c
index bc5ba0a..b4aa360 100644
--- a/src/common_io.c
+++ b/src/common_io.c
@@ -114,6 +114,8 @@ pci_device_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
 	    delete_io_handle(ret);
 	    return NULL;
 	}
+
+        return ret;
     }
 
     return NULL;

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>

diff --git a/include/pciaccess.h b/include/pciaccess.h
index 8128656..88515e2 100644
--- a/include/pciaccess.h
+++ b/include/pciaccess.h
@@ -1,5 +1,6 @@
 /*
  * (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
@@ -507,4 +508,22 @@ 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/src/Makefile.am b/src/Makefile.am
index 4dd7a5f..4c06c25 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -55,6 +55,7 @@ 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 \
diff --git a/src/common_init.c b/src/common_init.c
index 6b83d97..6b9b936 100644
--- a/src/common_init.c
+++ b/src/common_init.c
@@ -91,6 +91,7 @@ pci_system_cleanup( void )
 	return;
     }
 
+    pci_io_cleanup();
 
     if ( pci_sys->devices ) {
 	for ( i = 0 ; i < pci_sys->num_devices ; i++ ) {
diff --git a/src/common_io.c b/src/common_io.c
new file mode 100644
index 0000000..bc5ba0a
--- /dev/null
+++ b/src/common_io.c
@@ -0,0 +1,250 @@
+/*
+ * 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 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/linux_sysfs.c b/src/linux_sysfs.c
index 85095b3..1832ee7 100644
--- a/src/linux_sysfs.c
+++ b/src/linux_sysfs.c
@@ -55,52 +55,17 @@
 #include "pciaccess_private.h"
 #include "linux_devmem.h"
 
-static void pci_device_linux_sysfs_enable(struct pci_device *dev);
-
-static int pci_device_linux_sysfs_read_rom( struct pci_device * dev,
-    void * buffer );
-
-static int pci_device_linux_sysfs_probe( struct pci_device * dev );
-
-static int pci_device_linux_sysfs_map_range(struct pci_device *dev,
-    struct pci_device_mapping *map);
-
-static int pci_device_linux_sysfs_unmap_range(struct pci_device *dev,
-    struct pci_device_mapping *map);
-
-static int pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
-    pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_read );
-
-static int pci_device_linux_sysfs_write( struct pci_device * dev,
-    const void * data, pciaddr_t offset, pciaddr_t size,
-    pciaddr_t * bytes_written );
-
-static int pci_device_linux_sysfs_boot_vga( struct pci_device * dev );
-static int pci_device_linux_sysfs_has_kernel_driver(struct pci_device *dev);
-
-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,
-};
+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.
  */
@@ -759,3 +724,141 @@ static int pci_device_linux_sysfs_has_kernel_driver(struct pci_device *dev)
 	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/pciaccess_private.h b/src/pciaccess_private.h
index a9d8df0..77eb57b 100644
--- a/src/pciaccess_private.h
+++ b/src/pciaccess_private.h
@@ -62,6 +62,21 @@ struct pci_system_methods {
     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 {
@@ -72,6 +87,12 @@ struct pci_device_mapping {
     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;
@@ -146,3 +167,4 @@ 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 void pci_io_cleanup( void );

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>

diff --git a/include/pciaccess.h b/include/pciaccess.h
index 067954f..8128656 100644
--- a/include/pciaccess.h
+++ b/include/pciaccess.h
@@ -131,6 +131,8 @@ 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);
diff --git a/src/common_bridge.c b/src/common_bridge.c
index 7f26bdc..f37420f 100644
--- a/src/common_bridge.c
+++ b/src/common_bridge.c
@@ -322,3 +322,43 @@ pci_device_get_bridge_buses(struct pci_device * dev, int *primary_bus,
 
     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;
+}

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.

diff --git a/Makefile.am b/Makefile.am
index 0a6ec7f..ced72dc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -29,6 +29,7 @@ SUBDIRS = src
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = pciaccess.pc
 
+MAINTAINERCLEANFILES = ChangeLog INSTALL
 EXTRA_DIST = pciaccess.pc.in src/scanpci.c src/scanpci.man 
 
 .PHONY: ChangeLog INSTALL

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.

diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index 56b077d..0000000
--- a/INSTALL
+++ /dev/null
@@ -1,236 +0,0 @@
-Installation Instructions
-*************************
-
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
-Software Foundation, Inc.
-
-This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
-
-Basic Installation
-==================
-
-These are generic installation instructions.
-
-   The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation.  It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions.  Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
-   It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring.  (Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.)
-
-   If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release.  If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
-   The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'.  You only need
-`configure.ac' if you want to change it or regenerate `configure' using
-a newer version of `autoconf'.
-
-The simplest way to compile this package is:
-
-  1. `cd' to the directory containing the package's source code and type
-     `./configure' to configure the package for your system.  If you're
-     using `csh' on an old version of System V, you might need to type
-     `sh ./configure' instead to prevent `csh' from trying to execute
-     `configure' itself.
-
-     Running `configure' takes awhile.  While running, it prints some
-     messages telling which features it is checking for.
-
-  2. Type `make' to compile the package.
-
-  3. Optionally, type `make check' to run any self-tests that come with
-     the package.
-
-  4. Type `make install' to install the programs and any data files and
-     documentation.
-
-  5. You can remove the program binaries and object files from the
-     source code directory by typing `make clean'.  To also remove the
-     files that `configure' created (so you can compile the package for
-     a different kind of computer), type `make distclean'.  There is
-     also a `make maintainer-clean' target, but that is intended mainly
-     for the package's developers.  If you use it, you may have to get
-     all sorts of other programs in order to regenerate files that came
-     with the distribution.
-
-Compilers and Options
-=====================
-
-Some systems require unusual options for compilation or linking that the
-`configure' script does not know about.  Run `./configure --help' for
-details on some of the pertinent environment variables.
-
-   You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment.  Here
-is an example:
-
-     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
-
-   *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
-You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory.  To do this, you must use a version of `make' that
-supports the `VPATH' variable, such as GNU `make'.  `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script.  `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
-   If you have to use a `make' that does not support the `VPATH'
-variable, you have to compile the package for one architecture at a
-time in the source code directory.  After you have installed the
-package for one architecture, use `make distclean' before reconfiguring
-for another architecture.
-
-Installation Names
-==================
-
-By default, `make install' will install the package's files in
-`/usr/local/bin', `/usr/local/man', etc.  You can specify an
-installation prefix other than `/usr/local' by giving `configure' the
-option `--prefix=PREFIX'.
-
-   You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files.  If you
-give `configure' the option `--exec-prefix=PREFIX', the package will
-use PREFIX as the prefix for installing programs and libraries.
-Documentation and other data files will still use the regular prefix.
-
-   In addition, if you use an unusual directory layout you can give
-options like `--bindir=DIR' to specify different values for particular
-kinds of files.  Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
-
-   If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
-Optional Features
-=================
-
-Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System).  The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
-   For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
-Specifying the System Type
-==========================
-
-There may be some features `configure' cannot figure out automatically,
-but needs to determine by the type of machine the package will run on.
-Usually, assuming the package is built to be run on the _same_
-architectures, `configure' can figure that out, but if it prints a
-message saying it cannot guess the machine type, give it the
-`--build=TYPE' option.  TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
-     CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
-     OS KERNEL-OS
-
-   See the file `config.sub' for the possible values of each field.  If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
-   If you are _building_ compiler tools for cross-compiling, you should
-use the `--target=TYPE' option to select the type of system they will
-produce code for.
-
-   If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
-If you want to set default values for `configure' scripts to share, you
-can create a site shell script called `config.site' that gives default
-values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists.  Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
-Variables not defined in a site shell script can be set in the
-environment passed to `configure'.  However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost.  In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'.  For example:
-
-     ./configure CC=/usr/local2/bin/gcc
-
-causes the specified `gcc' to be used as the C compiler (unless it is
-overridden in the site shell script).  Here is a another example:
-
-     /bin/bash ./configure CONFIG_SHELL=/bin/bash
-
-Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
-configuration-related scripts to be executed by `/bin/bash'.
-
-`configure' Invocation


Reply to: