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