1 /* 2 * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stddef.h> 9 10 #include <platform_def.h> 11 12 #include <drivers/io/io_driver.h> 13 #include <drivers/io/io_storage.h> 14 15 /* Storage for a fixed maximum number of IO entities, definable by platform */ 16 static io_entity_t entity_pool[MAX_IO_HANDLES]; 17 18 /* Simple way of tracking used storage - each entry is NULL or a pointer to an 19 * entity */ 20 static io_entity_t *entity_map[MAX_IO_HANDLES]; 21 22 /* Track number of allocated entities */ 23 static unsigned int entity_count; 24 25 /* Array of fixed maximum of registered devices, definable by platform */ 26 static const io_dev_info_t *devices[MAX_IO_DEVICES]; 27 28 /* Number of currently registered devices */ 29 static unsigned int dev_count; 30 31 /* Extra validation functions only used when asserts are enabled */ 32 #if ENABLE_ASSERTIONS 33 34 /* Return a boolean value indicating whether a device connector is valid */ 35 static int is_valid_dev_connector(const io_dev_connector_t *dev_con) 36 { 37 int result = (dev_con != NULL) && (dev_con->dev_open != NULL); 38 return result; 39 } 40 41 42 /* Return a boolean value indicating whether a device handle is valid */ 43 static int is_valid_dev(const uintptr_t dev_handle) 44 { 45 const io_dev_info_t *dev = (io_dev_info_t *)dev_handle; 46 int result = (dev != NULL) && (dev->funcs != NULL) && 47 (dev->funcs->type != NULL) && 48 (dev->funcs->type() < IO_TYPE_MAX); 49 return result; 50 } 51 52 53 /* Return a boolean value indicating whether an IO entity is valid */ 54 static int is_valid_entity(const uintptr_t handle) 55 { 56 const io_entity_t *entity = (io_entity_t *)handle; 57 int result = (entity != NULL) && 58 (is_valid_dev((uintptr_t)entity->dev_handle)); 59 return result; 60 } 61 62 63 /* Return a boolean value indicating whether a seek mode is valid */ 64 static int is_valid_seek_mode(io_seek_mode_t mode) 65 { 66 return ((mode != IO_SEEK_INVALID) && (mode < IO_SEEK_MAX)); 67 } 68 69 #endif /* ENABLE_ASSERTIONS */ 70 /* End of extra validation functions only used when asserts are enabled */ 71 72 73 /* Open a connection to a specific device */ 74 static int dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec, 75 io_dev_info_t **dev_info) 76 { 77 int result; 78 assert(dev_info != NULL); 79 assert(is_valid_dev_connector(dev_con)); 80 81 result = dev_con->dev_open(dev_spec, dev_info); 82 return result; 83 } 84 85 86 /* Set a handle to track an entity */ 87 static void set_handle(uintptr_t *handle, io_entity_t *entity) 88 { 89 assert(handle != NULL); 90 *handle = (uintptr_t)entity; 91 } 92 93 94 /* Locate an entity in the pool, specified by address */ 95 static int find_first_entity(const io_entity_t *entity, unsigned int *index_out) 96 { 97 int result = -ENOENT; 98 for (unsigned int index = 0; index < MAX_IO_HANDLES; ++index) { 99 if (entity_map[index] == entity) { 100 result = 0; 101 *index_out = index; 102 break; 103 } 104 } 105 return result; 106 } 107 108 109 /* Allocate an entity from the pool and return a pointer to it */ 110 static int allocate_entity(io_entity_t **entity) 111 { 112 int result = -ENOMEM; 113 assert(entity != NULL); 114 115 if (entity_count < MAX_IO_HANDLES) { 116 unsigned int index = 0; 117 result = find_first_entity(NULL, &index); 118 assert(result == 0); 119 *entity = entity_map[index] = &entity_pool[index]; 120 ++entity_count; 121 } 122 123 return result; 124 } 125 126 127 /* Release an entity back to the pool */ 128 static int free_entity(const io_entity_t *entity) 129 { 130 int result; 131 unsigned int index = 0; 132 assert(entity != NULL); 133 134 result = find_first_entity(entity, &index); 135 if (result == 0) { 136 entity_map[index] = NULL; 137 --entity_count; 138 } 139 140 return result; 141 } 142 143 144 /* Exported API */ 145 146 /* Register a device driver */ 147 int io_register_device(const io_dev_info_t *dev_info) 148 { 149 int result = -ENOMEM; 150 assert(dev_info != NULL); 151 152 if (dev_count < MAX_IO_DEVICES) { 153 devices[dev_count] = dev_info; 154 dev_count++; 155 result = 0; 156 } 157 158 return result; 159 } 160 161 162 /* Open a connection to an IO device */ 163 int io_dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec, 164 uintptr_t *handle) 165 { 166 int result; 167 assert(handle != NULL); 168 169 result = dev_open(dev_con, dev_spec, (io_dev_info_t **)handle); 170 return result; 171 } 172 173 174 /* Initialise an IO device explicitly - to permit lazy initialisation or 175 * re-initialisation */ 176 int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params) 177 { 178 int result = 0; 179 assert(dev_handle != (uintptr_t)NULL); 180 assert(is_valid_dev(dev_handle)); 181 182 io_dev_info_t *dev = (io_dev_info_t *)dev_handle; 183 184 /* Absence of registered function implies NOP here */ 185 if (dev->funcs->dev_init != NULL) { 186 result = dev->funcs->dev_init(dev, init_params); 187 } 188 189 return result; 190 } 191 192 193 /* TODO: Consider whether an explicit "shutdown" API should be included */ 194 195 /* Close a connection to a device */ 196 int io_dev_close(uintptr_t dev_handle) 197 { 198 int result = 0; 199 assert(dev_handle != (uintptr_t)NULL); 200 assert(is_valid_dev(dev_handle)); 201 202 io_dev_info_t *dev = (io_dev_info_t *)dev_handle; 203 204 /* Absence of registered function implies NOP here */ 205 if (dev->funcs->dev_close != NULL) { 206 result = dev->funcs->dev_close(dev); 207 } 208 209 return result; 210 } 211 212 213 /* Synchronous operations */ 214 215 216 /* Open an IO entity */ 217 int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle) 218 { 219 int result; 220 assert((spec != (uintptr_t)NULL) && (handle != NULL)); 221 assert(is_valid_dev(dev_handle)); 222 223 io_dev_info_t *dev = (io_dev_info_t *)dev_handle; 224 io_entity_t *entity; 225 226 result = allocate_entity(&entity); 227 228 if (result == 0) { 229 assert(dev->funcs->open != NULL); 230 result = dev->funcs->open(dev, spec, entity); 231 232 if (result == 0) { 233 entity->dev_handle = dev; 234 set_handle(handle, entity); 235 } else 236 free_entity(entity); 237 } 238 return result; 239 } 240 241 242 /* Seek to a specific position in an IO entity */ 243 int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset) 244 { 245 int result = -ENODEV; 246 assert(is_valid_entity(handle) && is_valid_seek_mode(mode)); 247 248 io_entity_t *entity = (io_entity_t *)handle; 249 250 io_dev_info_t *dev = entity->dev_handle; 251 252 if (dev->funcs->seek != NULL) 253 result = dev->funcs->seek(entity, mode, offset); 254 255 return result; 256 } 257 258 259 /* Determine the length of an IO entity */ 260 int io_size(uintptr_t handle, size_t *length) 261 { 262 int result = -ENODEV; 263 assert(is_valid_entity(handle) && (length != NULL)); 264 265 io_entity_t *entity = (io_entity_t *)handle; 266 267 io_dev_info_t *dev = entity->dev_handle; 268 269 if (dev->funcs->size != NULL) 270 result = dev->funcs->size(entity, length); 271 272 return result; 273 } 274 275 276 /* Read data from an IO entity */ 277 int io_read(uintptr_t handle, 278 uintptr_t buffer, 279 size_t length, 280 size_t *length_read) 281 { 282 int result = -ENODEV; 283 assert(is_valid_entity(handle)); 284 285 io_entity_t *entity = (io_entity_t *)handle; 286 287 io_dev_info_t *dev = entity->dev_handle; 288 289 if (dev->funcs->read != NULL) 290 result = dev->funcs->read(entity, buffer, length, length_read); 291 292 return result; 293 } 294 295 296 /* Write data to an IO entity */ 297 int io_write(uintptr_t handle, 298 const uintptr_t buffer, 299 size_t length, 300 size_t *length_written) 301 { 302 int result = -ENODEV; 303 assert(is_valid_entity(handle)); 304 305 io_entity_t *entity = (io_entity_t *)handle; 306 307 io_dev_info_t *dev = entity->dev_handle; 308 309 if (dev->funcs->write != NULL) { 310 result = dev->funcs->write(entity, buffer, length, 311 length_written); 312 } 313 314 return result; 315 } 316 317 318 /* Close an IO entity */ 319 int io_close(uintptr_t handle) 320 { 321 int result = 0; 322 assert(is_valid_entity(handle)); 323 324 io_entity_t *entity = (io_entity_t *)handle; 325 326 io_dev_info_t *dev = entity->dev_handle; 327 328 /* Absence of registered function implies NOP here */ 329 if (dev->funcs->close != NULL) 330 result = dev->funcs->close(entity); 331 332 /* Ignore improbable free_entity failure */ 333 (void)free_entity(entity); 334 335 return result; 336 } 337