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 119 return NULL; 120 } 121 122 /** 123 * Open a handle to the legacy I/O space for the PCI domain containing 124 * \c dev. \c size is in bytes. 125 * 126 * \returns 127 * An opaque handle to the requested range, or \c NULL on error. 128 */ 129 struct pci_io_handle * 130 pci_legacy_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size) 131 { 132 struct pci_io_handle *ret; 133 134 if (!pci_sys->methods->open_legacy_io) 135 return NULL; 136 137 ret = new_io_handle(); 138 if (!ret) 139 return NULL; 140 141 if (!pci_sys->methods->open_legacy_io(ret, dev, base, size)) { 142 delete_io_handle(ret); 143 return NULL; 144 } 145 146 return ret; 147 } 148 149 /** 150 * Close an I/O handle. 151 */ 152 void 153 pci_device_close_io(struct pci_device *dev, struct pci_io_handle *handle) 154 { 155 if (dev && handle && pci_sys->methods->close_io) 156 pci_sys->methods->close_io(dev, handle); 157 158 delete_io_handle(handle); 159 } 160 161 /** 162 * Read a 32-bit value from the I/O space. \c reg is relative to the 163 * \c base specified when the handle was opened. Some platforms may 164 * require that \c reg be 32-bit-aligned. 165 * 166 * \returns 167 * The value read from the I/O port, or undefined on any error. 168 */ 169 uint32_t 170 pci_io_read32(struct pci_io_handle *handle, uint32_t reg) 171 { 172 if (reg + 4 > handle->size) 173 return UINT32_MAX; 174 175 return pci_sys->methods->read32(handle, reg); 176 } 177 178 /** 179 * Read a 16-bit value from the I/O space. \c reg is relative to the 180 * \c base specified when the handle was opened. Some platforms may 181 * require that \c reg be 16-bit-aligned. 182 * 183 * \returns 184 * The value read from the I/O port, or undefined on any error. 185 */ 186 uint16_t 187 pci_io_read16(struct pci_io_handle *handle, uint32_t reg) 188 { 189 if (reg + 2 > handle->size) 190 return UINT16_MAX; 191 192 return pci_sys->methods->read16(handle, reg); 193 } 194 195 /** 196 * Read a 8-bit value from the I/O space. \c reg is relative to the 197 * \c base specified when the handle was opened. 198 * 199 * \returns 200 * The value read from the I/O port, or undefined on any error. 201 */ 202 uint8_t 203 pci_io_read8(struct pci_io_handle *handle, uint32_t reg) 204 { 205 if (reg + 1 > handle->size) 206 return UINT8_MAX; 207 208 return pci_sys->methods->read8(handle, reg); 209 } 210 211 /** 212 * Write a 32-bit value to the I/O space. \c reg is relative to the 213 * \c base specified when the handle was opened. Some platforms may 214 * require that \c reg be 32-bit-aligned. 215 */ 216 void 217 pci_io_write32(struct pci_io_handle *handle, uint32_t reg, uint32_t data) 218 { 219 if (reg + 4 > handle->size) 220 return; 221 222 pci_sys->methods->write32(handle, reg, data); 223 } 224 225 /** 226 * Write a 16-bit value to the I/O space. \c reg is relative to the 227 * \c base specified when the handle was opened. Some platforms may 228 * require that \c reg be 16-bit-aligned. 229 */ 230 void 231 pci_io_write16(struct pci_io_handle *handle, uint32_t reg, uint16_t data) 232 { 233 if (reg + 2 > handle->size) 234 return; 235 236 pci_sys->methods->write16(handle, reg, data); 237 } 238 239 /** 240 * Write a 8-bit value to the I/O space. \c reg is relative to the 241 * \c base specified when the handle was opened. 242 */ 243 void 244 pci_io_write8(struct pci_io_handle *handle, uint32_t reg, uint8_t data) 245 { 246 if (reg + 1 > handle->size) 247 return; 248 249 pci_sys->methods->write8(handle, reg, data); 250 } 251