OSDN Git Service

linux_sysfs.c: Include <limits.h> for PATH_MAX
[android-x86/external-libpciaccess.git] / src / common_interface.c
index 57908f4..cb95e90 100644 (file)
  *
  * \author Ian Romanick <idr@us.ibm.com>
  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
 #include <stdlib.h>
+#include <string.h>
 #include <errno.h>
 
 #include "pciaccess.h"
 #include "pciaccess_private.h"
 
+#if defined(__linux__) || defined(__GLIBC__) || defined(__CYGWIN__)
 #include <byteswap.h>
 
 #if __BYTE_ORDER == __BIG_ENDIAN
 # define HTOLE_16(x)   (x)
 # define LETOH_32(x)   (x)
 # define HTOLE_32(x)   (x)
+#endif /* linux */
+
+#elif defined(__sun)
+
+#include <sys/byteorder.h>
+
+#ifdef _BIG_ENDIAN
+# define LETOH_16(x)   BSWAP_16(x)
+# define HTOLE_16(x)   BSWAP_16(x)
+# define LETOH_32(x)   BSWAP_32(x)
+# define HTOLE_32(x)   BSWAP_32(x)
+#else
+# define LETOH_16(x)   (x)
+# define HTOLE_16(x)   (x)
+# define LETOH_32(x)   (x)
+# define HTOLE_32(x)   (x)
+#endif /* Solaris */
+
+#else
+
+#include <sys/endian.h>
+
+#define HTOLE_16(x)    htole16(x)
+#define HTOLE_32(x)    htole32(x)
+
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
+#define LETOH_16(x)    le16toh(x)
+#define LETOH_32(x)    le32toh(x)
+#else
+#define LETOH_16(x)    letoh16(x)
+#define LETOH_32(x)    letoh32(x)
 #endif
 
+#endif /* others */
+
 /**
  * Read a device's expansion ROM.
- * 
+ *
  * Reads the device's expansion ROM and stores the data in the memory pointed
  * to by \c buffer.  The buffer must be at least \c pci_device::rom_size
  * bytes.
  *
  * \param dev    Device whose expansion ROM is to be read.
  * \param buffer Memory in which to store the ROM.
- * 
+ *
  * \return
  * Zero on success or an \c errno value on failure.
  */
@@ -73,19 +111,48 @@ pci_device_read_rom( struct pci_device * dev, void * buffer )
     return (pci_sys->methods->read_rom)( dev, buffer );
 }
 
+/**
+ * Probe a PCI (VGA) device to determine if its the boot VGA device
+ *
+ * \param dev    Device whose VGA status to query
+ * \return
+ * Zero if not the boot VGA, 1 if the boot VGA.
+ */
+int
+pci_device_is_boot_vga( struct pci_device * dev )
+{
+       if (!pci_sys->methods->boot_vga)
+               return 0;
+       return pci_sys->methods->boot_vga( dev );
+}
+
+/**
+ * Probe a PCI device to determine if a kernel driver is attached.
+ *
+ * \param dev Device to query
+ * \return
+ * Zero if no driver attached, 1 if attached kernel drviver
+ */
+int
+pci_device_has_kernel_driver( struct pci_device * dev )
+{
+       if (!pci_sys->methods->has_kernel_driver)
+               return 0;
+       return pci_sys->methods->has_kernel_driver( dev );
+}
 
 /**
  * Probe a PCI device to learn information about the device.
- * 
+ *
  * Probes a PCI device to learn various information about the device.  Before
  * calling this function, the only public fields in the \c pci_device
  * structure that have valid values are \c pci_device::domain,
  * \c pci_device::bus, \c pci_device::dev, and \c pci_device::func.
- * 
+ *
  * \param dev  Device to be probed.
- * 
+ *
  * \return
- * Zero on succes or an \c errno value on failure.
+ * Zero on success or an \c errno value on failure.
  */
 int
 pci_device_probe( struct pci_device * dev )
