xref: /aosp_15_r20/external/coreboot/payloads/libpayload/libc/console.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2008 Advanced Micro Devices, Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <libpayload-config.h>
30 #include <libpayload.h>
31 #include <usb/usb.h>
32 
33 struct console_output_driver *console_out;
34 struct console_input_driver *console_in;
35 static console_input_type last_getchar_input_type;
36 
output_driver_exists(struct console_output_driver * out)37 static int output_driver_exists(struct console_output_driver *out)
38 {
39 	struct console_output_driver *head = console_out;
40 
41 	while (head) {
42 		if (head == out)
43 			return 1;
44 		head = head->next;
45 	}
46 
47 	return 0;
48 }
49 
input_driver_exists(struct console_input_driver * in)50 static int input_driver_exists(struct console_input_driver *in)
51 {
52 	struct console_input_driver *head = console_in;
53 
54 	while (head) {
55 		if (head == in)
56 			return 1;
57 		head = head->next;
58 	}
59 
60 	return 0;
61 }
62 
console_add_output_driver(struct console_output_driver * out)63 void console_add_output_driver(struct console_output_driver *out)
64 {
65 	die_if(!out->putchar && !out->write, "Need at least one output func\n");
66 	/* Check if this driver was already added to the console list */
67 	if (output_driver_exists(out))
68 		return;
69 	out->next = console_out;
70 	console_out = out;
71 }
72 
console_add_input_driver(struct console_input_driver * in)73 void console_add_input_driver(struct console_input_driver *in)
74 {
75 	/* Check if this driver was already added to the console list */
76 	if (input_driver_exists(in))
77 		return;
78 	/* Flush out the driver input buffer. */
79 	while (in->havekey())
80 		in->getchar();
81 	in->next = console_in;
82 	console_in = in;
83 }
84 
85 /*
86  * For when you really need to silence an output driver (e.g. to avoid ugly
87  * recursions). Takes the pointer of either of the two output functions, since
88  * the struct console_output_driver itself is often static and inaccessible.
89  */
console_remove_output_driver(void * function)90 int console_remove_output_driver(void *function)
91 {
92 	struct console_output_driver **out;
93 	for (out = &console_out; *out; out = &(*out)->next)
94 		if ((*out)->putchar == function || (*out)->write == function) {
95 			*out = (*out)->next;
96 			return 1;
97 		}
98 
99 	return 0;
100 }
101 
console_init(void)102 void console_init(void)
103 {
104 #if CONFIG(LP_VIDEO_CONSOLE)
105 	video_console_init();
106 #endif
107 #if CONFIG(LP_SERIAL_CONSOLE)
108 	serial_console_init();
109 #endif
110 #if CONFIG(LP_PC_KEYBOARD)
111 	keyboard_init();
112 #endif
113 #if CONFIG(LP_CBMEM_CONSOLE)
114 	cbmem_console_init();
115 #endif
116 }
117 
console_write(const void * buffer,size_t count)118 void console_write(const void *buffer, size_t count)
119 {
120 	const char *ptr;
121 	struct console_output_driver *out;
122 	for (out = console_out; out != 0; out = out->next)
123 		if (out->write)
124 			out->write(buffer, count);
125 		else
126 			for (ptr = buffer; (void *)ptr < buffer + count; ptr++)
127 				out->putchar(*ptr);
128 }
129 
putchar(unsigned int i)130 int putchar(unsigned int i)
131 {
132 	unsigned char c = (unsigned char)i;
133 	console_write(&c, 1);
134 	return (int)c;
135 }
136 
puts(const char * s)137 int puts(const char *s)
138 {
139 	size_t size = strlen(s);
140 
141 	console_write(s, size);
142 
143 	putchar('\n');
144 	return size + 1;
145 }
146 
havekey(void)147 int havekey(void)
148 {
149 #if CONFIG(LP_USB)
150 	usb_poll();
151 #endif
152 	struct console_input_driver *in;
153 	for (in = console_in; in != 0; in = in->next)
154 		if (in->havekey())
155 			return 1;
156 	return 0;
157 }
158 
159 /**
160  * This returns an ASCII value - the two getchar functions
161  * cook the respective input from the device.
162  */
getchar(void)163 int getchar(void)
164 {
165 	while (1) {
166 #if CONFIG(LP_USB)
167 		usb_poll();
168 #endif
169 		struct console_input_driver *in;
170 		for (in = console_in; in != 0; in = in->next)
171 			if (in->havechar()) {
172 				last_getchar_input_type = in->input_type;
173 				return in->getchar();
174 			}
175 	}
176 }
177 
getchar_timeout(int * ms)178 int getchar_timeout(int *ms)
179 {
180 	while (*ms > 0) {
181 		if (havekey())
182 			return getchar();
183 
184 		mdelay(100);
185 		*ms -= 100;
186 	}
187 
188 	if (*ms < 0)
189 		*ms = 0;
190 
191 	return 0;
192 }
193 
last_key_input_type(void)194 console_input_type last_key_input_type(void)
195 {
196 	return last_getchar_input_type;
197 }
198