| File: | common_interface.c |
| Location: | line 444, column 26 |
| Description: | Call to 'realloc' has an allocation size of 0 bytes |
| 1 | /* | ||
| 2 | * (C) Copyright IBM Corporation 2006 | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 6 | * copy of this software and associated documentation files (the "Software"), | ||
| 7 | * to deal in the Software without restriction, including without limitation | ||
| 8 | * on the rights to use, copy, modify, merge, publish, distribute, sub | ||
| 9 | * license, and/or sell copies of the Software, and to permit persons to whom | ||
| 10 | * the Software is furnished to do so, subject to the following conditions: | ||
| 11 | * | ||
| 12 | * The above copyright notice and this permission notice (including the next | ||
| 13 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 14 | * Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
| 19 | * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 22 | * DEALINGS IN THE SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | /** | ||
| 26 | * \file common_interface.c | ||
| 27 | * Platform independent interface glue. | ||
| 28 | * | ||
| 29 | * \author Ian Romanick <idr@us.ibm.com> | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <stdlib.h> | ||
| 33 | #include <string.h> | ||
| 34 | #include <errno(*__errno_location ()).h> | ||
| 35 | |||
| 36 | #include "pciaccess.h" | ||
| 37 | #include "pciaccess_private.h" | ||
| 38 | |||
| 39 | #if defined(__linux__1) || defined(__GLIBC__2) | ||
| 40 | #include <byteswap.h> | ||
| 41 | |||
| 42 | #if __BYTE_ORDER4321 == __BIG_ENDIAN4321 | ||
| 43 | # define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) bswap_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) | ||
| 44 | # define HTOLE_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) bswap_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) | ||
| 45 | # define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) bswap_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) | ||
| 46 | # define HTOLE_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) bswap_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) | ||
| 47 | #else | ||
| 48 | # define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) (x) | ||
| 49 | # define HTOLE_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) (x) | ||
| 50 | # define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) (x) | ||
| 51 | # define HTOLE_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) (x) | ||
| 52 | #endif /* linux */ | ||
| 53 | |||
| 54 | #elif defined(__sun) | ||
| 55 | |||
| 56 | #include <sys/byteorder.h> | ||
| 57 | |||
| 58 | #ifdef _BIG_ENDIAN1 | ||
| 59 | # define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) BSWAP_16(x) | ||
| 60 | # define HTOLE_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) BSWAP_16(x) | ||
| 61 | # define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) BSWAP_32(x) | ||
| 62 | # define HTOLE_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) BSWAP_32(x) | ||
| 63 | #else | ||
| 64 | # define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) (x) | ||
| 65 | # define HTOLE_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) (x) | ||
| 66 | # define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) (x) | ||
| 67 | # define HTOLE_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) (x) | ||
| 68 | #endif /* Solaris */ | ||
| 69 | |||
| 70 | #else | ||
| 71 | |||
| 72 | #include <sys/endian.h> | ||
| 73 | |||
| 74 | #define HTOLE_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) htole16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) | ||
| 75 | #define HTOLE_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) htole32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) | ||
| 76 | |||
| 77 | #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) | ||
| 78 | #define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) le16toh(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) | ||
| 79 | #define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) le32toh(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) | ||
| 80 | #else | ||
| 81 | #define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) letoh16(x) | ||
| 82 | #define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) letoh32(x) | ||
| 83 | #endif | ||
| 84 | |||
| 85 | #endif /* others */ | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Read a device's expansion ROM. | ||
| 89 | * | ||
| 90 | * Reads the device's expansion ROM and stores the data in the memory pointed | ||
| 91 | * to by \c buffer. The buffer must be at least \c pci_device::rom_size | ||
| 92 | * bytes. | ||
| 93 | * | ||
| 94 | * \param dev Device whose expansion ROM is to be read. | ||
| 95 | * \param buffer Memory in which to store the ROM. | ||
| 96 | * | ||
| 97 | * \return | ||
| 98 | * Zero on success or an \c errno value on failure. | ||
| 99 | */ | ||
| 100 | int | ||
| 101 | pci_device_read_rom( struct pci_device * dev, void * buffer ) | ||
| 102 | { | ||
| 103 | if ( (dev == NULL((void*)0)) || (buffer == NULL((void*)0)) ) { | ||
| 104 | return EFAULT14; | ||
| 105 | } | ||
| 106 | |||
| 107 | |||
| 108 | return (pci_sys->methods->read_rom)( dev, buffer ); | ||
| 109 | } | ||
| 110 | |||
| 111 | /** | ||
| 112 | * Probe a PCI (VGA) device to determine if its the boot VGA device | ||
| 113 | * | ||
| 114 | * \param dev Device whose VGA status to query | ||
| 115 | * \return | ||
| 116 | * Zero if not the boot VGA, 1 if the boot VGA. | ||
| 117 | */ | ||
| 118 | int | ||
| 119 | pci_device_is_boot_vga( struct pci_device * dev ) | ||
| 120 | { | ||
| 121 | if (!pci_sys->methods->boot_vga) | ||
| 122 | return 0; | ||
| 123 | return pci_sys->methods->boot_vga( dev ); | ||
| 124 | } | ||
| 125 | |||
| 126 | /** | ||
| 127 | * Probe a PCI device to determine if a kernel driver is attached. | ||
| 128 | * | ||
| 129 | * \param dev Device to query | ||
| 130 | * \return | ||
| 131 | * Zero if no driver attached, 1 if attached kernel drviver | ||
| 132 | */ | ||
| 133 | int | ||
| 134 | pci_device_has_kernel_driver( struct pci_device * dev ) | ||
| 135 | { | ||
| 136 | if (!pci_sys->methods->has_kernel_driver) | ||
| 137 | return 0; | ||
| 138 | return pci_sys->methods->has_kernel_driver( dev ); | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * Probe a PCI device to learn information about the device. | ||
| 143 | * | ||
| 144 | * Probes a PCI device to learn various information about the device. Before | ||
| 145 | * calling this function, the only public fields in the \c pci_device | ||
| 146 | * structure that have valid values are \c pci_device::domain, | ||
| 147 | * \c pci_device::bus, \c pci_device::dev, and \c pci_device::func. | ||
| 148 | * | ||
| 149 | * \param dev Device to be probed. | ||
| 150 | * | ||
| 151 | * \return | ||
| 152 | * Zero on success or an \c errno value on failure. | ||
| 153 | */ | ||
| 154 | int | ||
| 155 | pci_device_probe( struct pci_device * dev ) | ||
| 156 | { | ||
| 157 | if ( dev == NULL((void*)0) ) { | ||
| 158 | return EFAULT14; | ||
| 159 | } | ||
| 160 | |||
| 161 | |||
| 162 | return (pci_sys->methods->probe)( dev ); | ||
| 163 | } | ||
| 164 | |||
| 165 | |||
| 166 | /** | ||
| 167 | * Map the specified BAR so that it can be accessed by the CPU. | ||
| 168 | * | ||
| 169 | * Maps the specified BAR for access by the processor. The pointer to the | ||
| 170 | * mapped region is stored in the \c pci_mem_region::memory pointer for the | ||
| 171 | * BAR. | ||
| 172 | * | ||
| 173 | * \param dev Device whose memory region is to be mapped. | ||
| 174 | * \param region Region, on the range [0, 5], that is to be mapped. | ||
| 175 | * \param write_enable Map for writing (non-zero). | ||
| 176 | * | ||
| 177 | * \return | ||
| 178 | * Zero on success or an \c errno value on failure. | ||
| 179 | * | ||
| 180 | * \sa pci_device_map_range, pci_device_unmap_range | ||
| 181 | * \deprecated | ||
| 182 | */ | ||
| 183 | int | ||
| 184 | pci_device_map_region(struct pci_device * dev, unsigned region, | ||
| 185 | int write_enable) | ||
| 186 | { | ||
| 187 | const unsigned map_flags = | ||
| 188 | (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE(1U<<0) : 0; | ||
| 189 | |||
| 190 | if ((region > 5) || (dev->regions[region].size == 0)) { | ||
| 191 | return ENOENT2; | ||
| 192 | } | ||
| 193 | |||
| 194 | if (dev->regions[region].memory != NULL((void*)0)) { | ||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | return pci_device_map_range(dev, dev->regions[region].base_addr, | ||
| 199 | dev->regions[region].size, map_flags, | ||
| 200 | &dev->regions[region].memory); | ||
| 201 | } | ||
| 202 | |||
| 203 | |||
| 204 | /** | ||
| 205 | * Map the specified memory range so that it can be accessed by the CPU. | ||
| 206 | * | ||
| 207 | * Maps the specified memory range for access by the processor. The pointer | ||
| 208 | * to the mapped region is stored in \c addr. In addition, the | ||
| 209 | * \c pci_mem_region::memory pointer for the BAR will be updated. | ||
| 210 | * | ||
| 211 | * \param dev Device whose memory region is to be mapped. | ||
| 212 | * \param base Base address of the range to be mapped. | ||
| 213 | * \param size Size of the range to be mapped. | ||
| 214 | * \param write_enable Map for writing (non-zero). | ||
| 215 | * \param addr Location to store the mapped address. | ||
| 216 | * | ||
| 217 | * \return | ||
| 218 | * Zero on success or an \c errno value on failure. | ||
| 219 | * | ||
| 220 | * \sa pci_device_map_range | ||
| 221 | */ | ||
| 222 | int pci_device_map_memory_range(struct pci_device *dev, | ||
| 223 | pciaddr_t base, pciaddr_t size, | ||
| 224 | int write_enable, void **addr) | ||
| 225 | { | ||
| 226 | return pci_device_map_range(dev, base, size, | ||
| 227 | (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE(1U<<0) : 0, | ||
| 228 | addr); | ||
| 229 | } | ||
| 230 | |||
| 231 | |||
| 232 | /** | ||
| 233 | * Map the specified memory range so that it can be accessed by the CPU. | ||
| 234 | * | ||
| 235 | * Maps the specified memory range for access by the processor. The pointer | ||
| 236 | * to the mapped region is stored in \c addr. In addition, the | ||
| 237 | * \c pci_mem_region::memory pointer for the BAR will be updated. | ||
| 238 | * | ||
| 239 | * \param dev Device whose memory region is to be mapped. | ||
| 240 | * \param base Base address of the range to be mapped. | ||
| 241 | * \param size Size of the range to be mapped. | ||
| 242 | * \param map_flags Flag bits controlling how the mapping is accessed. | ||
| 243 | * \param addr Location to store the mapped address. | ||
| 244 | * | ||
| 245 | * \return | ||
| 246 | * Zero on success or an \c errno value on failure. | ||
| 247 | * | ||
| 248 | * \sa pci_device_unmap_range | ||
| 249 | */ | ||
| 250 | int | ||
| 251 | pci_device_map_range(struct pci_device *dev, pciaddr_t base, | ||
| 252 | pciaddr_t size, unsigned map_flags, | ||
| 253 | void **addr) | ||
| 254 | { | ||
| 255 | struct pci_device_private *const devp = | ||
| 256 | (struct pci_device_private *) dev; | ||
| 257 | struct pci_device_mapping *mappings; | ||
| 258 | unsigned region; | ||
| 259 | unsigned i; | ||
| 260 | int err = 0; | ||
| 261 | |||
| 262 | |||
| 263 | *addr = NULL((void*)0); | ||
| 264 | |||
| 265 | if (dev == NULL((void*)0)) { | ||
| 266 | return EFAULT14; | ||
| 267 | } | ||
| 268 | |||
| 269 | |||
| 270 | for (region = 0; region < 6; region++) { | ||
| 271 | const struct pci_mem_region const* r = &dev->regions[region]; | ||
| 272 | |||
| 273 | if (r->size != 0) { | ||
| 274 | if ((r->base_addr <= base) && ((r->base_addr + r->size) > base)) { | ||
| 275 | if ((base + size) > (r->base_addr + r->size)) { | ||
| 276 | return E2BIG7; | ||
| 277 | } | ||
| 278 | |||
| 279 | break; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | if (region > 5) { | ||
| 285 | return ENOENT2; | ||
| 286 | } | ||
| 287 | |||
| 288 | /* Make sure that there isn't already a mapping with the same base and | ||
| 289 | * size. | ||
| 290 | */ | ||
| 291 | for (i = 0; i < devp->num_mappings; i++) { | ||
| 292 | if ((devp->mappings[i].base == base) | ||
| 293 | && (devp->mappings[i].size == size)) { | ||
| 294 | return EINVAL22; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | |||
| 299 | mappings = realloc(devp->mappings, | ||
| 300 | (sizeof(devp->mappings[0]) * (devp->num_mappings + 1))); | ||
| 301 | if (mappings == NULL((void*)0)) { | ||
| 302 | return ENOMEM12; | ||
| 303 | } | ||
| 304 | |||
| 305 | mappings[devp->num_mappings].base = base; | ||
| 306 | mappings[devp->num_mappings].size = size; | ||
| 307 | mappings[devp->num_mappings].region = region; | ||
| 308 | mappings[devp->num_mappings].flags = map_flags; | ||
| 309 | mappings[devp->num_mappings].memory = NULL((void*)0); | ||
| 310 | |||
| 311 | if (dev->regions[region].memory == NULL((void*)0)) { | ||
| 312 | err = (*pci_sys->methods->map_range)(dev, | ||
| 313 | &mappings[devp->num_mappings]); | ||
| 314 | } | ||
| 315 | |||
| 316 | if (err == 0) { | ||
| 317 | *addr = mappings[devp->num_mappings].memory; | ||
| 318 | devp->num_mappings++; | ||
| 319 | } else { | ||
| 320 | mappings = realloc(mappings, | ||
| 321 | (sizeof(mappings[0]) * devp->num_mappings)); | ||
| 322 | } | ||
| 323 | |||
| 324 | devp->mappings = mappings; | ||
| 325 | |||
| 326 | return err; | ||
| 327 | } | ||
| 328 | |||
| 329 | |||
| 330 | /** | ||
| 331 | * Unmap the specified BAR so that it can no longer be accessed by the CPU. | ||
| 332 | * | ||
| 333 | * Unmaps the specified BAR that was previously mapped via | ||
| 334 | * \c pci_device_map_region. | ||
| 335 | * | ||
| 336 | * \param dev Device whose memory region is to be mapped. | ||
| 337 | * \param region Region, on the range [0, 5], that is to be mapped. | ||
| 338 | * | ||
| 339 | * \return | ||
| 340 | * Zero on success or an \c errno value on failure. | ||
| 341 | * | ||
| 342 | * \sa pci_device_map_range, pci_device_unmap_range | ||
| 343 | * \deprecated | ||
| 344 | */ | ||
| 345 | int | ||
| 346 | pci_device_unmap_region( struct pci_device * dev, unsigned region ) | ||
| 347 | { | ||
| 348 | int err; | ||
| 349 | |||
| 350 | if (dev == NULL((void*)0)) { | ||
| 351 | return EFAULT14; | ||
| 352 | } | ||
| 353 | |||
| 354 | if ((region > 5) || (dev->regions[region].size == 0)) { | ||
| 355 | return ENOENT2; | ||
| 356 | } | ||
| 357 | |||
| 358 | err = pci_device_unmap_range(dev, dev->regions[region].memory, | ||
| 359 | dev->regions[region].size); | ||
| 360 | if (!err) { | ||
| 361 | dev->regions[region].memory = NULL((void*)0); | ||
| 362 | } | ||
| 363 | |||
| 364 | return err; | ||
| 365 | } | ||
| 366 | |||
| 367 | |||
| 368 | /** | ||
| 369 | * Unmap the specified memory range so that it can no longer be accessed by the CPU. | ||
| 370 | * | ||
| 371 | * Unmaps the specified memory range that was previously mapped via | ||
| 372 | * \c pci_device_map_memory_range. | ||
| 373 | * | ||
| 374 | * \param dev Device whose memory is to be unmapped. | ||
| 375 | * \param memory Pointer to the base of the mapped range. | ||
| 376 | * \param size Size, in bytes, of the range to be unmapped. | ||
| 377 | * | ||
| 378 | * \return | ||
| 379 | * Zero on success or an \c errno value on failure. | ||
| 380 | * | ||
| 381 | * \sa pci_device_map_range, pci_device_unmap_range | ||
| 382 | * \deprecated | ||
| 383 | */ | ||
| 384 | int | ||
| 385 | pci_device_unmap_memory_range(struct pci_device *dev, void *memory, | ||
| 386 | pciaddr_t size) | ||
| 387 | { | ||
| 388 | return pci_device_unmap_range(dev, memory, size); | ||
| 389 | } | ||
| 390 | |||
| 391 | |||
| 392 | /** | ||
| 393 | * Unmap the specified memory range so that it can no longer be accessed by the CPU. | ||
| 394 | * | ||
| 395 | * Unmaps the specified memory range that was previously mapped via | ||
| 396 | * \c pci_device_map_memory_range. | ||
| 397 | * | ||
| 398 | * \param dev Device whose memory is to be unmapped. | ||
| 399 | * \param memory Pointer to the base of the mapped range. | ||
| 400 | * \param size Size, in bytes, of the range to be unmapped. | ||
| 401 | * | ||
| 402 | * \return | ||
| 403 | * Zero on success or an \c errno value on failure. | ||
| 404 | * | ||
| 405 | * \sa pci_device_map_range | ||
| 406 | */ | ||
| 407 | int | ||
| 408 | pci_device_unmap_range(struct pci_device *dev, void *memory, | ||
| 409 | pciaddr_t size) | ||
| 410 | { | ||
| 411 | struct pci_device_private *const devp = | ||
| 412 | (struct pci_device_private *) dev; | ||
| 413 | unsigned i; | ||
| 414 | int err; | ||
| 415 | |||
| 416 | |||
| 417 | if (dev == NULL((void*)0)) { | ||
| |||
| |||
| 418 | return EFAULT14; | ||
| 419 | } | ||
| 420 | |||
| 421 | for (i = 0; i < devp->num_mappings; i++) { | ||
| |||
| 422 | if ((devp->mappings[i].memory == memory) | ||
| |||
| 423 | && (devp->mappings[i].size == size)) { | ||
| 424 | break; | ||
| |||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | if (i == devp->num_mappings) { | ||
| |||
| 429 | return ENOENT2; | ||
| 430 | } | ||
| 431 | |||
| 432 | |||
| 433 | err = (*pci_sys->methods->unmap_range)(dev, &devp->mappings[i]); | ||
| 434 | if (!err) { | ||
| |||
| |||
| 435 | const unsigned entries_to_move = (devp->num_mappings - i) - 1; | ||
| 436 | |||
| 437 | if (entries_to_move > 0) { | ||
| |||
| |||
| 438 | (void) memmove(&devp->mappings[i], | ||
| 439 | &devp->mappings[i + 1], | ||
| 440 | entries_to_move * sizeof(devp->mappings[0])); | ||
| 441 | } | ||
| 442 | |||
| 443 | devp->num_mappings--; | ||
| 444 | devp->mappings = realloc(devp->mappings, | ||
| |||
| 445 | (sizeof(devp->mappings[0]) * devp->num_mappings)); | ||
| 446 | } | ||
| 447 | |||
| 448 | return err; | ||
| 449 | } | ||
| 450 | |||
| 451 | |||
| 452 | /** | ||
| 453 | * Read arbitrary bytes from device's PCI config space | ||
| 454 | * | ||
| 455 | * Reads data from the device's PCI configuration space. As with the system | ||
| 456 | * read command, less data may be returned, without an error, than was | ||
| 457 | * requested. This is particularly the case if a non-root user tries to read | ||
| 458 | * beyond the first 64-bytes of configuration space. | ||
| 459 | * | ||
| 460 | * \param dev Device whose PCI configuration data is to be read. | ||
| 461 | * \param data Location to store the data | ||
| 462 | * \param offset Initial byte offset to read | ||
| 463 | * \param size Total number of bytes to read | ||
| 464 | * \param bytes_read Location to store the actual number of bytes read. This | ||
| 465 | * pointer may be \c NULL. | ||
| 466 | * | ||
| 467 | * \returns | ||
| 468 | * Zero on success or an errno value on failure. | ||
| 469 | * | ||
| 470 | * \note | ||
| 471 | * Data read from PCI configuration space using this routine is \b not | ||
| 472 | * byte-swapped to the host's byte order. PCI configuration data is always | ||
| 473 | * stored in little-endian order, and that is what this routine returns. | ||
| 474 | */ | ||
| 475 | int | ||
| 476 | pci_device_cfg_read( struct pci_device * dev, void * data, | ||
| 477 | pciaddr_t offset, pciaddr_t size, | ||
| 478 | pciaddr_t * bytes_read ) | ||
| 479 | { | ||
| 480 | pciaddr_t scratch; | ||
| 481 | |||
| 482 | if ( (dev == NULL((void*)0)) || (data == NULL((void*)0)) ) { | ||
| 483 | return EFAULT14; | ||
| 484 | } | ||
| 485 | |||
| 486 | return pci_sys->methods->read( dev, data, offset, size, | ||
| 487 | (bytes_read == NULL((void*)0)) | ||
| 488 | ? & scratch : bytes_read ); | ||
| 489 | } | ||
| 490 | |||
| 491 | |||
| 492 | int | ||
| 493 | pci_device_cfg_read_u8( struct pci_device * dev, uint8_t * data, | ||
| 494 | pciaddr_t offset ) | ||
| 495 | { | ||
| 496 | pciaddr_t bytes; | ||
| 497 | int err = pci_device_cfg_read( dev, data, offset, 1, & bytes ); | ||
| 498 | |||
| 499 | if ( (err == 0) && (bytes != 1) ) { | ||
| 500 | err = ENXIO6; | ||
| 501 | } | ||
| 502 | |||
| 503 | return err; | ||
| 504 | } | ||
| 505 | |||
| 506 | |||
| 507 | int | ||
| 508 | pci_device_cfg_read_u16( struct pci_device * dev, uint16_t * data, | ||
| 509 | pciaddr_t offset ) | ||
| 510 | { | ||
| 511 | pciaddr_t bytes; | ||
| 512 | int err = pci_device_cfg_read( dev, data, offset, 2, & bytes ); | ||
| 513 | |||
| 514 | if ( (err == 0) && (bytes != 2) ) { | ||
| 515 | err = ENXIO6; | ||
| 516 | } | ||
| 517 | |||
| 518 | *data = LETOH_16( *data )(__extension__ ({ unsigned short int __bsx = (*data); ((((__bsx ) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8 )); })); | ||
| 519 | return err; | ||
| 520 | } | ||
| 521 | |||
| 522 | |||
| 523 | int | ||
| 524 | pci_device_cfg_read_u32( struct pci_device * dev, uint32_t * data, | ||
| 525 | pciaddr_t offset ) | ||
| 526 | { | ||
| 527 | pciaddr_t bytes; | ||
| 528 | int err = pci_device_cfg_read( dev, data, offset, 4, & bytes ); | ||
| 529 | |||
| 530 | if ( (err == 0) && (bytes != 4) ) { | ||
| 531 | err = ENXIO6; | ||
| 532 | } | ||
| 533 | |||
| 534 | *data = LETOH_32( *data )(__extension__ ({ register unsigned int __bsx = (*data); (((( __bsx) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })); | ||
| 535 | return err; | ||
| 536 | } | ||
| 537 | |||
| 538 | |||
| 539 | /** | ||
| 540 | * Write arbitrary bytes to device's PCI config space | ||
| 541 | * | ||
| 542 | * Writes data to the device's PCI configuration space. As with the system | ||
| 543 | * write command, less data may be written, without an error, than was | ||
| 544 | * requested. | ||
| 545 | * | ||
| 546 | * \param dev Device whose PCI configuration data is to be written. | ||
| 547 | * \param data Location of the source data | ||
| 548 | * \param offset Initial byte offset to write | ||
| 549 | * \param size Total number of bytes to write | ||
| 550 | * \param bytes_read Location to store the actual number of bytes written. | ||
| 551 | * This pointer may be \c NULL. | ||
| 552 | * | ||
| 553 | * \returns | ||
| 554 | * Zero on success or an errno value on failure. | ||
| 555 | * | ||
| 556 | * \note | ||
| 557 | * Data written to PCI configuration space using this routine is \b not | ||
| 558 | * byte-swapped from the host's byte order. PCI configuration data is always | ||
| 559 | * stored in little-endian order, so data written with this routine should be | ||
| 560 | * put in that order in advance. | ||
| 561 | */ | ||
| 562 | int | ||
| 563 | pci_device_cfg_write( struct pci_device * dev, const void * data, | ||
| 564 | pciaddr_t offset, pciaddr_t size, | ||
| 565 | pciaddr_t * bytes_written ) | ||
| 566 | { | ||
| 567 | pciaddr_t scratch; | ||
| 568 | |||
| 569 | if ( (dev == NULL((void*)0)) || (data == NULL((void*)0)) ) { | ||
| 570 | return EFAULT14; | ||
| 571 | } | ||
| 572 | |||
| 573 | return pci_sys->methods->write( dev, data, offset, size, | ||
| 574 | (bytes_written == NULL((void*)0)) | ||
| 575 | ? & scratch : bytes_written ); | ||
| 576 | } | ||
| 577 | |||
| 578 | |||
| 579 | int | ||
| 580 | pci_device_cfg_write_u8(struct pci_device *dev, uint8_t data, | ||
| 581 | pciaddr_t offset) | ||
| 582 | { | ||
| 583 | pciaddr_t bytes; | ||
| 584 | int err = pci_device_cfg_write(dev, & data, offset, 1, & bytes); | ||
| 585 | |||
| 586 | if ( (err == 0) && (bytes != 1) ) { | ||
| 587 | err = ENOSPC28; | ||
| 588 | } | ||
| 589 | |||
| 590 | |||
| 591 | return err; | ||
| 592 | } | ||
| 593 | |||
| 594 | |||
| 595 | int | ||
| 596 | pci_device_cfg_write_u16(struct pci_device *dev, uint16_t data, | ||
| 597 | pciaddr_t offset) | ||
| 598 | { | ||
| 599 | pciaddr_t bytes; | ||
| 600 | const uint16_t temp = HTOLE_16(data)(__extension__ ({ unsigned short int __bsx = (data); ((((__bsx ) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8 )); })); | ||
| 601 | int err = pci_device_cfg_write( dev, & temp, offset, 2, & bytes ); | ||
| 602 | |||
| 603 | if ( (err == 0) && (bytes != 2) ) { | ||
| 604 | err = ENOSPC28; | ||
| 605 | } | ||
| 606 | |||
| 607 | |||
| 608 | return err; | ||
| 609 | } | ||
| 610 | |||
| 611 | |||
| 612 | int | ||
| 613 | pci_device_cfg_write_u32(struct pci_device *dev, uint32_t data, | ||
| 614 | pciaddr_t offset) | ||
| 615 | { | ||
| 616 | pciaddr_t bytes; | ||
| 617 | const uint32_t temp = HTOLE_32(data)(__extension__ ({ register unsigned int __bsx = (data); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })); | ||
| 618 | int err = pci_device_cfg_write( dev, & temp, offset, 4, & bytes ); | ||
| 619 | |||
| 620 | if ( (err == 0) && (bytes != 4) ) { | ||
| 621 | err = ENOSPC28; | ||
| 622 | } | ||
| 623 | |||
| 624 | |||
| 625 | return err; | ||
| 626 | } | ||
| 627 | |||
| 628 | |||
| 629 | int | ||
| 630 | pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask, | ||
| 631 | uint32_t data, pciaddr_t offset ) | ||
| 632 | { | ||
| 633 | uint32_t temp; | ||
| 634 | int err; | ||
| 635 | |||
| 636 | err = pci_device_cfg_read_u32( dev, & temp, offset ); | ||
| 637 | if ( ! err ) { | ||
| 638 | temp &= ~mask; | ||
| 639 | temp |= data; | ||
| 640 | |||
| 641 | err = pci_device_cfg_write_u32(dev, temp, offset); | ||
| 642 | } | ||
| 643 | |||
| 644 | return err; | ||
| 645 | } | ||
| 646 | |||
| 647 | void | ||
| 648 | pci_device_enable(struct pci_device *dev) | ||
| 649 | { | ||
| 650 | if (dev == NULL((void*)0)) { | ||
| 651 | return; | ||
| 652 | } | ||
| 653 | |||
| 654 | if (pci_sys->methods->enable) | ||
| 655 | pci_sys->methods->enable(dev); | ||
| 656 | } | ||
| 657 | |||
| 658 | /** | ||
| 659 | * Map the legacy memory space for the PCI domain containing \c dev. | ||
| 660 | * | ||
| 661 | * \param dev Device whose memory region is to be mapped. | ||
| 662 | * \param base Base address of the range to be mapped. | ||
| 663 | * \param size Size of the range to be mapped. | ||
| 664 | * \param map_flags Flag bits controlling how the mapping is accessed. | ||
| 665 | * \param addr Location to store the mapped address. | ||
| 666 | * | ||
| 667 | * \returns | ||
| 668 | * Zero on success or an \c errno value on failure. | ||
| 669 | */ | ||
| 670 | int | ||
| 671 | pci_device_map_legacy(struct pci_device *dev, pciaddr_t base, pciaddr_t size, | ||
| 672 | unsigned map_flags, void **addr) | ||
| 673 | { | ||
| 674 | if (base > 0x100000 || base + size > 0x100000) | ||
| 675 | return EINVAL22; | ||
| 676 | |||
| 677 | if (!pci_sys->methods->map_legacy) | ||
| 678 | return ENOSYS38; | ||
| 679 | |||
| 680 | return pci_sys->methods->map_legacy(dev, base, size, map_flags, addr); | ||
| 681 | } | ||
| 682 | |||
| 683 | /** | ||
| 684 | * Unmap the legacy memory space for the PCI domain containing \c dev. | ||
| 685 | * | ||
| 686 | * \param dev Device whose memory region is to be unmapped. | ||
| 687 | * \param addr Location of the mapped address. | ||
| 688 | * \param size Size of the range to be unmapped. | ||
| 689 | * | ||
| 690 | * \returns | ||
| 691 | * Zero on success or an \c errno value on failure. | ||
| 692 | */ | ||
| 693 | int | ||
| 694 | pci_device_unmap_legacy(struct pci_device *dev, void *addr, pciaddr_t size) | ||
| 695 | { | ||
| 696 | if (!pci_sys->methods->unmap_legacy) | ||
| 697 | return ENOSYS38; | ||
| 698 | |||
| 699 | return pci_sys->methods->unmap_legacy(dev, addr, size); | ||
| 700 | } |