summaryrefslogtreecommitdiff
path: root/src/common_interface.c
diff options
context:
space:
mode:
authorIan Romanick <idr@us.ibm.com>2006-03-18 00:12:48 +0000
committerIan Romanick <idr@us.ibm.com>2006-03-18 00:12:48 +0000
commit5a04522a921cd8737ef921dfd49b750a8c64dfc9 (patch)
tree3147bede119f7107fc0cab2e93ce78ef409fb590 /src/common_interface.c
Initial import of libpciaccess.
Diffstat (limited to 'src/common_interface.c')
-rw-r--r--src/common_interface.c345
1 files changed, 345 insertions, 0 deletions
diff --git a/src/common_interface.c b/src/common_interface.c
new file mode 100644
index 0000000..811d9a1
--- /dev/null
+++ b/src/common_interface.c
@@ -0,0 +1,345 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * 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 common_interface.c
+ * Platform independent interface glue.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "pciaccess.h"
+#include "pciaccess_private.h"
+
+#include <byteswap.h>
+
+#if __BYTE_ORDER == __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
+
+/**
+ * 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.
+ */
+int
+pci_device_read_rom( struct pci_device * dev, void * buffer )
+{
+ if ( (dev == NULL) || (buffer == NULL) ) {
+ return EFAULT;
+ }
+
+
+ return (pci_sys->methods->read_rom)( dev, buffer );
+}
+
+
+/**
+ * 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.
+ */
+int
+pci_device_probe( struct pci_device * dev )
+{
+ if ( dev == NULL ) {
+ return EFAULT;
+ }
+
+
+ return (pci_sys->methods->probe)( 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
+ * 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
+ */
+int
+pci_device_map_region( struct pci_device * dev, unsigned region,
+ int write_enable )
+{
+ if ( dev == NULL ) {
+ return EFAULT;
+ }
+
+ if ( (region > 5) || (dev->regions[ region ].size == 0) ) {
+ return ENOENT;
+ }
+
+ if ( dev->regions[ region ].memory != NULL ) {
+ return 0;
+ }
+
+ return (pci_sys->methods->map)( dev, region, write_enable );
+}
+
+
+/**
+ * Unmap the specified BAR so that it can no longer be accessed by the CPU.
+ *
+ * Unmaps the specified BAR that was previously mapped via
+ * \c pci_device_map_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
+ */
+int
+pci_device_unmap_region( struct pci_device * dev, unsigned region )
+{
+ if ( dev == NULL ) {
+ return EFAULT;
+ }
+
+ if ( (region > 5) || (dev->regions[ region ].size == 0) ) {
+ return ENOENT;
+ }
+
+ if ( dev->regions[ region ].memory == NULL ) {
+ return 0;
+ }
+
+ return (pci_sys->methods->unmap)( dev, region );
+}
+
+
+/**
+ * Read arbitrary bytes from device's PCI config space
+ *
+ * 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
+ * beyond the first 64-bytes of configuration space.
+ *
+ * \param dev Device whose PCI configuration data is to be read.
+ * \param data Location to store the data
+ * \param offset Initial byte offset to read
+ * \param size Total number of bytes to read
+ * \param bytes_read Location to store the actual number of bytes read. This
+ * pointer may be \c NULL.
+ *
+ * \returns
+ * Zero on success or an errno value on failure.
+ *
+ * \note
+ * Data read from PCI configuartion 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 * bytes_read )
+{
+ pciaddr_t scratch;
+
+ if ( (dev == NULL) || (data == NULL) ) {
+ return EFAULT;
+ }
+
+ return pci_sys->methods->read( dev, data, offset, size,
+ (bytes_read == NULL)
+ ? & scratch : bytes_read );
+}
+
+
+int
+pci_device_cfg_read_u8( struct pci_device * dev, uint8_t * data,
+ pciaddr_t offset )
+{
+ pciaddr_t bytes;
+ int err = pci_device_cfg_read( dev, data, offset, 1, & bytes );
+
+ if ( (err == 0) && (bytes != 1) ) {
+ err = ENODATA;
+ }
+
+ return err;
+}
+
+
+int
+pci_device_cfg_read_u16( struct pci_device * dev, uint16_t * data,
+ pciaddr_t offset )
+{
+ pciaddr_t bytes;
+ int err = pci_device_cfg_read( dev, data, offset, 2, & bytes );
+
+ if ( (err == 0) && (bytes != 2) ) {
+ err = ENODATA;
+ }
+
+ *data = LETOH_16( *data );
+ return err;
+}
+
+
+int
+pci_device_cfg_read_u32( struct pci_device * dev, uint32_t * data,
+ pciaddr_t offset )
+{
+ pciaddr_t bytes;
+ int err = pci_device_cfg_read( dev, data, offset, 4, & bytes );
+
+ if ( (err == 0) && (bytes != 4) ) {
+ err = ENODATA;
+ }
+
+ *data = LETOH_32( *data );
+ return err;
+}
+
+
+/**
+ * Write arbitrary bytes to device's PCI config space
+ *
+ * Writess 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.
+ *
+ * \param dev Device whose PCI configuration data is to be written.
+ * \param data Location of the source data
+ * \param offset Initial byte offset to write
+ * \param size Total number of bytes to write
+ * \param bytes_read Location to store the actual number of bytes written.
+ * This pointer may be \c NULL.
+ *
+ * \returns
+ * Zero on success or an errno value on failure.
+ *
+ * \note
+ * Data written to PCI configuartion 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 * bytes_written )
+{
+ pciaddr_t scratch;
+
+ if ( (dev == NULL) || (data == NULL) ) {
+ return EFAULT;
+ }
+
+ return pci_sys->methods->write( dev, data, offset, size,
+ (bytes_written == NULL)
+ ? & scratch : bytes_written );
+}
+
+
+int
+pci_device_cfg_write_u8( struct pci_device * dev, const uint8_t * data,
+ pciaddr_t offset )
+{
+ pciaddr_t bytes;
+ int err = pci_device_cfg_write( dev, data, offset, 1, & bytes );
+
+ if ( (err == 0) && (bytes != 1) ) {
+ err = ENOSPC;
+ }
+
+
+ return err;
+}
+
+
+int
+pci_device_cfg_write_u16( struct pci_device * dev, const uint16_t * data,
+ pciaddr_t offset )
+{
+ pciaddr_t bytes;
+ const uint16_t temp = HTOLE_16( *data );
+ int err = pci_device_cfg_write( dev, & temp, offset, 2, & bytes );
+
+ if ( (err == 0) && (bytes != 2) ) {
+ err = ENOSPC;
+ }
+
+
+ return err;
+}
+
+
+int
+pci_device_cfg_write_u32( struct pci_device * dev, const uint32_t * data,
+ pciaddr_t offset )
+{
+ pciaddr_t bytes;
+ const uint32_t temp = HTOLE_32( *data );
+ int err = pci_device_cfg_write( dev, & temp, offset, 4, & bytes );
+
+ if ( (err == 0) && (bytes != 4) ) {
+ err = ENOSPC;
+ }
+
+
+ return err;
+}