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 uint8_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 console->next = console_list;
29 console_list = console;
30
31 /* Return 1 for convenient tail-calling from console_xxx_register(). */
32 return 1;
33 }
34
console_unregister(console_t * to_be_deleted)35 console_t *console_unregister(console_t *to_be_deleted)
36 {
37 console_t **ptr;
38
39 assert(to_be_deleted != NULL);
40
41 for (ptr = &console_list; *ptr != NULL; ptr = &(*ptr)->next)
42 if (*ptr == to_be_deleted) {
43 *ptr = (*ptr)->next;
44 return to_be_deleted;
45 }
46
47 return NULL;
48 }
49
console_is_registered(console_t * to_find)50 int console_is_registered(console_t *to_find)
51 {
52 console_t *console;
53
54 assert(to_find != NULL);
55
56 for (console = console_list; console != NULL; console = console->next)
57 if (console == to_find)
58 return 1;
59
60 return 0;
61 }
62
console_switch_state(unsigned int new_state)63 void console_switch_state(unsigned int new_state)
64 {
65 console_state = new_state;
66 }
67
console_set_scope(console_t * console,unsigned int scope)68 void console_set_scope(console_t *console, unsigned int scope)
69 {
70 assert(console != NULL);
71
72 console->flags = (console->flags & ~CONSOLE_FLAG_SCOPE_MASK) | scope;
73 }
74
do_putc(int c,console_t * console)75 static int do_putc(int c, console_t *console)
76 {
77 int ret;
78
79 if ((c == '\n') &&
80 ((console->flags & CONSOLE_FLAG_TRANSLATE_CRLF) != 0)) {
81 ret = console->putc('\r', console);
82 if (ret < 0)
83 return ret;
84 }
85
86 return console->putc(c, console);
87 }
88
console_putc(int c)89 int console_putc(int c)
90 {
91 int err = ERROR_NO_VALID_CONSOLE;
92 console_t *console;
93
94 for (console = console_list; console != NULL; console = console->next)
95 if ((console->flags & console_state) && (console->putc != NULL)) {
96 int ret = do_putc(c, console);
97 if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err))
98 err = ret;
99 }
100 return err;
101 }
102
putchar(int c)103 int putchar(int c)
104 {
105 if (console_putc(c) == 0)
106 return c;
107 else
108 return EOF;
109 }
110
111 #if ENABLE_CONSOLE_GETC
console_getc(void)112 int console_getc(void)
113 {
114 int err = ERROR_NO_VALID_CONSOLE;
115 console_t *console;
116
117 do { /* Keep polling while at least one console works correctly. */
118 for (console = console_list; console != NULL;
119 console = console->next)
120 if ((console->flags & console_state) && (console->getc != NULL)) {
121 int ret = console->getc(console);
122 if (ret >= 0)
123 return ret;
124 if (err != ERROR_NO_PENDING_CHAR)
125 err = ret;
126 }
127 } while (err == ERROR_NO_PENDING_CHAR);
128
129 return err;
130 }
131 #endif
132
console_flush(void)133 void console_flush(void)
134 {
135 console_t *console;
136
137 for (console = console_list; console != NULL; console = console->next)
138 if ((console->flags & console_state) && (console->flush != NULL)) {
139 console->flush(console);
140 }
141 }
142