mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-11 18:35:28 +00:00
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:
@@ -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));
|
||||
|
||||
151
util/ectool.c
151
util/ectool.c
@@ -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},
|
||||
|
||||
Reference in New Issue
Block a user