From c65aa7630802c8dfcc06a20e515ace31ab0d0e48 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 11 Jan 2007 21:40:57 -0800 Subject: [PATCH] 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. --- configure.ac | 2 +- include/pciaccess.h | 6 +++ src/Makefile.am | 2 +- src/common_interface.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 99ea0cf..1c99739 100644 --- a/configure.ac +++ b/configure.ac @@ -41,7 +41,7 @@ dnl refers to ${prefix}. Thus we have to use `eval' twice. AC_PREREQ([2.57]) -AC_INIT(libpciaccess, 0.6.0, [none yet], libpciaccess) +AC_INIT(libpciaccess, 0.7.0, [none yet], libpciaccess) AM_INIT_AUTOMAKE([dist-bzip2]) AM_MAINTAINER_MODE diff --git a/include/pciaccess.h b/include/pciaccess.h index 4078f0f..a0cf067 100644 --- a/include/pciaccess.h +++ b/include/pciaccess.h @@ -47,6 +47,12 @@ int pci_device_map_region( struct pci_device * dev, unsigned region, int pci_device_unmap_region( struct pci_device * dev, unsigned region ); +int pci_device_map_memory_range(struct pci_device *dev, pciaddr_t base, + pciaddr_t size, int write_enable, void **addr); + +int 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 ); diff --git a/src/Makefile.am b/src/Makefile.am index da20076..de4e52a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,7 +43,7 @@ INCLUDES = -I$(top_srcdir)/include libpciaccess_la_LIBADD = @PCIACCESS_LIBS@ -libpciaccess_la_LDFLAGS = -version-number 0:6:0 -no-undefined +libpciaccess_la_LDFLAGS = -version-number 0:7:0 -no-undefined libpciaccessincludedir = $(includedir) libpciaccessinclude_HEADERS = \ diff --git a/src/common_interface.c b/src/common_interface.c index 67e8e9a..54c8b26 100644 --- a/src/common_interface.c +++ b/src/common_interface.c @@ -148,6 +148,72 @@ pci_device_map_region( struct pci_device * dev, unsigned region, /** + * 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 addtion, 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_unmap_memory_range, pci_device_map_region + */ +int +pci_device_map_memory_range(struct pci_device *dev, pciaddr_t base, + pciaddr_t size, int write_enable, + void **addr) +{ + unsigned region; + 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; + } + + if (dev->regions[region].memory == NULL) { + err = (*pci_sys->methods->map)(dev, region, write_enable); + } + + if (err == 0) { + const pciaddr_t offset = base - dev->regions[region].base_addr; + + *addr = ((uint8_t *)dev->regions[region].memory) + offset; + } + + 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 @@ -181,6 +247,57 @@ pci_device_unmap_region( struct pci_device * dev, unsigned region ) /** + * 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_memory_range, pci_device_unmap_region + */ +int +pci_device_unmap_memory_range(struct pci_device *dev, void *memory, + pciaddr_t size) +{ + unsigned region; + + + if (dev == NULL) { + return EFAULT; + } + + for (region = 0; region < 6; region++) { + const struct pci_mem_region const* r = &dev->regions[region]; + const uint8_t *const mem = r->memory; + + if (r->size != 0) { + if ((mem <= memory) && ((mem + r->size) > memory)) { + if ((memory + size) > (mem + r->size)) { + return E2BIG; + } + + break; + } + } + } + + if (region > 5) { + return ENOENT; + } + + return (dev->regions[region].memory != NULL) + ? (*pci_sys->methods->unmap)(dev, region) + : 0; +} + + +/** * Read arbitrary bytes from device's PCI config space * * Reads data from the device's PCI configuration space. As with the system -- 2.7.4