1 /* 2 * Arm SCP/MCP Software 3 * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved. 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 8 #ifndef FWK_IO_H 9 #define FWK_IO_H 10 11 #include <fwk_assert.h> 12 #include <fwk_id.h> 13 #include <fwk_macros.h> 14 15 #include <stdarg.h> 16 #include <stddef.h> 17 18 #if FWK_HAS_INCLUDE(<fmw_io.h>) 19 # include <fmw_io.h> 20 #endif 21 22 /*! 23 * \addtogroup GroupLibFramework Framework 24 * \{ 25 */ 26 27 /*! 28 * \defgroup GroupIo Input/Output 29 * 30 * \details This framework component provides low-level input/output facilities 31 * for byte-level read/write operations on streams, where a stream 32 * represents any abstract entity that can accept or return byte data. 33 * 34 * The I/O framework is largely modelled on the C standard library 35 * interfaces provided by `<stdio.h>`, except for the key difference that 36 * the I/O framework does not open files, but system entities. A system 37 * entity can be anything with an associated runtime: a module, an element 38 * or a sub-element. This leaves the precise implementation details of 39 * operating on the stream to the entity. 40 * 41 * The four key interface functions are ::fwk_io_open, ::fwk_io_read, 42 * ::fwk_io_write, and ::fwk_io_close. These functions operate on streams, 43 * which are created by a call to ::fwk_io_open provided with an identifier 44 * of an entity implementing ::fwk_io_adapter. See the individual 45 * documentation for these functions for their usage documentation. 46 * 47 * Creating an I/O-capable entity is a simple process, consisting of 48 * implementing the ::fwk_module::adapter field when creating your module. 49 * See the documentation for the ::fwk_io_adapter structure for more 50 * information. 51 * 52 * The framework component also exposes two default streams opened upon 53 * initialization of the component: ::fwk_io_stdin and ::fwk_io_stdout. 54 * These streams are opened on the entities given by ::FMW_IO_STDIN_ID and 55 * ::FMW_IO_STDOUT_ID. 56 * 57 * \{ 58 */ 59 60 struct fwk_io_stream; 61 62 /*! 63 * \def FMW_IO_STDIN_ID 64 * 65 * \brief Standard input identifier. 66 * 67 * \details This macro defines the identifier of the entity responsible for 68 * handling standard input, similar to `stdin` from the standard library. 69 * It represents the primary source of user input. 70 */ 71 72 #ifndef FMW_IO_STDIN_ID 73 # define FMW_IO_STDIN_ID FWK_ID_NONE 74 #endif 75 76 /*! 77 * \def FMW_IO_STDOUT_ID 78 * 79 * \brief Standard output identifier. 80 * 81 * \details This macro defines the identifier of the entity responsible for 82 * handling standard output, similar to `stdout` from the standard library. 83 * It represents the primary destination for user output. 84 */ 85 86 #ifndef FMW_IO_STDOUT_ID 87 # define FMW_IO_STDOUT_ID FWK_ID_NONE 88 #endif 89 90 /*! 91 * \brief System entity input/output access modes. 92 */ 93 enum fwk_io_mode { 94 /*! 95 * \brief Open the entity for reading. 96 * 97 * \details This flag indicates that the entity should be opened with 98 * reading capabilities. 99 */ 100 FWK_IO_MODE_READ = (1 << 0), 101 102 /*! 103 * \brief Open the entity for writing. 104 * 105 * \details This flag indicates that the stream should be opened with 106 * writing capabilities. 107 */ 108 FWK_IO_MODE_WRITE = (1 << 1), 109 110 /*! 111 * \brief Treat the stream as a binary stream, rather than a text stream. 112 * 113 * \details This flag indicates that the stream should be treated as a 114 * binary data. How the behaviour differs between text and binary modes 115 * is defined by the system entity that owns the stream adapter. 116 */ 117 FWK_IO_MODE_BINARY = (1 << 2), 118 }; 119 120 /*! 121 * \brief Stream adapter. 122 * 123 * \details Stream adapters enable system entities, like modules, elements and 124 * sub-elements, to handle input/output operations in a manner similar to 125 * standard library file streams. 126 */ 127 struct fwk_io_adapter { 128 /*! 129 * \brief Open the entity for input/output operations. 130 * 131 * \details This function is intended to provide an opportunity for the 132 * system entity to configure any contexts or peripherals required for 133 * later input/output operations. 134 * 135 * The `stream` parameter is guaranteed to be non-null. 136 * 137 * \note This field may be set to a null pointer value if it does not need 138 * to do any extra validation or preparation. 139 * 140 * \param[in] stream Stream to open. 141 * 142 * \return Status code representing the result of the operation. 143 * 144 * \retval ::FWK_SUCCESS The stream was successfully opened. 145 */ 146 int (*open)(const struct fwk_io_stream *stream); 147 148 /*! 149 * \brief Read a character from the stream. 150 * 151 * \details Fetch a single character from the stream. The function may 152 * return ::FWK_PENDING to indicate that there are no more characters 153 * to fetch. 154 * 155 * The `stream` and `ch` parameters are guaranteed to be non-null. 156 * 157 * \param[in] stream Stream to read from. 158 * \param[out] ch Character read from the stream. 159 * 160 * \return Status code representing the result of the operation. 161 * 162 * \retval ::FWK_SUCCESS A character was successfully read. 163 * \retval ::FWK_PENDING There are no more characters to read. 164 */ 165 int (*getch)(const struct fwk_io_stream *stream, char *ch); 166 167 /*! 168 * \brief Write a character to the stream. 169 * 170 * \details Write a single character to the stream. 171 * 172 * The `stream` parameter is guaranteed to be non-null. 173 * 174 * \param[in] stream Stream to write to. 175 * \param[in] ch Character to write to the stream. 176 * 177 * \return Status code representing the result of the operation. 178 * 179 * \retval ::FWK_SUCCESS A character was successfully read. 180 */ 181 int (*putch)(const struct fwk_io_stream *stream, char ch); 182 183 /*! 184 * \brief Close the stream. 185 * 186 * \details Close the stream, preventing any further operations from 187 * occurring. 188 * 189 * The `stream` parameter is guaranteed to be non-null. 190 * 191 * \note This field may be set to a null pointer value if nothing is 192 * required to close the stream. 193 * 194 * \param[in] stream Stream. 195 * 196 * \return Status code representing the result of the operation. 197 */ 198 int (*close)(const struct fwk_io_stream *stream); 199 }; 200 201 /*! 202 * \brief Input/output stream. 203 * 204 * \details This structure represents the context of a system entity opened 205 * for input/output operations. 206 */ 207 struct fwk_io_stream { 208 /*! 209 * \brief Stream adapter. 210 * 211 * \note This field is set to a null pointer value if the stream has been 212 * closed. 213 */ 214 const struct fwk_io_adapter *adapter; 215 216 /*! 217 * \brief Identifier of the system entity. 218 * 219 * \details This reflects the entity that the stream was opened for, and not 220 * necessarily the owning entity of the stream adapter. For example, if 221 * the stream was opened on a sub-element of module X, while the 222 * adapter would belong to the module, this identifier would represent 223 * the sub-element. 224 */ 225 fwk_id_t id; 226 227 /*! 228 * \brief Access mode that the entity was opened with. 229 * 230 * \details Multiple access modes may be combined, possibly subject to 231 * certain limitations depending on the access mode. An entity may opt 232 * to reject certain modes if it cannot support them. 233 */ 234 enum fwk_io_mode mode; 235 }; 236 237 /*! 238 * \brief Open an entity for input/output operations. 239 * 240 * \details Prepares a system entity for handling input/output operations, in a 241 * similar fashion to the standard library `fopen` function. This function 242 * returns a stream on which input/output operations can be done. 243 * 244 * Whether an entity may be opened more than once is defined by the entity 245 * itself. Unlike the standard library file operations, these operations 246 * are not buffered. 247 * 248 * A system entity may provide an interface for doing input/output 249 * operations by configuring a [stream adapter](::fwk_module::adapter). 250 * 251 * Access modes are defined by the ::fwk_io_mode type, and multiple modes 252 * may be used in combination with one another (certain modes may have 253 * stipulations on which other modes they may be used with). 254 * 255 * \warning Framework text streams do not support wide characters. 256 * 257 * \param[out] stream Input/output stream. 258 * \param[in] id Identifier of the system entity. 259 * \param[in] mode Access mode. 260 * 261 * \return Status code representing the result of the operation. 262 * 263 * \retval ::FWK_SUCCESS The entity was successfully opened. 264 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 265 * - The `stream` parameter was a null pointer value. 266 * - The `id` parameter was not a valid system entity identifier. 267 * - The `mode` parameter was not a valid access mode. 268 * \retval ::FWK_E_SUPPORT The system entity does not support this access mode. 269 * \retval ::FWK_E_HANDLER The stream adapter encountered an error. 270 */ 271 int fwk_io_open( 272 struct fwk_io_stream *restrict stream, 273 fwk_id_t id, 274 enum fwk_io_mode mode); 275 276 /*! 277 * \brief Reads a character from a stream. 278 * 279 * \details Reads a character into `ch` from the input stream `stream`, or 280 * returns ::FWK_PENDING if the end of the stream was reached. 281 * 282 * \param[in] stream Stream to read from. 283 * \param[out] ch Storage for the character to read. 284 * 285 * \return Status code representing the result of the operation. 286 * 287 * \retval ::FWK_SUCCESS A character was successfully read. 288 * \retval ::FWK_PENDING The end of the stream was reached. 289 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 290 * - The `stream` parameter was a null pointer value. 291 * - The `ch` parameter was a null pointer value. 292 * \retval ::FWK_E_STATE The stream has already been closed. 293 * \retval ::FWK_E_SUPPORT The stream was not opened with read access. 294 * \retval ::FWK_E_HANDLER The stream adapter encountered an error. 295 */ 296 int fwk_io_getch( 297 const struct fwk_io_stream *restrict stream, 298 char *restrict ch); 299 300 /*! 301 * \brief Write a character to a stream. 302 * 303 * \details Writes a character `ch` to the output stream `stream`. 304 * 305 * \param[in] stream Stream to write to. 306 * \param[in] ch Character to write. 307 * 308 * \return Status code representing the result of the operation. 309 * 310 * \retval ::FWK_SUCCESS The character was successfully written. 311 * \retval ::FWK_E_PARAM The `stream` parameter was a null pointer value. 312 * \retval ::FWK_E_STATE The stream has already been closed. 313 * \retval ::FWK_E_SUPPORT The stream was not opened with write access. 314 * \retval ::FWK_E_HANDLER The stream adapter encountered an error. 315 */ 316 int fwk_io_putch(const struct fwk_io_stream *stream, char ch); 317 318 /*! 319 * \brief Read data from a stream. 320 * 321 * \details Reads `count` objects into the given array buffer from the input 322 * stream `stream`. The objects are read as if by retrieving a single 323 * `char` `size` times for each object and storing the results in `buffer` 324 * in the order they are read. The `read` parameter is updated with the 325 * number of objects successfully read. 326 * 327 * If the `read` parameter is a null pointer value, the function will 328 * return an ::FWK_E_DATA error if the operation completes successfully but 329 * the number of objects read is less than `count`. This error is not 330 * returned if the `read` parameter is not a null pointer value. 331 * 332 * \param[in] stream Input stream. 333 * \param[out] read Number of objects read. 334 * \param[out] buffer Pointer to the array of uninitialized objects to write to. 335 * \param[in] size Size of each object 336 * \param[in] count Number of objects to read. 337 * 338 * \return Status code representing the result of the operation. 339 * 340 * \retval ::FWK_SUCCESS The read completed successfully. 341 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 342 * - The `stream` parameter was a null pointer value. 343 * - The `buffer` parameter was a null pointer value. 344 * \retval ::FWK_E_STATE The stream has already been closed. 345 * \retval ::FWK_E_SUPPORT The stream was not opened with read access. 346 * \retval ::FWK_E_DATA The read succeeded but the buffer was not filled. 347 * \retval ::FWK_E_HANDLER The stream adapter encountered an error. 348 */ 349 int fwk_io_read( 350 const struct fwk_io_stream *restrict stream, 351 size_t *restrict read, 352 void *restrict buffer, 353 size_t size, 354 size_t count); 355 356 /*! 357 * \brief Write data to a stream. 358 * 359 * \details Writes `count` objects from the given array buffer to the output 360 * stream `stream`. The objects are written as if by reinterpreting each 361 * object as an array of `char` and writing them character by character 362 * `size` times for each object, in order. The `written` parameter is 363 * optional, and may be set to a null pointer value. 364 * 365 * \param[in] stream Output stream. 366 * \param[out] written Number of objects written. 367 * \param[in] buffer Pointer to the first object in the array to be written. 368 * \param[in] size Size of each object. 369 * \param[in] count Number of objects to write. 370 * 371 * \return Status code representing the result of the operation. 372 * 373 * \retval ::FWK_SUCCESS All the objects were successfully written. 374 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 375 * - The `stream` parameter was a null pointer value. 376 * - The `buffer` parameter was a null pointer value. 377 * \retval ::FWK_E_STATE The stream has already been closed. 378 * \retval ::FWK_E_SUPPORT The stream was not opened with write access. 379 * \retval ::FWK_E_HANDLER The stream adapter encountered an error. 380 */ 381 int fwk_io_write( 382 const struct fwk_io_stream *restrict stream, 383 size_t *restrict written, 384 const void *restrict buffer, 385 size_t size, 386 size_t count); 387 388 /*! 389 * \brief Write a string to a stream. 390 * 391 * \details Writes a string, character by character, to an output stream. 392 * 393 * \param[in] stream Stream to write to. 394 * \param[in] str String to write. 395 * 396 * \return Status code representing the result of the operation. 397 * 398 * \retval ::FWK_SUCCESS The string was successfully written. 399 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 400 * - The `stream` parameter was a null pointer value. 401 * - The `str` parameter was a null pointer value. 402 * \retval ::FWK_E_STATE The stream has already been closed. 403 * \retval ::FWK_E_SUPPORT The stream was not opened with write access. 404 * \retval ::FWK_E_HANDLER The stream adapter encountered an error. 405 */ 406 int fwk_io_puts( 407 const struct fwk_io_stream *restrict stream, 408 const char *restrict str); 409 410 /*! 411 * \brief Write a formatted string to a stream. 412 * 413 * \details Writes a string, formatted with the arguments provided as part of 414 * an argument list, to an output stream. This function behaves as if the 415 * call were to directly use the standard library's `vsprintf` function to 416 * create the final string. The string is written to the stream as though 417 * ::fwk_io_write were called with the final string. 418 * 419 * \param[in] stream Stream to write to. 420 * \param[in] format Format string. 421 * \param[in] args Format arguments. 422 * 423 * \return Status code representing the result of the operation. 424 * 425 * \retval ::FWK_SUCCESS The formatted string was successfully written. 426 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 427 * - The `stream` parameter was a null pointer value. 428 * - The `format` parameter was a null pointer value. 429 * \retval ::FWK_E_NOMEM There is not enough memory to format the string. 430 * \retval ::FWK_E_STATE An internal error occurred: 431 * - An error occurred attempting to format the string. 432 * - The stream has already been closed. 433 * \retval ::FWK_E_SUPPORT The stream was not opened with write access. 434 * \retval ::FWK_E_HANDLER The stream adapter encountered an error. 435 */ 436 int fwk_io_vprintf( 437 const struct fwk_io_stream *restrict stream, 438 const char *restrict format, 439 va_list args); 440 441 /*! 442 * \brief Write a formatted string to a stream. 443 * 444 * \details Writes a string, formatted with the given arguments, to an output 445 * stream. This function behaves as if the call were to directly use the 446 * standard library's `sprintf` function to create the final string. The 447 * string is written to the stream as though ::fwk_io_write were called 448 * with the final string. 449 * 450 * \param[in] stream Stream to write to. 451 * \param[in] format Format string. 452 * \param[in] ... 453 * 454 * \return Status code representing the result of the operation. 455 * 456 * \retval ::FWK_SUCCESS The formatted string was successfully written. 457 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 458 * - The `stream` parameter was a null pointer value. 459 * - The `format` parameter was a null pointer value. 460 * \retval ::FWK_E_NOMEM There is not enough memory to format the string. 461 * \retval ::FWK_E_STATE An internal error occurred: 462 * - An error occurred attempting to format the string. 463 * - The stream has already been closed. 464 * \retval ::FWK_E_SUPPORT The stream was not opened with write access. 465 * \retval ::FWK_E_HANDLER The stream adapter encountered an error. 466 */ 467 int fwk_io_printf( 468 const struct fwk_io_stream *restrict stream, 469 const char *restrict format, 470 ...); 471 472 /*! 473 * \brief Close a stream. 474 * 475 * \details Closes the given stream. Whether or not the operation succeeds, the 476 * stream is no longer associated with a system entity. Any operations 477 * using the stream after the stream has been closed will return an error. 478 * Closing an already-closed stream has no effect. 479 * 480 * \param[in] stream Stream to close. 481 * 482 * \return Status code representing the result of the operation. 483 * 484 * \retval ::FWK_SUCCESS The stream was successfully closed. 485 * \retval ::FWK_E_PARAM The `stream` parameter was a null pointer value. 486 * \retval ::FWK_E_HANDLER The stream adapter encountered an error. 487 */ 488 int fwk_io_close(struct fwk_io_stream *stream); 489 490 /*! 491 * \brief Standard input stream. 492 * 493 * \details This stream represents the standard input stream managed by the 494 * framework. This is an open stream with read permissions to the entity 495 * identified by ::FMW_IO_STDIN_ID, or `NULL` if no identifier is given or 496 * there was an error opening the stream 497 */ 498 extern struct fwk_io_stream *fwk_io_stdin; 499 500 /*! 501 * \brief Standard output stream. 502 * 503 * \details This stream represents the standard output stream managed by the 504 * framework. This is an open stream with write permissions to the entity 505 * identified by ::FMW_IO_STDOUT_ID, or `NULL` if no identifier is given or 506 * there was an error opening the stream. 507 */ 508 extern struct fwk_io_stream *fwk_io_stdout; 509 510 /*! 511 * \internal 512 * 513 * \brief Initialize the input/output component. 514 * 515 * \details Initializes the input/output framework component, including 516 * configuring the standard input and output streams. 517 * 518 * \return Status code representing the result of the operation. 519 */ 520 int fwk_io_init(void); 521 522 /*! 523 * \ 524 */ 525 526 /*! 527 * \} 528 */ 529 530 /*! 531 * \} 532 */ 533 534 #endif /* FWK_IO_H */ 535