| /* Copyright (c) 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. |
| * |
| * Tests for keyboard MKBP protocol |
| */ |
| |
| #include "common.h" |
| #include "console.h" |
| #include "ec_commands.h" |
| #include "gpio.h" |
| #include "i8042_protocol.h" |
| #include "keyboard_8042.h" |
| #include "keyboard_protocol.h" |
| #include "keyboard_scan.h" |
| #include "lpc.h" |
| #include "power_button.h" |
| #include "system.h" |
| #include "test_util.h" |
| #include "timer.h" |
| #include "util.h" |
| |
| static const char *action[2] = {"release", "press"}; |
| |
| #define BUF_SIZE 16 |
| static char lpc_char_buf[BUF_SIZE]; |
| static unsigned int lpc_char_cnt; |
| |
| /*****************************************************************************/ |
| /* Mock functions */ |
| |
| int lid_is_open(void) |
| { |
| return 1; |
| } |
| |
| void lpc_keyboard_put_char(uint8_t chr, int send_irq) |
| { |
| lpc_char_buf[lpc_char_cnt++] = chr; |
| } |
| |
| /*****************************************************************************/ |
| /* Test utilities */ |
| |
| static void press_key(int c, int r, int pressed) |
| { |
| ccprintf("Input %s (%d, %d)\n", action[pressed], c, r); |
| keyboard_state_changed(r, c, pressed); |
| } |
| |
| static void enable_keystroke(int enabled) |
| { |
| uint8_t data = enabled ? I8042_CMD_ENABLE : I8042_CMD_RESET_DIS; |
| keyboard_host_write(data, 0); |
| msleep(30); |
| } |
| |
| static void reset_8042(void) |
| { |
| keyboard_host_write(I8042_CMD_RESET_DEF, 0); |
| msleep(30); |
| } |
| |
| static void set_typematic(uint8_t val) |
| { |
| keyboard_host_write(I8042_CMD_SETREP, 0); |
| msleep(30); |
| keyboard_host_write(val, 0); |
| msleep(30); |
| } |
| |
| static void set_scancode(uint8_t s) |
| { |
| keyboard_host_write(I8042_CMD_SSCANSET, 0); |
| msleep(30); |
| keyboard_host_write(s, 0); |
| msleep(30); |
| } |
| |
| static void write_cmd_byte(uint8_t val) |
| { |
| keyboard_host_write(I8042_WRITE_CMD_BYTE, 1); |
| msleep(30); |
| keyboard_host_write(val, 0); |
| msleep(30); |
| } |
| |
| static uint8_t read_cmd_byte(void) |
| { |
| lpc_char_cnt = 0; |
| keyboard_host_write(I8042_READ_CMD_BYTE, 1); |
| msleep(30); |
| return lpc_char_buf[0]; |
| } |
| |
| static int __verify_lpc_char(char *arr, unsigned int sz, int delay_ms) |
| { |
| int i; |
| |
| lpc_char_cnt = 0; |
| for (i = 0; i < sz; ++i) |
| lpc_char_buf[i] = 0; |
| msleep(delay_ms); |
| TEST_ASSERT_ARRAY_EQ(arr, lpc_char_buf, sz); |
| return EC_SUCCESS; |
| } |
| |
| #define VERIFY_LPC_CHAR(s) \ |
| TEST_ASSERT(__verify_lpc_char(s, strlen(s), 30) == EC_SUCCESS) |
| #define VERIFY_LPC_CHAR_DELAY(s, t) \ |
| TEST_ASSERT(__verify_lpc_char(s, strlen(s), t) == EC_SUCCESS) |
| |
| static int __verify_no_char(void) |
| { |
| lpc_char_cnt = 0; |
| msleep(30); |
| TEST_CHECK(lpc_char_cnt == 0); |
| } |
| |
| #define VERIFY_NO_CHAR() TEST_ASSERT(__verify_no_char() == EC_SUCCESS) |
| |
| /*****************************************************************************/ |
| /* Tests */ |
| |
| static int test_single_key_press(void) |
| { |
| enable_keystroke(1); |
| press_key(1, 1, 1); |
| VERIFY_LPC_CHAR("\x01"); |
| press_key(1, 1, 0); |
| VERIFY_LPC_CHAR("\x81"); |
| |
| press_key(12, 6, 1); |
| VERIFY_LPC_CHAR("\xe0\x4d"); |
| press_key(12, 6, 0); |
| VERIFY_LPC_CHAR("\xe0\xcd"); |
| |
| return EC_SUCCESS; |
| } |
| |
| static int test_disable_keystroke(void) |
| { |
| enable_keystroke(0); |
| press_key(1, 1, 1); |
| VERIFY_NO_CHAR(); |
| press_key(1, 1, 0); |
| VERIFY_NO_CHAR(); |
| |
| return EC_SUCCESS; |
| } |
| |
| static int test_typematic(void) |
| { |
| enable_keystroke(1); |
| |
| /* |
| * 250ms delay, 8 chars / sec. |
| */ |
| set_typematic(0xf); |
| |
| press_key(1, 1, 1); |
| VERIFY_LPC_CHAR_DELAY("\x01\x01\x01\x01\x01", 650); |
| press_key(1, 1, 0); |
| VERIFY_LPC_CHAR_DELAY("\x81", 300); |
| |
| /* |
| * 500ms delay, 10.9 chars / sec. |
| */ |
| reset_8042(); |
| |
| press_key(1, 1, 1); |
| VERIFY_LPC_CHAR_DELAY("\x01\x01\x01", 650); |
| press_key(1, 1, 0); |
| VERIFY_LPC_CHAR_DELAY("\x81", 200); |
| |
| return EC_SUCCESS; |
| } |
| |
| static int test_scancode_set2(void) |
| { |
| set_scancode(2); |
| |
| write_cmd_byte(read_cmd_byte() | I8042_XLATE); |
| press_key(1, 1, 1); |
| VERIFY_LPC_CHAR("\x01"); |
| press_key(1, 1, 0); |
| VERIFY_LPC_CHAR("\x81"); |
| |
| write_cmd_byte(read_cmd_byte() & ~I8042_XLATE); |
| press_key(1, 1, 1); |
| VERIFY_LPC_CHAR("\x76"); |
| press_key(1, 1, 0); |
| VERIFY_LPC_CHAR("\xf0\x76"); |
| |
| return EC_SUCCESS; |
| } |
| |
| static int test_power_button(void) |
| { |
| gpio_set_level(GPIO_POWER_BUTTON_L, 1); |
| set_scancode(1); |
| test_chipset_on(); |
| |
| gpio_set_level(GPIO_POWER_BUTTON_L, 0); |
| VERIFY_LPC_CHAR_DELAY("\xe0\x5e", 100); |
| |
| gpio_set_level(GPIO_POWER_BUTTON_L, 1); |
| VERIFY_LPC_CHAR_DELAY("\xe0\xde", 100); |
| |
| set_scancode(2); |
| write_cmd_byte(read_cmd_byte() & ~I8042_XLATE); |
| |
| gpio_set_level(GPIO_POWER_BUTTON_L, 0); |
| VERIFY_LPC_CHAR_DELAY("\xe0\x37", 100); |
| |
| gpio_set_level(GPIO_POWER_BUTTON_L, 1); |
| VERIFY_LPC_CHAR_DELAY("\xe0\xf0\x37", 100); |
| |
| test_chipset_off(); |
| |
| gpio_set_level(GPIO_POWER_BUTTON_L, 0); |
| VERIFY_NO_CHAR(); |
| |
| gpio_set_level(GPIO_POWER_BUTTON_L, 1); |
| VERIFY_NO_CHAR(); |
| |
| return EC_SUCCESS; |
| } |
| |
| static int test_sysjump(void) |
| { |
| set_scancode(2); |
| enable_keystroke(1); |
| |
| system_run_image_copy(SYSTEM_IMAGE_RW); |
| |
| /* Shouldn't reach here */ |
| return EC_ERROR_UNKNOWN; |
| } |
| |
| static int test_sysjump_cont(void) |
| { |
| write_cmd_byte(read_cmd_byte() | I8042_XLATE); |
| press_key(1, 1, 1); |
| VERIFY_LPC_CHAR("\x01"); |
| press_key(1, 1, 0); |
| VERIFY_LPC_CHAR("\x81"); |
| |
| write_cmd_byte(read_cmd_byte() & ~I8042_XLATE); |
| press_key(1, 1, 1); |
| VERIFY_LPC_CHAR("\x76"); |
| press_key(1, 1, 0); |
| VERIFY_LPC_CHAR("\xf0\x76"); |
| |
| return EC_SUCCESS; |
| } |
| |
| void run_test(void) |
| { |
| test_reset(); |
| wait_for_task_started(); |
| |
| if (system_get_image_copy() == SYSTEM_IMAGE_RO) { |
| RUN_TEST(test_single_key_press); |
| RUN_TEST(test_disable_keystroke); |
| RUN_TEST(test_typematic); |
| RUN_TEST(test_scancode_set2); |
| RUN_TEST(test_power_button); |
| RUN_TEST(test_sysjump); |
| } else { |
| RUN_TEST(test_sysjump_cont); |
| } |
| |
| test_print_result(); |
| } |