1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <mod_stdio.h>
9 
10 #include <fwk_id.h>
11 #include <fwk_mm.h>
12 #include <fwk_module.h>
13 #include <fwk_module_idx.h>
14 #include <fwk_status.h>
15 
16 #include <stddef.h>
17 
18 struct mod_stdio_element_ctx {
19     FILE *stream;
20 };
21 
22 static struct {
23     bool initialized;
24 
25     struct mod_stdio_element_ctx *elements;
26 } mod_stdio_ctx = {
27     .initialized = false,
28 };
29 
mod_stdio_init_ctx(void)30 static int mod_stdio_init_ctx(void)
31 {
32     size_t element_count = fwk_module_get_element_count(fwk_module_id_stdio);
33 
34     mod_stdio_ctx.elements =
35         fwk_mm_calloc(element_count, sizeof(*mod_stdio_ctx.elements));
36     if (mod_stdio_ctx.elements == NULL)
37         return FWK_E_NOMEM;
38 
39     mod_stdio_ctx.initialized = true;
40 
41     return FWK_SUCCESS;
42 }
43 
mod_stdio_init(fwk_id_t module_id,unsigned int element_count,const void * specific_config)44 static int mod_stdio_init(
45     fwk_id_t module_id,
46     unsigned int element_count,
47     const void *specific_config)
48 {
49     if (!mod_stdio_ctx.initialized)
50         return mod_stdio_init_ctx();
51 
52     return FWK_SUCCESS;
53 }
54 
mod_stdio_element_init(fwk_id_t element_id,unsigned int unused,const void * data)55 static int mod_stdio_element_init(
56     fwk_id_t element_id,
57     unsigned int unused,
58     const void *data)
59 {
60     return FWK_SUCCESS;
61 }
62 
mod_stdio_open(const struct fwk_io_stream * stream)63 static int mod_stdio_open(const struct fwk_io_stream *stream)
64 {
65     int status = FWK_SUCCESS;
66 
67     const struct mod_stdio_element_cfg *cfg;
68     struct mod_stdio_element_ctx *ctx;
69 
70     unsigned int element_idx;
71 
72     if (!fwk_id_is_type(stream->id, FWK_ID_TYPE_ELEMENT))
73         return FWK_E_SUPPORT;
74 
75     if (!mod_stdio_ctx.initialized) {
76         status = mod_stdio_init_ctx();
77         if (status != FWK_SUCCESS)
78             return status;
79     }
80 
81     element_idx = fwk_id_get_element_idx(stream->id);
82 
83     cfg = fwk_module_get_data(stream->id);
84     ctx = &mod_stdio_ctx.elements[element_idx];
85 
86     if (cfg->type == MOD_STDIO_ELEMENT_TYPE_PATH) {
87         ctx->stream = fopen(cfg->file.path, cfg->file.mode);
88         if (ctx->stream == NULL)
89             status = FWK_E_OS;
90     } else {
91         ctx->stream = cfg->stream;
92     }
93 
94     return status;
95 }
96 
mod_stdio_getc(const struct fwk_io_stream * stream,char * ch)97 static int mod_stdio_getc(const struct fwk_io_stream *stream, char *ch)
98 {
99     struct mod_stdio_element_ctx *ctx =
100         &mod_stdio_ctx.elements[fwk_id_get_element_idx(stream->id)];
101 
102     int ich = fgetc(ctx->stream);
103 
104     *ch = (char)ich;
105 
106     if (ferror(ctx->stream))
107         return FWK_E_OS;
108     else if (feof(ctx->stream))
109         return FWK_PENDING;
110 
111     return FWK_SUCCESS;
112 }
113 
mod_stdio_putc(const struct fwk_io_stream * stream,char ch)114 static int mod_stdio_putc(const struct fwk_io_stream *stream, char ch)
115 {
116     struct mod_stdio_element_ctx *ctx =
117         &mod_stdio_ctx.elements[fwk_id_get_element_idx(stream->id)];
118 
119     fputc(ch, ctx->stream);
120 
121     if (ferror(ctx->stream))
122         return FWK_E_OS;
123 
124     return FWK_SUCCESS;
125 }
126 
mod_stdio_close(const struct fwk_io_stream * stream)127 static int mod_stdio_close(const struct fwk_io_stream *stream)
128 {
129     int status = FWK_SUCCESS;
130 
131     const struct mod_stdio_element_cfg *cfg;
132     struct mod_stdio_element_ctx *ctx;
133 
134     unsigned int element_idx;
135 
136     element_idx = fwk_id_get_element_idx(stream->id);
137 
138     cfg = fwk_module_get_data(stream->id);
139     ctx = &mod_stdio_ctx.elements[element_idx];
140 
141     if (cfg->type == MOD_STDIO_ELEMENT_TYPE_PATH)
142         status = (fclose(ctx->stream) == 0) ? FWK_SUCCESS : FWK_E_OS;
143 
144     return status;
145 }
146 
147 const struct fwk_module module_stdio = {
148     .type = FWK_MODULE_TYPE_DRIVER,
149 
150     .init = mod_stdio_init,
151     .element_init = mod_stdio_element_init,
152 
153     .adapter = {
154         .open = mod_stdio_open,
155         .getch = mod_stdio_getc,
156         .putch = mod_stdio_putc,
157         .close = mod_stdio_close,
158     },
159 };
160