summaryrefslogtreecommitdiff
path: root/lib/libpciaccess/src/common_interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpciaccess/src/common_interface.c')
-rw-r--r--lib/libpciaccess/src/common_interface.c255
1 files changed, 182 insertions, 73 deletions
diff --git a/lib/libpciaccess/src/common_interface.c b/lib/libpciaccess/src/common_interface.c
index 908e91589..663ab44ef 100644
--- a/lib/libpciaccess/src/common_interface.c
+++ b/lib/libpciaccess/src/common_interface.c
@@ -30,12 +30,13 @@
*/
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include "pciaccess.h"
#include "pciaccess_private.h"
-#ifdef __linux__
+#if defined(__linux__) || defined(__GLIBC__)
#include <byteswap.h>
#if __BYTE_ORDER == __BIG_ENDIAN
@@ -56,23 +57,20 @@
#define LETOH_32(x) (x)
#define HTOLE_32(x) (x)
-#elif defined(__OpenBSD__)
+#else
-#include <sys/types.h>
+#include <sys/endian.h>
-#define LETOH_16(x) letoh16(x)
#define HTOLE_16(x) htole16(x)
-#define LETOH_32(x) letoh32(x)
#define HTOLE_32(x) htole32(x)
-#else
-
-#include <sys/endian.h>
-
+#if defined(__FreeBSD__) || defined(__DragonFly__)
#define LETOH_16(x) le16toh(x)
-#define HTOLE_16(x) htole16(x)
#define LETOH_32(x) le32toh(x)
-#define HTOLE_32(x) htole32(x)
+#else
+#define LETOH_16(x) letoh16(x)
+#define LETOH_32(x) letoh32(x)
+#endif
#endif /* others */
@@ -140,25 +138,27 @@ pci_device_probe( struct pci_device * dev )
* \return
* Zero on success or an \c errno value on failure.
*
- * \sa pci_device_unmap_region
+ * \sa pci_device_map_range, pci_device_unmap_range
+ * \deprecated
*/
int
-pci_device_map_region( struct pci_device * dev, unsigned region,
- int write_enable )
+pci_device_map_region(struct pci_device * dev, unsigned region,
+ int write_enable)
{
- if ( dev == NULL ) {
- return EFAULT;
- }
+ const unsigned map_flags =
+ (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE : 0;
- if ( (region > 5) || (dev->regions[ region ].size == 0) ) {
- return ENOENT;
+ if ((region > 5) || (dev->regions[region].size == 0)) {
+ return ENOENT;
}
- if ( dev->regions[ region ].memory != NULL ) {
- return 0;
+ if (dev->regions[region].memory != NULL) {
+ return 0;
}
- return (pci_sys->methods->map)( dev, region, write_enable );
+ return pci_device_map_range(dev, dev->regions[region].base_addr,
+ dev->regions[region].size, map_flags,
+ &dev->regions[region].memory);
}
@@ -178,52 +178,112 @@ pci_device_map_region( struct pci_device * dev, unsigned region,
* \return
* Zero on success or an \c errno value on failure.
*
- * \sa pci_device_unmap_memory_range, pci_device_map_region
+ * \sa pci_device_map_range
+ */
+int pci_device_map_memory_range(struct pci_device *dev,
+ pciaddr_t base, pciaddr_t size,
+ int write_enable, void **addr)
+{
+ return pci_device_map_range(dev, base, size,
+ (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE : 0,
+ addr);
+}
+
+
+/**
+ * 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 map_flags Flag bits controlling how the mapping is accessed.
+ * \param addr Location to store the mapped address.
+ *
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_unmap_range
*/
int
-pci_device_map_memory_range(struct pci_device *dev, pciaddr_t base,
- pciaddr_t size, int write_enable,
- void **addr)
+pci_device_map_range(struct pci_device *dev, pciaddr_t base,
+ pciaddr_t size, unsigned map_flags,
+ void **addr)
{
+ struct pci_device_private *const devp =
+ (struct pci_device_private *) dev;
+ struct pci_device_mapping *mappings;
unsigned region;
+ unsigned i;
int err = 0;
*addr = NULL;
if (dev == NULL) {
- return EFAULT;
+ return EFAULT;
}
for (region = 0; region < 6; region++) {
- const struct pci_mem_region const* r = &dev->regions[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;
- }
+ 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;
- }
- }
+ break;
+ }
+ }
}
if (region > 5) {
- return ENOENT;
+ return ENOENT;
}
+ /* Make sure that there isn't already a mapping with the same base and
+ * size.
+ */
+ for (i = 0; i < devp->num_mappings; i++) {
+ if ((devp->mappings[i].base == base)
+ && (devp->mappings[i].size == size)) {
+ return EINVAL;
+ }
+ }
+
+
+ mappings = realloc(devp->mappings,
+ (sizeof(devp->mappings[0]) * (devp->num_mappings + 1)));
+ if (mappings == NULL) {
+ return ENOMEM;
+ }
+
+ mappings[devp->num_mappings].base = base;
+ mappings[devp->num_mappings].size = size;
+ mappings[devp->num_mappings].region = region;
+ mappings[devp->num_mappings].flags = map_flags;
+ mappings[devp->num_mappings].memory = NULL;
+
if (dev->regions[region].memory == NULL) {
- err = (*pci_sys->methods->map)(dev, region, write_enable);
+ err = (*pci_sys->methods->map_range)(dev,
+ &mappings[devp->num_mappings]);
}
-
- if (err == 0) {
- const pciaddr_t offset = base - dev->regions[region].base_addr;
- *addr = ((uint8_t *)dev->regions[region].memory) + offset;
+ if (err == 0) {
+ *addr = mappings[devp->num_mappings].memory;
+ devp->num_mappings++;
+ } else {
+ mappings = realloc(devp->mappings,
+ (sizeof(devp->mappings[0]) * devp->num_mappings));
}
+ devp->mappings = mappings;
+
return err;
}
@@ -240,24 +300,29 @@ pci_device_map_memory_range(struct pci_device *dev, pciaddr_t base,
* \return
* Zero on success or an \c errno value on failure.
*
- * \sa pci_device_map_region
+ * \sa pci_device_map_range, pci_device_unmap_range
+ * \deprecated
*/
int
pci_device_unmap_region( struct pci_device * dev, unsigned region )
{
- if ( dev == NULL ) {
- return EFAULT;
+ int err;
+
+ if (dev == NULL) {
+ return EFAULT;
}
- if ( (region > 5) || (dev->regions[ region ].size == 0) ) {
- return ENOENT;
+ if ((region > 5) || (dev->regions[region].size == 0)) {
+ return ENOENT;
}
- if ( dev->regions[ region ].memory == NULL ) {
- return 0;
+ err = pci_device_unmap_range(dev, dev->regions[region].memory,
+ dev->regions[region].size);
+ if (!err) {
+ dev->regions[region].memory = NULL;
}
-
- return (pci_sys->methods->unmap)( dev, region );
+
+ return err;
}
@@ -274,41 +339,74 @@ pci_device_unmap_region( struct pci_device * dev, unsigned region )
* \return
* Zero on success or an \c errno value on failure.
*
- * \sa pci_device_map_memory_range, pci_device_unmap_region
+ * \sa pci_device_map_range, pci_device_unmap_range
+ * \deprecated
*/
int
pci_device_unmap_memory_range(struct pci_device *dev, void *memory,
- pciaddr_t size)
+ pciaddr_t size)
{
- unsigned region;
+ return pci_device_unmap_range(dev, memory, size);
+}
+
+
+/**
+ * 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_range
+ */
+int
+pci_device_unmap_range(struct pci_device *dev, void *memory,
+ pciaddr_t size)
+{
+ struct pci_device_private *const devp =
+ (struct pci_device_private *) dev;
+ unsigned i;
+ int err;
if (dev == NULL) {
- return EFAULT;
+ 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;
- }
- }
+ for (i = 0; i < devp->num_mappings; i++) {
+ if ((devp->mappings[i].memory == memory)
+ && (devp->mappings[i].size == size)) {
+ break;
+ }
}
- if (region > 5) {
- return ENOENT;
+ if (i == devp->num_mappings) {
+ return ENOENT;
+ }
+
+
+ err = (*pci_sys->methods->unmap_range)(dev, &devp->mappings[i]);
+ if (!err) {
+ const unsigned entries_to_move = (devp->num_mappings - i) - 1;
+
+ if (entries_to_move > 0) {
+ (void) memmove(&devp->mappings[i],
+ &devp->mappings[i + 1],
+ entries_to_move * sizeof(devp->mappings[0]));
+ }
+
+ devp->num_mappings--;
+ devp->mappings = realloc(devp->mappings,
+ (sizeof(devp->mappings[0]) * devp->num_mappings));
}
- return (dev->regions[region].memory != NULL)
- ? (*pci_sys->methods->unmap)(dev, region)
- : 0;
+ return err;
}
@@ -506,3 +604,14 @@ pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask,
return err;
}
+
+void
+pci_device_enable(struct pci_device *dev)
+{
+ if (dev == NULL) {
+ return;
+ }
+
+ if (pci_sys->methods->enable)
+ pci_sys->methods->enable(dev);
+}