summaryrefslogtreecommitdiff
path: root/payloads/libpayload/drivers/i8042
diff options
context:
space:
mode:
Diffstat (limited to 'payloads/libpayload/drivers/i8042')
-rw-r--r--payloads/libpayload/drivers/i8042/keyboard.c49
1 files changed, 47 insertions, 2 deletions
diff --git a/payloads/libpayload/drivers/i8042/keyboard.c b/payloads/libpayload/drivers/i8042/keyboard.c
index 114e18bc40..14089bd51e 100644
--- a/payloads/libpayload/drivers/i8042/keyboard.c
+++ b/payloads/libpayload/drivers/i8042/keyboard.c
@@ -233,9 +233,12 @@ static bool set_scancode_set(const unsigned char set)
static enum keyboard_state {
STATE_INIT = 0,
+ STATE_SIMPLIFIED_INIT,
STATE_DISABLE_SCAN,
STATE_DRAIN_INPUT,
STATE_DISABLE_TRANSLATION,
+ STATE_START_SELF_TEST,
+ STATE_SELF_TEST,
STATE_CONFIGURE,
STATE_CONFIGURE_SET1,
STATE_ENABLE_TRANSLATION,
@@ -258,6 +261,15 @@ static void keyboard_poll(void)
/* Wait until keyboard_init() has been called. */
break;
+ case STATE_SIMPLIFIED_INIT:
+ /* On the first try, start opportunistically, do
+ the first steps at once and skip the self-test. */
+ (void)keyboard_cmd(I8042_KBCMD_DEFAULT_DIS);
+ keyboard_drain_input();
+ (void)i8042_set_kbd_translation(false);
+ next_state = STATE_CONFIGURE;
+ break;
+
case STATE_DISABLE_SCAN:
(void)keyboard_cmd(I8042_KBCMD_DEFAULT_DIS);
next_state = STATE_DRAIN_INPUT;
@@ -274,7 +286,40 @@ static void keyboard_poll(void)
case STATE_DISABLE_TRANSLATION:
/* Be opportunistic and assume it's disabled on failure. */
(void)i8042_set_kbd_translation(false);
- next_state = STATE_CONFIGURE;
+ next_state = STATE_START_SELF_TEST;
+ break;
+
+ case STATE_START_SELF_TEST:
+ if (!keyboard_cmd(I8042_KBCMD_RESET))
+ printf("ERROR: Keyboard self-test couldn't be started.\n");
+ /* We ignore errors and always move to the self-test state
+ which will simply try again if necessary. */
+ next_state = STATE_SELF_TEST;
+ break;
+
+ case STATE_SELF_TEST:
+ if (!i8042_data_ready_ps2()) {
+ if (timer_us(state_time) > 5*1000*1000)
+ next_state = STATE_DISABLE_SCAN;
+ break;
+ }
+
+ const uint8_t self_test_result = i8042_read_data_ps2();
+ switch (self_test_result) {
+ case 0xaa:
+ /* Success! */
+ next_state = STATE_CONFIGURE;
+ break;
+ case 0xfc:
+ case 0xfd:
+ /* Failure. Try again. */
+ next_state = STATE_START_SELF_TEST;
+ break;
+ default:
+ printf("WARNING: Keyboard self-test received spurious 0x%02x\n",
+ self_test_result);
+ break;
+ }
break;
case STATE_CONFIGURE:
@@ -491,7 +536,7 @@ void keyboard_init(void)
/* Enable first PS/2 port */
i8042_cmd(I8042_CMD_EN_KB);
- keyboard_state = STATE_DISABLE_SCAN;
+ keyboard_state = STATE_SIMPLIFIED_INIT;
keyboard_time = state_time = timer_us(0);
console_add_input_driver(&cons);