io_storage.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <stddef.h>
  8. #include <platform_def.h>
  9. #include <drivers/io/io_driver.h>
  10. #include <drivers/io/io_storage.h>
  11. /* Storage for a fixed maximum number of IO entities, definable by platform */
  12. static io_entity_t entity_pool[MAX_IO_HANDLES];
  13. /* Simple way of tracking used storage - each entry is NULL or a pointer to an
  14. * entity */
  15. static io_entity_t *entity_map[MAX_IO_HANDLES];
  16. /* Track number of allocated entities */
  17. static unsigned int entity_count;
  18. /* Array of fixed maximum of registered devices, definable by platform */
  19. static const io_dev_info_t *devices[MAX_IO_DEVICES];
  20. /* Number of currently registered devices */
  21. static unsigned int dev_count;
  22. /* Extra validation functions only used when asserts are enabled */
  23. #if ENABLE_ASSERTIONS
  24. /* Return a boolean value indicating whether a device connector is valid */
  25. static bool is_valid_dev_connector(const io_dev_connector_t *dev_con)
  26. {
  27. return (dev_con != NULL) && (dev_con->dev_open != NULL);
  28. }
  29. /* Return a boolean value indicating whether a device handle is valid */
  30. static bool is_valid_dev(const uintptr_t dev_handle)
  31. {
  32. const io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
  33. return (dev != NULL) && (dev->funcs != NULL) &&
  34. (dev->funcs->type != NULL) &&
  35. (dev->funcs->type() < IO_TYPE_MAX);
  36. }
  37. /* Return a boolean value indicating whether an IO entity is valid */
  38. static bool is_valid_entity(const uintptr_t handle)
  39. {
  40. const io_entity_t *entity = (io_entity_t *)handle;
  41. return (entity != NULL) &&
  42. (is_valid_dev((uintptr_t)entity->dev_handle));
  43. }
  44. /* Return a boolean value indicating whether a seek mode is valid */
  45. static bool is_valid_seek_mode(io_seek_mode_t mode)
  46. {
  47. return ((mode != IO_SEEK_INVALID) && (mode < IO_SEEK_MAX));
  48. }
  49. #endif /* ENABLE_ASSERTIONS */
  50. /* End of extra validation functions only used when asserts are enabled */
  51. /* Open a connection to a specific device */
  52. static int io_storage_dev_open(const io_dev_connector_t *dev_con,
  53. const uintptr_t dev_spec,
  54. io_dev_info_t **dev_info)
  55. {
  56. assert(dev_info != NULL);
  57. assert(is_valid_dev_connector(dev_con));
  58. return dev_con->dev_open(dev_spec, dev_info);
  59. }
  60. /* Set a handle to track an entity */
  61. static void set_handle(uintptr_t *handle, io_entity_t *entity)
  62. {
  63. assert(handle != NULL);
  64. *handle = (uintptr_t)entity;
  65. }
  66. /* Locate an entity in the pool, specified by address */
  67. static int find_first_entity(const io_entity_t *entity, unsigned int *index_out)
  68. {
  69. int result = -ENOENT;
  70. for (unsigned int index = 0; index < MAX_IO_HANDLES; ++index) {
  71. if (entity_map[index] == entity) {
  72. result = 0;
  73. *index_out = index;
  74. break;
  75. }
  76. }
  77. return result;
  78. }
  79. /* Allocate an entity from the pool and return a pointer to it */
  80. static int allocate_entity(io_entity_t **entity)
  81. {
  82. int result = -ENOMEM;
  83. assert(entity != NULL);
  84. if (entity_count < MAX_IO_HANDLES) {
  85. unsigned int index = 0;
  86. result = find_first_entity(NULL, &index);
  87. assert(result == 0);
  88. *entity = &entity_pool[index];
  89. entity_map[index] = &entity_pool[index];
  90. ++entity_count;
  91. }
  92. return result;
  93. }
  94. /* Release an entity back to the pool */
  95. static int free_entity(const io_entity_t *entity)
  96. {
  97. int result;
  98. unsigned int index = 0;
  99. assert(entity != NULL);
  100. result = find_first_entity(entity, &index);
  101. if (result == 0) {
  102. entity_map[index] = NULL;
  103. --entity_count;
  104. }
  105. return result;
  106. }
  107. /* Exported API */
  108. /* Register a device driver */
  109. int io_register_device(const io_dev_info_t *dev_info)
  110. {
  111. int result = -ENOMEM;
  112. assert(dev_info != NULL);
  113. if (dev_count < MAX_IO_DEVICES) {
  114. devices[dev_count] = dev_info;
  115. dev_count++;
  116. result = 0;
  117. }
  118. return result;
  119. }
  120. /* Open a connection to an IO device */
  121. int io_dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec,
  122. uintptr_t *handle)
  123. {
  124. assert(handle != NULL);
  125. return io_storage_dev_open(dev_con, dev_spec, (io_dev_info_t **)handle);
  126. }
  127. /* Initialise an IO device explicitly - to permit lazy initialisation or
  128. * re-initialisation */
  129. int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params)
  130. {
  131. int result = 0;
  132. assert(dev_handle != (uintptr_t)NULL);
  133. assert(is_valid_dev(dev_handle));
  134. io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
  135. /* Absence of registered function implies NOP here */
  136. if (dev->funcs->dev_init != NULL) {
  137. result = dev->funcs->dev_init(dev, init_params);
  138. }
  139. return result;
  140. }
  141. /* Close a connection to a device */
  142. int io_dev_close(uintptr_t dev_handle)
  143. {
  144. int result = 0;
  145. assert(dev_handle != (uintptr_t)NULL);
  146. assert(is_valid_dev(dev_handle));
  147. io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
  148. /* Absence of registered function implies NOP here */
  149. if (dev->funcs->dev_close != NULL) {
  150. result = dev->funcs->dev_close(dev);
  151. }
  152. return result;
  153. }
  154. /* Synchronous operations */
  155. /* Open an IO entity */
  156. int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle)
  157. {
  158. int result;
  159. assert((spec != (uintptr_t)NULL) && (handle != NULL));
  160. assert(is_valid_dev(dev_handle));
  161. io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
  162. io_entity_t *entity;
  163. result = allocate_entity(&entity);
  164. if (result == 0) {
  165. assert(dev->funcs->open != NULL);
  166. result = dev->funcs->open(dev, spec, entity);
  167. if (result == 0) {
  168. entity->dev_handle = dev;
  169. set_handle(handle, entity);
  170. } else
  171. free_entity(entity);
  172. }
  173. return result;
  174. }
  175. /* Seek to a specific position in an IO entity */
  176. int io_seek(uintptr_t handle, io_seek_mode_t mode, signed long long offset)
  177. {
  178. int result = -ENODEV;
  179. assert(is_valid_entity(handle) && is_valid_seek_mode(mode));
  180. io_entity_t *entity = (io_entity_t *)handle;
  181. io_dev_info_t *dev = entity->dev_handle;
  182. if (dev->funcs->seek != NULL)
  183. result = dev->funcs->seek(entity, mode, offset);
  184. return result;
  185. }
  186. /* Determine the length of an IO entity */
  187. int io_size(uintptr_t handle, size_t *length)
  188. {
  189. int result = -ENODEV;
  190. assert(is_valid_entity(handle) && (length != NULL));
  191. io_entity_t *entity = (io_entity_t *)handle;
  192. io_dev_info_t *dev = entity->dev_handle;
  193. if (dev->funcs->size != NULL)
  194. result = dev->funcs->size(entity, length);
  195. return result;
  196. }
  197. /* Read data from an IO entity */
  198. int io_read(uintptr_t handle,
  199. uintptr_t buffer,
  200. size_t length,
  201. size_t *length_read)
  202. {
  203. int result = -ENODEV;
  204. assert(is_valid_entity(handle));
  205. io_entity_t *entity = (io_entity_t *)handle;
  206. io_dev_info_t *dev = entity->dev_handle;
  207. if (dev->funcs->read != NULL)
  208. result = dev->funcs->read(entity, buffer, length, length_read);
  209. return result;
  210. }
  211. /* Write data to an IO entity */
  212. int io_write(uintptr_t handle,
  213. const uintptr_t buffer,
  214. size_t length,
  215. size_t *length_written)
  216. {
  217. int result = -ENODEV;
  218. assert(is_valid_entity(handle));
  219. io_entity_t *entity = (io_entity_t *)handle;
  220. io_dev_info_t *dev = entity->dev_handle;
  221. if (dev->funcs->write != NULL) {
  222. result = dev->funcs->write(entity, buffer, length,
  223. length_written);
  224. }
  225. return result;
  226. }
  227. /* Close an IO entity */
  228. int io_close(uintptr_t handle)
  229. {
  230. int result = 0;
  231. assert(is_valid_entity(handle));
  232. io_entity_t *entity = (io_entity_t *)handle;
  233. io_dev_info_t *dev = entity->dev_handle;
  234. /* Absence of registered function implies NOP here */
  235. if (dev->funcs->close != NULL)
  236. result = dev->funcs->close(entity);
  237. /* Ignore improbable free_entity failure */
  238. (void)free_entity(entity);
  239. return result;
  240. }