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