1 /* 2 * Copyright 2009 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software") 6 * to deal in the software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * them Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER 19 * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Author: 23 * Adam Jackson <[email protected]> 24 */ 25 26 #include <stdlib.h> 27 #include <string.h> 28 #include "pciaccess.h" 29 #include "pciaccess_private.h" 30 31 static struct pci_io_handle **ios; 32 static unsigned int num_ios; 33 34 static struct pci_io_handle * 35 new_io_handle(void) 36 { 37 struct pci_io_handle **new; 38 39 new = realloc(ios, sizeof(struct pci_io_handle) * (num_ios + 1)); 40 if (!new) 41 return NULL; 42 43 ios = new; 44 num_ios++; 45 46 return ios[num_ios - 1]; 47 } 48 49 static void 50 delete_io_handle(struct pci_io_handle *handle) 51 { 52 struct pci_io_handle **new; 53 int i = 0; 54 55 if (!handle || !num_ios || (void *)handle < (void *)ios || 56 (void *)handle > (void *)(ios + num_ios - 1)) 57 return; 58 59 for (i = 0; i < num_ios; i++) { 60 if (ios[i] == handle) { 61 memmove(&ios[i], &ios[i+1], sizeof(struct pci_io_handle) * 62 (num_ios - i - 1)); 63 break; 64 } 65 } 66 67 new = realloc(ios, sizeof(struct pci_io_handle) * (num_ios - 1)); 68 if (new) 69 ios = new; 70 num_ios--; 71 } 72 73 _pci_hidden void 74 pci_io_cleanup(void) 75 { 76 free(ios); 77 ios = NULL; 78 num_ios = 0; 79 } 80 81 /** 82 * Open a handle to a PCI device I/O range. The \c base and \c size 83 * requested must fit entirely within a single I/O BAR on the device. 84 * \c size is in bytes. 85 * 86 * \returns 87 * An opaque handle to the I/O BAR, or \c NULL on error. 88 */ 89 struct pci_io_handle * 90 pci_device_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size) 91 { 92 struct pci_io_handle *ret; 93 int bar; 94 95 if (!pci_sys->methods->open_device_io) 96 return NULL; 97 98 for (bar = 0; bar < 6; bar++) { 99 struct pci_mem_region *region = &(dev->regions[bar]); 100 if (!region->is_IO) 101 continue; 102 103 if (base < region->base_addr || base > (region->base_addr+region->size)) 104 continue; 105 106 if ((base + size) > (region->base_addr + region->size)) 107 continue; 108 109 ret = new_io_handle(); 110 if (!ret) 111 return NULL; 112 113 if (!pci_sys->methods->open_device_io(ret, dev, bar, base, size)) { 114 delete_io_handle(ret); 115 return NULL; 116 } 117 118 return ret; 119 } 120 121 return NULL; 122 } 123 124 /** 125 * Open a handle to the legacy I/O space for the PCI domain containing 126 * \c dev. \c size is in bytes. 127 * 128 * \returns 129 * An opaque handle to the requested range, or \c NULL on error. 130 */ 131 struct pci_io_handle * 132 pci_legacy_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size) 133 { 134 struct pci_io_handle *ret; 135 136 if (!pci_sys->methods->open_legacy_io) 137 return NULL; 138 139 ret = new_io_handle(); 140 if (!ret) 141 return NULL; 142 143 if (!pci_sys->methods->open_legacy_io(ret, dev, base, size)) { 144 delete_io_handle(ret); 145 return NULL; 146 } 147 148 return ret; 149 } 150 151 /** 152 * Close an I/O handle. 153 */ 154 void 155 pci_device_close_io(struct pci_device *dev, struct pci_io_handle *handle) 156 { 157 if (dev && handle && pci_sys->methods->close_io) 158 pci_sys->methods->close_io(dev, handle); 159 160 delete_io_handle(handle); 161 } 162 163 /** 164 * Read a 32-bit value from the I/O space. \c reg is relative to the 165 * \c base specified when the handle was opened. Some platforms may 166 * require that \c reg be 32-bit-aligned. 167 * 168 * \returns 169 * The value read from the I/O port, or undefined on any error. 170 */ 171 uint32_t 172 pci_io_read32(struct pci_io_handle *handle, uint32_t reg) 173 { 174 if (reg + 4 > handle->size) 175 return UINT32_MAX; 176 177 return pci_sys->methods->read32(handle, reg); 178 } 179 180 /** 181 * Read a 16-bit value from the I/O space. \c reg is relative to the 182 * \c base specified when the handle was opened. Some platforms may 183 * require that \c reg be 16-bit-aligned. 184 * 185 * \returns 186 * The value read from the I/O port, or undefined on any error. 187 */ 188 uint16_t 189 pci_io_read16(struct pci_io_handle *handle, uint32_t reg) 190 { 191 if (reg + 2 > handle->size) 192 return UINT16_MAX; 193 194 return pci_sys->methods->read16(handle, reg); 195 } 196 197 /** 198 * Read a 8-bit value from the I/O space. \c reg is relative to the 199 * \c base specified when the handle was opened. 200 * 201 * \returns 202 * The value read from the I/O port, or undefined on any error. 203 */ 204 uint8_t 205 pci_io_read8(struct pci_io_handle *handle, uint32_t reg) 206 { 207 if (reg + 1 > handle->size) 208 return UINT8_MAX; 209 210 return pci_sys->methods->read8(handle, reg); 211 } 212 213 /** 214 * Write a 32-bit value to the I/O space. \c reg is relative to the 215 * \c base specified when the handle was opened. Some platforms may 216 * require that \c reg be 32-bit-aligned. 217 */ 218 void 219 pci_io_write32(struct pci_io_handle *handle, uint32_t reg, uint32_t data) 220 { 221 if (reg + 4 > handle->size) 222 return; 223 224 pci_sys->methods->write32(handle, reg, data); 225 } 226 227 /** 228 * Write a 16-bit value to the I/O space. \c reg is relative to the 229 * \c base specified when the handle was opened. Some platforms may 230 * require that \c reg be 16-bit-aligned. 231 */ 232 void 233 pci_io_write16(struct pci_io_handle *handle, uint32_t reg, uint16_t data) 234 { 235 if (reg + 2 > handle->size) 236 return; 237 238 pci_sys->methods->write16(handle, reg, data); 239 } 240 241 /** 242 * Write a 8-bit value to the I/O space. \c reg is relative to the 243 * \c base specified when the handle was opened. 244 */ 245 void 246 pci_io_write8(struct pci_io_handle *handle, uint32_t reg, uint8_t data) 247 { 248 if (reg + 1 > handle->size) 249 return; 250 251 pci_sys->methods->write8(handle, reg, data); 252 } 253