xref: /aosp_15_r20/external/coreboot/payloads/libpayload/drivers/i8042/keyboard.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2008 Advanced Micro Devices, Inc.
4  * Copyright (C) 2017 Patrick Rudolph <[email protected]>
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 #include <stdbool.h>
31 #include <stdint.h>
32 
33 #include <keycodes.h>
34 #include <libpayload-config.h>
35 #include <libpayload.h>
36 
37 #include "i8042.h"
38 
39 #ifdef DEBUG
40 #define debug(x...) printf(x)
41 #else
42 #define debug(x...) do {} while (0)
43 #endif
44 
45 #define POWER_BUTTON         0x90
46 #define MEDIA_KEY_PREFIX     0xE0
47 
48 struct layout_maps {
49 	const char *country;
50 	const unsigned short map[4][0x59];
51 };
52 
53 static struct layout_maps *map;
54 static int modifier = 0;
55 int (*media_key_mapping_callback)(char ch);
56 
57 static struct layout_maps keyboard_layouts[] = {
58 #if CONFIG(LP_PC_KEYBOARD_LAYOUT_US)
59 { .country = "us", .map = {
60 	{ /* No modifier */
61 	 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
62 	 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,
63 	 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
64 	 0x6F, 0x70, 0x5B, 0x5D, 0x0A, 0x00, 0x61, 0x73,
65 	 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
66 	 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
67 	 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
68 	 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
69 	 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
70 	 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
71 	 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00, KEY_F(11),
72 	 KEY_F(12),
73 	 },
74 	{ /* Shift */
75 	 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
76 	 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
77 	 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
78 	 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
79 	 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
80 	 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
81 	 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
82 	 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
83 	 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
84 	 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
85 	 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00, KEY_F(11),
86 	 KEY_F(12),
87 	 },
88 	{ /* ALT */
89 	 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
90 	 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,
91 	 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
92 	 0x6F, 0x70, 0x5B, 0x5D, 0x0A, 0x00, 0x61, 0x73,
93 	 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
94 	 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
95 	 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
96 	 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
97 	 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
98 	 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
99 	 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00, KEY_F(11),
100 	 KEY_F(12),
101 	 },
102 	{ /* Shift-ALT */
103 	 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
104 	 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
105 	 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
106 	 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
107 	 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
108 	 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
109 	 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
110 	 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
111 	 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
112 	 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
113 	 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00, KEY_F(11),
114 	 KEY_F(12),
115 	 }
116 }},
117 #endif
118 #if CONFIG(LP_PC_KEYBOARD_LAYOUT_DE)
119 { .country = "de", .map = {
120 	{ /* No modifier */
121 	 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
122 	 0x37, 0x38, 0x39, 0x30, 0x00, 0x27, 0x08, 0x09,
123 	 0x71, 0x77, 0x65, 0x72, 0x74, 0x7A, 0x75, 0x69,
124 	 0x6F, 0x70, 0x00, 0x2B, 0x0A, 0x00, 0x61, 0x73,
125 	 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x00,
126 	 0x00, 0x5E, 0x00, 0x23, 0x79, 0x78, 0x63, 0x76,
127 	 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2D, 0x00, 0x2A,
128 	 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
129 	 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
130 	 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
131 	 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x3C, KEY_F(11),
132 	 KEY_F(12),
133 	 },
134 	{ /* Shift */
135 	 0x00, 0x1B, 0x21, 0x22, 0xA7, 0x24, 0x25, 0x26,
136 	 0x2F, 0x28, 0x29, 0x3D, 0x3F, 0x60, 0x08, 0x00,
137 	 0x51, 0x57, 0x45, 0x52, 0x54, 0x5A, 0x55, 0x49,
138 	 0x4F, 0x50, 0x00, 0x2A, 0x0A, 0x00, 0x41, 0x53,
139 	 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x00,
140 	 0x00, 0x7E, 0x00, 0x27, 0x59, 0x58, 0x43, 0x56,
141 	 0x42, 0x4E, 0x4D, 0x3B, 0x3A, 0x5F, 0x00, 0x2A,
142 	 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
143 	 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
144 	 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
145 	 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x3E, KEY_F(11),
146 	 KEY_F(12),
147 	 },
148 	{ /* ALT */
149 	 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
150 	 0x7B, 0x5B, 0x5D, 0x7D, 0x5C, 0x3D, 0x08, 0x09,
151 	 0x40, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
152 	 0x6F, 0x70, 0x5B, 0x7E, 0x0A, 0x00, 0x61, 0x73,
153 	 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
154 	 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
155 	 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
156 	 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
157 	 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
158 	 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
159 	 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x7C, KEY_F(11),
160 	 KEY_F(12),
161 	 },
162 	{ /* Shift-ALT */
163 	 /* copied from US */
164 	 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
165 	 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
166 	 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
167 	 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
168 	 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
169 	 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
170 	 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
171 	 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
172 	 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
173 	 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
174 	 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00, KEY_F(11),
175 	 KEY_F(12),
176 	 }
177 }},
178 #endif
179 };
180 
keyboard_drain_input(void)181 static void keyboard_drain_input(void)
182 {
183 	while (i8042_data_ready_ps2())
184 		(void)i8042_read_data_ps2();
185 }
186 
keyboard_cmd(unsigned char cmd)187 static bool keyboard_cmd(unsigned char cmd)
188 {
189 	const uint64_t timeout_us = cmd == I8042_KBCMD_RESET ? 1*1000*1000 : 200*1000;
190 	const uint64_t start_time = timer_us(0);
191 
192 	i8042_write_data(cmd);
193 
194 	do {
195 		if (!i8042_data_ready_ps2()) {
196 			udelay(50);
197 			continue;
198 		}
199 
200 		const uint8_t data = i8042_read_data_ps2();
201 		switch (data) {
202 		case 0xfa:
203 			return true;
204 		case 0xfe:
205 			return false;
206 		default:
207 			/* Warn only if we already disabled keyboard input. */
208 			if (cmd != I8042_KBCMD_DEFAULT_DIS)
209 				debug("WARNING: Keyboard sent spurious 0x%02x.\n", data);
210 			break;
211 		}
212 	} while (timer_us(start_time) < timeout_us);
213 
214 	debug("ERROR: Keyboard command timed out.\n");
215 	return false;
216 }
217 
set_scancode_set(const unsigned char set)218 static bool set_scancode_set(const unsigned char set)
219 {
220 	bool ret;
221 
222 	if (set < 1 || set > 3)
223 		return false;
224 
225 	ret = keyboard_cmd(I8042_KBCMD_SET_SCANCODE);
226 	if (!ret) {
227 		debug("ERROR: Keyboard set scancode failed!\n");
228 		return ret;
229 	}
230 
231 	ret = keyboard_cmd(set);
232 	if (!ret) {
233 		debug("ERROR: Keyboard scancode set#%u failed!\n", set);
234 		return ret;
235 	}
236 
237 	return ret;
238 }
239 
keyboard_peek_echo_result(void)240 static bool keyboard_peek_echo_result(void)
241 {
242 	const uint8_t ch = i8042_peek_data_ps2();
243 	return ch == 0xee || ch == 0xfe;
244 }
245 
246 static enum keyboard_state {
247 	STATE_INIT = 0,
248 	STATE_SIMPLIFIED_INIT,
249 	STATE_HOTPLUG,
250 	STATE_HOTPLUG_ECHO,
251 	STATE_DISABLE_SCAN,
252 	STATE_DRAIN_INPUT,
253 	STATE_DISABLE_TRANSLATION,
254 	STATE_START_SELF_TEST,
255 	STATE_SELF_TEST,
256 	STATE_CONFIGURE,
257 	STATE_CONFIGURE_SET1,
258 	STATE_ENABLE_TRANSLATION,
259 	STATE_ENABLE_SCAN,
260 	STATE_RUNNING,
261 	STATE_RUNNING_ECHO,
262 	STATE_DETENTION,
263 } keyboard_state;
264 
265 #define STATE_NAMES_ENTRY(name) [STATE_##name] = #name
266 static const char *const state_names[] = {
267 	STATE_NAMES_ENTRY(INIT),
268 	STATE_NAMES_ENTRY(SIMPLIFIED_INIT),
269 	STATE_NAMES_ENTRY(HOTPLUG),
270 	STATE_NAMES_ENTRY(HOTPLUG_ECHO),
271 	STATE_NAMES_ENTRY(DISABLE_SCAN),
272 	STATE_NAMES_ENTRY(DRAIN_INPUT),
273 	STATE_NAMES_ENTRY(DISABLE_TRANSLATION),
274 	STATE_NAMES_ENTRY(START_SELF_TEST),
275 	STATE_NAMES_ENTRY(SELF_TEST),
276 	STATE_NAMES_ENTRY(CONFIGURE),
277 	STATE_NAMES_ENTRY(CONFIGURE_SET1),
278 	STATE_NAMES_ENTRY(ENABLE_TRANSLATION),
279 	STATE_NAMES_ENTRY(ENABLE_SCAN),
280 	STATE_NAMES_ENTRY(RUNNING),
281 	STATE_NAMES_ENTRY(RUNNING_ECHO),
282 	STATE_NAMES_ENTRY(DETENTION),
283 };
284 
285 __attribute__((unused))
state_name(enum keyboard_state state)286 static const char *state_name(enum keyboard_state state)
287 {
288 	if (state >= ARRAY_SIZE(state_names) || !state_names[state])
289 		return "<unknown>";
290 	return state_names[state];
291 }
292 
293 static uint64_t keyboard_time;
294 static uint64_t state_time;
295 
keyboard_poll(void)296 static void keyboard_poll(void)
297 {
298 	enum keyboard_state next_state = keyboard_state;
299 	unsigned int i;
300 
301 	switch (keyboard_state) {
302 
303 	case STATE_INIT:
304 		/* Wait until keyboard_init() has been called. */
305 		break;
306 
307 	case STATE_SIMPLIFIED_INIT:
308 		/* On the first try, start opportunistically, do
309 		   the first steps at once and skip the self-test. */
310 		(void)keyboard_cmd(I8042_KBCMD_DEFAULT_DIS);
311 		keyboard_drain_input();
312 		(void)i8042_set_kbd_translation(false);
313 		next_state = STATE_CONFIGURE;
314 		break;
315 
316 	case STATE_HOTPLUG:
317 		if (timer_us(state_time) > 1*1000*1000) {
318 			i8042_write_data(I8042_KBCMD_ECHO);
319 			next_state = STATE_HOTPLUG_ECHO;
320 		}
321 		break;
322 
323 	case STATE_HOTPLUG_ECHO:
324 		if (!i8042_data_ready_ps2()) {
325 			if (timer_us(state_time) > 200*1000)
326 				next_state = STATE_HOTPLUG;
327 			break;
328 		}
329 
330 		if (keyboard_peek_echo_result()) {
331 			next_state = STATE_DISABLE_SCAN;
332 			keyboard_time = timer_us(0);
333 		}
334 		(void)i8042_read_data_ps2();
335 
336 		break;
337 
338 	case STATE_DISABLE_SCAN:
339 		(void)keyboard_cmd(I8042_KBCMD_DEFAULT_DIS);
340 		next_state = STATE_DRAIN_INPUT;
341 		break;
342 
343 	case STATE_DRAIN_INPUT:
344 		/* Limit number of bytes drained per poll. */
345 		for (i = 0; i < 50 && i8042_data_ready_ps2(); ++i)
346 			(void)i8042_read_data_ps2();
347 		if (i == 0)
348 			next_state = STATE_DISABLE_TRANSLATION;
349 		break;
350 
351 	case STATE_DISABLE_TRANSLATION:
352 		/* Be opportunistic and assume it's disabled on failure. */
353 		(void)i8042_set_kbd_translation(false);
354 		next_state = STATE_START_SELF_TEST;
355 		break;
356 
357 	case STATE_START_SELF_TEST:
358 		if (!keyboard_cmd(I8042_KBCMD_RESET))
359 			debug("ERROR: Keyboard self-test couldn't be started.\n");
360 		/* We ignore errors and always move to the self-test state
361 		   which will simply try again if necessary. */
362 		next_state = STATE_SELF_TEST;
363 		break;
364 
365 	case STATE_SELF_TEST:
366 		if (!i8042_data_ready_ps2()) {
367 			if (timer_us(state_time) > 5*1000*1000) {
368 				debug("WARNING: Keyboard self-test timed out.\n");
369 				next_state = STATE_DISABLE_SCAN;
370 			}
371 			break;
372 		}
373 
374 		const uint8_t self_test_result = i8042_read_data_ps2();
375 		switch (self_test_result) {
376 		case 0xaa:
377 			debug("INFO: Keyboard self-test succeeded.\n");
378 			next_state = STATE_CONFIGURE;
379 			break;
380 		case 0xfc:
381 		case 0xfd:
382 			/* Failure. Try again. */
383 			debug("WARNING: Keyboard self-test failed.\n");
384 			next_state = STATE_START_SELF_TEST;
385 			break;
386 		default:
387 			debug("WARNING: Keyboard self-test received spurious 0x%02x\n",
388 			       self_test_result);
389 			break;
390 		}
391 		break;
392 
393 	case STATE_CONFIGURE:
394 		if (set_scancode_set(2))
395 			next_state = STATE_ENABLE_TRANSLATION;
396 		else
397 			next_state = STATE_CONFIGURE_SET1;
398 		break;
399 
400 	case STATE_CONFIGURE_SET1:
401 		if (!set_scancode_set(1)) {
402 			debug("ERROR: Keyboard failed to set any scancode set.\n");
403 			next_state = STATE_DISABLE_SCAN;
404 			break;
405 		}
406 
407 		next_state = STATE_ENABLE_SCAN;
408 		break;
409 
410 	case STATE_ENABLE_TRANSLATION:
411 		if (i8042_set_kbd_translation(true) != 0) {
412 			debug("ERROR: Keyboard controller set translation failed!\n");
413 			next_state = STATE_DISABLE_SCAN;
414 			break;
415 		}
416 
417 		next_state = STATE_ENABLE_SCAN;
418 		break;
419 
420 	case STATE_ENABLE_SCAN:
421 		if (!keyboard_cmd(I8042_KBCMD_EN)) {
422 			debug("ERROR: Keyboard enable scanning failed!\n");
423 			next_state = STATE_DISABLE_SCAN;
424 			break;
425 		}
426 
427 		next_state = STATE_RUNNING;
428 		break;
429 
430 	case STATE_RUNNING:
431 		if (!i8042_data_ready_ps2()) {
432 			if (timer_us(state_time) > 500*1000) {
433 				i8042_write_data(I8042_KBCMD_ECHO);
434 				next_state = STATE_RUNNING_ECHO;
435 			}
436 		} else {
437 			state_time = timer_us(0);
438 		}
439 		break;
440 
441 	case STATE_RUNNING_ECHO:
442 		if (!i8042_data_ready_ps2()) {
443 			if (timer_us(state_time) > 200*1000) {
444 				debug("INFO: Keyboard echo timed out.\n");
445 				next_state = STATE_HOTPLUG;
446 			}
447 			break;
448 		}
449 
450 		if (keyboard_peek_echo_result()) {
451 			(void)i8042_read_data_ps2();
452 			next_state = STATE_RUNNING;
453 		}
454 
455 		state_time = timer_us(0);
456 		break;
457 
458 	case STATE_DETENTION:
459 		if (timer_us(state_time) > 5*1000*1000)
460 			next_state = STATE_HOTPLUG;
461 		break;
462 
463 	}
464 
465 	switch (next_state) {
466 	case STATE_INIT:
467 	case STATE_HOTPLUG:
468 	case STATE_HOTPLUG_ECHO:
469 	case STATE_RUNNING:
470 	case STATE_RUNNING_ECHO:
471 	case STATE_DETENTION:
472 		break;
473 	default:
474 		if (timer_us(keyboard_time) > 30*1000*1000)
475 			next_state = STATE_DETENTION;
476 		break;
477 	}
478 
479 	if (keyboard_state != next_state) {
480 		debug("INFO: Keyboard advancing state to '%s'.\n", state_name(next_state));
481 		keyboard_state = next_state;
482 		state_time = timer_us(0);
483 	}
484 }
485 
keyboard_havechar(void)486 bool keyboard_havechar(void)
487 {
488 	keyboard_poll();
489 	return i8042_data_ready_ps2() &&
490 	       (keyboard_state == STATE_RUNNING ||
491 		(keyboard_state == STATE_RUNNING_ECHO && !keyboard_peek_echo_result()));
492 }
493 
keyboard_get_scancode(void)494 unsigned char keyboard_get_scancode(void)
495 {
496 	unsigned char ch;
497 
498 	while (!keyboard_havechar()) ;
499 
500 	ch = i8042_read_data_ps2();
501 
502 	switch (ch) {
503 	case 0x36:
504 	case 0x2a:
505 		modifier |= KB_MOD_SHIFT;
506 		break;
507 	case 0x80 | 0x36:
508 	case 0x80 | 0x2a:
509 		modifier &= ~KB_MOD_SHIFT;
510 		break;
511 	case 0x38:
512 		modifier |= KB_MOD_ALT;
513 		break;
514 	case 0x80 | 0x38:
515 		modifier &= ~KB_MOD_ALT;
516 		break;
517 	case 0x1d:
518 		modifier |= KB_MOD_CTRL;
519 		break;
520 	case 0x80 | 0x1d:
521 		modifier &= ~KB_MOD_CTRL;
522 		break;
523 	case 0x3a:
524 		if (modifier & KB_MOD_CAPSLOCK) {
525 			modifier &= ~KB_MOD_CAPSLOCK;
526 			if (keyboard_cmd(I8042_KBCMD_SET_MODE_IND))
527 				keyboard_cmd(I8042_MODE_CAPS_LOCK_OFF);
528 		} else {
529 			modifier |= KB_MOD_CAPSLOCK;
530 			if (keyboard_cmd(I8042_KBCMD_SET_MODE_IND))
531 				keyboard_cmd(I8042_MODE_CAPS_LOCK_ON);
532 		}
533 		break;
534 	}
535 
536 	return ch;
537 }
538 
keyboard_getmodifier(void)539 int keyboard_getmodifier(void)
540 {
541 	return modifier;
542 }
543 
initialize_keyboard_media_key_mapping_callback(int (* media_key_mapper)(char))544 void initialize_keyboard_media_key_mapping_callback(int (*media_key_mapper)(char))
545 {
546 	media_key_mapping_callback = media_key_mapper;
547 }
548 
keyboard_getchar(void)549 int keyboard_getchar(void)
550 {
551 	unsigned char ch;
552 	int shift;
553 	int ret = 0;
554 
555 	while (!keyboard_havechar()) ;
556 
557 	ch = keyboard_get_scancode();
558 	if ((media_key_mapping_callback != NULL) && (ch == MEDIA_KEY_PREFIX)) {
559 		ch = keyboard_get_scancode();
560 		return media_key_mapping_callback(ch);
561 	}
562 
563 	if (!(ch & 0x80) && ch < 0x59) {
564 		shift =
565 		    (modifier & KB_MOD_SHIFT) ^ (modifier & KB_MOD_CAPSLOCK) ? 1 : 0;
566 
567 		if (modifier & KB_MOD_ALT)
568 			shift += 2;
569 
570 		ret = map->map[shift][ch];
571 
572 		if (modifier & KB_MOD_CTRL) {
573 			switch (ret) {
574 			case 'a' ... 'z':
575 				ret &= 0x1f;
576 				break;
577 			case KEY_DC:
578 				/* vulcan nerve pinch */
579 				if ((modifier & KB_MOD_ALT) && reset_handler)
580 					reset_handler();
581 				__fallthrough;
582 			default:
583 				ret = 0;
584 			}
585 		}
586 	}
587 
588 	if (ch == 0x5e)
589 		ret = POWER_BUTTON;
590 
591 	return ret;
592 }
593 
594 /**
595  * Set keyboard layout
596  * @param country string describing the keyboard layout language.
597  * Valid values are "us", "de".
598  */
599 
keyboard_set_layout(char * country)600 int keyboard_set_layout(char *country)
601 {
602 	int i;
603 
604 	for (i=0; i<ARRAY_SIZE(keyboard_layouts); i++) {
605 		if (strncmp(keyboard_layouts[i].country, country,
606 					strlen(keyboard_layouts[i].country)))
607 			continue;
608 
609 		/* Found, changing keyboard layout */
610 		map = &keyboard_layouts[i];
611 		return 0;
612 	}
613 
614 	/* Nothing found, not changed */
615 	return -1;
616 }
617 
618 static struct console_input_driver cons = {
619 	.havekey = (int (*)(void))keyboard_havechar,
620 	.getchar = keyboard_getchar,
621 	.input_type = CONSOLE_INPUT_TYPE_EC,
622 };
623 
keyboard_init(void)624 void keyboard_init(void)
625 {
626 	if (keyboard_state != STATE_INIT)
627 		return;
628 
629 	map = &keyboard_layouts[0];
630 
631 	/* Initialized keyboard controller. */
632 	if (!i8042_probe() || !i8042_has_ps2())
633 		return;
634 
635 	/* Enable first PS/2 port */
636 	i8042_cmd(I8042_CMD_EN_KB);
637 
638 	keyboard_state = STATE_SIMPLIFIED_INIT;
639 	keyboard_time = state_time = timer_us(0);
640 
641 	console_add_input_driver(&cons);
642 }
643 
keyboard_disconnect(void)644 void keyboard_disconnect(void)
645 {
646 	/* If 0x64 returns 0xff, then we have no keyboard
647 	 * controller */
648 	if (inb(0x64) == 0xFF)
649 		return;
650 
651 	if (!i8042_has_ps2())
652 		return;
653 
654 	/* Disable scanning */
655 	keyboard_cmd(I8042_KBCMD_DEFAULT_DIS);
656 	keyboard_drain_input();
657 
658 	/* Nobody but us seems to still use scancode set #1.
659 	   So try to hand over with more modern settings. */
660 	set_scancode_set(2);
661 	i8042_set_kbd_translation(CONFIG(LP_PC_KEYBOARD_TRANSLATION));
662 
663 	/* Send keyboard disconnect command */
664 	i8042_cmd(I8042_CMD_DIS_KB);
665 
666 	/* Hand off with empty buffer */
667 	keyboard_drain_input();
668 
669 	/* Release keyboard controller driver */
670 	i8042_close();
671 
672 	keyboard_state = STATE_INIT;
673 }
674