libpayload/keyboard: Implement hot (un)plugging
While we assume a keyboard is attached, we send an echo command every 500ms. If there is no data coming from the keyboard within 200ms, we assume it was detached. Correspondingly, if we assume no keyboard is attached, we run an echo command once per second. Change-Id: I2c75182761729bf30711305f3d8b9d43eafad675 Signed-off-by: Nico Huber <nico.h@gmx.de> Reviewed-on: https://review.coreboot.org/c/coreboot/+/47593 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Angel Pons <th3fanbus@gmail.com>
This commit is contained in:
parent
5d884837f4
commit
e97d320df2
|
@ -55,6 +55,7 @@
|
||||||
#define I8042_MODE_NUM_LOCK_OFF (0 << 1)
|
#define I8042_MODE_NUM_LOCK_OFF (0 << 1)
|
||||||
#define I8042_MODE_SCROLL_LOCK_ON (1 << 0)
|
#define I8042_MODE_SCROLL_LOCK_ON (1 << 0)
|
||||||
#define I8042_MODE_SCROLL_LOCK_OFF (0 << 0)
|
#define I8042_MODE_SCROLL_LOCK_OFF (0 << 0)
|
||||||
|
#define I8042_KBCMD_ECHO 0xee
|
||||||
#define I8042_KBCMD_SET_SCANCODE 0xf0
|
#define I8042_KBCMD_SET_SCANCODE 0xf0
|
||||||
#define I8042_KBCMD_SET_TYPEMATIC 0xf3
|
#define I8042_KBCMD_SET_TYPEMATIC 0xf3
|
||||||
#define I8042_KBCMD_EN 0xf4
|
#define I8042_KBCMD_EN 0xf4
|
||||||
|
|
|
@ -237,9 +237,17 @@ static bool set_scancode_set(const unsigned char set)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool keyboard_peek_echo_result(void)
|
||||||
|
{
|
||||||
|
const uint8_t ch = i8042_peek_data_ps2();
|
||||||
|
return ch == 0xee || ch == 0xfe;
|
||||||
|
}
|
||||||
|
|
||||||
static enum keyboard_state {
|
static enum keyboard_state {
|
||||||
STATE_INIT = 0,
|
STATE_INIT = 0,
|
||||||
STATE_SIMPLIFIED_INIT,
|
STATE_SIMPLIFIED_INIT,
|
||||||
|
STATE_HOTPLUG,
|
||||||
|
STATE_HOTPLUG_ECHO,
|
||||||
STATE_DISABLE_SCAN,
|
STATE_DISABLE_SCAN,
|
||||||
STATE_DRAIN_INPUT,
|
STATE_DRAIN_INPUT,
|
||||||
STATE_DISABLE_TRANSLATION,
|
STATE_DISABLE_TRANSLATION,
|
||||||
|
@ -250,6 +258,7 @@ static enum keyboard_state {
|
||||||
STATE_ENABLE_TRANSLATION,
|
STATE_ENABLE_TRANSLATION,
|
||||||
STATE_ENABLE_SCAN,
|
STATE_ENABLE_SCAN,
|
||||||
STATE_RUNNING,
|
STATE_RUNNING,
|
||||||
|
STATE_RUNNING_ECHO,
|
||||||
STATE_IGNORE,
|
STATE_IGNORE,
|
||||||
} keyboard_state;
|
} keyboard_state;
|
||||||
|
|
||||||
|
@ -257,6 +266,8 @@ static enum keyboard_state {
|
||||||
static const char *const state_names[] = {
|
static const char *const state_names[] = {
|
||||||
STATE_NAMES_ENTRY(INIT),
|
STATE_NAMES_ENTRY(INIT),
|
||||||
STATE_NAMES_ENTRY(SIMPLIFIED_INIT),
|
STATE_NAMES_ENTRY(SIMPLIFIED_INIT),
|
||||||
|
STATE_NAMES_ENTRY(HOTPLUG),
|
||||||
|
STATE_NAMES_ENTRY(HOTPLUG_ECHO),
|
||||||
STATE_NAMES_ENTRY(DISABLE_SCAN),
|
STATE_NAMES_ENTRY(DISABLE_SCAN),
|
||||||
STATE_NAMES_ENTRY(DRAIN_INPUT),
|
STATE_NAMES_ENTRY(DRAIN_INPUT),
|
||||||
STATE_NAMES_ENTRY(DISABLE_TRANSLATION),
|
STATE_NAMES_ENTRY(DISABLE_TRANSLATION),
|
||||||
|
@ -267,6 +278,7 @@ static const char *const state_names[] = {
|
||||||
STATE_NAMES_ENTRY(ENABLE_TRANSLATION),
|
STATE_NAMES_ENTRY(ENABLE_TRANSLATION),
|
||||||
STATE_NAMES_ENTRY(ENABLE_SCAN),
|
STATE_NAMES_ENTRY(ENABLE_SCAN),
|
||||||
STATE_NAMES_ENTRY(RUNNING),
|
STATE_NAMES_ENTRY(RUNNING),
|
||||||
|
STATE_NAMES_ENTRY(RUNNING_ECHO),
|
||||||
STATE_NAMES_ENTRY(IGNORE),
|
STATE_NAMES_ENTRY(IGNORE),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -301,6 +313,28 @@ static void keyboard_poll(void)
|
||||||
next_state = STATE_CONFIGURE;
|
next_state = STATE_CONFIGURE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case STATE_HOTPLUG:
|
||||||
|
if (timer_us(state_time) > 1*1000*1000) {
|
||||||
|
i8042_write_data(I8042_KBCMD_ECHO);
|
||||||
|
next_state = STATE_HOTPLUG_ECHO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_HOTPLUG_ECHO:
|
||||||
|
if (!i8042_data_ready_ps2()) {
|
||||||
|
if (timer_us(state_time) > 200*1000)
|
||||||
|
next_state = STATE_HOTPLUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyboard_peek_echo_result()) {
|
||||||
|
next_state = STATE_DISABLE_SCAN;
|
||||||
|
keyboard_time = timer_us(0);
|
||||||
|
}
|
||||||
|
(void)i8042_read_data_ps2();
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case STATE_DISABLE_SCAN:
|
case STATE_DISABLE_SCAN:
|
||||||
(void)keyboard_cmd(I8042_KBCMD_DEFAULT_DIS);
|
(void)keyboard_cmd(I8042_KBCMD_DEFAULT_DIS);
|
||||||
next_state = STATE_DRAIN_INPUT;
|
next_state = STATE_DRAIN_INPUT;
|
||||||
|
@ -394,7 +428,31 @@ static void keyboard_poll(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_RUNNING:
|
case STATE_RUNNING:
|
||||||
/* TODO: Use echo command to detect detach. */
|
if (!i8042_data_ready_ps2()) {
|
||||||
|
if (timer_us(state_time) > 500*1000) {
|
||||||
|
i8042_write_data(I8042_KBCMD_ECHO);
|
||||||
|
next_state = STATE_RUNNING_ECHO;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state_time = timer_us(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_RUNNING_ECHO:
|
||||||
|
if (!i8042_data_ready_ps2()) {
|
||||||
|
if (timer_us(state_time) > 200*1000) {
|
||||||
|
debug("INFO: Keyboard echo timed out.\n");
|
||||||
|
next_state = STATE_HOTPLUG;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyboard_peek_echo_result()) {
|
||||||
|
(void)i8042_read_data_ps2();
|
||||||
|
next_state = STATE_RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
state_time = timer_us(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_IGNORE:
|
case STATE_IGNORE:
|
||||||
|
@ -405,7 +463,10 @@ static void keyboard_poll(void)
|
||||||
|
|
||||||
switch (next_state) {
|
switch (next_state) {
|
||||||
case STATE_INIT:
|
case STATE_INIT:
|
||||||
|
case STATE_HOTPLUG:
|
||||||
|
case STATE_HOTPLUG_ECHO:
|
||||||
case STATE_RUNNING:
|
case STATE_RUNNING:
|
||||||
|
case STATE_RUNNING_ECHO:
|
||||||
case STATE_IGNORE:
|
case STATE_IGNORE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -424,7 +485,9 @@ static void keyboard_poll(void)
|
||||||
bool keyboard_havechar(void)
|
bool keyboard_havechar(void)
|
||||||
{
|
{
|
||||||
keyboard_poll();
|
keyboard_poll();
|
||||||
return keyboard_state == STATE_RUNNING && i8042_data_ready_ps2();
|
return i8042_data_ready_ps2() &&
|
||||||
|
(keyboard_state == STATE_RUNNING ||
|
||||||
|
(keyboard_state == STATE_RUNNING_ECHO && !keyboard_peek_echo_result()));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char keyboard_get_scancode(void)
|
unsigned char keyboard_get_scancode(void)
|
||||||
|
|
Loading…
Reference in New Issue