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