summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Yung-Chieh Lo <yjlou@chromium.org>2012-04-30 17:55:42 +0800
committerLouis Yung-Chieh Lo <yjlou@chromium.org>2012-05-24 13:32:35 +0800
commit29d25d807c18330c1426425e8c53af1067be7640 (patch)
tree3a5c5538b97e74433d6ab6ea189180f696ce5289
parenteb7765c0c41986e225506447de0d9f722c66e32b (diff)
downloadchrome-ec-29d25d807c18330c1426425e8c53af1067be7640.tar.gz
Keyboard scan must stop driving columns when power button is pressed.
Tristage all columns as soon as possible right after the power button is pressed. This can avoid the silego chip to reset the EC. Resume the interrupt mode after power button is released so that the deasserted columns doesn't trigger EC reset. Also change some function names for export. BUG=chrome-os-partner:7486 TEST= press g first, then power button. repeat many times. system is not rebooted. press power button first, then g. repeat many times. system is not rebooted. ESC+power is still reseting system. The long press power button still shutdowns system. Change-Id: Ie5dec20ec3d3c4ffbd4acf5a4dd7f63eec38af56
-rw-r--r--chip/lm4/keyboard_scan.c41
-rw-r--r--chip/lm4/power_button.c7
-rw-r--r--common/i8042.c2
-rw-r--r--common/keyboard.c14
-rw-r--r--include/i8042.h2
-rw-r--r--include/keyboard.h3
-rw-r--r--include/keyboard_scan.h5
7 files changed, 58 insertions, 16 deletions
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 */