stm32: Implement keyscan configuration command

Implement a command to allow getting and setting the keyboard
configuration.

BUG=chrome-os-partner:12179
TEST=manual
- use ectool to read all keyscan paramters
- use ectool to update flags to 0, see that keyboard stops working,
then set flags to 1 and see that it starts working again.
- use ectool to update scanning period to 100ms, see that it drops lots
of keys when typing
- use ectool to set fifo size to 1, see that the fifo no longer fills
up

Change-Id: I5afb3b48b1262a1570d7411ffd8b2e6ea3a65f6b
BRANCH=snow,link
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/34635
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Simon Glass
2012-10-04 09:28:26 -07:00
committed by Gerrit
parent 9bf1539d21
commit dd2d41003d
2 changed files with 239 additions and 0 deletions

View File

@@ -550,3 +550,91 @@ DECLARE_CONSOLE_COMMAND(kbpress, command_keyboard_press,
"[col] [row] [0 | 1]",
"Simulate keypress",
NULL);
/**
* Copy keyscan configuration from one place to another according to flags
*
* This is like a structure copy, except that only selected fields are
* copied.
*
* TODO(sjg@chromium.org): Consider making this table drive as ectool.
*
* @param src Source config
* @param dst Destination config
* @param valid_mask Bits representing which fields to copy - each bit is
* from enum mkbp_config_valid
* @param valid_flags Bit mask controlling flags to copy. Any 1 bit means
* that the corresponding bit in src->flags is copied
* over to dst->flags
*/
static void keyscan_copy_config(const struct ec_mkbp_config *src,
struct ec_mkbp_config *dst,
uint32_t valid_mask, uint8_t valid_flags)
{
uint8_t new_flags;
if (valid_mask & EC_MKBP_VALID_SCAN_PERIOD)
dst->scan_period_us = src->scan_period_us;
if (valid_mask & EC_MKBP_VALID_POLL_TIMEOUT)
dst->poll_timeout_us = src->poll_timeout_us;
if (valid_mask & EC_MKBP_VALID_MIN_POST_SCAN_DELAY) {
/*
* Key scanning is high priority, so we should require at
* least 100us min delay here. Setting this to 0 will cause
* watchdog events. Use 200 to be safe.
*/
dst->min_post_scan_delay_us =
MAX(src->min_post_scan_delay_us, 200);
}
if (valid_mask & EC_MKBP_VALID_OUTPUT_SETTLE)
dst->output_settle_us = src->output_settle_us;
if (valid_mask & EC_MKBP_VALID_DEBOUNCE_DOWN)
dst->debounce_down_us = src->debounce_down_us;
if (valid_mask & EC_MKBP_VALID_DEBOUNCE_UP)
dst->debounce_up_us = src->debounce_up_us;
if (valid_mask & EC_MKBP_VALID_FIFO_MAX_DEPTH) {
/* Sanity check for fifo depth */
dst->fifo_max_depth = MIN(src->fifo_max_depth,
KB_FIFO_DEPTH);
}
new_flags = dst->flags & ~valid_flags;
new_flags |= src->flags & valid_flags;
dst->flags = new_flags;
/*
* If we just enabled key scanning, kick the task so that it will
* fall out of the task_wait_event() in keyboard_scan_task().
*/
if ((new_flags & EC_MKBP_FLAGS_ENABLE) &&
!(dst->flags & EC_MKBP_FLAGS_ENABLE))
task_wake(TASK_ID_KEYSCAN);
}
static int host_command_mkbp_set_config(struct host_cmd_handler_args *args)
{
const struct ec_params_mkbp_set_config *req = args->params;
keyscan_copy_config(&req->config, &config,
config.valid_mask & req->config.valid_mask,
config.valid_flags & req->config.valid_flags);
return EC_RES_SUCCESS;
}
static int host_command_mkbp_get_config(struct host_cmd_handler_args *args)
{
struct ec_response_mkbp_get_config *resp = args->response;
memcpy(&resp->config, &config, sizeof(config));
args->response_size = sizeof(*resp);
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_MKBP_SET_CONFIG,
host_command_mkbp_set_config,
EC_VER_MASK(0));
DECLARE_HOST_COMMAND(EC_CMD_MKBP_GET_CONFIG,
host_command_mkbp_get_config,
EC_VER_MASK(0));

View File

