diff options
author | Ian Romanick <idr@us.ibm.com> | 2006-03-18 00:12:48 +0000 |
---|---|---|
committer | Ian Romanick <idr@us.ibm.com> | 2006-03-18 00:12:48 +0000 |
commit | 5a04522a921cd8737ef921dfd49b750a8c64dfc9 (patch) | |
tree | 3147bede119f7107fc0cab2e93ce78ef409fb590 /src/common_interface.c |
Initial import of libpciaccess.
Diffstat (limited to 'src/common_interface.c')
-rw-r--r-- | src/common_interface.c | 345 |
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; +} |