[PATCH 2/2] I/O port access routines
Adam Jackson
ajax at redhat.com
Wed Nov 18 11:28:57 PST 2009
Signed-off-by: Adam Jackson <ajax at redhat.com>
---
include/pciaccess.h | 14 ++++
src/Makefile.am | 1 +
src/common_io.c | 95 ++++++++++++++++++++++++
src/linux_sysfs.c | 184 ++++++++++++++++++++++++++++++++++++----------
src/pciaccess_private.h | 9 +++
5 files changed, 263 insertions(+), 40 deletions(-)
create mode 100644 src/common_io.c
diff --git a/include/pciaccess.h b/include/pciaccess.h
index 8128656..b4a431a 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,17 @@ 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.
+ */
+void *pci_device_open_io(struct pci_device *dev, int bar);
+void *pci_legacy_open_io(struct pci_device *dev);
+void pci_device_close_io(struct pci_device *dev, void *handle);
+uint32_t pci_io_inl(void *handle, uint16_t reg);
+uint16_t pci_io_inw(void *handle, uint16_t reg);
+uint8_t pci_io_inb(void *handle, uint16_t reg);
+void pci_io_outl(void *handle, uint16_t reg, uint32_t data);
+void pci_io_outw(void *handle, uint16_t reg, uint16_t data);
+void pci_io_outb(void *handle, uint16_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_io.c b/src/common_io.c
new file mode 100644
index 0000000..9828af4
--- /dev/null
+++ b/src/common_io.c
@@ -0,0 +1,95 @@
+/*
+ * 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 at redhat.com>
+ */
+
+#include <stdlib.h>
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+void *
+pci_device_open_io(struct pci_device *dev, int bar)
+{
+ if (!pci_sys->methods->open_device_io)
+ return NULL;
+
+ if (bar < 0 || bar > 6)
+ return NULL;
+
+ if (!dev->regions[bar].is_IO)
+ return NULL;
+
+ return pci_sys->methods->open_device_io(dev, bar);
+}
+
+void *
+pci_legacy_open_io(struct pci_device *dev)
+{
+ if (!pci_sys->methods->open_legacy_io)
+ return NULL;
+
+ return pci_sys->methods->open_legacy_io(dev);
+}
+
+void
+pci_device_close_io(struct pci_device *dev, void *handle)
+{
+ if (dev && handle && pci_sys->methods->close_io)
+ pci_sys->methods->close_io(dev, handle);
+}
+
+uint32_t
+pci_io_inl(void *handle, uint16_t reg)
+{
+ return pci_sys->methods->inl(handle, reg);
+}
+
+uint16_t
+pci_io_inw(void *handle, uint16_t reg)
+{
+ return pci_sys->methods->inw(handle, reg);
+}
+
+uint8_t
+pci_io_inb(void *handle, uint16_t reg)
+{
+ return pci_sys->methods->inb(handle, reg);
+}
+
+void
+pci_io_outl(void *handle, uint16_t reg, uint32_t data)
+{
+ pci_sys->methods->outl(handle, reg, data);
+}
+
+void
+pci_io_outw(void *handle, uint16_t reg, uint16_t data)
+{
+ pci_sys->methods->outw(handle, reg, data);
+}
+
+void
+pci_io_outb(void *handle, uint16_t reg, uint8_t data)
+{
+ pci_sys->methods->outb(handle, reg, data);
+}
diff --git a/src/linux_sysfs.c b/src/linux_sysfs.c
index 85095b3..eb8ea5f 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,142 @@ static int pci_device_linux_sysfs_has_kernel_driver(struct pci_device *dev)
return 0;
return 1;
}
+
+static void *
+pci_device_linux_sysfs_open_device_io(struct pci_device *dev, int bar)
+{
+ char name[PATH_MAX];
+ int ret;
+
+ snprintf(name, PATH_MAX, "%s/%04x:%02x:%02x.%1u/resource%d",
+ SYS_BUS_PCI, dev->domain, dev->bus, dev->dev, dev->func, bar);
+
+ ret = open(name, O_RDWR);
+
+ /* Avoid returning fd 0 since it's not distinguishable from failure */
+ if (ret == 0) {
+ int new = dup(ret);
+ close(ret);
+ ret = new;
+ }
+
+ if (ret < 0)
+ return NULL;
+
+ return (void *)ret;
+}
+
+static void *
+pci_device_linux_sysfs_open_legacy_io(struct pci_device *dev)
+{
+ char name[PATH_MAX];
+ int ret;
+
+ /* 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 = open(name, O_RDWR);
+ if (ret >= 0)
+ goto out;
+
+ dev = pci_device_get_parent_bridge(dev);
+ }
+
+ /* If not, /dev/port is the best we can do */
+ ret = open("/dev/port", O_RDWR);
+
+out:
+ if (ret == 0) {
+ int new = dup(ret);
+ close(ret);
+ ret = new;
+ }
+
+ if (ret < 0)
+ return NULL;
+
+ return (void *)ret;
+}
+
+static void
+pci_device_linux_sysfs_close_io(struct pci_device *dev, void *handle)
+{
+ close((int)handle);
+}
+
+static uint32_t
+pci_device_linux_sysfs_inl(void *handle, uint16_t port)
+{
+ uint32_t ret;
+
+ pread((int)handle, &ret, 4, port);
+
+ return ret;
+}
+
+static uint16_t
+pci_device_linux_sysfs_inw(void *handle, uint16_t port)
+{
+ uint16_t ret;
+
+ pread((int)handle, &ret, 2, port);
+
+ return ret;
+}
+
+static uint8_t
+pci_device_linux_sysfs_inb(void *handle, uint16_t port)
+{
+ uint8_t ret;
+
+ pread((int)handle, &ret, 1, port);
+
+ return ret;
+}
+
+static void
+pci_device_linux_sysfs_outl(void *handle, uint16_t port, uint32_t data)
+{
+ pwrite((int)handle, &data, 4, port);
+}
+
+static void
+pci_device_linux_sysfs_outw(void *handle, uint16_t port, uint16_t data)
+{
+ pwrite((int)handle, &data, 2, port);
+}
+
+static void
+pci_device_linux_sysfs_outb(void *handle, uint16_t port, uint8_t data)
+{
+ pwrite((int)handle, &data, 1, port);
+}
+
+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,
+ .inl = pci_device_linux_sysfs_inl,
+ .inw = pci_device_linux_sysfs_inw,
+ .inb = pci_device_linux_sysfs_inb,
+ .outl = pci_device_linux_sysfs_outl,
+ .outw = pci_device_linux_sysfs_outw,
+ .outb = pci_device_linux_sysfs_outb,
+};
diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h
index a9d8df0..b39d9a7 100644
--- a/src/pciaccess_private.h
+++ b/src/pciaccess_private.h
@@ -62,6 +62,15 @@ 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 );
+ void *(*open_device_io)( struct pci_device *dev, int bar );
+ void *(*open_legacy_io)( struct pci_device *dev );
+ void (*close_io)( struct pci_device *dev, void *handle );
+ uint32_t (*inl)( void *handle, uint16_t reg );
+ uint16_t (*inw)( void *handle, uint16_t reg );
+ uint8_t (*inb)( void *handle, uint16_t reg );
+ void (*outl)( void *handle, uint16_t reg, uint32_t data );
+ void (*outw)( void *handle, uint16_t reg, uint16_t data );
+ void (*outb)( void *handle, uint16_t reg, uint8_t data );
};
struct pci_device_mapping {
--
1.6.5.2
More information about the xorg-devel
mailing list