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