libpciaccess: Changes to 'upstream-experimental'
src/Makefile.am | 2
src/linux_devmem.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++
src/linux_devmem.h | 34 ++++++++++
src/linux_sysfs.c | 7 +-
src/pciaccess_private.h | 5 +
5 files changed, 201 insertions(+), 2 deletions(-)
New commits:
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.
diff --git a/src/Makefile.am b/src/Makefile.am
index c6554ba..760711c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,7 +26,7 @@ AM_CFLAGS = @PCIACCESS_CFLAGS@
lib_LTLIBRARIES = libpciaccess.la
if LINUX
-OS_SUPPORT = linux_sysfs.c
+OS_SUPPORT = linux_sysfs.c linux_devmem.c
endif
if FREEBSD
diff --git a/src/linux_devmem.c b/src/linux_devmem.c
new file mode 100644
index 0000000..8650efd
--- /dev/null
+++ b/src/linux_devmem.c
@@ -0,0 +1,155 @@
+/*
+ * (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?
+ */
+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 < priv->base.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 occured.
+ */
+ if (err == 0) {
+ err = tmp_err;
+ }
+ }
+
+ return err;
+}
diff --git a/src/linux_devmem.h b/src/linux_devmem.h
new file mode 100644
index 0000000..2337f30
--- /dev/null
+++ b/src/linux_devmem.h
@@ -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
index 8a4bd0f..ba5dce2 100644
--- a/src/linux_sysfs.c
+++ b/src/linux_sysfs.c
@@ -46,6 +46,7 @@
#include "pciaccess.h"
#include "pciaccess_private.h"
+#include "linux_devmem.h"
static int pci_device_linux_sysfs_read_rom( struct pci_device * dev,
void * buffer );
@@ -278,6 +279,7 @@ pci_device_linux_sysfs_probe( struct pci_device * dev )
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;
}
}
@@ -306,7 +308,10 @@ pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer )
fd = open( name, O_RDWR );
if ( fd == -1 ) {
- return errno;
+ /* If reading the ROM using sysfs fails, fall back to the old
+ * /dev/mem based interface.
+ */
+ return pci_device_linux_devmem_read_rom(dev, buffer);
}
diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h
index b23e589..afbeb75 100644
--- a/src/pciaccess_private.h
+++ b/src/pciaccess_private.h
@@ -63,6 +63,11 @@ struct pci_device_private {
/*@}*/
/**
+ * Base address of the device's expansion ROM.
+ */
+ pciaddr_t rom_base;
+
+ /**
* \name Bridge information.
*/
/*@{*/
Reply to: