chrome-ec/test/kb_8042.c

346 lines
7.2 KiB
C

/* 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.
*
* 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(EC_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;
}
static const struct ec_response_keybd_config keybd_config = {
.num_top_row_keys = 13,
.action_keys = {
TK_BACK, /* T1 */
TK_REFRESH, /* T2 */
TK_FULLSCREEN, /* T3 */
TK_OVERVIEW, /* T4 */
TK_SNAPSHOT, /* T5 */
TK_BRIGHTNESS_DOWN, /* T6 */
TK_BRIGHTNESS_UP, /* T7 */
TK_KBD_BKLIGHT_DOWN, /* T8 */
TK_KBD_BKLIGHT_UP, /* T9 */
TK_PLAY_PAUSE, /* T10 */
TK_VOL_MUTE, /* T11 */
TK_VOL_DOWN, /* T12 */
TK_VOL_UP, /* T13 */
},
};
__override const struct ec_response_keybd_config
*board_vivaldi_keybd_config(void)
{
return &keybd_config;
}
static int test_ec_cmd_get_keybd_config(void)
{
struct ec_response_keybd_config resp;
int rv;
rv = test_send_host_command(EC_CMD_GET_KEYBD_CONFIG, 0, NULL, 0,
&resp, sizeof(resp));
if (rv != EC_RES_SUCCESS) {
ccprintf("Error: EC_CMD_GET_KEYBD_CONFIG cmd returns %d\n", rv);
return EC_ERROR_INVAL;
}
if (memcmp(&resp, &keybd_config, sizeof(resp))) {
ccprintf("Error: EC_CMD_GET_KEYBD_CONFIG returned bad cfg\n");
return EC_ERROR_INVAL;
}
ccprintf("EC_CMD_GET_KEYBD_CONFIG response is good\n");
return EC_SUCCESS;
}
static int test_vivaldi_top_keys(void)
{
set_scancode(2);
/* Test REFRESH key */
write_cmd_byte(read_cmd_byte() | I8042_XLATE);
press_key(2, 3, 1); /* Press T2 */
VERIFY_LPC_CHAR("\xe0\x67"); /* Check REFRESH scancode in set-1 */
/* Test SNAPSHOT key */
write_cmd_byte(read_cmd_byte() | I8042_XLATE);
press_key(4, 3, 1); /* Press T2 */
VERIFY_LPC_CHAR("\xe0\x13"); /* Check SNAPSHOT scancode in set-1 */
/* Test VOL_UP key */
write_cmd_byte(read_cmd_byte() | I8042_XLATE);
press_key(5, 3, 1); /* Press T2 */
VERIFY_LPC_CHAR("\xe0\x30"); /* Check VOL_UP scancode in set-1 */
return EC_SUCCESS;
}
void run_test(int argc, char **argv)
{
test_reset();
wait_for_task_started();
if (system_get_image_copy() == EC_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_ec_cmd_get_keybd_config);
RUN_TEST(test_vivaldi_top_keys);
RUN_TEST(test_sysjump);
} else {
RUN_TEST(test_sysjump_cont);
}
test_print_result();
}