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