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