191b48c9fSJulius Werner /*
203bd4810SYann Gautier * Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved.
391b48c9fSJulius Werner *
491b48c9fSJulius Werner * SPDX-License-Identifier: BSD-3-Clause
591b48c9fSJulius Werner */
691b48c9fSJulius Werner
791b48c9fSJulius Werner #include <assert.h>
8885e2683SClaus Pedersen #include <stddef.h>
9e0b6826eSClaus Pedersen #include <stdlib.h>
1009d40e0eSAntonio Nino Diaz
1191b48c9fSJulius Werner #include <drivers/console.h>
1291b48c9fSJulius Werner
1391b48c9fSJulius Werner console_t *console_list;
1451df71c3SMaheedhar Bollapalli static uint32_t console_state = CONSOLE_FLAG_BOOT;
1591b48c9fSJulius Werner
IMPORT_SYM(console_t *,__STACKS_START__,stacks_start)1691b48c9fSJulius Werner IMPORT_SYM(console_t *, __STACKS_START__, stacks_start)
1791b48c9fSJulius Werner IMPORT_SYM(console_t *, __STACKS_END__, stacks_end)
1891b48c9fSJulius Werner
19bde2836fSAmbroise Vincent int console_register(console_t *console)
20bde2836fSAmbroise Vincent {
2191b48c9fSJulius Werner /* Assert that the struct is not on the stack (common mistake). */
2291b48c9fSJulius Werner assert((console < stacks_start) || (console >= stacks_end));
2371892ca3SAmbroise Vincent
2471892ca3SAmbroise Vincent /* Check that we won't make a circle in the list. */
259ded5e8dSMaheedhar Bollapalli if (console_is_registered(console) == 1) {
2671892ca3SAmbroise Vincent return 1;
279ded5e8dSMaheedhar Bollapalli }
2891b48c9fSJulius Werner
2991b48c9fSJulius Werner console->next = console_list;
3091b48c9fSJulius Werner console_list = console;
3191b48c9fSJulius Werner
3291b48c9fSJulius Werner /* Return 1 for convenient tail-calling from console_xxx_register(). */
3391b48c9fSJulius Werner return 1;
3491b48c9fSJulius Werner }
3591b48c9fSJulius Werner
console_unregister(console_t * to_be_deleted)3691b48c9fSJulius Werner console_t *console_unregister(console_t *to_be_deleted)
3791b48c9fSJulius Werner {
3891b48c9fSJulius Werner console_t **ptr;
3991b48c9fSJulius Werner
4091b48c9fSJulius Werner assert(to_be_deleted != NULL);
4191b48c9fSJulius Werner
42*efea4aecSSaivardhan Thatikonda for (ptr = &console_list; *ptr != NULL; ptr = &(*ptr)->next) {
4391b48c9fSJulius Werner if (*ptr == to_be_deleted) {
4491b48c9fSJulius Werner *ptr = (*ptr)->next;
4591b48c9fSJulius Werner return to_be_deleted;
4691b48c9fSJulius Werner }
47*efea4aecSSaivardhan Thatikonda }
4891b48c9fSJulius Werner
4991b48c9fSJulius Werner return NULL;
5091b48c9fSJulius Werner }
5191b48c9fSJulius Werner
console_is_registered(console_t * to_find)5291b48c9fSJulius Werner int console_is_registered(console_t *to_find)
5391b48c9fSJulius Werner {
5491b48c9fSJulius Werner console_t *console;
5591b48c9fSJulius Werner
5691b48c9fSJulius Werner assert(to_find != NULL);
5791b48c9fSJulius Werner
589ded5e8dSMaheedhar Bollapalli for (console = console_list; console != NULL; console = console->next) {
599ded5e8dSMaheedhar Bollapalli if (console == to_find) {
6091b48c9fSJulius Werner return 1;
619ded5e8dSMaheedhar Bollapalli }
629ded5e8dSMaheedhar Bollapalli }
6391b48c9fSJulius Werner
6491b48c9fSJulius Werner return 0;
6591b48c9fSJulius Werner }
6691b48c9fSJulius Werner
console_switch_state(unsigned int new_state)6791b48c9fSJulius Werner void console_switch_state(unsigned int new_state)
6891b48c9fSJulius Werner {
6991b48c9fSJulius Werner console_state = new_state;
7091b48c9fSJulius Werner }
7191b48c9fSJulius Werner
console_set_scope(console_t * console,unsigned int scope)7291b48c9fSJulius Werner void console_set_scope(console_t *console, unsigned int scope)
7391b48c9fSJulius Werner {
7491b48c9fSJulius Werner assert(console != NULL);
7591b48c9fSJulius Werner
7691b48c9fSJulius Werner console->flags = (console->flags & ~CONSOLE_FLAG_SCOPE_MASK) | scope;
7791b48c9fSJulius Werner }
7891b48c9fSJulius Werner
do_putc(int c,console_t * console)79f51df475SMasahiro Yamada static int do_putc(int c, console_t *console)
80f51df475SMasahiro Yamada {
81f51df475SMasahiro Yamada int ret;
82f51df475SMasahiro Yamada
8397eefd99SNithin G if ((c == (int)'\n') &&
8497eefd99SNithin G ((console->flags & CONSOLE_FLAG_TRANSLATE_CRLF) != 0U)) {
85f51df475SMasahiro Yamada ret = console->putc('\r', console);
86f51df475SMasahiro Yamada if (ret < 0)
87f51df475SMasahiro Yamada return ret;
88f51df475SMasahiro Yamada }
89f51df475SMasahiro Yamada
90f51df475SMasahiro Yamada return console->putc(c, console);
91f51df475SMasahiro Yamada }
92f51df475SMasahiro Yamada
console_putc(int c)9391b48c9fSJulius Werner int console_putc(int c)
9491b48c9fSJulius Werner {
9591b48c9fSJulius Werner int err = ERROR_NO_VALID_CONSOLE;
9691b48c9fSJulius Werner console_t *console;
9791b48c9fSJulius Werner
989ded5e8dSMaheedhar Bollapalli for (console = console_list; console != NULL; console = console->next) {
995bbe4fdfSMaheedhar Bollapalli if (((console->flags & console_state) != 0U) && (console->putc != NULL)) {
100f51df475SMasahiro Yamada int ret = do_putc(c, console);
1019ded5e8dSMaheedhar Bollapalli if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err)) {
10291b48c9fSJulius Werner err = ret;
10391b48c9fSJulius Werner }
1049ded5e8dSMaheedhar Bollapalli }
1059ded5e8dSMaheedhar Bollapalli }
10691b48c9fSJulius Werner return err;
10791b48c9fSJulius Werner }
10891b48c9fSJulius Werner
putchar(int c)109e0b6826eSClaus Pedersen int putchar(int c)
110e0b6826eSClaus Pedersen {
1119ded5e8dSMaheedhar Bollapalli if (console_putc(c) == 0) {
112e0b6826eSClaus Pedersen return c;
1139ded5e8dSMaheedhar Bollapalli } else {
114e0b6826eSClaus Pedersen return EOF;
115e0b6826eSClaus Pedersen }
1169ded5e8dSMaheedhar Bollapalli }
117e0b6826eSClaus Pedersen
11885bebe18SSandrine Bailleux #if ENABLE_CONSOLE_GETC
console_getc(void)11991b48c9fSJulius Werner int console_getc(void)
12091b48c9fSJulius Werner {
12191b48c9fSJulius Werner int err = ERROR_NO_VALID_CONSOLE;
12291b48c9fSJulius Werner console_t *console;
12391b48c9fSJulius Werner
12491b48c9fSJulius Werner do { /* Keep polling while at least one console works correctly. */
12591b48c9fSJulius Werner for (console = console_list; console != NULL;
12691b48c9fSJulius Werner console = console->next)
1275bbe4fdfSMaheedhar Bollapalli if (((console->flags & console_state) != 0U) && (console->getc != NULL)) {
12891b48c9fSJulius Werner int ret = console->getc(console);
1299ded5e8dSMaheedhar Bollapalli if (ret >= 0) {
13091b48c9fSJulius Werner return ret;
1319ded5e8dSMaheedhar Bollapalli }
1329ded5e8dSMaheedhar Bollapalli if (err != ERROR_NO_PENDING_CHAR) {
13391b48c9fSJulius Werner err = ret;
13491b48c9fSJulius Werner }
1359ded5e8dSMaheedhar Bollapalli }
13691b48c9fSJulius Werner } while (err == ERROR_NO_PENDING_CHAR);
13791b48c9fSJulius Werner
13891b48c9fSJulius Werner return err;
13991b48c9fSJulius Werner }
14085bebe18SSandrine Bailleux #endif
14191b48c9fSJulius Werner
console_flush(void)142831b0e98SJimmy Brisson void console_flush(void)
14391b48c9fSJulius Werner {
14491b48c9fSJulius Werner console_t *console;
14591b48c9fSJulius Werner
14691b48c9fSJulius Werner for (console = console_list; console != NULL; console = console->next)
1475bbe4fdfSMaheedhar Bollapalli if (((console->flags & console_state) != 0U) && (console->flush != NULL)) {
148831b0e98SJimmy Brisson console->flush(console);
14991b48c9fSJulius Werner }
15091b48c9fSJulius Werner }
151