link: fix race condition enabling keyboard interrupt

Previously, an edge on a keyboard row could be missed if it occurred
after the last scan, but before interrupts are enabled.  Now we
explicitly check if any keys are down before waiting for an interrupt,
and if any are, we simply don't wait to scan.

BUG=chrome-os-partner:7484
BRANCH=link
TEST=the race condition's really tricky to hit

The best we can do for testing is to ensure that we ARE sleeping in
the normal case where no keys are held down.  For that, don't press
any keys, and run 'taskinfo' from the EC console twice about 10 sec
apart.  Both printouts should have virtually identical times for the
KEYSCAN task.

Change-Id: I4e0ef18a2d71d0a5d3655742bd49fc15afc4aaed
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/34709
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Yung-Chieh Lo <yjlou@chromium.org>
This commit is contained in:
Randall Spangler
2012-10-04 16:22:53 -07:00
committed by Gerrit
parent 6d6cfad2a0
commit a752e1f5d1

View File

@@ -83,7 +83,7 @@ static const uint8_t actual_key_masks[4][KB_COLS] = {
#define MASK_INDEX_KEY_H 6
#define MASK_VALUE_KEY_H 0x02
static void wait_for_interrupt(void)
static void enable_interrupt(void)
{
CPRINTF("[%T KB wait]\n");
@@ -442,11 +442,19 @@ void keyboard_scan_task(void)
while (1) {
/* Enable all outputs */
wait_for_interrupt();
enable_interrupt();
/* Wait for scanning enabled and key pressed. */
do {
task_wait_event(-1);
/*
* Don't wait if scanning is enabled and a key is
* already pressed. This prevents a race between the
* user pressing a key and enable_interrupt()
* starting to pay attention to edges.
*/
if ((lm4_read_raw_row_state() == 0xff) ||
!lm4_get_scanning_enabled())
task_wait_event(-1);
} while (!lm4_get_scanning_enabled());
enter_polling_mode();
@@ -487,8 +495,8 @@ void keyboard_enable_scanning(int 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().
* 'else' statement below); we need a wake-up to unlock the
* task_wait_event() loop after enable_interrupt().
*/
task_wake(TASK_ID_KEYSCAN);
} else {