From dd2d41003d9860955b0899a2a7f20f31b2f3a47d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Oct 2012 09:28:26 -0700 Subject: 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 Reviewed-on: https://gerrit.chromium.org/gerrit/34635 Reviewed-by: Randall Spangler --- chip/stm32/keyboard_scan.c | 88 ++++++++++++++++++++++++++ util/ectool.c | 151 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) diff --git a/chip/stm32/keyboard_scan.c b/chip/stm32/keyboard_scan.c index 10bc3e4004..d4dd144d24 100644 --- a/chip/stm32/keyboard_scan.c +++ b/chip/stm32/keyboard_scan.c @@ -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)); diff --git a/util/ectool.c b/util/ectool.c index 4516014b46..263477c951 100644 --- a/util/ectool.c +++ b/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 [] - print params\n" + "\t%s set [> ]\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}, -- cgit v1.2.1