X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fcommon_interface.c;h=cb95e90b46e0845a07d81e510faa2cace9994533;hb=6bd2f7f92eae713663f4e13f6e2cb23526607b8c;hp=57908f419e096edb55350583a60e3ec4d33efe1f;hpb=64af050c3803ed61837d9e9109c7a4e239a5c0b8;p=android-x86%2Fexternal-libpciaccess.git diff --git a/src/common_interface.c b/src/common_interface.c index 57908f4..cb95e90 100644 --- a/src/common_interface.c +++ b/src/common_interface.c @@ -28,13 +28,18 @@ * * \author Ian Romanick */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include +#include #include #include "pciaccess.h" #include "pciaccess_private.h" +#if defined(__linux__) || defined(__GLIBC__) || defined(__CYGWIN__) #include #if __BYTE_ORDER == __BIG_ENDIAN @@ -47,18 +52,51 @@ # define HTOLE_16(x) (x) # define LETOH_32(x) (x) # define HTOLE_32(x) (x) +#endif /* linux */ + +#elif defined(__sun) + +#include + +#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 + +#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); +}