diff options
Diffstat (limited to 'test/kb_scan.c')
-rw-r--r-- | test/kb_scan.c | 653 |
1 files changed, 0 insertions, 653 deletions
diff --git a/test/kb_scan.c b/test/kb_scan.c deleted file mode 100644 index a43808c0c1..0000000000 --- a/test/kb_scan.c +++ /dev/null @@ -1,653 +0,0 @@ -/* Copyright 2013 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * Copyright 2013 Google Inc. - * - * Tests for keyboard scan deghosting and debouncing. - */ - -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "host_command.h" -#include "keyboard_raw.h" -#include "keyboard_scan.h" -#include "lid_switch.h" -#include "system.h" -#include "task.h" -#include "test_util.h" -#include "timer.h" -#include "util.h" - -#define KEYDOWN_DELAY_MS 10 -#define KEYDOWN_RETRY 10 -#define NO_KEYDOWN_DELAY_MS 100 - -#define CHECK_KEY_COUNT(old, expected) \ - do { \ - if (verify_key_presses(old, expected) != EC_SUCCESS) \ - return EC_ERROR_UNKNOWN; \ - old = fifo_add_count; \ - } while (0) - -/* Emulated physical key state */ -static uint8_t mock_state[KEYBOARD_COLS_MAX]; - -/* Snapshot of last known key state */ -static uint8_t key_state[KEYBOARD_COLS_MAX]; - -/* Counters for key state changes (UP/DOWN) */ -static int key_state_change[KEYBOARD_COLS_MAX][KEYBOARD_ROWS]; -static int total_key_state_change; - -static int column_driven; -static int fifo_add_count; -static int lid_open; -#ifdef EMU_BUILD -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) -{ - return lid_open; -} -#endif - -void keyboard_raw_drive_column(int out) -{ - column_driven = out; -} - -int keyboard_raw_read_rows(void) -{ - int i; - int r = 0; - - if (column_driven == KEYBOARD_COLUMN_NONE) { - return 0; - } else if (column_driven == KEYBOARD_COLUMN_ALL) { - for (i = 0; i < KEYBOARD_COLS_MAX; ++i) - r |= mock_state[i]; - return r; - } else { - return mock_state[column_driven]; - } -} - -int mkbp_keyboard_add(const uint8_t *buffp) -{ - int c, r; - - fifo_add_count++; - - for (c = 0; c < KEYBOARD_COLS_MAX; c++) { - uint8_t diff = key_state[c] ^ buffp[c]; - - for (r = 0; r < KEYBOARD_ROWS; r++) { - if (diff & BIT(r)) { - key_state_change[c][r]++; - total_key_state_change++; - } - } - } - - /* Save a snapshot. */ - memcpy(key_state, buffp, sizeof(key_state)); - - return EC_SUCCESS; -} - -#ifdef EMU_BUILD -void system_hibernate(uint32_t s, uint32_t us) -{ - hibernated = 1; -} - -void chipset_reset(void) -{ - reset_called = 1; -} -#endif - -#define mock_defined_key(k, p) mock_key(KEYBOARD_ROW_ ## k, \ - KEYBOARD_COL_ ## k, \ - p) - -#define mock_default_key(k, p) mock_key(KEYBOARD_DEFAULT_ROW_ ## k, \ - KEYBOARD_DEFAULT_COL_ ## k, \ - p) - -static void mock_key(int r, int c, int keydown) -{ - ccprintf(" %s (%d, %d)\n", keydown ? "Pressing" : "Releasing", r, c); - if (keydown) - mock_state[c] |= (1 << r); - else - mock_state[c] &= ~(1 << r); -} - -static void reset_key_state(void) -{ - memset(mock_state, 0, sizeof(mock_state)); - memset(key_state, 0, sizeof(key_state)); - memset(key_state_change, 0, sizeof(key_state_change)); - task_wake(TASK_ID_KEYSCAN); - msleep(NO_KEYDOWN_DELAY_MS); - total_key_state_change = 0; -} - -static int expect_keychange(void) -{ - int old_count = fifo_add_count; - int retry = KEYDOWN_RETRY; - task_wake(TASK_ID_KEYSCAN); - while (retry--) { - msleep(KEYDOWN_DELAY_MS); - if (fifo_add_count > old_count) - return EC_SUCCESS; - } - return EC_ERROR_UNKNOWN; -} - -static int expect_no_keychange(void) -{ - int old_count = fifo_add_count; - task_wake(TASK_ID_KEYSCAN); - msleep(NO_KEYDOWN_DELAY_MS); - return (fifo_add_count == old_count) ? EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -static int host_command_simulate(int r, int c, int keydown) -{ - struct ec_params_mkbp_simulate_key params; - - params.col = c; - params.row = r; - params.pressed = keydown; - - return test_send_host_command(EC_CMD_MKBP_SIMULATE_KEY, 0, ¶ms, - sizeof(params), NULL, 0); -} - -static int verify_key_presses(int old, int expected) -{ - int retry = KEYDOWN_RETRY; - - if (expected == 0) { - msleep(NO_KEYDOWN_DELAY_MS); - return (fifo_add_count == old) ? EC_SUCCESS : EC_ERROR_UNKNOWN; - } else { - while (retry--) { - msleep(KEYDOWN_DELAY_MS); - if (fifo_add_count == old + expected) - return EC_SUCCESS; - } - return EC_ERROR_UNKNOWN; - } -} - -static int deghost_test(void) -{ - reset_key_state(); - - /* Test we can detect a keypress */ - mock_key(1, 1, 1); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - mock_key(1, 1, 0); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - - /* (1, 1) (1, 2) (2, 1) (2, 2) form ghosting keys */ - mock_key(1, 1, 1); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - mock_key(2, 2, 1); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - mock_key(1, 2, 1); - mock_key(2, 1, 1); - TEST_ASSERT(expect_no_keychange() == EC_SUCCESS); - mock_key(2, 1, 0); - mock_key(1, 2, 0); - TEST_ASSERT(expect_no_keychange() == EC_SUCCESS); - mock_key(2, 2, 0); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - mock_key(1, 1, 0); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - - /* (1, 1) (2, 0) (2, 1) don't form ghosting keys */ - mock_key(1, 1, 1); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - mock_key(2, 0, 1); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - mock_key(1, 0, 1); - mock_key(2, 1, 1); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - mock_key(1, 0, 0); - mock_key(2, 1, 0); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - mock_key(2, 0, 0); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - mock_key(1, 1, 0); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - - return EC_SUCCESS; -} - -static int strict_debounce_test(void) -{ - reset_key_state(); - - ccprintf("Test key press & hold.\n"); - mock_key(1, 1, 1); - TEST_EQ(expect_keychange(), EC_SUCCESS, "%d"); - TEST_EQ(key_state_change[1][1], 1, "%d"); - TEST_EQ(total_key_state_change, 1, "%d"); - ccprintf("Pass.\n"); - - reset_key_state(); - - ccprintf("Test a short stroke.\n"); - mock_key(1, 1, 1); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 0); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - TEST_EQ(expect_no_keychange(), EC_SUCCESS, "%d"); - TEST_EQ(key_state_change[1][1], 0, "%d"); - ccprintf("Pass.\n"); - - reset_key_state(); - - ccprintf("Test ripples being suppressed.\n"); - /* DOWN */ - mock_key(1, 1, 1); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 0); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 1); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - TEST_EQ(expect_keychange(), EC_SUCCESS, "%d"); - TEST_EQ(key_state_change[1][1], 1, "%d"); - TEST_EQ(total_key_state_change, 1, "%d"); - /* UP */ - mock_key(1, 1, 0); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 1); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 0); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - TEST_EQ(expect_keychange(), EC_SUCCESS, "%d"); - TEST_EQ(key_state_change[1][1], 2, "%d"); - TEST_EQ(total_key_state_change, 2, "%d"); - ccprintf("Pass.\n"); - - reset_key_state(); - - ccprintf("Test simultaneous strokes.\n"); - mock_key(1, 1, 1); - mock_key(2, 1, 1); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - TEST_EQ(expect_keychange(), EC_SUCCESS, "%d"); - TEST_EQ(key_state_change[1][1], 1, "%d"); - TEST_EQ(key_state_change[1][2], 1, "%d"); - TEST_EQ(total_key_state_change, 2, "%d"); - ccprintf("Pass.\n"); - - reset_key_state(); - - ccprintf("Test simultaneous strokes in two columns.\n"); - mock_key(1, 1, 1); - mock_key(1, 2, 1); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - TEST_EQ(expect_keychange(), EC_SUCCESS, "%d"); - TEST_EQ(key_state_change[1][1], 1, "%d"); - TEST_EQ(key_state_change[2][1], 1, "%d"); - TEST_EQ(total_key_state_change, 2, "%d"); - ccprintf("Pass.\n"); - - reset_key_state(); - - ccprintf("Test normal & short simultaneous strokes.\n"); - mock_key(1, 1, 1); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(2, 1, 1); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 0); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - TEST_EQ(expect_keychange(), EC_SUCCESS, "%d"); - TEST_EQ(key_state_change[1][1], 0, "%d"); - TEST_EQ(key_state_change[1][2], 1, "%d"); - TEST_EQ(total_key_state_change, 1, "%d"); - ccprintf("Pass.\n"); - - reset_key_state(); - - ccprintf("Test normal & short simultaneous strokes in two columns.\n"); - reset_key_state(); - mock_key(1, 1, 1); - task_wake(TASK_ID_KEYSCAN); - mock_key(1, 2, 1); - task_wake(TASK_ID_KEYSCAN); - mock_key(1, 1, 0); - task_wake(TASK_ID_KEYSCAN); - TEST_EQ(expect_keychange(), EC_SUCCESS, "%d"); - TEST_EQ(key_state_change[1][1], 0, "%d"); - TEST_EQ(key_state_change[2][1], 1, "%d"); - TEST_EQ(total_key_state_change, 1, "%d"); - ccprintf("Pass.\n"); - - return EC_SUCCESS; -} - -static int debounce_test(void) -{ - int old_count = fifo_add_count; - int i; - - reset_key_state(); - - /* One brief keypress is detected. */ - msleep(40); - mock_key(1, 1, 1); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 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_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 0); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 1); - 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_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 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_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 1); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - mock_key(1, 1, 0); - task_wake_then_sleep_1ms(TASK_ID_KEYSCAN); - CHECK_KEY_COUNT(old_count, 1); - - /* - * 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; -} - -static int simulate_key_test(void) -{ - int old_count; - - reset_key_state(); - - 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; -} - -#ifdef EMU_BUILD -static int wait_variable_set(int *var) -{ - int retry = KEYDOWN_RETRY; - *var = 0; - task_wake(TASK_ID_KEYSCAN); - while (retry--) { - msleep(KEYDOWN_DELAY_MS); - if (*var == 1) - return EC_SUCCESS; - } - return EC_ERROR_UNKNOWN; -} - -static int verify_variable_not_set(int *var) -{ - *var = 0; - task_wake(TASK_ID_KEYSCAN); - msleep(NO_KEYDOWN_DELAY_MS); - return *var ? EC_ERROR_UNKNOWN : EC_SUCCESS; -} - -static int runtime_key_test(void) -{ - reset_key_state(); - - /* Alt-VolUp-H triggers system hibernation */ - mock_defined_key(LEFT_ALT, 1); - mock_default_key(VOL_UP, 1); - mock_defined_key(KEY_H, 1); - TEST_ASSERT(wait_variable_set(&hibernated) == EC_SUCCESS); - mock_defined_key(LEFT_ALT, 0); - mock_default_key(VOL_UP, 0); - mock_defined_key(KEY_H, 0); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - - /* Alt-VolUp-R triggers chipset reset */ - mock_defined_key(RIGHT_ALT, 1); - mock_default_key(VOL_UP, 1); - mock_defined_key(KEY_R, 1); - TEST_ASSERT(wait_variable_set(&reset_called) == EC_SUCCESS); - mock_defined_key(RIGHT_ALT, 0); - mock_default_key(VOL_UP, 0); - mock_defined_key(KEY_R, 0); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - - /* Must press exactly 3 keys to trigger runtime keys */ - mock_defined_key(LEFT_ALT, 1); - mock_defined_key(KEY_H, 1); - mock_defined_key(KEY_R, 1); - mock_default_key(VOL_UP, 1); - TEST_ASSERT(verify_variable_not_set(&hibernated) == EC_SUCCESS); - TEST_ASSERT(verify_variable_not_set(&reset_called) == EC_SUCCESS); - mock_default_key(VOL_UP, 0); - mock_defined_key(KEY_R, 0); - mock_defined_key(KEY_H, 0); - mock_defined_key(LEFT_ALT, 0); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - - return EC_SUCCESS; -} -#endif - -#ifdef CONFIG_LID_SWITCH -static int lid_test(void) -{ - reset_key_state(); - - 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); - TEST_ASSERT(expect_no_keychange() == EC_SUCCESS); - - 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); - TEST_ASSERT(expect_keychange() == EC_SUCCESS); - - return EC_SUCCESS; -} -#endif - -static int test_check_boot_esc(void) -{ - TEST_CHECK(keyboard_scan_get_boot_keys() == BOOT_KEY_ESC); -} - -static int test_check_boot_down(void) -{ - TEST_CHECK(keyboard_scan_get_boot_keys() == BOOT_KEY_DOWN_ARROW); -} - -void test_init(void) -{ - uint32_t state; - - system_get_scratchpad(&state); - - if (state & TEST_STATE_MASK(TEST_STATE_STEP_2)) { - /* Power-F3-ESC */ - system_set_reset_flags(system_get_reset_flags() | - EC_RESET_FLAG_RESET_PIN); - mock_key(KEYBOARD_ROW_ESC, KEYBOARD_COL_ESC, 1); - } else if (state & TEST_STATE_MASK(TEST_STATE_STEP_3)) { - /* Power-F3-Down */ - system_set_reset_flags(system_get_reset_flags() | - EC_RESET_FLAG_RESET_PIN); - mock_key(6, 11, 1); - } -} - -static void run_test_step1(void) -{ - lid_open = 1; - hook_notify(HOOK_LID_CHANGE); - test_reset(); - - RUN_TEST(deghost_test); - - if (IS_ENABLED(CONFIG_KEYBOARD_STRICT_DEBOUNCE)) - RUN_TEST(strict_debounce_test); - else - RUN_TEST(debounce_test); - - if (0) /* crbug.com/976974 */ - RUN_TEST(simulate_key_test); -#ifdef EMU_BUILD - RUN_TEST(runtime_key_test); -#endif -#ifdef CONFIG_LID_SWITCH - RUN_TEST(lid_test); -#endif - - if (test_get_error_count()) - test_reboot_to_next_step(TEST_STATE_FAILED); - else - test_reboot_to_next_step(TEST_STATE_STEP_2); -} - -static void run_test_step2(void) -{ - lid_open = 1; - hook_notify(HOOK_LID_CHANGE); - test_reset(); - - RUN_TEST(test_check_boot_esc); - - if (test_get_error_count()) - test_reboot_to_next_step(TEST_STATE_FAILED); - else - test_reboot_to_next_step(TEST_STATE_STEP_3); -} - -static void run_test_step3(void) -{ - lid_open = 1; - hook_notify(HOOK_LID_CHANGE); - test_reset(); - - RUN_TEST(test_check_boot_down); - - if (test_get_error_count()) - test_reboot_to_next_step(TEST_STATE_FAILED); - else - test_reboot_to_next_step(TEST_STATE_PASSED); -} - -void test_run_step(uint32_t state) -{ - if (state & TEST_STATE_MASK(TEST_STATE_STEP_1)) - run_test_step1(); - else if (state & TEST_STATE_MASK(TEST_STATE_STEP_2)) - run_test_step2(); - else if (state & TEST_STATE_MASK(TEST_STATE_STEP_3)) - run_test_step3(); -} - -int test_task(void *data) -{ - test_run_multistep(); - return EC_SUCCESS; -} - -void run_test(int argc, char **argv) -{ - msleep(30); /* Wait for TASK_ID_TEST to initialize */ - task_wake(TASK_ID_TEST); -} |