xref: /aosp_15_r20/external/coreboot/payloads/libpayload/curses/keyboard.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2007 Uwe Hermann <[email protected]>
4  * Copyright (C) 2008 Advanced Micro Devices, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * This file handles reading keystrokes from serial and the console
32  * and "cooking" them so that they are correct for curses.
33  * Also, implement key related functions (mainly wgetch)
34  *
35  * TODO:
36  * Actually cook the serial (handle special keys)
37  */
38 
39 #include <libpayload-config.h>
40 #include <usb/usb.h>
41 #include "local.h"
42 
43 static int _halfdelay = 0;
44 
45 /* ============== Serial ==================== */
46 
47 #if CONFIG(LP_SERIAL_CONSOLE)
48 /* We treat serial like a vt100 terminal.  For now we
49    do the cooking in here, but we should probably eventually
50    pass it to dedicated vt100 code */
51 
getkeyseq(char * buffer,int len,int max)52 static int getkeyseq(char *buffer, int len, int max)
53 {
54 	int i;
55 
56 	while (1) {
57 		for(i = 0; i < 75; i++) {
58 			if (serial_havechar())
59 				break;
60 			mdelay(1);
61 		}
62 
63 		if (i == 75)
64 			return len;
65 
66 		buffer[len++] = serial_getchar();
67 		if (len == max)
68 			return len;
69 	}
70 }
71 
72 static struct {
73 	const char *seq;
74 	int key;
75 } escape_codes[] = {
76 	{ "[A", KEY_UP },
77 	{ "[B", KEY_DOWN },
78 	{ "[C", KEY_RIGHT },
79 	{ "[D", KEY_LEFT },
80 	{ "[F", KEY_END },
81 	{ "[H", KEY_HOME },
82 	{ "[2~", KEY_IC },
83 	{ "[3~", KEY_DC },
84 	{ "[5~", KEY_PPAGE },
85 	{ "[6~", KEY_NPAGE },
86 	{ "OP", KEY_F(1) },
87 	{ "OQ", KEY_F(2) },
88 	{ "OR", KEY_F(3) },
89 	{ "OS", KEY_F(4) },
90 	{ "[15~", KEY_F(5) },
91 	{ "[17~", KEY_F(6) },
92 	{ "[18~", KEY_F(7) },
93 	{ "[19~", KEY_F(8) },
94 	{ "[20~", KEY_F(9) },
95 	{ "[21~", KEY_F(10) },
96 	{ "[23~", KEY_F(11) },
97 	{ "[24~", KEY_F(12) },
98 	{ NULL },
99 };
100 
handle_escape(void)101 static int handle_escape(void)
102 {
103 	char buffer[5];
104 	int len = getkeyseq(buffer, 0, sizeof(buffer));
105 	int i, t;
106 
107 	if (len == 0)
108 		return 27;
109 
110 	for(i = 0; escape_codes[i].seq != NULL; i++) {
111 		const char *p = escape_codes[i].seq;
112 
113 		for(t = 0; t < len; t++) {
114 			if (!*p || *p != buffer[t])
115 				break;
116 			p++;
117 		}
118 
119 		if (t == len)
120 			return escape_codes[i].key;
121 	}
122 
123 	return 0;
124 }
125 
cook_serial(unsigned char ch)126 static int cook_serial(unsigned char ch)
127 {
128 	switch(ch) {
129 	case 8:
130 		return KEY_BACKSPACE;
131 
132 	case 13:
133 		return KEY_ENTER;
134 
135 	case 27:
136 		return handle_escape();
137 
138 	default:
139 		return ch;
140 	}
141 }
142 #endif
143 
144 /* ================ Keyboard ================ */
145 
curses_getchar(int _delay)146 static int curses_getchar(int _delay)
147 {
148 #if CONFIG(LP_USB_HID) || CONFIG(LP_PC_KEYBOARD) || \
149 	CONFIG(LP_SERIAL_CONSOLE)
150 	unsigned short c;
151 #endif
152 
153 	do {
154 #if CONFIG(LP_USB_HID)
155 		usb_poll();
156 		if ((curses_flags & F_ENABLE_CONSOLE) &&
157 		    usbhid_havechar()) {
158 			c = usbhid_getchar();
159 			if (c != 0) return c;
160 		}
161 #endif
162 #if CONFIG(LP_PC_KEYBOARD)
163 		if ((curses_flags & F_ENABLE_CONSOLE) &&
164 		    keyboard_havechar()) {
165 			c = keyboard_getchar();
166 			if (c != 0) return c;
167 		}
168 #endif
169 
170 #if CONFIG(LP_SERIAL_CONSOLE)
171 		if ((curses_flags & F_ENABLE_SERIAL) &&
172 		    serial_havechar()) {
173 			c = serial_getchar();
174 			return cook_serial(c);
175 		}
176 #endif
177 
178 		if (_delay == 0) {
179 			break;
180 		} else if (_delay >= 10) {
181 			mdelay(10);
182 			_delay -= 10;
183 		} else if (_delay > 0) {
184 			mdelay(_delay);
185 			_delay = 0;
186 		}
187 	} while (1);
188 
189 	return ERR;
190 }
191 
192 /* === Public functions === */
193 
wgetch(WINDOW * win)194 int wgetch(WINDOW *win)
195 {
196 	int _delay = -1;
197 
198 	if (_halfdelay)
199 		_delay = _halfdelay;
200 	else
201 		_delay = win->_delay;
202 
203 	return curses_getchar(_delay);
204 }
205 
nodelay(WINDOW * win,NCURSES_BOOL flag)206 int nodelay(WINDOW *win, NCURSES_BOOL flag)
207 {
208 	win->_delay = flag ? 0 : -1;
209 	return 0;
210 }
211 
halfdelay(int tenths)212 int halfdelay(int tenths)
213 {
214 	if (tenths > 255)
215 		return ERR;
216 
217 	_halfdelay = tenths;
218 	return 0;
219 }
220 
nocbreak(void)221 int nocbreak(void)
222 {
223 	/* Remove half delay timeout. */
224 	_halfdelay = 0;
225 	return 0;
226 }
227 
228 #if CONFIG(LP_VGA_VIDEO_CONSOLE)
curses_enable_vga(int state)229 void curses_enable_vga(int state)
230 {
231 	if (state)
232 		curses_flags |= F_ENABLE_CONSOLE;
233 	else
234 		curses_flags &= ~F_ENABLE_CONSOLE;
235 }
236 
curses_vga_enabled(void)237 int curses_vga_enabled(void)
238 {
239 	return (curses_flags & F_ENABLE_CONSOLE) != 0;
240 }
241 #else
curses_enable_vga(int state)242 void curses_enable_vga(int state) { }
curses_vga_enabled(void)243 int curses_vga_enabled(void) { return 0; }
244 #endif
245 
246 #if CONFIG(LP_SERIAL_CONSOLE)
curses_enable_serial(int state)247 void curses_enable_serial(int state)
248 {
249 	if (state)
250 		curses_flags |= F_ENABLE_SERIAL;
251 	else
252 		curses_flags &= ~F_ENABLE_SERIAL;
253 }
254 
curses_serial_enabled(void)255 int curses_serial_enabled(void)
256 {
257 	return (curses_flags & F_ENABLE_SERIAL) != 0;
258 }
259 
260 #else
curses_enable_serial(int state)261 void curses_enable_serial(int state) { }
curses_serial_enabled(void)262 int curses_serial_enabled(void) { return 0; }
263 #endif
264