blob: de8c3bf63a97ec528eaac823037210347adb4549 [file] [log] [blame]
James Morrisseyf2f9bb52014-02-10 16:18:59 +00001/*
Antonio Nino Diaz3759e3f2017-03-22 15:48:51 +00002 * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
James Morrisseyf2f9bb52014-02-10 16:18:59 +00003 *
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
James Morrisseyf2f9bb52014-02-10 16:18:59 +000031#include <assert.h>
Dan Handley714a0d22014-04-09 13:13:04 +010032#include <io_driver.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010033#include <io_storage.h>
Dan Handley3aa92162014-08-04 18:31:43 +010034#include <platform_def.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010035#include <stddef.h>
James Morrisseyf2f9bb52014-02-10 16:18:59 +000036
37
James Morrisseyf2f9bb52014-02-10 16:18:59 +000038/* Storage for a fixed maximum number of IO entities, definable by platform */
Dan Handleye2712bc2014-04-10 15:37:22 +010039static io_entity_t entity_pool[MAX_IO_HANDLES];
James Morrisseyf2f9bb52014-02-10 16:18:59 +000040
41/* Simple way of tracking used storage - each entry is NULL or a pointer to an
42 * entity */
Dan Handleye2712bc2014-04-10 15:37:22 +010043static io_entity_t *entity_map[MAX_IO_HANDLES];
James Morrisseyf2f9bb52014-02-10 16:18:59 +000044
45/* Track number of allocated entities */
46static unsigned int entity_count;
47
Dan Handley3aa92162014-08-04 18:31:43 +010048/* Array of fixed maximum of registered devices, definable by platform */
49static const io_dev_info_t *devices[MAX_IO_DEVICES];
James Morrisseyf2f9bb52014-02-10 16:18:59 +000050
Dan Handley3aa92162014-08-04 18:31:43 +010051/* Number of currently registered devices */
52static unsigned int dev_count;
James Morrisseyf2f9bb52014-02-10 16:18:59 +000053
Antonio Nino Diaz3759e3f2017-03-22 15:48:51 +000054/* Extra validation functions only used when asserts are enabled */
55#if ENABLE_ASSERTIONS
James Morrisseyf2f9bb52014-02-10 16:18:59 +000056
57/* Return a boolean value indicating whether a device connector is valid */
Dan Handleye2712bc2014-04-10 15:37:22 +010058static int is_valid_dev_connector(const io_dev_connector_t *dev_con)
James Morrisseyf2f9bb52014-02-10 16:18:59 +000059{
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 */
Dan Handleya4cb68e2014-04-23 13:47:06 +010066static int is_valid_dev(const uintptr_t dev_handle)
James Morrisseyf2f9bb52014-02-10 16:18:59 +000067{
Dan Handleya4cb68e2014-04-23 13:47:06 +010068 const io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +000069 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 */
Dan Handleya4cb68e2014-04-23 13:47:06 +010077static int is_valid_entity(const uintptr_t handle)
James Morrisseyf2f9bb52014-02-10 16:18:59 +000078{
Dan Handleya4cb68e2014-04-23 13:47:06 +010079 const io_entity_t *entity = (io_entity_t *)handle;
80 int result = (entity != NULL) &&
81 (is_valid_dev((uintptr_t)entity->dev_handle));
James Morrisseyf2f9bb52014-02-10 16:18:59 +000082 return result;
83}
84
85
86/* Return a boolean value indicating whether a seek mode is valid */
Dan Handleye2712bc2014-04-10 15:37:22 +010087static int is_valid_seek_mode(io_seek_mode_t mode)
James Morrisseyf2f9bb52014-02-10 16:18:59 +000088{
89 return ((mode != IO_SEEK_INVALID) && (mode < IO_SEEK_MAX));
90}
91
Antonio Nino Diaz3759e3f2017-03-22 15:48:51 +000092#endif /* ENABLE_ASSERTIONS */
93/* End of extra validation functions only used when asserts are enabled */
James Morrisseyf2f9bb52014-02-10 16:18:59 +000094
95
96/* Open a connection to a specific device */
Dan Handleya4cb68e2014-04-23 13:47:06 +010097static int dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010098 io_dev_info_t **dev_info)
James Morrisseyf2f9bb52014-02-10 16:18:59 +000099{
Juan Castillo6e762062015-11-02 10:47:01 +0000100 int result;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000101 assert(dev_info != NULL);
102 assert(is_valid_dev_connector(dev_con));
103
104 result = dev_con->dev_open(dev_spec, dev_info);
105 return result;
106}
107
108
109/* Set a handle to track an entity */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100110static void set_handle(uintptr_t *handle, io_entity_t *entity)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000111{
112 assert(handle != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100113 *handle = (uintptr_t)entity;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000114}
115
116
117/* Locate an entity in the pool, specified by address */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100118static int find_first_entity(const io_entity_t *entity, unsigned int *index_out)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000119{
Juan Castillo6e762062015-11-02 10:47:01 +0000120 int result = -ENOENT;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000121 for (int index = 0; index < MAX_IO_HANDLES; ++index) {
122 if (entity_map[index] == entity) {
Juan Castillo6e762062015-11-02 10:47:01 +0000123 result = 0;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000124 *index_out = index;
125 break;
126 }
127 }
128 return result;
129}
130
131
132/* Allocate an entity from the pool and return a pointer to it */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100133static int allocate_entity(io_entity_t **entity)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000134{
Juan Castillo6e762062015-11-02 10:47:01 +0000135 int result = -ENOMEM;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000136 assert(entity != NULL);
137
138 if (entity_count < MAX_IO_HANDLES) {
139 unsigned int index = 0;
140 result = find_first_entity(NULL, &index);
Juan Castillo6e762062015-11-02 10:47:01 +0000141 assert(result == 0);
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000142 *entity = entity_map[index] = &entity_pool[index];
143 ++entity_count;
Juan Castillo6e762062015-11-02 10:47:01 +0000144 }
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000145
146 return result;
147}
148
149
150/* Release an entity back to the pool */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100151static int free_entity(const io_entity_t *entity)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000152{
Juan Castillo6e762062015-11-02 10:47:01 +0000153 int result;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000154 unsigned int index = 0;
155 assert(entity != NULL);
156
157 result = find_first_entity(entity, &index);
Juan Castillo6e762062015-11-02 10:47:01 +0000158 if (result == 0) {
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000159 entity_map[index] = NULL;
160 --entity_count;
161 }
162
163 return result;
164}
165
166
167/* Exported API */
168
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000169/* Register a device driver */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100170int io_register_device(const io_dev_info_t *dev_info)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000171{
Juan Castillo6e762062015-11-02 10:47:01 +0000172 int result = -ENOMEM;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000173 assert(dev_info != NULL);
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000174
Dan Handley3aa92162014-08-04 18:31:43 +0100175 if (dev_count < MAX_IO_DEVICES) {
176 devices[dev_count] = dev_info;
177 dev_count++;
Juan Castillo6e762062015-11-02 10:47:01 +0000178 result = 0;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000179 }
180
181 return result;
182}
183
184
185/* Open a connection to an IO device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100186int io_dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec,
187 uintptr_t *handle)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000188{
Juan Castillo6e762062015-11-02 10:47:01 +0000189 int result;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000190 assert(handle != NULL);
191
Dan Handleya4cb68e2014-04-23 13:47:06 +0100192 result = dev_open(dev_con, dev_spec, (io_dev_info_t **)handle);
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000193 return result;
194}
195
196
197/* Initialise an IO device explicitly - to permit lazy initialisation or
198 * re-initialisation */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100199int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000200{
Juan Castillo6e762062015-11-02 10:47:01 +0000201 int result = 0;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100202 assert(dev_handle != (uintptr_t)NULL);
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000203 assert(is_valid_dev(dev_handle));
204
Dan Handleya4cb68e2014-04-23 13:47:06 +0100205 io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000206
Juan Castillo6e762062015-11-02 10:47:01 +0000207 /* Absence of registered function implies NOP here */
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000208 if (dev->funcs->dev_init != NULL) {
209 result = dev->funcs->dev_init(dev, init_params);
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000210 }
Juan Castillo6e762062015-11-02 10:47:01 +0000211
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000212 return result;
213}
214
215
216/* TODO: Consider whether an explicit "shutdown" API should be included */
217
218/* Close a connection to a device */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100219int io_dev_close(uintptr_t dev_handle)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000220{
Juan Castillo6e762062015-11-02 10:47:01 +0000221 int result = 0;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100222 assert(dev_handle != (uintptr_t)NULL);
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000223 assert(is_valid_dev(dev_handle));
224
Dan Handleya4cb68e2014-04-23 13:47:06 +0100225 io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000226
Juan Castillo6e762062015-11-02 10:47:01 +0000227 /* Absence of registered function implies NOP here */
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000228 if (dev->funcs->dev_close != NULL) {
229 result = dev->funcs->dev_close(dev);
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000230 }
231
232 return result;
233}
234
235
236/* Synchronous operations */
237
238
239/* Open an IO entity */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100240int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000241{
Juan Castillo6e762062015-11-02 10:47:01 +0000242 int result;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100243 assert((spec != (uintptr_t)NULL) && (handle != NULL));
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000244 assert(is_valid_dev(dev_handle));
245
Dan Handleya4cb68e2014-04-23 13:47:06 +0100246 io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
Dan Handleye2712bc2014-04-10 15:37:22 +0100247 io_entity_t *entity;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000248
249 result = allocate_entity(&entity);
250
Juan Castillo6e762062015-11-02 10:47:01 +0000251 if (result == 0) {
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000252 assert(dev->funcs->open != NULL);
253 result = dev->funcs->open(dev, spec, entity);
254
Juan Castillo6e762062015-11-02 10:47:01 +0000255 if (result == 0) {
Dan Handleya4cb68e2014-04-23 13:47:06 +0100256 entity->dev_handle = dev;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000257 set_handle(handle, entity);
258 } else
259 free_entity(entity);
260 }
261 return result;
262}
263
264
265/* Seek to a specific position in an IO entity */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100266int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000267{
Juan Castillo6e762062015-11-02 10:47:01 +0000268 int result = -ENODEV;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000269 assert(is_valid_entity(handle) && is_valid_seek_mode(mode));
270
Dan Handleya4cb68e2014-04-23 13:47:06 +0100271 io_entity_t *entity = (io_entity_t *)handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000272
Dan Handleye2712bc2014-04-10 15:37:22 +0100273 io_dev_info_t *dev = entity->dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000274
275 if (dev->funcs->seek != NULL)
276 result = dev->funcs->seek(entity, mode, offset);
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000277
278 return result;
279}
280
281
282/* Determine the length of an IO entity */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100283int io_size(uintptr_t handle, size_t *length)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000284{
Juan Castillo6e762062015-11-02 10:47:01 +0000285 int result = -ENODEV;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000286 assert(is_valid_entity(handle) && (length != NULL));
287
Dan Handleya4cb68e2014-04-23 13:47:06 +0100288 io_entity_t *entity = (io_entity_t *)handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000289
Dan Handleye2712bc2014-04-10 15:37:22 +0100290 io_dev_info_t *dev = entity->dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000291
292 if (dev->funcs->size != NULL)
293 result = dev->funcs->size(entity, length);
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000294
295 return result;
296}
297
298
299/* Read data from an IO entity */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100300int io_read(uintptr_t handle,
301 uintptr_t buffer,
302 size_t length,
303 size_t *length_read)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000304{
Juan Castillo6e762062015-11-02 10:47:01 +0000305 int result = -ENODEV;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100306 assert(is_valid_entity(handle) && (buffer != (uintptr_t)NULL));
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000307
Dan Handleya4cb68e2014-04-23 13:47:06 +0100308 io_entity_t *entity = (io_entity_t *)handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000309
Dan Handleye2712bc2014-04-10 15:37:22 +0100310 io_dev_info_t *dev = entity->dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000311
312 if (dev->funcs->read != NULL)
313 result = dev->funcs->read(entity, buffer, length, length_read);
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000314
315 return result;
316}
317
318
319/* Write data to an IO entity */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100320int io_write(uintptr_t handle,
321 const uintptr_t buffer,
322 size_t length,
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000323 size_t *length_written)
324{
Juan Castillo6e762062015-11-02 10:47:01 +0000325 int result = -ENODEV;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100326 assert(is_valid_entity(handle) && (buffer != (uintptr_t)NULL));
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000327
Dan Handleya4cb68e2014-04-23 13:47:06 +0100328 io_entity_t *entity = (io_entity_t *)handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000329
Dan Handleye2712bc2014-04-10 15:37:22 +0100330 io_dev_info_t *dev = entity->dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000331
332 if (dev->funcs->write != NULL) {
333 result = dev->funcs->write(entity, buffer, length,
334 length_written);
Juan Castillo6e762062015-11-02 10:47:01 +0000335 }
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000336
337 return result;
338}
339
340
341/* Close an IO entity */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100342int io_close(uintptr_t handle)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000343{
Juan Castillo6e762062015-11-02 10:47:01 +0000344 int result = 0;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000345 assert(is_valid_entity(handle));
346
Dan Handleya4cb68e2014-04-23 13:47:06 +0100347 io_entity_t *entity = (io_entity_t *)handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000348
Dan Handleye2712bc2014-04-10 15:37:22 +0100349 io_dev_info_t *dev = entity->dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000350
Juan Castillo6e762062015-11-02 10:47:01 +0000351 /* Absence of registered function implies NOP here */
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000352 if (dev->funcs->close != NULL)
353 result = dev->funcs->close(entity);
Juan Castillo6e762062015-11-02 10:47:01 +0000354
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000355 /* Ignore improbable free_entity failure */
356 (void)free_entity(entity);
357
358 return result;
359}