Blob Blame History Raw
diff -up libpciaccess-0.10.9/src/linux_sysfs.c.da libpciaccess-0.10.9/src/linux_sysfs.c
--- libpciaccess-0.10.9/src/linux_sysfs.c.da	2009-09-24 10:06:55.000000000 +1000
+++ libpciaccess-0.10.9/src/linux_sysfs.c	2009-09-25 11:51:21.000000000 +1000
@@ -57,6 +57,8 @@
 
 static void pci_device_linux_sysfs_enable(struct pci_device *dev);
 
+static void pci_device_linux_sysfs_destroy( void );
+
 static int pci_device_linux_sysfs_read_rom( struct pci_device * dev,
     void * buffer );
 
@@ -79,7 +81,7 @@ static int pci_device_linux_sysfs_boot_v
 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 = pci_device_linux_sysfs_destroy,
     .destroy_device = NULL,
     .read_rom = pci_device_linux_sysfs_read_rom,
     .probe = pci_device_linux_sysfs_probe,
@@ -382,6 +384,53 @@ pci_device_linux_sysfs_read_rom( struct 
     return err;
 }
 
+static struct pci_device *last_config_dev = NULL;
+static int config_fd = -1;
+
+static void
+pci_device_linux_sysfs_destroy( void )
+{
+    if (config_fd != -1)
+	close( config_fd );
+}
+
+static int
+open_config_fd( struct pci_device * dev, int flags )
+{
+    int fd;
+    char name[256];
+
+    /* 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.
+     */
+
+    if ( last_config_dev != dev ) {
+	if ( config_fd != -1 ) {
+	    close( config_fd );
+	    last_config_dev = NULL;
+	}
+
+	snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/config",
+		  SYS_BUS_PCI,
+	          dev->domain,
+	          dev->bus,
+	          dev->dev,
+	          dev->func );
+
+	fd = open( name, flags );
+	if ( fd == -1 ) {
+	    return -1;
+	}
+	config_fd = fd;
+	last_config_dev = dev;
+    } else {
+	fd = config_fd;
+    }
+
+    return fd;
+}
 
 static int
 pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
@@ -398,23 +447,9 @@ pci_device_linux_sysfs_read( struct pci_
 	*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 ) {
+    fd = open_config_fd( dev, O_RDWR );
+    if ( fd == -1 )
 	return errno;
-    }
-
 
     while ( temp_size > 0 ) {
 	const ssize_t bytes = pread64( fd, data_bytes, temp_size, offset );
@@ -436,7 +471,6 @@ pci_device_linux_sysfs_read( struct pci_
 	*bytes_read = size - temp_size;
     }
 
-    close( fd );
     return err;
 }
 
@@ -456,23 +490,9 @@ pci_device_linux_sysfs_write( struct pci
 	*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 ) {
+    fd = open_config_fd( dev, O_RDWR );
+    if ( fd == -1 )
 	return errno;
-    }
-
 
     while ( temp_size > 0 ) {
 	const ssize_t bytes = pwrite64( fd, data_bytes, temp_size, offset );
@@ -494,7 +514,6 @@ pci_device_linux_sysfs_write( struct pci
 	*bytes_written = size - temp_size;
     }
 
-    close( fd );
     return err;
 }