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 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 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 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 6791b48c9fSJulius Werner void console_switch_state(unsigned int new_state) 6891b48c9fSJulius Werner { 6991b48c9fSJulius Werner console_state = new_state; 7091b48c9fSJulius Werner } 7191b48c9fSJulius Werner 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 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 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 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 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 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