blob: 01ca1c686a5ca3669de92c27d3c56db91b345541 [file] [log] [blame]
James Morrisseyf2f9bb52014-02-10 16:18:59 +00001/*
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
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>
34#include <stddef.h>
James Morrisseyf2f9bb52014-02-10 16:18:59 +000035
36
37#define MAX_DEVICES(plat_data) \
38 (sizeof((plat_data)->devices)/sizeof((plat_data)->devices[0]))
39
40
41/* Storage for a fixed maximum number of IO entities, definable by platform */
Dan Handleye2712bc2014-04-10 15:37:22 +010042static io_entity_t entity_pool[MAX_IO_HANDLES];
James Morrisseyf2f9bb52014-02-10 16:18:59 +000043
44/* Simple way of tracking used storage - each entry is NULL or a pointer to an
45 * entity */
Dan Handleye2712bc2014-04-10 15:37:22 +010046static io_entity_t *entity_map[MAX_IO_HANDLES];
James Morrisseyf2f9bb52014-02-10 16:18:59 +000047
48/* Track number of allocated entities */
49static unsigned int entity_count;
50
51
52/* Used to keep a reference to platform-specific data */
Dan Handleye2712bc2014-04-10 15:37:22 +010053static io_plat_data_t *platform_data;
James Morrisseyf2f9bb52014-02-10 16:18:59 +000054
55
56#if DEBUG /* Extra validation functions only used in debug builds */
57
58/* Return a boolean value indicating whether a device connector is valid */
Dan Handleye2712bc2014-04-10 15:37:22 +010059static int is_valid_dev_connector(const io_dev_connector_t *dev_con)
James Morrisseyf2f9bb52014-02-10 16:18:59 +000060{
61 int result = (dev_con != NULL) && (dev_con->dev_open != NULL);
62 return result;
63}
64
65
66/* Return a boolean value indicating whether a device handle is valid */
67static int is_valid_dev(io_dev_handle handle)
68{
Dan Handleye2712bc2014-04-10 15:37:22 +010069 const io_dev_info_t *dev = handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +000070 int result = (dev != NULL) && (dev->funcs != NULL) &&
71 (dev->funcs->type != NULL) &&
72 (dev->funcs->type() < IO_TYPE_MAX);
73 return result;
74}
75
76
77/* Return a boolean value indicating whether an IO entity is valid */
78static int is_valid_entity(io_handle handle)
79{
Dan Handleye2712bc2014-04-10 15:37:22 +010080 const io_entity_t *entity = handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +000081 int result = (entity != NULL) && (is_valid_dev(entity->dev_handle));
82 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
92#endif /* End of debug-only validation functions */
93
94
95/* Open a connection to a specific device */
Dan Handleye2712bc2014-04-10 15:37:22 +010096static int dev_open(const io_dev_connector_t *dev_con, void *dev_spec,
97 io_dev_info_t **dev_info)
James Morrisseyf2f9bb52014-02-10 16:18:59 +000098{
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 */
Dan Handleye2712bc2014-04-10 15:37:22 +0100109static void set_handle(io_handle *handle, io_entity_t *entity)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000110{
111 assert(handle != NULL);
112 *handle = entity;
113}
114
115
116/* Locate an entity in the pool, specified by address */
117static int find_first_entity(struct io_entity *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 */
132static int allocate_entity(struct io_entity **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 */
151static int free_entity(struct io_entity *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
170/* Initialise the IO layer */
171void io_init(struct io_plat_data *data)
172{
173 assert(data != NULL);
174 platform_data = data;
175}
176
177
178/* Register a device driver */
179int io_register_device(struct io_dev_info *dev_info)
180{
181 int result = IO_FAIL;
182 assert(dev_info != NULL);
183 assert(platform_data != NULL);
184
185 unsigned int dev_count = platform_data->dev_count;
186
187 if (dev_count < MAX_DEVICES(platform_data)) {
188 platform_data->devices[dev_count] = dev_info;
189 platform_data->dev_count++;
190 result = IO_SUCCESS;
191 } else {
192 result = IO_RESOURCES_EXHAUSTED;
193 }
194
195 return result;
196}
197
198
199/* Open a connection to an IO device */
200int io_dev_open(struct io_dev_connector *dev_con, void *dev_spec,
201 io_dev_handle *handle)
202{
203 int result = IO_FAIL;
204 assert(handle != NULL);
205
206 result = dev_open(dev_con, dev_spec, handle);
207 return result;
208}
209
210
211/* Initialise an IO device explicitly - to permit lazy initialisation or
212 * re-initialisation */
213int io_dev_init(struct io_dev_info *dev_handle, const void *init_params)
214{
215 int result = IO_FAIL;
216 assert(dev_handle != NULL);
217 assert(is_valid_dev(dev_handle));
218
Dan Handleye2712bc2014-04-10 15:37:22 +0100219 io_dev_info_t *dev = dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000220
221 if (dev->funcs->dev_init != NULL) {
222 result = dev->funcs->dev_init(dev, init_params);
223 } else {
224 /* Absence of registered function implies NOP here */
225 result = IO_SUCCESS;
226 }
227 return result;
228}
229
230
231/* TODO: Consider whether an explicit "shutdown" API should be included */
232
233/* Close a connection to a device */
234int io_dev_close(io_dev_handle dev_handle)
235{
236 int result = IO_FAIL;
237 assert(dev_handle != NULL);
238 assert(is_valid_dev(dev_handle));
239
Dan Handleye2712bc2014-04-10 15:37:22 +0100240 io_dev_info_t *dev = dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000241
242 if (dev->funcs->dev_close != NULL) {
243 result = dev->funcs->dev_close(dev);
244 } else {
245 /* Absence of registered function implies NOP here */
246 result = IO_SUCCESS;
247 }
248
249 return result;
250}
251
252
253/* Synchronous operations */
254
255
256/* Open an IO entity */
257int io_open(io_dev_handle dev_handle, const void *spec, io_handle *handle)
258{
259 int result = IO_FAIL;
260 assert((spec != NULL) && (handle != NULL));
261 assert(is_valid_dev(dev_handle));
262
Dan Handleye2712bc2014-04-10 15:37:22 +0100263 io_dev_info_t *dev = dev_handle;
264 io_entity_t *entity;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000265
266 result = allocate_entity(&entity);
267
268 if (result == IO_SUCCESS) {
269 assert(dev->funcs->open != NULL);
270 result = dev->funcs->open(dev, spec, entity);
271
272 if (result == IO_SUCCESS) {
273 entity->dev_handle = dev_handle;
274 set_handle(handle, entity);
275 } else
276 free_entity(entity);
277 }
278 return result;
279}
280
281
282/* Seek to a specific position in an IO entity */
Dan Handleye2712bc2014-04-10 15:37:22 +0100283int io_seek(io_handle handle, io_seek_mode_t mode, ssize_t offset)
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000284{
285 int result = IO_FAIL;
286 assert(is_valid_entity(handle) && is_valid_seek_mode(mode));
287
Dan Handleye2712bc2014-04-10 15:37:22 +0100288 io_entity_t *entity = 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->seek != NULL)
293 result = dev->funcs->seek(entity, mode, offset);
294 else
295 result = IO_NOT_SUPPORTED;
296
297 return result;
298}
299
300
301/* Determine the length of an IO entity */
302int io_size(io_handle handle, size_t *length)
303{
304 int result = IO_FAIL;
305 assert(is_valid_entity(handle) && (length != NULL));
306
Dan Handleye2712bc2014-04-10 15:37:22 +0100307 io_entity_t *entity = handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000308
Dan Handleye2712bc2014-04-10 15:37:22 +0100309 io_dev_info_t *dev = entity->dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000310
311 if (dev->funcs->size != NULL)
312 result = dev->funcs->size(entity, length);
313 else
314 result = IO_NOT_SUPPORTED;
315
316 return result;
317}
318
319
320/* Read data from an IO entity */
321int io_read(io_handle handle, void *buffer, size_t length, size_t *length_read)
322{
323 int result = IO_FAIL;
324 assert(is_valid_entity(handle) && (buffer != NULL));
325
Dan Handleye2712bc2014-04-10 15:37:22 +0100326 io_entity_t *entity = handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000327
Dan Handleye2712bc2014-04-10 15:37:22 +0100328 io_dev_info_t *dev = entity->dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000329
330 if (dev->funcs->read != NULL)
331 result = dev->funcs->read(entity, buffer, length, length_read);
332 else
333 result = IO_NOT_SUPPORTED;
334
335 return result;
336}
337
338
339/* Write data to an IO entity */
340int io_write(io_handle handle, const void *buffer, size_t length,
341 size_t *length_written)
342{
343 int result = IO_FAIL;
344 assert(is_valid_entity(handle) && (buffer != NULL));
345
Dan Handleye2712bc2014-04-10 15:37:22 +0100346 io_entity_t *entity = handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000347
Dan Handleye2712bc2014-04-10 15:37:22 +0100348 io_dev_info_t *dev = entity->dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000349
350 if (dev->funcs->write != NULL) {
351 result = dev->funcs->write(entity, buffer, length,
352 length_written);
353 } else
354 result = IO_NOT_SUPPORTED;
355
356 return result;
357}
358
359
360/* Close an IO entity */
361int io_close(io_handle handle)
362{
363 int result = IO_FAIL;
364 assert(is_valid_entity(handle));
365
Dan Handleye2712bc2014-04-10 15:37:22 +0100366 io_entity_t *entity = handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000367
Dan Handleye2712bc2014-04-10 15:37:22 +0100368 io_dev_info_t *dev = entity->dev_handle;
James Morrisseyf2f9bb52014-02-10 16:18:59 +0000369
370 if (dev->funcs->close != NULL)
371 result = dev->funcs->close(entity);
372 else {
373 /* Absence of registered function implies NOP here */
374 result = IO_SUCCESS;
375 }
376 /* Ignore improbable free_entity failure */
377 (void)free_entity(entity);
378
379 return result;
380}