summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/keyboard_scan.c67
-rw-r--r--test/kb_scan.c114
2 files changed, 105 insertions, 76 deletions
diff --git a/common/keyboard_scan.c b/common/keyboard_scan.c
index a8f843e0a2..1c0f9759d1 100644
--- a/common/keyboard_scan.c
+++ b/common/keyboard_scan.c
@@ -86,8 +86,6 @@ uint8_t keyboard_cols = KEYBOARD_COLS_MAX;
/* Debounced key matrix */
static uint8_t __bss_slow debounced_state[KEYBOARD_COLS_MAX];
-/* Matrix from previous scan */
-static uint8_t __bss_slow prev_state[KEYBOARD_COLS_MAX];
/* Mask of keys being debounced */
static uint8_t __bss_slow debouncing[KEYBOARD_COLS_MAX];
/* Keys simulated-pressed */
@@ -475,46 +473,27 @@ static int check_keys_changed(uint8_t *state)
/* Check for changes between previous scan and this one */
for (c = 0; c < keyboard_cols; c++) {
- int diff = new_state[c] ^ prev_state[c];
+ int diff;
- if (!diff)
- continue;
-
- for (i = 0; i < KEYBOARD_ROWS; i++) {
- if (diff & BIT(i))
- scan_edge_index[c][i] = scan_time_index;
- }
-
- debouncing[c] |= diff;
- prev_state[c] = new_state[c];
- }
-
- /* Check for keys which are done debouncing */
- for (c = 0; c < keyboard_cols; c++) {
- int debc = debouncing[c];
-
- if (!debc)
- continue;
-
- for (i = 0; i < KEYBOARD_ROWS; i++) {
- int mask = 1 << i;
- int new_mask = new_state[c] & mask;
-
- /* Are we done debouncing this key? */
- if (!(debc & mask))
- continue; /* Not debouncing this key */
+ /* Clear debouncing flag, if sufficient time has elapsed. */
+ for (i = 0; i < KEYBOARD_ROWS && debouncing[c]; i++) {
+ if (!(debouncing[c] & BIT(i)))
+ continue;
if (tnow - scan_time[scan_edge_index[c][i]] <
- (new_mask ? keyscan_config.debounce_down_us :
+ (state[c] ? keyscan_config.debounce_down_us :
keyscan_config.debounce_up_us))
continue; /* Not done debouncing */
+ debouncing[c] &= ~BIT(i);
+ }
- debouncing[c] &= ~mask;
-
- /* Did the key change from its previous state? */
- if ((state[c] & mask) == new_mask)
- continue; /* No */
-
- state[c] ^= mask;
+ /* Recognize change in state, unless debounce in effect. */
+ diff = (new_state[c] ^ state[c]) & ~debouncing[c];
+ if (!diff)
+ continue;
+ for (i = 0; i < KEYBOARD_ROWS; i++) {
+ if (!(diff & BIT(i)))
+ continue;
+ scan_edge_index[c][i] = scan_time_index;
any_change = 1;
/* Inform keyboard module if scanning is enabled */
@@ -522,9 +501,19 @@ static int check_keys_changed(uint8_t *state)
/* This is no-op for protocols that require a
* full keyboard matrix (e.g., MKBP).
*/
- keyboard_state_changed(i, c, new_mask ? 1 : 0);
+ keyboard_state_changed(
+ i, c, !!(new_state[c] & BIT(i)));
}
}
+
+ /* For any keyboard events just sent, turn on debouncing. */
+ debouncing[c] |= diff;
+ /*
+ * Note: In order to "remember" what was last reported
+ * (up or down), the state bits are only updated if the
+ * edge was not suppressed due to debouncing.
+ */
+ state[c] ^= diff;
}
if (any_change) {
@@ -681,7 +670,6 @@ void keyboard_scan_init(void)
/* Initialize raw state */
read_matrix(debounced_state);
- memcpy(prev_state, debounced_state, sizeof(prev_state));
#ifdef CONFIG_KEYBOARD_LANGUAGE_ID
/* Check keyboard ID state */
@@ -982,7 +970,6 @@ static int command_ksstate(int argc, char **argv)
}
print_state(debounced_state, "debounced ");
- print_state(prev_state, "prev ");
print_state(debouncing, "debouncing");
ccprintf("Keyboard scan disable mask: 0x%08x\n",
diff --git a/test/kb_scan.c b/test/kb_scan.c
index b364d19368..3e066c041f 100644
--- a/test/kb_scan.c
+++ b/test/kb_scan.c
@@ -40,6 +40,15 @@ static int hibernated;
static int reset_called;
#endif
+/*
+ * Helper method to wake a given task, and provide immediate opportunity to run.
+ */
+static void task_wake_then_sleep_1ms(int task_id)
+{
+ task_wake(task_id);
+ msleep(1);
+}
+
#ifdef CONFIG_LID_SWITCH
int lid_is_open(void)
{
@@ -195,59 +204,83 @@ static int deghost_test(void)
static int debounce_test(void)
{
int old_count = fifo_add_count;
+ int i;
+
+ /* One brief keypress is detected. */
+ msleep(40);
mock_key(1, 1, 1);
- task_wake(TASK_ID_KEYSCAN);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
mock_key(1, 1, 0);
- task_wake(TASK_ID_KEYSCAN);
- CHECK_KEY_COUNT(old_count, 0);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
+ CHECK_KEY_COUNT(old_count, 2);
+ /* Brief bounce, followed by continuous press is detected as one. */
+ msleep(40);
mock_key(1, 1, 1);
- task_wake(TASK_ID_KEYSCAN);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
mock_key(1, 1, 0);
- task_wake(TASK_ID_KEYSCAN);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
mock_key(1, 1, 1);
- task_wake(TASK_ID_KEYSCAN);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
CHECK_KEY_COUNT(old_count, 1);
+ /* Brief lifting, then re-presseing is detected as new keypress. */
+ msleep(40);
mock_key(1, 1, 0);
- task_wake(TASK_ID_KEYSCAN);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
mock_key(1, 1, 1);
- task_wake(TASK_ID_KEYSCAN);
- CHECK_KEY_COUNT(old_count, 0);
-
- mock_key(2, 2, 1);
- task_wake(TASK_ID_KEYSCAN);
- mock_key(2, 2, 0);
- task_wake(TASK_ID_KEYSCAN);
- CHECK_KEY_COUNT(old_count, 0);
-
- mock_key(2, 2, 1);
- task_wake(TASK_ID_KEYSCAN);
- mock_key(2, 2, 0);
- task_wake(TASK_ID_KEYSCAN);
- mock_key(2, 2, 1);
- task_wake(TASK_ID_KEYSCAN);
- CHECK_KEY_COUNT(old_count, 1);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
+ CHECK_KEY_COUNT(old_count, 2);
+ /* One bouncy re-contact while lifting is ignored. */
+ msleep(40);
mock_key(1, 1, 0);
- task_wake(TASK_ID_KEYSCAN);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
mock_key(1, 1, 1);
- task_wake(TASK_ID_KEYSCAN);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
mock_key(1, 1, 0);
- task_wake(TASK_ID_KEYSCAN);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
CHECK_KEY_COUNT(old_count, 1);
- mock_key(2, 2, 0);
- task_wake(TASK_ID_KEYSCAN);
- mock_key(2, 2, 1);
- task_wake(TASK_ID_KEYSCAN);
- mock_key(2, 2, 0);
- task_wake(TASK_ID_KEYSCAN);
- mock_key(2, 2, 1);
- task_wake(TASK_ID_KEYSCAN);
- mock_key(2, 2, 0);
- task_wake(TASK_ID_KEYSCAN);
+ /*
+ * Debounce interval of first key is not affected by continued
+ * activity of other keys.
+ */
+ msleep(40);
+ /* Push the first key */
+ mock_key(0, 1, 0);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
+ /*
+ * Push down each subsequent key, until all 8 are pressed, each
+ * time bouncing the former one once.
+ */
+ for (i = 1 ; i < 8; i++) {
+ mock_key(i, 1, 1);
+ task_wake(TASK_ID_KEYSCAN);
+ msleep(3);
+ mock_key(i - 1, 1, 0);
+ task_wake(TASK_ID_KEYSCAN);
+ msleep(1);
+ mock_key(i - 1, 1, 1);
+ task_wake(TASK_ID_KEYSCAN);
+ msleep(1);
+ }
+ /* Verify that the bounces were. ignored */
+ CHECK_KEY_COUNT(old_count, 8);
+ /*
+ * Now briefly lift and re-press the first one, which should now be past
+ * its debounce interval
+ */
+ mock_key(0, 1, 0);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
+ CHECK_KEY_COUNT(old_count, 1);
+ mock_key(0, 1, 1);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
CHECK_KEY_COUNT(old_count, 1);
+ /* For good measure, release all keys before proceeding. */
+ for (i = 0; i < 8; i++)
+ mock_key(i, 1, 0);
+ task_wake_then_sleep_1ms(TASK_ID_KEYSCAN);
return EC_SUCCESS;
}
@@ -256,12 +289,17 @@ static int simulate_key_test(void)
{
int old_count;
+ task_wake(TASK_ID_KEYSCAN);
+ msleep(40); /* Wait for debouncing to settle */
+
old_count = fifo_add_count;
host_command_simulate(1, 1, 1);
TEST_ASSERT(fifo_add_count > old_count);
+ msleep(40);
old_count = fifo_add_count;
host_command_simulate(1, 1, 0);
TEST_ASSERT(fifo_add_count > old_count);
+ msleep(40);
return EC_SUCCESS;
}
@@ -330,8 +368,11 @@ static int runtime_key_test(void)
#ifdef CONFIG_LID_SWITCH
static int lid_test(void)
{
+ msleep(40); /* Allow debounce to settle */
+
lid_open = 0;
hook_notify(HOOK_LID_CHANGE);
+ msleep(1); /* Allow hooks to run */
mock_key(1, 1, 1);
TEST_ASSERT(expect_no_keychange() == EC_SUCCESS);
mock_key(1, 1, 0);
@@ -339,6 +380,7 @@ static int lid_test(void)
lid_open = 1;
hook_notify(HOOK_LID_CHANGE);
+ msleep(1); /* Allow hooks to run */
mock_key(1, 1, 1);
TEST_ASSERT(expect_keychange() == EC_SUCCESS);
mock_key(1, 1, 0);