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 uint8_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 return NULL; 49 } 50 51 int console_is_registered(console_t *to_find) 52 { 53 console_t *console; 54 55 assert(to_find != NULL); 56 57 for (console = console_list; console != NULL; console = console->next) { 58 if (console == to_find) { 59 return 1; 60 } 61 } 62 63 return 0; 64 } 65 66 void console_switch_state(unsigned int new_state) 67 { 68 console_state = new_state; 69 } 70 71 void console_set_scope(console_t *console, unsigned int scope) 72 { 73 assert(console != NULL); 74 75 console->flags = (console->flags & ~CONSOLE_FLAG_SCOPE_MASK) | scope; 76 } 77 78 static int do_putc(int c, console_t *console) 79 { 80 int ret; 81 82 if ((c == '\n') && 83 ((console->flags & CONSOLE_FLAG_TRANSLATE_CRLF) != 0)) { 84 ret = console->putc('\r', console); 85 if (ret < 0) 86 return ret; 87 } 88 89 return console->putc(c, console); 90 } 91 92 int console_putc(int c) 93 { 94 int err = ERROR_NO_VALID_CONSOLE; 95 console_t *console; 96 97 for (console = console_list; console != NULL; console = console->next) { 98 if ((console->flags & console_state) && (console->putc != NULL)) { 99 int ret = do_putc(c, console); 100 if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err)) { 101 err = ret; 102 } 103 } 104 } 105 return err; 106 } 107 108 int putchar(int c) 109 { 110 if (console_putc(c) == 0) { 111 return c; 112 } else { 113 return EOF; 114 } 115 } 116 117 #if ENABLE_CONSOLE_GETC 118 int console_getc(void) 119 { 120 int err = ERROR_NO_VALID_CONSOLE; 121 console_t *console; 122 123 do { /* Keep polling while at least one console works correctly. */ 124 for (console = console_list; console != NULL; 125 console = console->next) 126 if ((console->flags & console_state) && (console->getc != NULL)) { 127 int ret = console->getc(console); 128 if (ret >= 0) { 129 return ret; 130 } 131 if (err != ERROR_NO_PENDING_CHAR) { 132 err = ret; 133 } 134 } 135 } while (err == ERROR_NO_PENDING_CHAR); 136 137 return err; 138 } 139 #endif 140 141 void console_flush(void) 142 { 143 console_t *console; 144 145 for (console = console_list; console != NULL; console = console->next) 146 if ((console->flags & console_state) && (console->flush != NULL)) { 147 console->flush(console); 148 } 149 } 150