From a160d93dda188b33b4b28bb888bd78120e42695d Mon Sep 17 00:00:00 2001 From: Nico Huber Date: Sun, 1 Nov 2020 19:36:48 +0100 Subject: libpayload/keyboard: Revise keyboard_cmd() error handling Even if we are careful, it's still possible that we read spurious data from the keyboard, e.g. keystrokes. Namely, when we send the reset/disable command, there is a race before the command is pro- cessed. So we should always process data from the keyboard in a loop. We break it, when an ACK (0xfa) or a NAK (0xfe) is received, and warn on unexpected data unless it might be due to the mentioned race. This also gives us the opportunity to use command-specific timeouts which we take from Linux: 1s for the keyboard self-test (as there are keyboards that perform the test before acking the command) and 200ms for all other commands. Change-Id: I60a2643a8ff4b9231c63bf970c8749c97c7d8926 Signed-off-by: Nico Huber Reviewed-on: https://review.coreboot.org/c/coreboot/+/47083 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons --- payloads/libpayload/drivers/i8042/keyboard.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'payloads/libpayload/drivers') diff --git a/payloads/libpayload/drivers/i8042/keyboard.c b/payloads/libpayload/drivers/i8042/keyboard.c index 22747ff79d..42d4fdccf5 100644 --- a/payloads/libpayload/drivers/i8042/keyboard.c +++ b/payloads/libpayload/drivers/i8042/keyboard.c @@ -28,6 +28,7 @@ */ #include +#include #include #include @@ -173,9 +174,33 @@ static struct layout_maps keyboard_layouts[] = { static bool keyboard_cmd(unsigned char cmd) { + const uint64_t timeout_us = cmd == I8042_KBCMD_RESET ? 1*1000*1000 : 200*1000; + const uint64_t start_time = timer_us(0); + i8042_write_data(cmd); - return i8042_wait_read_ps2() == 0xfa; + do { + if (!i8042_data_ready_ps2()) { + udelay(50); + continue; + } + + const uint8_t data = i8042_read_data_ps2(); + switch (data) { + case 0xfa: + return true; + case 0xfe: + return false; + default: + /* Warn only if we already disabled keyboard input. */ + if (cmd != I8042_KBCMD_DEFAULT_DIS) + printf("WARNING: Keyboard sent spurious 0x%02x.\n", data); + break; + } + } while (timer_us(start_time) < timeout_us); + + printf("ERROR: Keyboard command timed out.\n"); + return false; } bool keyboard_havechar(void) -- cgit v1.2.3