@@ -2233,6 +2233,156 @@ int cmd_port_80_flood(int argc, char *argv[])
return 0;
}
struct param_info {
const char *name; /* name of this parameter */
const char *help; /* help message */
int size; /* size in bytes */
int offset; /* offset within structure */
};
#define FIELD(fname, field, help_str) \
{ \
.name = fname, \
.help = help_str, \
.size = sizeof(((struct ec_mkbp_config *)NULL)->field), \
.offset = __builtin_offsetof(struct ec_mkbp_config, field), \
}
static const struct param_info keyconfig_params[] = {
FIELD("scan_period", scan_period_us, "period between scans"),
FIELD("poll_timeout", poll_timeout_us,
"revert to irq mode after no activity for this long"),
FIELD("min_post_scan_delay", min_post_scan_delay_us,
"minimum post-scan delay before starting a new scan"),
FIELD("output_settle", output_settle_us,
"delay to wait for output to settle"),
FIELD("debounce_down", debounce_down_us,
"time for debounce on key down"),
FIELD("debounce_up", debounce_up_us, "time for debounce on key up"),
FIELD("fifo_max_depth", fifo_max_depth,
"maximum depth to allow for fifo (0 = disable)"),
FIELD("flags", flags, "0 to disable scanning, 1 to enable"),
};
static const struct param_info *find_field(const struct param_info *params,
int count, const char *name, unsigned int *nump)
{
const struct param_info *param;
int i;
for (i = 0, param = params; i < count; i++, param++) {
if (0 == strcmp(param->name, name)) {
if (nump)
*nump = i;
return param;
}
}
fprintf(stderr, "Unknown parameter '%s'\n", name);
return NULL;
}
static int get_value(const struct param_info *param, const char *config)
{
const char *field;
field = config + param->offset;
switch (param->size) {
case 1:
return *(uint8_t *)field;
case 2:
return *(uint16_t *)field;
case 4:
return *(uint32_t *)field;
default:
fprintf(stderr, "Internal error: unknown size %d\n",
param->size);
}
return -1;
}
static int show_fields(struct ec_mkbp_config *config, int argc, char *argv[])
{
const struct param_info *param;
uint32_t mask ;
int i;
if (!argc) {
mask = -1U; /* show all fields */
} else {
mask = 0;
while (argc > 0) {
unsigned int num;
param = find_field(keyconfig_params,
ARRAY_SIZE(keyconfig_params),
argv[0], &num);
if (!param)
return -1;
mask |= 1 << num;
argc--;
argv++;
}
}
param = keyconfig_params;
for (i = 0; i < ARRAY_SIZE(keyconfig_params); i++, param++) {
if (mask & (1 << i)) {
fprintf(stderr, "%-12s %u\n", param->name,
get_value(param, (char *)config));
}
}
return 0;
}
static int cmd_keyconfig(int argc, char *argv[])
{
struct ec_params_mkbp_set_config req;
int cmd;
int rv;
if (argc < 2) {
const struct param_info *param;
int i;
fprintf(stderr, "Usage: %s get [<param>] - print params\n"
"\t%s set [<param>> <value>]\n"
" Available params are: (all time values are in us)",
argv[0], argv[0]);
param = keyconfig_params;
for (i = 0; i < ARRAY_SIZE(keyconfig_params); i++, param++) {
fprintf(stderr, "%-12s %s\n", param->name,
param->name);
}
return -1;
}
/* Get the command */
if (0 == strcmp(argv[1], "get")) {
cmd = EC_CMD_MKBP_GET_CONFIG;
} else if (0 == strcmp(argv[1], "set")) {
cmd = EC_CMD_MKBP_SET_CONFIG;
} else {
fprintf(stderr, "Invalid command '%s\n", argv[1]);
return -1;
}
switch (cmd) {
case EC_CMD_MKBP_GET_CONFIG:
/* Read the existing config */
rv = ec_command(cmd, 0, NULL, 0, &req, sizeof(req));
if (rv < 0)
return rv;
show_fields(&req.config, argc - 2, argv + 2);
break;
}
return 0;
}
struct command {
const char *name;
int (*handler)(int argc, char *argv[]);
@@ -2273,6 +2423,7 @@ const struct command commands[] = {
{"i2cread", cmd_i2c_read},
{"i2cwrite", cmd_i2c_write},
{"lightbar", cmd_lightbar},
{"keyconfig", cmd_keyconfig},
{"pstoreinfo", cmd_pstore_info},
{"pstoreread", cmd_pstore_read},
{"pstorewrite", cmd_pstore_write},