xref: /rk3399_ARM-atf/drivers/console/multi_console.c (revision 2d3b44e3073e8d6ec49dde45ec353d6f41290917)
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 
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 	return NULL;
49 }
50 
51 int console_is_registered(console_t *to_find)
52 {
53 	console_t *console;
54 
55 	assert(to_find != NULL);
56 
57 	for (console = console_list; console != NULL; console = console->next) {
58 		if (console == to_find) {
59 			return 1;
60 		}
61 	}
62 
63 	return 0;
64 }
65 
66 void console_switch_state(unsigned int new_state)
67 {
68 	console_state = new_state;
69 }
70 
71 void console_set_scope(console_t *console, unsigned int scope)
72 {
73 	assert(console != NULL);
74 
75 	console->flags = (console->flags & ~CONSOLE_FLAG_SCOPE_MASK) | scope;
76 }
77 
78 static int do_putc(int c, console_t *console)
79 {
80 	int ret;
81 
82 	if ((c == (int)'\n') &&
83 	    ((console->flags & CONSOLE_FLAG_TRANSLATE_CRLF) != 0U)) {
84 		ret = console->putc('\r', console);
85 		if (ret < 0)
86 			return ret;
87 	}
88 
89 	return console->putc(c, console);
90 }
91 
92 int console_putc(int c)
93 {
94 	int err = ERROR_NO_VALID_CONSOLE;
95 	console_t *console;
96 
97 	for (console = console_list; console != NULL; console = console->next) {
98 		if ((console->flags & console_state) && (console->putc != NULL)) {
99 			int ret = do_putc(c, console);
100 			if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err)) {
101 				err = ret;
102 			}
103 		}
104 	}
105 	return err;
106 }
107 
108 int putchar(int c)
109 {
110 	if (console_putc(c) == 0) {
111 		return c;
112 	} else {
113 		return EOF;
114 	}
115 }
116 
117 #if ENABLE_CONSOLE_GETC
118 int console_getc(void)
119 {
120 	int err = ERROR_NO_VALID_CONSOLE;
121 	console_t *console;
122 
123 	do {	/* Keep polling while at least one console works correctly. */
124 		for (console = console_list; console != NULL;
125 		     console = console->next)
126 			if ((console->flags & console_state) && (console->getc != NULL)) {
127 				int ret = console->getc(console);
128 				if (ret >= 0) {
129 					return ret;
130 				}
131 				if (err != ERROR_NO_PENDING_CHAR) {
132 					err = ret;
133 				}
134 			}
135 	} while (err == ERROR_NO_PENDING_CHAR);
136 
137 	return err;
138 }
139 #endif
140 
141 void console_flush(void)
142 {
143 	console_t *console;
144 
145 	for (console = console_list; console != NULL; console = console->next)
146 		if ((console->flags & console_state) && (console->flush != NULL)) {
147 			console->flush(console);
148 		}
149 }
150