From a752e1f5d18ac5bd129dbc60ca74abfdcb47ea09 Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Thu, 4 Oct 2012 16:22:53 -0700 Subject: 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 Reviewed-on: https://gerrit.chromium.org/gerrit/34709 Reviewed-by: Simon Glass Reviewed-by: Yung-Chieh Lo --- chip/lm4/keyboard_scan.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/chip/lm4/keyboard_scan.c b/chip/lm4/keyboard_scan.c index ea4b5b82cd..33c894e8c1 100644 --- a/chip/lm4/keyboard_scan.c +++ b/chip/lm4/keyboard_scan.c @@ -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 { -- cgit v1.2.1