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