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