Home | History | Annotate | Download | only in io
      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