@@ -102,36 +169,164 @@ pci_device_probe( struct pci_device * dev )
 /**
  * Map the specified BAR so that it can be accessed by the CPU.
  *
- * Maps the specified BAR for acces by the processor.  The pointer to the
+ * Maps the specified BAR for access by the processor.  The pointer to the
  * mapped region is stored in the \c pci_mem_region::memory pointer for the
  * BAR.
  *
  * \param dev          Device whose memory region is to be mapped.
  * \param region       Region, on the range [0, 5], that is to be mapped.
  * \param write_enable Map for writing (non-zero).
- * 
+ *
  * \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_device_map_range(dev, dev->regions[region].base_addr,
+                                dev->regions[region].size, map_flags,
+                                &dev->regions[region].memory);
+}
+
+
+/**
+ * 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 addition, 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_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 addition, 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_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;
+    }
+
+
+    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;
+    }
+
+    /* 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_range)(dev,
+                                             &mappings[devp->num_mappings]);
     }
-    
-    return (pci_sys->methods->map)( dev, region, write_enable );
+
+    if (err == 0) {
+        *addr =  mappings[devp->num_mappings].memory;
+        devp->num_mappings++;
+    } else {
+        mappings = realloc(mappings,
+                           (sizeof(mappings[0]) * devp->num_mappings));
+    }
+
+    devp->mappings = mappings;
+
+    return err;
 }
 
 
@@ -143,28 +338,117 @@ pci_device_map_region( struct pci_device * dev, unsigned region,
  *
  * \param dev          Device whose memory region is to be mapped.
  * \param region       Region, on the range [0, 5], that is to be mapped.
- * 
+ *
  * \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;
+    }
+
+    err = pci_device_unmap_range(dev, dev->regions[region].memory,
+                                 dev->regions[region].size);
+    if (!err) {
+        dev->regions[region].memory = NULL;
+    }
+
+    return err;
+}
+
+
+/**
+ * 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, pci_device_unmap_range
+ * \deprecated
+ */
+int
+pci_device_unmap_memory_range(struct pci_device *dev, void *memory,
+                              pciaddr_t size)
+{
+    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;
     }
 
