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 console->next = console_list; 29 console_list = console; 30 31 /* Return 1 for convenient tail-calling from console_xxx_register(). */ 32 return 1; 33 } 34 35 console_t *console_unregister(console_t *to_be_deleted) 36 { 37 console_t **ptr; 38 39 assert(to_be_deleted != NULL); 40 41 for (ptr = &console_list; *ptr != NULL; ptr = &(*ptr)->next) 42 if (*ptr == to_be_deleted) { 43 *ptr = (*ptr)->next; 44 return to_be_deleted; 45 } 46 47 return NULL; 48 } 49 50 int console_is_registered(console_t *to_find) 51 { 52 console_t *console; 53 54 assert(to_find != NULL); 55 56 for (console = console_list; console != NULL; console = console->next) 57 if (console == to_find) 58 return 1; 59 60 return 0; 61 } 62 63 void console_switch_state(unsigned int new_state) 64 { 65 console_state = new_state; 66 } 67 68 void console_set_scope(console_t *console, unsigned int scope) 69 { 70 assert(console != NULL); 71 72 console->flags = (console->flags & ~CONSOLE_FLAG_SCOPE_MASK) | scope; 73 } 74 75 static int do_putc(int c, console_t *console) 76 { 77 int ret; 78 79 if ((c == '\n') && 80 ((console->flags & CONSOLE_FLAG_TRANSLATE_CRLF) != 0)) { 81 ret = console->putc('\r', console); 82 if (ret < 0) 83 return ret; 84 } 85 86 return console->putc(c, console); 87 } 88 89 int console_putc(int c) 90 { 91 int err = ERROR_NO_VALID_CONSOLE; 92 console_t *console; 93 94 for (console = console_list; console != NULL; console = console->next) 95 if ((console->flags & console_state) && (console->putc != NULL)) { 96 int ret = do_putc(c, console); 97 if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err)) 98 err = ret; 99 } 100 return err; 101 } 102 103 int putchar(int c) 104 { 105 if (console_putc(c) == 0) 106 return c; 107 else 108 return EOF; 109 } 110 111 int console_getc(void) 112 { 113 int err = ERROR_NO_VALID_CONSOLE; 114 console_t *console; 115 116 do { /* Keep polling while at least one console works correctly. */ 117 for (console = console_list; console != NULL; 118 console = console->next) 119 if ((console->flags & console_state) && (console->getc != NULL)) { 120 int ret = console->getc(console); 121 if (ret >= 0) 122 return ret; 123 if (err != ERROR_NO_PENDING_CHAR) 124 err = ret; 125 } 126 } while (err == ERROR_NO_PENDING_CHAR); 127 128 return err; 129 } 130 131 void console_flush(void) 132 { 133 console_t *console; 134 135 for (console = console_list; console != NULL; console = console->next) 136 if ((console->flags & console_state) && (console->flush != NULL)) { 137 console->flush(console); 138 } 139 } 140