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