1 /*
2 * Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <stddef.h>
9 #include <stdlib.h>
10
11 #include <drivers/console.h>
12
13 console_t *console_list;
14 static uint32_t console_state = CONSOLE_FLAG_BOOT;
15
IMPORT_SYM(console_t *,__STACKS_START__,stacks_start)16 IMPORT_SYM(console_t *, __STACKS_START__, stacks_start)
17 IMPORT_SYM(console_t *, __STACKS_END__, stacks_end)
18
19 int console_register(console_t *console)
20 {
21 /* Assert that the struct is not on the stack (common mistake). */
22 assert((console < stacks_start) || (console >= stacks_end));
23
24 /* Check that we won't make a circle in the list. */
25 if (console_is_registered(console) == 1) {
26 return 1;
27 }
28
29 console->next = console_list;
30 console_list = console;
31
32 /* Return 1 for convenient tail-calling from console_xxx_register(). */
33 return 1;
34 }
35
console_unregister(console_t * to_be_deleted)36 console_t *console_unregister(console_t *to_be_deleted)
37 {
38 console_t **ptr;
39
40 assert(to_be_deleted != NULL);
41
42 for (ptr = &console_list; *ptr != NULL; ptr = &(*ptr)->next) {
43 if (*ptr == to_be_deleted) {
44 *ptr = (*ptr)->next;
45 return to_be_deleted;
46 }
47 }
48
49 return NULL;
50 }
51
console_is_registered(console_t * to_find)52 int console_is_registered(console_t *to_find)
53 {
54 console_t *console;
55
56 assert(to_find != NULL);
57
58 for (console = console_list; console != NULL; console = console->next) {
59 if (console == to_find) {
60 return 1;
61 }
62 }
63
64 return 0;
65 }
66
console_switch_state(unsigned int new_state)67 void console_switch_state(unsigned int new_state)
68 {
69 console_state = new_state;
70 }
71
console_set_scope(console_t * console,unsigned int scope)72 void console_set_scope(console_t *console, unsigned int scope)
73 {
74 assert(console != NULL);
75
76 console->flags = (console->flags & ~CONSOLE_FLAG_SCOPE_MASK) | scope;
77 }
78
do_putc(int c,console_t * console)79 static int do_putc(int c, console_t *console)
80 {
81 int ret;
82
83 if ((c == (int)'\n') &&
84 ((console->flags & CONSOLE_FLAG_TRANSLATE_CRLF) != 0U)) {
85 ret = console->putc('\r', console);
86 if (ret < 0)
87 return ret;
88 }
89
90 return console->putc(c, console);
91 }
92
console_putc(int c)93 int console_putc(int c)
94 {
95 int err = ERROR_NO_VALID_CONSOLE;
96 console_t *console;
97
98 for (console = console_list; console != NULL; console = console->next) {
99 if (((console->flags & console_state) != 0U) && (console->putc != NULL)) {
100 int ret = do_putc(c, console);
101 if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err)) {
102 err = ret;
103 }
104 }
105 }
106 return err;
107 }
108
putchar(int c)109 int putchar(int c)
110 {
111 if (console_putc(c) == 0) {
112 return c;
113 } else {
114 return EOF;
115 }
116 }
117
118 #if ENABLE_CONSOLE_GETC
console_getc(void)119 int console_getc(void)
120 {
121 int err = ERROR_NO_VALID_CONSOLE;
122 console_t *console;
123
124 do { /* Keep polling while at least one console works correctly. */
125 for (console = console_list; console != NULL;
126 console = console->next)
127 if (((console->flags & console_state) != 0U) && (console->getc != NULL)) {
128 int ret = console->getc(console);
129 if (ret >= 0) {
130 return ret;
131 }
132 if (err != ERROR_NO_PENDING_CHAR) {
133 err = ret;
134 }
135 }
136 } while (err == ERROR_NO_PENDING_CHAR);
137
138 return err;
139 }
140 #endif
141
console_flush(void)142 void console_flush(void)
143 {
144 console_t *console;
145
146 for (console = console_list; console != NULL; console = console->next)
147 if (((console->flags & console_state) != 0U) && (console->flush != NULL)) {
148 console->flush(console);
149 }
150 }
151