-    if ( (region > 5) || (dev->regions[ region ].size == 0) ) {
-       return ENOENT;
+    for (i = 0; i < devp->num_mappings; i++) {
+        if ((devp->mappings[i].memory == memory)
+            && (devp->mappings[i].size == size)) {
+            break;
+        }
     }
 
-    if ( dev->regions[ region ].memory == NULL ) {
-       return 0;
+    if (i == devp->num_mappings) {
+        return ENOENT;
     }
-    
-    return (pci_sys->methods->unmap)( dev, region );
+
+
+    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 err;
 }
 
 
@@ -173,7 +457,7 @@ pci_device_unmap_region( struct pci_device * dev, unsigned region )
  *
  * Reads data from the device's PCI configuration space.  As with the system
  * read command, less data may be returned, without an error, than was
- * requested.  This is particuarly the case if a non-root user tries to read
+ * requested.  This is particularly the case if a non-root user tries to read
  * beyond the first 64-bytes of configuration space.
  *
  * \param dev         Device whose PCI configuration data is to be read.
@@ -187,13 +471,13 @@ pci_device_unmap_region( struct pci_device * dev, unsigned region )
  * Zero on success or an errno value on failure.
  *
  * \note
- * Data read from PCI configuartion space using this routine is \b not
+ * Data read from PCI configuration space using this routine is \b not
  * byte-swapped to the host's byte order.  PCI configuration data is always
  * stored in little-endian order, and that is what this routine returns.
  */
 int
 pci_device_cfg_read( struct pci_device * dev, void * data,
-                    pciaddr_t offset, pciaddr_t size, 
+                    pciaddr_t offset, pciaddr_t size,
                     pciaddr_t * bytes_read )
 {
     pciaddr_t  scratch;
@@ -203,7 +487,7 @@ pci_device_cfg_read( struct pci_device * dev, void * data,
     }
 
     return pci_sys->methods->read( dev, data, offset, size,
-                                  (bytes_read == NULL) 
+                                  (bytes_read == NULL)
                                   ? & scratch : bytes_read );
 }
 
@@ -214,9 +498,9 @@ pci_device_cfg_read_u8( struct pci_device * dev, uint8_t * data,
 {
     pciaddr_t bytes;
     int err = pci_device_cfg_read( dev, data, offset, 1, & bytes );
-    
+
     if ( (err == 0) && (bytes != 1) ) {
-       err = ENODATA;
+       err = ENXIO;
     }
 
     return err;
@@ -229,9 +513,9 @@ pci_device_cfg_read_u16( struct pci_device * dev, uint16_t * data,
 {
     pciaddr_t bytes;
     int err = pci_device_cfg_read( dev, data, offset, 2, & bytes );
-    
+
     if ( (err == 0) && (bytes != 2) ) {
-       err = ENODATA;
+       err = ENXIO;
     }
 
     *data = LETOH_16( *data );
@@ -247,7 +531,7 @@ pci_device_cfg_read_u32( struct pci_device * dev, uint32_t * data,
     int err = pci_device_cfg_read( dev, data, offset, 4, & bytes );
 
     if ( (err == 0) && (bytes != 4) ) {
-       err = ENODATA;
+       err = ENXIO;
     }
 
     *data = LETOH_32( *data );
@@ -258,7 +542,7 @@ pci_device_cfg_read_u32( struct pci_device * dev, uint32_t * data,
 /**
  * Write arbitrary bytes to device's PCI config space
  *
- * Writess data to the device's PCI configuration space.  As with the system
+ * Writes data to the device's PCI configuration space.  As with the system
  * write command, less data may be written, without an error, than was
  * requested.
  *
@@ -273,14 +557,14 @@ pci_device_cfg_read_u32( struct pci_device * dev, uint32_t * data,
  * Zero on success or an errno value on failure.
  *
  * \note
- * Data written to PCI configuartion space using this routine is \b not
+ * Data written to PCI configuration space using this routine is \b not
  * byte-swapped from the host's byte order.  PCI configuration data is always
  * stored in little-endian order, so data written with this routine should be
  * put in that order in advance.
  */
 int
 pci_device_cfg_write( struct pci_device * dev, const void * data,
-                     pciaddr_t offset, pciaddr_t size, 
+                     pciaddr_t offset, pciaddr_t size,
                      pciaddr_t * bytes_written )
 {
     pciaddr_t  scratch;
@@ -290,17 +574,17 @@ pci_device_cfg_write( struct pci_device * dev, const void * data,
     }
 
     return pci_sys->methods->write( dev, data, offset, size,
-                                   (bytes_written == NULL) 
+                                   (bytes_written == NULL)
                                    ? & scratch : bytes_written );
 }
 
 
 int
-pci_device_cfg_write_u8( struct pci_device * dev, const uint8_t * data,
-                        pciaddr_t offset )
+pci_device_cfg_write_u8(struct pci_device *dev, uint8_t data,
+                       pciaddr_t offset)
 {
     pciaddr_t bytes;
-    int err = pci_device_cfg_write( dev, data, offset, 1, & bytes );
+    int err = pci_device_cfg_write(dev, & data, offset, 1, & bytes);
 
     if ( (err == 0) && (bytes != 1) ) {
        err = ENOSPC;
@@ -309,14 +593,14 @@ pci_device_cfg_write_u8( struct pci_device * dev, const uint8_t * data,
 
     return err;
 }
-  
+
 
 int
-pci_device_cfg_write_u16( struct pci_device * dev, const uint16_t * data,
-                         pciaddr_t offset )
+pci_device_cfg_write_u16(struct pci_device *dev, uint16_t data,
+                        pciaddr_t offset)
 {
     pciaddr_t bytes;
-    const uint16_t temp = HTOLE_16( *data );
+    const uint16_t temp = HTOLE_16(data);
     int err = pci_device_cfg_write( dev, & temp, offset, 2, & bytes );
 
     if ( (err == 0) && (bytes != 2) ) {
@@ -329,11 +613,11 @@ pci_device_cfg_write_u16( struct pci_device * dev, const uint16_t * data,
 
 
 int
-pci_device_cfg_write_u32( struct pci_device * dev, const uint32_t * data,
-                         pciaddr_t offset )
+pci_device_cfg_write_u32(struct pci_device *dev, uint32_t data,
+                        pciaddr_t offset)
 {
     pciaddr_t bytes;
-    const uint32_t temp = HTOLE_32( *data );
+    const uint32_t temp = HTOLE_32(data);
     int err = pci_device_cfg_write( dev, & temp, offset, 4, & bytes );
 
     if ( (err == 0) && (bytes != 4) ) {
@@ -346,7 +630,7 @@ pci_device_cfg_write_u32( struct pci_device * dev, const uint32_t * data,
 
 
 int
-pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask, 
+pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask,
                           uint32_t data, pciaddr_t offset )
 {
     uint32_t  temp;
@@ -357,8 +641,63 @@ pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask,
        temp &= ~mask;
        temp |= data;
 
-       err = pci_device_cfg_write_u32( dev, & temp, offset );
+       err = pci_device_cfg_write_u32(dev, temp, offset);
     }
 
     return err;
 }
+
+void
+pci_device_enable(struct pci_device *dev)
+{
+    if (dev == NULL) {
+       return;
+    }
+
+    if (pci_sys->methods->enable)
+       pci_sys->methods->enable(dev);
+}
+
+/**
+ * Map the legacy memory space for the PCI domain containing \c dev.
+ *
+ * \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.
+ *
+ * \returns
+ * Zero on success or an \c errno value on failure.
+ */
+int
+pci_device_map_legacy(struct pci_device *dev, pciaddr_t base, pciaddr_t size,
+                     unsigned map_flags, void **addr)
+{
+    if (base > 0x100000 || base + size > 0x100000)
+       return EINVAL;
+
+    if (!pci_sys->methods->map_legacy)
+       return ENOSYS;
+
+    return pci_sys->methods->map_legacy(dev, base, size, map_flags, addr);
+}
+
+/**
+ * Unmap the legacy memory space for the PCI domain containing \c dev.
+ *
+ * \param dev          Device whose memory region is to be unmapped.
+ * \param addr         Location of the mapped address.
+ * \param size         Size of the range to be unmapped.
+ *
+ * \returns
+ * Zero on success or an \c errno value on failure.
+ */
+int
+pci_device_unmap_legacy(struct pci_device *dev, void *addr, pciaddr_t size)
+{
+    if (!pci_sys->methods->unmap_legacy)
+       return ENOSYS;
+
+    return pci_sys->methods->unmap_legacy(dev, addr, size);
+}