blob: aeb8edbbbef209b113f9c4887dada8b920b34743 [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
31
32#include <stddef.h>
33#include <assert.h>
34#include "io_storage.h"
35#include "io_driver.h"
36
37
38#define MAX_DEVICES(plat_data) \
39 (sizeof((plat_data)->devices)/sizeof((plat_data)->devices[0]))
40
41
42/* Storage for a fixed maximum number of IO entities, definable by platform */
43static struct io_entity entity_pool[MAX_IO_HANDLES];
44
45/* Simple way of tracking used storage - each entry is NULL or a pointer to an
46 * entity */
47static struct io_entity *entity_map[MAX_IO_HANDLES];
48
49/* Track number of allocated entities */
50static unsigned int entity_count;
51
52
53/* Used to keep a reference to platform-specific data */
54static struct io_plat_data *platform_data;
55
56
57#if DEBUG /* Extra validation functions only used in debug builds */
58
59/* Return a boolean value indicating whether a device connector is valid */
60static int is_valid_dev_connector(const struct io_dev_connector *dev_con)
61{
62 int result = (dev_con != NULL) && (dev_con->dev_open != NULL);
63 return result;
64}
65
66
67/* Return a boolean value indicating whether a device handle is valid */
68static int is_valid_dev(io_dev_handle handle)
69{
70 const struct io_dev_info *dev = handle;
71 int result = (dev != NULL) && (dev->funcs != NULL) &&
72 (dev->funcs->type != NULL) &&
73 (dev->funcs->type() < IO_TYPE_MAX);
74 return result;
75}
76
77
78/* Return a boolean value indicating whether an IO entity is valid */
79static int is_valid_entity(io_handle handle)
80{
81 const struct io_entity *entity = handle;
82 int result = (entity != NULL) && (is_valid_dev(entity->dev_handle));
83 return result;
84}
85
86
87/* Return a boolean value indicating whether a seek mode is valid */
88static int is_valid_seek_mode(io_seek_mode mode)
89{
90 return ((mode != IO_SEEK_INVALID) && (mode < IO_SEEK_MAX));
91}
92
93#endif /* End of debug-only validation functions */
94
95
96/* Open a connection to a specific device */
97static int dev_open(const struct io_dev_connector *dev_con, void *dev_spec,
98 struct io_dev_info **dev_info)
99{
100 int result = IO_FAIL;
101 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 */
110static void set_handle(io_handle *handle, struct io_entity *entity)
111{
112 assert(handle != NULL);
113 *handle = entity;
114}
115
116
117/* Locate an entity in the pool, specified by address */
118static int find_first_entity(struct io_entity *entity, unsigned int *index_out)
119{
120 int result = IO_FAIL;
121 for (int index = 0; index < MAX_IO_HANDLES; ++index) {
122 if (entity_map[index] == entity) {
123 result = IO_SUCCESS;
124 *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 */
133static int allocate_entity(struct io_entity **entity)
134{
135 int result = IO_FAIL;
136 assert(entity != NULL);
137
138 if (entity_count < MAX_IO_HANDLES) {
139 unsigned int index = 0;
140 result = find_first_entity(NULL, &index);
141 assert(result == IO_SUCCESS);
142 *entity = entity_map[index] = &entity_pool[index];
143 ++entity_count;
144 } else
145 result = IO_RESOURCES_EXHAUSTED;
146
147 return result;
148}
149
150
151/* Release an entity back to the pool */
152static int free_entity(struct io_entity *entity)
153{
154 int result = IO_FAIL;
155 unsigned int index = 0;
156 assert(entity != NULL);
157
158 result = find_first_entity(entity, &index);
159 if (result == IO_SUCCESS) {
160 entity_map[index] = NULL;
161 --entity_count;
162 }
163
164 return result;
165}
166
167
168/* Exported API */
169
170
171/* Initialise the IO layer */
172void io_init(struct io_plat_data *data)
173{
174 assert(data != NULL);
175 platform_data = data;
176}
177
178
179/* Register a device driver */
180int io_register_device(struct io_dev_info *dev_info)
181{
182 int result = IO_FAIL;
183 assert(dev_info != NULL);
184 assert(platform_data != NULL);
185
186 unsigned int dev_count = platform_data->dev_count;
187
188 if (dev_count < MAX_DEVICES(platform_data)) {
189 platform_data->devices[dev_count] = dev_info;
190 platform_data->dev_count++;
191 result = IO_SUCCESS;
192 } else {
193 result = IO_RESOURCES_EXHAUSTED;
194 }
195
196 return result;
197}
198
199
200/* Open a connection to an IO device */
201int io_dev_open(struct io_dev_connector *dev_con, void *dev_spec,
202 io_dev_handle *handle)
203{
204 int result = IO_FAIL;
205 assert(handle != NULL);
206
207 result = dev_open(dev_con, dev_spec, handle);
208 return result;
209}
210
211
212/* Initialise an IO device explicitly - to permit lazy initialisation or
213 * re-initialisation */
214int io_dev_init(struct io_dev_info *dev_handle, const void *init_params)
215{
216 int result = IO_FAIL;
217 assert(dev_handle != NULL);
218 assert(is_valid_dev(dev_handle));
219
220 struct io_dev_info *dev = dev_handle;
221
222 if (dev->funcs->dev_init != NULL) {
223 result = dev->funcs->dev_init(dev, init_params);
224 } else {
225 /* Absence of registered function implies NOP here */
226 result = IO_SUCCESS;
227 }
228 return result;
229}
230
231
232/* TODO: Consider whether an explicit "shutdown" API should be included */
233
234/* Close a connection to a device */
235int io_dev_close(io_dev_handle dev_handle)
236{
237 int result = IO_FAIL;
238 assert(dev_handle != NULL);
239 assert(is_valid_dev(dev_handle));
240
241 struct io_dev_info *dev = dev_handle;
242
243 if (dev->funcs->dev_close != NULL) {
244 result = dev->funcs->dev_close(dev);
245 } else {
246 /* Absence of registered function implies NOP here */
247 result = IO_SUCCESS;
248 }
249
250 return result;
251}
252
253
254/* Synchronous operations */
255
256
257/* Open an IO entity */
258int io_open(io_dev_handle dev_handle, const void *spec, io_handle *handle)
259{
260 int result = IO_FAIL;
261 assert((spec != NULL) && (handle != NULL));
262 assert(is_valid_dev(dev_handle));
263
264 struct io_dev_info *dev = dev_handle;
265 struct io_entity *entity;
266
267 result = allocate_entity(&entity);
268
269 if (result == IO_SUCCESS) {
270 assert(dev->funcs->open != NULL);
271 result = dev->funcs->open(dev, spec, entity);
272
273 if (result == IO_SUCCESS) {
274 entity->dev_handle = dev_handle;
275 set_handle(handle, entity);
276 } else
277 free_entity(entity);
278 }
279 return result;
280}
281
282
283/* Seek to a specific position in an IO entity */
284int io_seek(io_handle handle, io_seek_mode mode, ssize_t offset)
285{
286 int result = IO_FAIL;
287 assert(is_valid_entity(handle) && is_valid_seek_mode(mode));
288
289 struct io_entity *entity = handle;
290
291 struct io_dev_info *dev = entity->dev_handle;
292
293 if (dev->funcs->seek != NULL)
294 result = dev->funcs->seek(entity, mode, offset);
295 else
296 result = IO_NOT_SUPPORTED;
297
298 return result;
299}
300
301
302/* Determine the length of an IO entity */
303int io_size(io_handle handle, size_t *length)
304{
305 int result = IO_FAIL;
306 assert(is_valid_entity(handle) && (length != NULL));
307
308 struct io_entity *entity = handle;
309
310 struct io_dev_info *dev = entity->dev_handle;
311
312 if (dev->funcs->size != NULL)
313 result = dev->funcs->size(entity, length);
314 else
315 result = IO_NOT_SUPPORTED;
316
317 return result;
318}
319
320
321/* Read data from an IO entity */
322int io_read(io_handle handle, void *buffer, size_t length, size_t *length_read)
323{
324 int result = IO_FAIL;
325 assert(is_valid_entity(handle) && (buffer != NULL));
326
327 struct io_entity *entity = handle;
328
329 struct io_dev_info *dev = entity->dev_handle;
330
331 if (dev->funcs->read != NULL)
332 result = dev->funcs->read(entity, buffer, length, length_read);
333 else
334 result = IO_NOT_SUPPORTED;
335
336 return result;
337}
338
339
340/* Write data to an IO entity */
341int io_write(io_handle handle, const void *buffer, size_t length,
342 size_t *length_written)
343{
344 int result = IO_FAIL;
345 assert(is_valid_entity(handle) && (buffer != NULL));
346
347 struct io_entity *entity = handle;
348
349 struct io_dev_info *dev = entity->dev_handle;
350
351 if (dev->funcs->write != NULL) {
352 result = dev->funcs->write(entity, buffer, length,
353 length_written);
354 } else
355 result = IO_NOT_SUPPORTED;
356
357 return result;
358}
359
360
361/* Close an IO entity */
362int io_close(io_handle handle)
363{
364 int result = IO_FAIL;
365 assert(is_valid_entity(handle));
366
367 struct io_entity *entity = handle;
368
369 struct io_dev_info *dev = entity->dev_handle;
370
371 if (dev->funcs->close != NULL)
372 result = dev->funcs->close(entity);
373 else {
374 /* Absence of registered function implies NOP here */
375 result = IO_SUCCESS;
376 }
377 /* Ignore improbable free_entity failure */
378 (void)free_entity(entity);
379
380 return result;
381}