304 lines
6.5 KiB
C
304 lines
6.5 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 "host_command.h"
|
||
|
#include "keyboard_mkbp.h"
|
||
|
#include "keyboard_protocol.h"
|
||
|
#include "keyboard_scan.h"
|
||
|
#include "test_util.h"
|
||
|
#include "util.h"
|
||
|
|
||
|
static uint8_t state[KEYBOARD_COLS_MAX];
|
||
|
static int ec_int_level;
|
||
|
|
||
|
static const char *action[2] = {"release", "press"};
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
/* Mock functions */
|
||
|
|
||
|
void host_send_response(struct host_cmd_handler_args *args)
|
||
|
{
|
||
|
/* Do nothing */
|
||
|
}
|
||
|
|
||
|
void gpio_set_level(enum gpio_signal signal, int level)
|
||
|
{
|
||
|
if (signal == GPIO_EC_INT_L)
|
||
|
ec_int_level = !!level;
|
||
|
}
|
||
|
|
||
|
int lid_is_open(void)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
/* Test utilities */
|
||
|
|
||
|
#define FIFO_EMPTY() (ec_int_level == 1)
|
||
|
#define FIFO_NOT_EMPTY() (ec_int_level == 0)
|
||
|
|
||
|
void clear_state(void)
|
||
|
{
|
||
|
memset(state, 0xff, KEYBOARD_COLS_MAX);
|
||
|
}
|
||
|
|
||
|
void set_state(int c, int r, int pressed)
|
||
|
{
|
||
|
uint8_t mask = (1 << r);
|
||
|
|
||
|
if (pressed)
|
||
|
state[c] &= ~mask;
|
||
|
else
|
||
|
state[c] |= mask;
|
||
|
}
|
||
|
|
||
|
int press_key(int c, int r, int pressed)
|
||
|
{
|
||
|
ccprintf("Input %s (%d, %d)\n", action[pressed], c, r);
|
||
|
set_state(c, r, pressed);
|
||
|
return keyboard_fifo_add(state);
|
||
|
}
|
||
|
|
||
|
int verify_key(int c, int r, int pressed)
|
||
|
{
|
||
|
struct host_cmd_handler_args args;
|
||
|
struct ec_response_get_next_event event;
|
||
|
int i;
|
||
|
|
||
|
args.version = 0;
|
||
|
args.command = EC_CMD_GET_NEXT_EVENT;
|
||
|
args.params = NULL;
|
||
|
args.params_size = 0;
|
||
|
args.response = &event;
|
||
|
args.response_max = sizeof(event);
|
||
|
args.response_size = 0;
|
||
|
|
||
|
if (c >= 0 && r >= 0) {
|
||
|
ccprintf("Verify %s (%d, %d)\n", action[pressed], c, r);
|
||
|
set_state(c, r, pressed);
|
||
|
|
||
|
if (host_command_process(&args) != EC_RES_SUCCESS)
|
||
|
return 0;
|
||
|
|
||
|
for (i = 0; i < KEYBOARD_COLS_MAX; ++i)
|
||
|
if (event.data.key_matrix[i] != state[i])
|
||
|
return 0;
|
||
|
} else {
|
||
|
ccprintf("Verify no events available\n");
|
||
|
if (host_command_process(&args) != EC_RES_UNAVAILABLE)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int verify_key_v2(int c, int r, int pressed, int expect_more)
|
||
|
{
|
||
|
struct host_cmd_handler_args args;
|
||
|
struct ec_response_get_next_event_v1 event;
|
||
|
int i;
|
||
|
|
||
|
args.version = 2;
|
||
|
args.command = EC_CMD_GET_NEXT_EVENT;
|
||
|
args.params = NULL;
|
||
|
args.params_size = 0;
|
||
|
args.response = &event;
|
||
|
args.response_max = sizeof(event);
|
||
|
args.response_size = 0;
|
||
|
|
||
|
if (c >= 0 && r >= 0) {
|
||
|
ccprintf("Verify %s (%d, %d). Expect %smore.\n",
|
||
|
action[pressed], c, r, expect_more ? "" : "no ");
|
||
|
set_state(c, r, pressed);
|
||
|
|
||
|
if (host_command_process(&args) != EC_RES_SUCCESS)
|
||
|
return 0;
|
||
|
|
||
|
if (!!(event.event_type & EC_MKBP_HAS_MORE_EVENTS) !=
|
||
|
expect_more) {
|
||
|
ccprintf("Incorrect more events!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < KEYBOARD_COLS_MAX; ++i)
|
||
|
if (event.data.key_matrix[i] != state[i])
|
||
|
return 0;
|
||
|
} else {
|
||
|
ccprintf("Verify no events available\n");
|
||
|
if (host_command_process(&args) != EC_RES_UNAVAILABLE)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int mkbp_config(struct ec_params_mkbp_set_config params)
|
||
|
{
|
||
|
struct host_cmd_handler_args args;
|
||
|
|
||
|
args.version = 0;
|
||
|
args.command = EC_CMD_MKBP_SET_CONFIG;
|
||
|
args.params = ¶ms;
|
||
|
args.params_size = sizeof(params);
|
||
|
args.response = NULL;
|
||
|
args.response_max = 0;
|
||
|
args.response_size = 0;
|
||
|
|
||
|
return host_command_process(&args) == EC_RES_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int set_fifo_size(int sz)
|
||
|
{
|
||
|
struct ec_params_mkbp_set_config params;
|
||
|
|
||
|
params.config.valid_mask = EC_MKBP_VALID_FIFO_MAX_DEPTH;
|
||
|
params.config.valid_flags = 0;
|
||
|
params.config.fifo_max_depth = sz;
|
||
|
|
||
|
return mkbp_config(params);
|
||
|
}
|
||
|
|
||
|
int set_kb_scan_enabled(int enabled)
|
||
|
{
|
||
|
struct ec_params_mkbp_set_config params;
|
||
|
|
||
|
params.config.valid_mask = 0;
|
||
|
params.config.valid_flags = EC_MKBP_FLAGS_ENABLE;
|
||
|
params.config.flags = (enabled ? EC_MKBP_FLAGS_ENABLE : 0);
|
||
|
|
||
|
return mkbp_config(params);
|
||
|
}
|
||
|
|
||
|
void clear_mkbp_events(void)
|
||
|
{
|
||
|
struct host_cmd_handler_args args;
|
||
|
struct ec_response_get_next_event event;
|
||
|
|
||
|
args.version = 0;
|
||
|
args.command = EC_CMD_GET_NEXT_EVENT;
|
||
|
args.params = NULL;
|
||
|
args.params_size = 0;
|
||
|
args.response = &event;
|
||
|
args.response_max = sizeof(event);
|
||
|
args.response_size = 0;
|
||
|
|
||
|
/*
|
||
|
* We should return EC_RES_UNAVAILABLE if there are no MKBP events left.
|
||
|
*/
|
||
|
while (host_command_process(&args) != EC_RES_UNAVAILABLE)
|
||
|
;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
/* Tests */
|
||
|
|
||
|
int single_key_press(void)
|
||
|
{
|
||
|
keyboard_clear_buffer();
|
||
|
clear_state();
|
||
|
TEST_ASSERT(press_key(0, 0, 1) == EC_SUCCESS);
|
||
|
TEST_ASSERT(FIFO_NOT_EMPTY());
|
||
|
TEST_ASSERT(press_key(0, 0, 0) == EC_SUCCESS);
|
||
|
TEST_ASSERT(FIFO_NOT_EMPTY());
|
||
|
|
||
|
clear_state();
|
||
|
TEST_ASSERT(verify_key(0, 0, 1));
|
||
|
TEST_ASSERT(FIFO_NOT_EMPTY());
|
||
|
TEST_ASSERT(verify_key(0, 0, 0));
|
||
|
TEST_ASSERT(FIFO_EMPTY());
|
||
|
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int single_key_press_v2(void)
|
||
|
{
|
||
|
keyboard_clear_buffer();
|
||
|
clear_state();
|
||
|
TEST_ASSERT(press_key(0, 0, 1) == EC_SUCCESS);
|
||
|
TEST_ASSERT(FIFO_NOT_EMPTY());
|
||
|
TEST_ASSERT(press_key(0, 0, 0) == EC_SUCCESS);
|
||
|
TEST_ASSERT(FIFO_NOT_EMPTY());
|
||
|
|
||
|
clear_state();
|
||
|
TEST_ASSERT(verify_key_v2(0, 0, 1, 1));
|
||
|
TEST_ASSERT(FIFO_NOT_EMPTY());
|
||
|
TEST_ASSERT(verify_key_v2(0, 0, 0, 0));
|
||
|
TEST_ASSERT(FIFO_EMPTY());
|
||
|
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int test_fifo_size(void)
|
||
|
{
|
||
|
keyboard_clear_buffer();
|
||
|
clear_state();
|
||
|
TEST_ASSERT(set_fifo_size(1));
|
||
|
TEST_ASSERT(press_key(0, 0, 1) == EC_SUCCESS);
|
||
|
TEST_ASSERT(press_key(0, 0, 0) == EC_ERROR_OVERFLOW);
|
||
|
|
||
|
clear_state();
|
||
|
TEST_ASSERT(verify_key(0, 0, 1));
|
||
|
TEST_ASSERT(FIFO_EMPTY());
|
||
|
|
||
|
/* Restore FIFO size */
|
||
|
TEST_ASSERT(set_fifo_size(100));
|
||
|
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int test_enable(void)
|
||
|
{
|
||
|
keyboard_clear_buffer();
|
||
|
clear_state();
|
||
|
TEST_ASSERT(set_kb_scan_enabled(0));
|
||
|
TEST_ASSERT(press_key(0, 0, 1) == EC_SUCCESS);
|
||
|
TEST_ASSERT(FIFO_EMPTY());
|
||
|
|
||
|
TEST_ASSERT(set_kb_scan_enabled(1));
|
||
|
TEST_ASSERT(press_key(0, 0, 1) == EC_SUCCESS);
|
||
|
TEST_ASSERT(FIFO_NOT_EMPTY());
|
||
|
TEST_ASSERT(verify_key(0, 0, 1));
|
||
|
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int fifo_underrun(void)
|
||
|
{
|
||
|
keyboard_clear_buffer();
|
||
|
clear_state();
|
||
|
TEST_ASSERT(press_key(0, 0, 1) == EC_SUCCESS);
|
||
|
|
||
|
clear_state();
|
||
|
TEST_ASSERT(verify_key(0, 0, 1));
|
||
|
|
||
|
/* When FIFO under run, host command reutns last known state */
|
||
|
TEST_ASSERT(verify_key(-1, -1, -1));
|
||
|
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
void run_test(void)
|
||
|
{
|
||
|
ec_int_level = 1;
|
||
|
test_reset();
|
||
|
|
||
|
/* Clear any pending events such as lid open. */
|
||
|
clear_mkbp_events();
|
||
|
RUN_TEST(single_key_press);
|
||
|
RUN_TEST(single_key_press_v2);
|
||
|
RUN_TEST(test_fifo_size);
|
||
|
RUN_TEST(test_enable);
|
||
|
RUN_TEST(fifo_underrun);
|
||
|
|
||
|
test_print_result();
|
||
|
}
|