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