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