1 /* 2 * Arm SCP/MCP Software 3 * Copyright (c) 2020-2023, 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 written. 180 * \retval ::FWK_E_BUSY The resource is currently unavailable and it cannot 181 * accept new characters. 182 */ 183 int (*putch)(const struct fwk_io_stream *stream, char ch); 184 185 /*! 186 * \brief Close the stream. 187 * 188 * \details Close the stream, preventing any further operations from 189 * occurring. 190 * 191 * The `stream` parameter is guaranteed to be non-null. 192 * 193 * \note This field may be set to a null pointer value if nothing is 194 * required to close the stream. 195 * 196 * \param[in] stream Stream. 197 * 198 * \return Status code representing the result of the operation. 199 */ 200 int (*close)(const struct fwk_io_stream *stream); 201 }; 202 203 /*! 204 * \brief Input/output stream. 205 * 206 * \details This structure represents the context of a system entity opened 207 * for input/output operations. 208 */ 209 struct fwk_io_stream { 210 /*! 211 * \brief Stream adapter. 212 * 213 * \note This field is set to a null pointer value if the stream has been 214 * closed. 215 */ 216 const struct fwk_io_adapter *adapter; 217 218 /*! 219 * \brief Identifier of the system entity. 220 * 221 * \details This reflects the entity that the stream was opened for, and not 222 * necessarily the owning entity of the stream adapter. For example, if 223 * the stream was opened on a sub-element of module X, while the 224 * adapter would belong to the module, this identifier would represent 225 * the sub-element. 226 */ 227 fwk_id_t id; 228 229 /*! 230 * \brief Access mode that the entity was opened with. 231 * 232 * \details Multiple access modes may be combined, possibly subject to 233 * certain limitations depending on the access mode. An entity may opt 234 * to reject certain modes if it cannot support them. 235 */ 236 enum fwk_io_mode mode; 237 }; 238 239 /*! 240 * \brief Open an entity for input/output operations. 241 * 242 * \details Prepares a system entity for handling input/output operations, in a 243 * similar fashion to the standard library `fopen` function. This function 244 * returns a stream on which input/output operations can be done. 245 * 246 * Whether an entity may be opened more than once is defined by the entity 247 * itself. Unlike the standard library file operations, these operations 248 * are not buffered. 249 * 250 * A system entity may provide an interface for doing input/output 251 * operations by configuring a [stream adapter](::fwk_module::adapter). 252 * 253 * Access modes are defined by the ::fwk_io_mode type, and multiple modes 254 * may be used in combination with one another (certain modes may have 255 * stipulations on which other modes they may be used with). 256 * 257 * \warning Framework text streams do not support wide characters. 258 * 259 * \param[out] stream Input/output stream. 260 * \param[in] id Identifier of the system entity. 261 * \param[in] mode Access mode. 262 * 263 * \return Status code representing the result of the operation. 264 * 265 * \retval ::FWK_SUCCESS The entity was successfully opened. 266 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 267 * - The `stream` parameter was a null pointer value. 268 * - The `id` parameter was not a valid system entity identifier. 269 * - The `mode` parameter was not a valid access mode. 270 * \retval ::FWK_E_SUPPORT The system entity does not support this access mode. 271 * \retval ::FWK_E_HANDLER The `stream` adapter encountered an error. 272 */ 273 int fwk_io_open( 274 struct fwk_io_stream *restrict stream, 275 fwk_id_t id, 276 enum fwk_io_mode mode); 277 278 /*! 279 * \brief Reads a character from a stream. 280 * 281 * \details Reads a character into `ch` from the input stream `stream`, or 282 * returns ::FWK_PENDING if the end of the stream was reached. 283 * 284 * \param[in] stream Stream to read from. 285 * \param[out] ch Storage for the character to read. 286 * 287 * \return Status code representing the result of the operation. 288 * 289 * \retval ::FWK_SUCCESS A character was successfully read. 290 * \retval ::FWK_PENDING The end of the stream was reached. 291 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 292 * - The `stream` parameter was a null pointer value. 293 * - The `ch` parameter was a null pointer value. 294 * \retval ::FWK_E_STATE The `stream` has already been closed. 295 * \retval ::FWK_E_SUPPORT The `stream` was not opened with read access. 296 * \retval ::FWK_E_HANDLER The `stream` adapter encountered an error. 297 */ 298 int fwk_io_getch( 299 const struct fwk_io_stream *restrict stream, 300 char *restrict ch); 301 302 /*! 303 * \brief Write a character to a stream. 304 * 305 * \details Writes a character `ch` to the output stream `stream`. If the driver 306 * is busy, it waits until the resource is freed and available to receive 307 * new characters. 308 * 309 * \param[in] stream Stream to write to. 310 * \param[in] ch Character to write. 311 * 312 * \return Status code representing the result of the operation. 313 * 314 * \retval ::FWK_SUCCESS The character was successfully written. 315 * \retval ::FWK_E_PARAM The `stream` parameter was a null pointer value. 316 * \retval ::FWK_E_STATE The `stream` has already been closed. 317 * \retval ::FWK_E_SUPPORT The `stream` was not opened with write access. 318 * \retval ::FWK_E_HANDLER The `stream` adapter encountered an error. 319 */ 320 int fwk_io_putch(const struct fwk_io_stream *stream, char ch); 321 322 /*! 323 * \brief Write a character to a stream. 324 * 325 * \details Writes a character `ch` to the output stream `stream`. If the driver 326 * is busy `FWK_E_BUSY` will be returned. 327 * 328 * \param[in] stream Stream to write to. 329 * \param[in] ch Character to write. 330 * 331 * \return Status code representing the result of the operation. 332 * 333 * \retval ::FWK_SUCCESS The character was successfully written. 334 * \retval ::FWK_E_BUSY The `stream` resource is currently busy. 335 * \retval ::FWK_E_PARAM The `stream` parameter was a null pointer value. 336 * \retval ::FWK_E_STATE The `stream` has already been closed. 337 * \retval ::FWK_E_SUPPORT The `stream` was not opened with write access. 338 * \retval ::FWK_E_HANDLER The `stream` adapter encountered an error. 339 */ 340 int fwk_io_putch_nowait(const struct fwk_io_stream *stream, char ch); 341 342 /*! 343 * \brief Read data from a stream. 344 * 345 * \details Reads `count` objects into the given array buffer from the input 346 * stream `stream`. The objects are read as if by retrieving a single 347 * `char` `size` times for each object and storing the results in `buffer` 348 * in the order they are read. The `read` parameter is updated with the 349 * number of objects successfully read. 350 * 351 * If the `read` parameter is a null pointer value, the function will 352 * return an ::FWK_E_DATA error if the operation completes successfully but 353 * the number of objects read is less than `count`. This error is not 354 * returned if the `read` parameter is not a null pointer value. 355 * 356 * \param[in] stream Input stream. 357 * \param[out] read Number of objects read. 358 * \param[out] buffer Pointer to the array of uninitialized objects to write to. 359 * \param[in] size Size of each object 360 * \param[in] count Number of objects to read. 361 * 362 * \return Status code representing the result of the operation. 363 * 364 * \retval ::FWK_SUCCESS The read completed successfully. 365 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 366 * - The `stream` parameter was a null pointer value. 367 * - The `buffer` parameter was a null pointer value. 368 * \retval ::FWK_E_STATE The `stream` has already been closed. 369 * \retval ::FWK_E_SUPPORT The `stream` was not opened with read access. 370 * \retval ::FWK_E_DATA The read succeeded but the buffer was not filled. 371 * \retval ::FWK_E_HANDLER The `stream` adapter encountered an error. 372 */ 373 int fwk_io_read( 374 const struct fwk_io_stream *restrict stream, 375 size_t *restrict read, 376 void *restrict buffer, 377 size_t size, 378 size_t count); 379 380 /*! 381 * \brief Write data to a stream. 382 * 383 * \details Writes `count` objects from the given array buffer to the output 384 * stream `stream`. The objects are written as if by reinterpreting each 385 * object as an array of `char` and writing them character by character 386 * `size` times for each object, in order. The `written` parameter is 387 * optional, and may be set to a null pointer value. 388 * 389 * \param[in] stream Output stream. 390 * \param[out] written Number of objects written. 391 * \param[in] buffer Pointer to the first object in the array to be written. 392 * \param[in] size Size of each object. 393 * \param[in] count Number of objects to write. 394 * 395 * \return Status code representing the result of the operation. 396 * 397 * \retval ::FWK_SUCCESS All the objects were successfully written. 398 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 399 * - The `stream` parameter was a null pointer value. 400 * - The `buffer` parameter was a null pointer value. 401 * \retval ::FWK_E_STATE The `stream` has already been closed. 402 * \retval ::FWK_E_SUPPORT The `stream` was not opened with write access. 403 * \retval ::FWK_E_HANDLER The `stream` adapter encountered an error. 404 */ 405 int fwk_io_write( 406 const struct fwk_io_stream *restrict stream, 407 size_t *restrict written, 408 const void *restrict buffer, 409 size_t size, 410 size_t count); 411 412 /*! 413 * \brief Write a string to a stream. 414 * 415 * \details Writes a string, character by character, to an output stream. 416 * 417 * \param[in] stream Stream to write to. 418 * \param[in] str String to write. 419 * 420 * \return Status code representing the result of the operation. 421 * 422 * \retval ::FWK_SUCCESS The string was successfully written. 423 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 424 * - The `stream` parameter was a null pointer value. 425 * - The `str` parameter was a null pointer value. 426 * \retval ::FWK_E_STATE The `stream` has already been closed. 427 * \retval ::FWK_E_SUPPORT The `stream` was not opened with write access. 428 * \retval ::FWK_E_HANDLER The `stream` adapter encountered an error. 429 */ 430 int fwk_io_puts( 431 const struct fwk_io_stream *restrict stream, 432 const char *restrict str); 433 434 /*! 435 * \brief Write a formatted string to a stream. 436 * 437 * \details Writes a string, formatted with the arguments provided as part of 438 * an argument list, to an output stream. This function behaves as if the 439 * call were to directly use the standard library's `vsprintf` function to 440 * create the final string. The string is written to the stream as though 441 * ::fwk_io_write were called with the final string. 442 * 443 * \param[in] stream Stream to write to. 444 * \param[in] format Format string. 445 * \param[in] args Format arguments. 446 * 447 * \return Status code representing the result of the operation. 448 * 449 * \retval ::FWK_SUCCESS The formatted string was successfully written. 450 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 451 * - The `stream` parameter was a null pointer value. 452 * - The `format` parameter was a null pointer value. 453 * \retval ::FWK_E_NOMEM There is not enough memory to format the string. 454 * \retval ::FWK_E_STATE An internal error occurred: 455 * - An error occurred attempting to format the string. 456 * - The `stream` has already been closed. 457 * \retval ::FWK_E_SUPPORT The `stream` was not opened with write access. 458 * \retval ::FWK_E_HANDLER The `stream` adapter encountered an error. 459 */ 460 int fwk_io_vprintf( 461 const struct fwk_io_stream *restrict stream, 462 const char *restrict format, 463 va_list args); 464 465 /*! 466 * \brief Write a formatted string to a stream. 467 * 468 * \details Writes a string, formatted with the given arguments, to an output 469 * stream. This function behaves as if the call were to directly use the 470 * standard library's `sprintf` function to create the final string. The 471 * string is written to the stream as though ::fwk_io_write were called 472 * with the final string. 473 * 474 * \param[in] stream Stream to write to. 475 * \param[in] format Format string. 476 * \param[in] ... 477 * 478 * \return Status code representing the result of the operation. 479 * 480 * \retval ::FWK_SUCCESS The formatted string was successfully written. 481 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 482 * - The `stream` parameter was a null pointer value. 483 * - The `format` parameter was a null pointer value. 484 * \retval ::FWK_E_NOMEM There is not enough memory to format the string. 485 * \retval ::FWK_E_STATE An internal error occurred: 486 * - An error occurred attempting to format the string. 487 * - The `stream` has already been closed. 488 * \retval ::FWK_E_SUPPORT The `stream` was not opened with write access. 489 * \retval ::FWK_E_HANDLER The `stream` adapter encountered an error. 490 */ 491 int fwk_io_printf( 492 const struct fwk_io_stream *restrict stream, 493 const char *restrict format, 494 ...); 495 496 /*! 497 * \brief Close a stream. 498 * 499 * \details Closes the given stream. Whether or not the operation succeeds, the 500 * stream is no longer associated with a system entity. Any operations 501 * using the stream after the stream has been closed will return an error. 502 * Closing an already-closed stream has no effect. 503 * 504 * \param[in] stream Stream to close. 505 * 506 * \return Status code representing the result of the operation. 507 * 508 * \retval ::FWK_SUCCESS The `stream` was successfully closed. 509 * \retval ::FWK_E_PARAM The `stream` parameter was a null pointer value. 510 * \retval ::FWK_E_HANDLER The `stream` adapter encountered an error. 511 */ 512 int fwk_io_close(struct fwk_io_stream *stream); 513 514 /*! 515 * \brief Standard input stream. 516 * 517 * \details This stream represents the standard input stream managed by the 518 * framework. This is an open stream with read permissions to the entity 519 * identified by ::FMW_IO_STDIN_ID, or `NULL` if no identifier is given or 520 * there was an error opening the stream 521 */ 522 extern struct fwk_io_stream *fwk_io_stdin; 523 524 /*! 525 * \brief Standard output stream. 526 * 527 * \details This stream represents the standard output stream managed by the 528 * framework. This is an open stream with write permissions to the entity 529 * identified by ::FMW_IO_STDOUT_ID, or `NULL` if no identifier is given or 530 * there was an error opening the stream. 531 */ 532 extern struct fwk_io_stream *fwk_io_stdout; 533 534 /*! 535 * \internal 536 * 537 * \brief Initialize the input/output component. 538 * 539 * \details Initializes the input/output framework component, including 540 * configuring the standard input and output streams. 541 * 542 * \return Status code representing the result of the operation. 543 */ 544 int fwk_io_init(void); 545 546 /*! 547 * \ 548 */ 549 550 /*! 551 * \} 552 */ 553 554 /*! 555 * \} 556 */ 557 558 #endif /* FWK_IO_H */ 559