1 /* 2 * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <assert.h> 32 #include <io_driver.h> 33 #include <io_storage.h> 34 #include <platform_def.h> 35 #include <stddef.h> 36 37 38 /* Storage for a fixed maximum number of IO entities, definable by platform */ 39 static io_entity_t entity_pool[MAX_IO_HANDLES]; 40 41 /* Simple way of tracking used storage - each entry is NULL or a pointer to an 42 * entity */ 43 static io_entity_t *entity_map[MAX_IO_HANDLES]; 44 45 /* Track number of allocated entities */ 46 static unsigned int entity_count; 47 48 /* Array of fixed maximum of registered devices, definable by platform */ 49 static const io_dev_info_t *devices[MAX_IO_DEVICES]; 50 51 /* Number of currently registered devices */ 52 static unsigned int dev_count; 53 54 55 #if DEBUG /* Extra validation functions only used in debug builds */ 56 57 /* Return a boolean value indicating whether a device connector is valid */ 58 static int is_valid_dev_connector(const io_dev_connector_t *dev_con) 59 { 60 int result = (dev_con != NULL) && (dev_con->dev_open != NULL); 61 return result; 62 } 63 64 65 /* Return a boolean value indicating whether a device handle is valid */ 66 static int is_valid_dev(const uintptr_t dev_handle) 67 { 68 const io_dev_info_t *dev = (io_dev_info_t *)dev_handle; 69 int result = (dev != NULL) && (dev->funcs != NULL) && 70 (dev->funcs->type != NULL) && 71 (dev->funcs->type() < IO_TYPE_MAX); 72 return result; 73 } 74 75 76 /* Return a boolean value indicating whether an IO entity is valid */ 77 static int is_valid_entity(const uintptr_t handle) 78 { 79 const io_entity_t *entity = (io_entity_t *)handle; 80 int result = (entity != NULL) && 81 (is_valid_dev((uintptr_t)entity->dev_handle)); 82 return result; 83 } 84 85 86 /* Return a boolean value indicating whether a seek mode is valid */ 87 static int is_valid_seek_mode(io_seek_mode_t mode) 88 { 89 return ((mode != IO_SEEK_INVALID) && (mode < IO_SEEK_MAX)); 90 } 91 92 #endif /* End of debug-only validation functions */ 93 94 95 /* Open a connection to a specific device */ 96 static int dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec, 97 io_dev_info_t **dev_info) 98 { 99 int result = IO_FAIL; 100 assert(dev_info != NULL); 101 assert(is_valid_dev_connector(dev_con)); 102 103 result = dev_con->dev_open(dev_spec, dev_info); 104 return result; 105 } 106 107 108 /* Set a handle to track an entity */ 109 static void set_handle(uintptr_t *handle, io_entity_t *entity) 110 { 111 assert(handle != NULL); 112 *handle = (uintptr_t)entity; 113 } 114 115 116 /* Locate an entity in the pool, specified by address */ 117 static int find_first_entity(const io_entity_t *entity, unsigned int *index_out) 118 { 119 int result = IO_FAIL; 120 for (int index = 0; index < MAX_IO_HANDLES; ++index) { 121 if (entity_map[index] == entity) { 122 result = IO_SUCCESS; 123 *index_out = index; 124 break; 125 } 126 } 127 return result; 128 } 129 130 131 /* Allocate an entity from the pool and return a pointer to it */ 132 static int allocate_entity(io_entity_t **entity) 133 { 134 int result = IO_FAIL; 135 assert(entity != NULL); 136 137 if (entity_count < MAX_IO_HANDLES) { 138 unsigned int index = 0; 139 result = find_first_entity(NULL, &index); 140 assert(result == IO_SUCCESS); 141 *entity = entity_map[index] = &entity_pool[index]; 142 ++entity_count; 143 } else 144 result = IO_RESOURCES_EXHAUSTED; 145 146 return result; 147 } 148 149 150 /* Release an entity back to the pool */ 151 static int free_entity(const io_entity_t *entity) 152 { 153 int result = IO_FAIL; 154 unsigned int index = 0; 155 assert(entity != NULL); 156 157 result = find_first_entity(entity, &index); 158 if (result == IO_SUCCESS) { 159 entity_map[index] = NULL; 160 --entity_count; 161 } 162 163 return result; 164 } 165 166 167 /* Exported API */ 168 169 /* Register a device driver */ 170 int io_register_device(const io_dev_info_t *dev_info) 171 { 172 int result = IO_FAIL; 173 assert(dev_info != NULL); 174 175 if (dev_count < MAX_IO_DEVICES) { 176 devices[dev_count] = dev_info; 177 dev_count++; 178 result = IO_SUCCESS; 179 } else { 180 result = IO_RESOURCES_EXHAUSTED; 181 } 182 183 return result; 184 } 185 186 187 /* Open a connection to an IO device */ 188 int io_dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec, 189 uintptr_t *handle) 190 { 191 int result = IO_FAIL; 192 assert(handle != NULL); 193 194 result = dev_open(dev_con, dev_spec, (io_dev_info_t **)handle); 195 return result; 196 } 197 198 199 /* Initialise an IO device explicitly - to permit lazy initialisation or 200 * re-initialisation */ 201 int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params) 202 { 203 int result = IO_FAIL; 204 assert(dev_handle != (uintptr_t)NULL); 205 assert(is_valid_dev(dev_handle)); 206 207 io_dev_info_t *dev = (io_dev_info_t *)dev_handle; 208 209 if (dev->funcs->dev_init != NULL) { 210 result = dev->funcs->dev_init(dev, init_params); 211 } else { 212 /* Absence of registered function implies NOP here */ 213 result = IO_SUCCESS; 214 } 215 return result; 216 } 217 218 219 /* TODO: Consider whether an explicit "shutdown" API should be included */ 220 221 /* Close a connection to a device */ 222 int io_dev_close(uintptr_t dev_handle) 223 { 224 int result = IO_FAIL; 225 assert(dev_handle != (uintptr_t)NULL); 226 assert(is_valid_dev(dev_handle)); 227 228 io_dev_info_t *dev = (io_dev_info_t *)dev_handle; 229 230 if (dev->funcs->dev_close != NULL) { 231 result = dev->funcs->dev_close(dev); 232 } else { 233 /* Absence of registered function implies NOP here */ 234 result = IO_SUCCESS; 235 } 236 237 return result; 238 } 239 240 241 /* Synchronous operations */ 242 243 244 /* Open an IO entity */ 245 int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle) 246 { 247 int result = IO_FAIL; 248 assert((spec != (uintptr_t)NULL) && (handle != NULL)); 249 assert(is_valid_dev(dev_handle)); 250 251 io_dev_info_t *dev = (io_dev_info_t *)dev_handle; 252 io_entity_t *entity; 253 254 result = allocate_entity(&entity); 255 256 if (result == IO_SUCCESS) { 257 assert(dev->funcs->open != NULL); 258 result = dev->funcs->open(dev, spec, entity); 259 260 if (result == IO_SUCCESS) { 261 entity->dev_handle = dev; 262 set_handle(handle, entity); 263 } else 264 free_entity(entity); 265 } 266 return result; 267 } 268 269 270 /* Seek to a specific position in an IO entity */ 271 int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset) 272 { 273 int result = IO_FAIL; 274 assert(is_valid_entity(handle) && is_valid_seek_mode(mode)); 275 276 io_entity_t *entity = (io_entity_t *)handle; 277 278 io_dev_info_t *dev = entity->dev_handle; 279 280 if (dev->funcs->seek != NULL) 281 result = dev->funcs->seek(entity, mode, offset); 282 else 283 result = IO_NOT_SUPPORTED; 284 285 return result; 286 } 287 288 289 /* Determine the length of an IO entity */ 290 int io_size(uintptr_t handle, size_t *length) 291 { 292 int result = IO_FAIL; 293 assert(is_valid_entity(handle) && (length != NULL)); 294 295 io_entity_t *entity = (io_entity_t *)handle; 296 297 io_dev_info_t *dev = entity->dev_handle; 298 299 if (dev->funcs->size != NULL) 300 result = dev->funcs->size(entity, length); 301 else 302 result = IO_NOT_SUPPORTED; 303 304 return result; 305 } 306 307 308 /* Read data from an IO entity */ 309 int io_read(uintptr_t handle, 310 uintptr_t buffer, 311 size_t length, 312 size_t *length_read) 313 { 314 int result = IO_FAIL; 315 assert(is_valid_entity(handle) && (buffer != (uintptr_t)NULL)); 316 317 io_entity_t *entity = (io_entity_t *)handle; 318 319 io_dev_info_t *dev = entity->dev_handle; 320 321 if (dev->funcs->read != NULL) 322 result = dev->funcs->read(entity, buffer, length, length_read); 323 else 324 result = IO_NOT_SUPPORTED; 325 326 return result; 327 } 328 329 330 /* Write data to an IO entity */ 331 int io_write(uintptr_t handle, 332 const uintptr_t buffer, 333 size_t length, 334 size_t *length_written) 335 { 336 int result = IO_FAIL; 337 assert(is_valid_entity(handle) && (buffer != (uintptr_t)NULL)); 338 339 io_entity_t *entity = (io_entity_t *)handle; 340 341 io_dev_info_t *dev = entity->dev_handle; 342 343 if (dev->funcs->write != NULL) { 344 result = dev->funcs->write(entity, buffer, length, 345 length_written); 346 } else 347 result = IO_NOT_SUPPORTED; 348 349 return result; 350 } 351 352 353 /* Close an IO entity */ 354 int io_close(uintptr_t handle) 355 { 356 int result = IO_FAIL; 357 assert(is_valid_entity(handle)); 358 359 io_entity_t *entity = (io_entity_t *)handle; 360 361 io_dev_info_t *dev = entity->dev_handle; 362 363 if (dev->funcs->close != NULL) 364 result = dev->funcs->close(entity); 365 else { 366 /* Absence of registered function implies NOP here */ 367 result = IO_SUCCESS; 368 } 369 /* Ignore improbable free_entity failure */ 370 (void)free_entity(entity); 371 372 return result; 373 } 374