summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/stm32/keyboard_scan.c88
-rw-r--r--util/ectool.c151
2 files changed, 239 insertions, 0 deletions
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 [<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},