diff --git a/chip/lm4/keyboard_scan.c b/chip/lm4/keyboard_scan.c index bb92ad2689..2faa2a88f6 100644 --- a/chip/lm4/keyboard_scan.c +++ b/chip/lm4/keyboard_scan.c @@ -63,6 +63,8 @@ enum COLUMN_INDEX { #define KB_COLS 13 + +static int enable_scanning = 1; static uint8_t raw_state[KB_COLS]; static uint8_t raw_state_at_boot[KB_COLS]; static int recovery_key_pressed; @@ -95,6 +97,8 @@ static const uint8_t actual_key_masks[4][KB_COLS] = { static void select_column(int col) { if (col == COLUMN_ASSERT_ALL) { + if (!enable_scanning) + return; LM4_GPIO_DIR(LM4_GPIO_P) = 0xff; LM4_GPIO_DIR(LM4_GPIO_Q) |= 0x1f; LM4_GPIO_DATA(LM4_GPIO_P, 0xff) = 0; @@ -102,7 +106,11 @@ static void select_column(int col) } else { LM4_GPIO_DIR(LM4_GPIO_P) = 0; LM4_GPIO_DIR(LM4_GPIO_Q) &= ~0x1f; - if (col < 8) { + /* Return after the above TRI_STATE_ALL has be run. */ + if (!enable_scanning) + return; + + if (col >= 0 && col < 8) { LM4_GPIO_DIR(LM4_GPIO_P) |= 1 << col; LM4_GPIO_DATA(LM4_GPIO_P, 1 << col) = 0; } else if (col != COLUMN_TRI_STATE_ALL) { @@ -232,7 +240,7 @@ static int check_keys_changed(void) for (i = 0; i < 8; ++i) { uint8_t prev = (raw_state[c] >> i) & 1; uint8_t now = (r >> i) & 1; - if (prev != now) { + if (prev != now && enable_scanning) { keyboard_state_changed(i, c, now); } } @@ -360,6 +368,7 @@ void keyboard_scan_task(void) /* Enable interrupts */ task_enable_irq(KB_SCAN_ROW_IRQ); + enable_scanning = 1; while (1) { wait_for_interrupt(); @@ -367,7 +376,7 @@ void keyboard_scan_task(void) enter_polling_mode(); /* Busy polling keyboard state. */ - while (1) { + while (enable_scanning) { /* sleep for debounce. */ usleep(SCAN_LOOP_DELAY); /* Check for keys down */ @@ -381,10 +390,10 @@ void keyboard_scan_task(void) } } } - /* TODO: (crosbug.com/p/7484) A race condition here. - * If a key state is changed here (before interrupt is - * enabled), it will be lost. - */ + /* Don't continue if the power button is not released yet. */ + while (!enable_scanning) { + usleep(SCAN_LOOP_DELAY); + } } } @@ -441,3 +450,21 @@ int keyboard_get_scan(uint8_t **buffp, int max_bytes) { return -1; } + + +/* The actuall implementation is controlling the enable_scanning variable, + * then that controls whether select_column() can pull-down columns or not. + */ +void keyboard_enable_scanning(int enable) +{ + enable_scanning = enable; + if (enable) { + /* A power button press had tri-stated all columns (see the + * 'else' statement below), we need a wake-up to unlock + * the task_wait_event() loop after wait_for_interrupt(). */ + task_wake(TASK_ID_KEYSCAN); + } else { + select_column(COLUMN_TRI_STATE_ALL); + keyboard_clear_underlying_buffer(); + } +} diff --git a/chip/lm4/power_button.c b/chip/lm4/power_button.c index 66505d3e59..66fc7b7589 100644 --- a/chip/lm4/power_button.c +++ b/chip/lm4/power_button.c @@ -200,6 +200,7 @@ static void power_button_released(uint64_t tnow) tnext_state = tnow; *memmap_switches &= ~EC_SWITCH_POWER_BUTTON_PRESSED; keyboard_set_power_button(0); + keyboard_enable_scanning(1); } @@ -528,6 +529,12 @@ void power_button_interrupt(enum gpio_signal signal) case GPIO_POWER_BUTTONn: /* Reset power button debounce time */ tdebounce_pwr = get_time().val + PWRBTN_DEBOUNCE_US; + if (get_power_button_pressed()) { + /* We want to disable the matrix scan as soon as + * possible to reduce the risk of false-reboot triggered + * by those keys on the same column with ESC key. */ + keyboard_enable_scanning(0); + } break; case GPIO_PCH_BKLTEN: update_backlight(); diff --git a/common/i8042.c b/common/i8042.c index 35e1f2b094..54eb668f3c 100644 --- a/common/i8042.c +++ b/common/i8042.c @@ -46,7 +46,7 @@ static int i8042_irq_enabled = 0; /* Reset all i8042 buffer */ -void i8042_init() +void i8042_flush_buffer() { head_to_buffer = tail_to_buffer = 0; keyboard_clear_buffer(); diff --git a/common/keyboard.c b/common/keyboard.c index 2d69dba438..6b2dc48088 100644 --- a/common/keyboard.c +++ b/common/keyboard.c @@ -255,9 +255,9 @@ static void reset_rate_and_delay(void) } -static void clear_underlying_buffer(void) +void keyboard_clear_underlying_buffer(void) { - i8042_init(); + i8042_flush_buffer(); } @@ -482,25 +482,25 @@ int handle_keyboard_data(uint8_t data, uint8_t *output) case I8042_CMD_ENABLE: output[out_len++] = I8042_RET_ACK; keyboard_enable(1); - clear_underlying_buffer(); + keyboard_clear_underlying_buffer(); break; case I8042_CMD_RESET_DIS: output[out_len++] = I8042_RET_ACK; keyboard_enable(0); reset_rate_and_delay(); - clear_underlying_buffer(); + keyboard_clear_underlying_buffer(); break; case I8042_CMD_RESET_DEF: output[out_len++] = I8042_RET_ACK; reset_rate_and_delay(); - clear_underlying_buffer(); + keyboard_clear_underlying_buffer(); break; case I8042_CMD_RESET_BAT: reset_rate_and_delay(); - clear_underlying_buffer(); + keyboard_clear_underlying_buffer(); output[out_len++] = I8042_RET_ACK; output[out_len++] = I8042_RET_BAT; output[out_len++] = I8042_RET_BAT; @@ -613,7 +613,7 @@ int handle_keyboard_command(uint8_t command, uint8_t *output) } else { CPRINTF("[Unsupported cmd: 0x%02x]\n", command); reset_rate_and_delay(); - clear_underlying_buffer(); + keyboard_clear_underlying_buffer(); output[out_len++] = I8042_RET_NAK; data_port_state = STATE_NORMAL; } diff --git a/include/i8042.h b/include/i8042.h index c3d858bee1..d88e3acb1f 100644 --- a/include/i8042.h +++ b/include/i8042.h @@ -90,7 +90,7 @@ #define I8042_ENIRQ1 (1 << 0) -void i8042_init(void); +void i8042_flush_buffer(void); /* common/i8042.c implements this function, which is called by lpc.c diff --git a/include/keyboard.h b/include/keyboard.h index 78884c1053..775135f1b7 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -53,6 +53,9 @@ void kblog_put(char type, uint8_t byte); #define MAX_KEYBOARD_MATRIX_ROWS 8 #define MAX_KEYBOARD_MATRIX_COLS 16 +/* Clear the keyboard buffer to host. */ +void keyboard_clear_underlying_buffer(void); + /* Asks the underlayer EC lib what keys are pressed right now. * * Sets bit_array to a debounced array of which keys are currently pressed, diff --git a/include/keyboard_scan.h b/include/keyboard_scan.h index 684885c82a..67e09e0312 100644 --- a/include/keyboard_scan.h +++ b/include/keyboard_scan.h @@ -19,4 +19,9 @@ int keyboard_scan_recovery_pressed(void); /* clear any saved keyboard state (empty FIFO, etc) */ void keyboard_clear_state(void); + +/* Enables/disables keyboard matrix scan. */ +void keyboard_enable_scanning(int enable); + + #endif /* __CROS_KEYBOARD_SCAN_H */