xref: /rk3399_ARM-atf/drivers/console/multi_console.c (revision 04cf04c72d403e0c057505882fac9002d39d4102)
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 
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 
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 
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 
67 void console_switch_state(unsigned int new_state)
68 {
69 	console_state = new_state;
70 }
71 
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 
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 
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 
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
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 
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