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