summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-03-22 09:35:00 -0700
committerChromeBot <chrome-bot@google.com>2013-03-29 11:40:34 -0700
commitfe3ccdf70a002e651bc1a13bcc305ae1e3422154 (patch)
treea4e1f70850c720d2a1599285304816269fc489f1
parent4311bc5ccf666d7425f1ea50eee08e3a032e2508 (diff)
downloadchrome-ec-fe3ccdf70a002e651bc1a13bcc305ae1e3422154.tar.gz
Merge lm4 and stm32 implementations of keyboard_scan
Scanning is now performed identically on all platforms. keyboard_scan talks to chip-specific keyboard_raw on the bottom end, and 8042 or mkbp keyboard protocol on the top end. 8042 can now take advantage of CONFIG_KEYBOARD_TEST to simulate scan results. BUG=chrome-os-partner:18360 BRANCH=none TEST=compile all boards; test keyboard on spring and link 1) Type on keyboard. Should produce keystrokes. 2) At EC console: kbpress 3 7 1 kbpress 3 7 0 Should produce 'r' keystroke(s); key repeat should kick in if you wait a while between the commands. 3) Hold power button while typing. Should not produce keystrokes. 4) Reboot with power+refresh+esc. Should go to recovery mode. 5) While the system is up, alt+volup+R should reboot the AP. Change-Id: I48e0bca15b869162672b5f54ffcb561f6fcf0f45 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/46666 Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--common/build.mk4
-rw-r--r--common/keyboard_8042.c76
-rw-r--r--common/keyboard_mkbp.c563
-rw-r--r--common/keyboard_scan.c290
-rw-r--r--include/keyboard_scan.h34
5 files changed, 358 insertions, 609 deletions
diff --git a/common/build.mk b/common/build.mk
index 1136015b7d..fffb708394 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -21,10 +21,7 @@ common-$(CONFIG_FLASH)+=flash_common.o fmap.o
common-$(CONFIG_I2C)+=i2c_commands.o
common-$(CONFIG_I2C_ARBITRATION)+=i2c_arbitration.o
common-$(CONFIG_IR357x)+=ir357x.o
-# TODO: combine common bits of keyboard_scan into one file
-# (coming in a follow-up CL)
common-$(CONFIG_KEYBOARD_PROTOCOL_MKBP)+=keyboard_mkbp.o
-common-$(CONFIG_KEYBOARD_PROTOCOL_8042)+=keyboard_scan.o
common-$(CONFIG_KEYBOARD_TEST)+=keyboard_test.o
common-$(CONFIG_LP5562)+=lp5562.o lp5562_battery_led.o
common-$(CONFIG_LPC)+=port80.o
@@ -35,6 +32,7 @@ common-$(CONFIG_TASK_CHARGER)+=charge_state.o battery_precharge.o
common-$(CONFIG_TASK_CONSOLE)+=console.o
common-$(CONFIG_TASK_HOSTCMD)+=host_command.o host_event_commands.o
common-$(CONFIG_TASK_I8042CMD)+=i8042.o keyboard_8042.o
+common-$(CONFIG_TASK_KEYSCAN)+=keyboard_scan.o
common-$(CONFIG_TASK_LIGHTBAR)+=lightbar.o
common-$(CONFIG_TASK_THERMAL)+=thermal.o
common-$(CONFIG_TASK_VBOOTHASH)+=sha256.o vboot_hash.o
diff --git a/common/keyboard_8042.c b/common/keyboard_8042.c
index 1a991d7075..54cc5d0310 100644
--- a/common/keyboard_8042.c
+++ b/common/keyboard_8042.c
@@ -146,11 +146,6 @@ static const uint16_t scancode_set2[KEYBOARD_ROWS][KEYBOARD_COLS] = {
0x0044, 0x0000, 0xe075, 0xe06b},
};
-
-/* Recording which key is being simulated pressed. */
-static uint8_t simulated_key[KEYBOARD_COLS];
-
-
/* Log the traffic between EC and host -- for debug only */
#define MAX_KBLOG 512 /* Max events in keyboard log */
struct kblog_t {
@@ -834,53 +829,6 @@ DECLARE_CONSOLE_COMMAND(ctrlram, command_controller_ram,
"Get/set keyboard controller RAM",
NULL);
-
-static int command_keyboard_press(int argc, char **argv)
-{
- if (argc == 1) {
- int i, j;
-
- ccputs("Simulated key:\n");
- for (i = 0; i < KEYBOARD_COLS; ++i) {
- if (simulated_key[i] == 0)
- continue;
- for (j = 0; j < KEYBOARD_ROWS; ++j)
- if (simulated_key[i] & (1 << j))
- ccprintf("\t%d %d\n", i, j);
- }
-
- } else if (argc == 4) {
- int r, c, p;
- char *e;
-
- c = strtoi(argv[1], &e, 0);
- if (*e || c < 0 || c >= KEYBOARD_COLS)
- return EC_ERROR_PARAM1;
-
- r = strtoi(argv[2], &e, 0);
- if (*e || r < 0 || r >= KEYBOARD_ROWS)
- return EC_ERROR_PARAM2;
-
- p = strtoi(argv[3], &e, 0);
- if (*e || p < 0 || p > 1)
- return EC_ERROR_PARAM3;
-
- if ((simulated_key[c] & (1 << r)) == (p << r))
- return EC_SUCCESS;
-
- simulated_key[c] = (simulated_key[c] & ~(1 << r)) | (p << r);
-
- keyboard_state_changed(r, c, p);
- }
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(kbpress, command_keyboard_press,
- "[col] [row] [0 | 1]",
- "Simulate keypress",
- NULL);
-
-
static int command_keyboard_log(int argc, char **argv)
{
int i;
@@ -940,30 +888,6 @@ DECLARE_CONSOLE_COMMAND(kbd, command_keyboard,
NULL);
/*****************************************************************************/
-/* Host commands */
-
-static int mkbp_command_simulate_key(struct host_cmd_handler_args *args)
-{
- const struct ec_params_mkbp_simulate_key *p = args->params;
-
- /* Only available on unlocked systems */
- if (system_is_locked())
- return EC_RES_ACCESS_DENIED;
-
- if (p->col >= ARRAY_SIZE(simulated_key))
- return EC_RES_INVALID_PARAM;
-
- simulated_key[p->col] = (simulated_key[p->col] & ~(1 << p->row)) |
- (p->pressed << p->row);
-
- keyboard_state_changed(p->row, p->col, p->pressed);
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_MKBP_SIMULATE_KEY,
- mkbp_command_simulate_key,
- EC_VER_MASK(0));
-
-/*****************************************************************************/
/* Hooks */
/**
diff --git a/common/keyboard_mkbp.c b/common/keyboard_mkbp.c
index 9d2613b187..336fd7e0be 100644
--- a/common/keyboard_mkbp.c
+++ b/common/keyboard_mkbp.c
@@ -2,7 +2,7 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
- * Keyboard scanner module for Chrome EC STM32
+ * MKBP keyboard protocol
*/
#include "atomic.h"
@@ -21,86 +21,49 @@
#include "util.h"
/* Console output macros */
-#define CPUTS(outstr) cputs(CC_KEYSCAN, outstr)
-#define CPRINTF(format, args...) cprintf(CC_KEYSCAN, format, ## args)
+#define CPUTS(outstr) cputs(CC_KEYBOARD, outstr)
+#define CPRINTF(format, args...) cprintf(CC_KEYBOARD, format, ## args)
-#define SCAN_TIME_COUNT 32
-
-static struct mutex scanning_enabled;
-
-static uint8_t debounced_state[KEYBOARD_COLS]; /* Debounced key matrix */
-static uint8_t prev_state[KEYBOARD_COLS]; /* Matrix from previous scan */
-static uint8_t debouncing[KEYBOARD_COLS]; /* Mask of keys being debounced */
-static uint32_t scan_time[SCAN_TIME_COUNT]; /* Times of last scans */
-static int scan_time_index; /* Current scan_time[] index */
-/* Index into scan_time[] when each key started debouncing */
-static uint8_t scan_edge_index[KEYBOARD_COLS][KEYBOARD_ROWS];
+#define KB_FIFO_DEPTH 16 /* FIXME: this is pretty huge */
-/*****************************************************************************/
+/* Changes to col,row here need to also be reflected in kernel.
+ * drivers/input/mkbp.c ... see KEY_BATTERY.
+ */
+#define BATTERY_KEY_COL 0
+#define BATTERY_KEY_ROW 7
+#define BATTERY_KEY_ROW_MASK (1 << BATTERY_KEY_ROW)
-#define KB_FIFO_DEPTH 16 /* FIXME: this is pretty huge */
static uint32_t kb_fifo_start; /* first entry */
-static uint32_t kb_fifo_end; /* last entry */
+static uint32_t kb_fifo_end; /* last entry */
static uint32_t kb_fifo_entries; /* number of existing entries */
static uint8_t kb_fifo[KB_FIFO_DEPTH][KEYBOARD_COLS];
+static struct mutex fifo_mutex;
-/*
- * Our configuration. The debounce parameters are not yet supported.
- */
-static struct ec_mkbp_config config = {
+/* Config for mkbp protocol; does not include fields from scan config */
+struct ec_mkbp_protocol_config {
+ uint32_t valid_mask; /* valid fields */
+ uint8_t flags; /* some flags (enum mkbp_config_flags) */
+ uint8_t valid_flags; /* which flags are valid */
+
+ /* maximum depth to allow for fifo (0 = no keyscan output) */
+ uint8_t fifo_max_depth;
+} __packed;
+
+static struct ec_mkbp_protocol_config config = {
.valid_mask = EC_MKBP_VALID_SCAN_PERIOD | EC_MKBP_VALID_POLL_TIMEOUT |
EC_MKBP_VALID_MIN_POST_SCAN_DELAY |
EC_MKBP_VALID_OUTPUT_SETTLE | EC_MKBP_VALID_DEBOUNCE_DOWN |
EC_MKBP_VALID_DEBOUNCE_UP | EC_MKBP_VALID_FIFO_MAX_DEPTH,
.valid_flags = EC_MKBP_FLAGS_ENABLE,
.flags = EC_MKBP_FLAGS_ENABLE,
- .scan_period_us = 3000,
- .poll_timeout_us = 100 * 1000,
- .min_post_scan_delay_us = 1000,
- .output_settle_us = 50,
- .debounce_down_us = 9000,
- .debounce_up_us = 30000,
.fifo_max_depth = KB_FIFO_DEPTH,
};
-void keyboard_clear_state(void)
-{
- int i;
-
- CPRINTF("clearing keyboard fifo\n");
- kb_fifo_start = 0;
- kb_fifo_end = 0;
- kb_fifo_entries = 0;
- for (i = 0; i < KB_FIFO_DEPTH; i++)
- memset(kb_fifo[i], 0, KEYBOARD_COLS);
-}
-
-int keyboard_fifo_add(const uint8_t *buffp)
-{
- int ret = EC_SUCCESS;
-
- if (kb_fifo_entries >= config.fifo_max_depth) {
- CPRINTF("%s: FIFO depth %d reached\n", __func__,
- config.fifo_max_depth);
- ret = EC_ERROR_OVERFLOW;
- goto kb_fifo_push_done;
- }
-
- memcpy(kb_fifo[kb_fifo_end], buffp, KEYBOARD_COLS);
-
- kb_fifo_end = (kb_fifo_end + 1) % KB_FIFO_DEPTH;
-
- atomic_add(&kb_fifo_entries, 1);
-
-kb_fifo_push_done:
- return ret;
-}
-
/**
- * Pop keyboard state from FIFO
- *
- * @return EC_SUCCESS if entry popped, EC_ERROR_UNKNOWN if FIFO is empty
- */
+ * Pop keyboard state from FIFO
+ *
+ * @return EC_SUCCESS if entry popped, EC_ERROR_UNKNOWN if FIFO is empty
+ */
static int kb_fifo_remove(uint8_t *buffp)
{
if (!kb_fifo_entries) {
@@ -133,331 +96,68 @@ static void set_host_interrupt(int active)
gpio_set_level(GPIO_EC_INT, !active);
}
-/**
- * Check special runtime key combinations.
- *
- * @param state Keyboard state to use when checking keys.
- * @return 1 if a special key was pressed, 0 if not
- */
-static int check_runtime_keys(const uint8_t *state)
-{
- int num_press;
- int c;
-
- /* Count number of key pressed */
- for (c = num_press = 0; c < KEYBOARD_COLS; c++) {
- if (state[c])
- ++num_press;
- }
-
- if (num_press != 3)
- return 0;
-
- if (state[KEYBOARD_COL_KEY_R] == KEYBOARD_MASK_KEY_R &&
- state[KEYBOARD_COL_VOL_UP] == KEYBOARD_MASK_VOL_UP &&
- (state[KEYBOARD_COL_RIGHT_ALT] == KEYBOARD_MASK_RIGHT_ALT ||
- state[KEYBOARD_COL_LEFT_ALT] == KEYBOARD_MASK_LEFT_ALT)) {
- keyboard_clear_state();
- chipset_reset(0);
- return 1;
- }
-
- return 0;
-}
+/*****************************************************************************/
+/* Interface */
-/* Print the keyboard state. */
-static void print_state(const uint8_t *state, const char *msg)
+void keyboard_clear_buffer(void)
{
- int c;
-
- CPRINTF("[%T KB %s:", msg);
- for (c = 0; c < KEYBOARD_COLS; c++) {
- if (state[c])
- CPRINTF(" %02x", state[c]);
- else
- CPUTS(" --");
- }
- CPUTS("]\n");
-}
+ int i;
-/**
- * Read the raw keyboard matrix state.
- *
- * Used in pre-init, so must not make task-switching-dependent calls; udelay()
- * is ok because it's a spin-loop.
- *
- * @param state Destination for new state (must be KEYBOARD_COLS long).
- *
- * @return 1 if at least one key is pressed, else zero.
- */
-static int read_matrix(uint8_t *state)
-{
- int c;
- uint8_t r;
- int pressed = 0;
-
- for (c = 0; c < KEYBOARD_COLS; c++) {
- /* Assert output, then wait a bit for it to settle */
- keyboard_raw_drive_column(c);
- udelay(config.output_settle_us);
-
- r = keyboard_raw_read_rows();
-
-#ifdef CONFIG_KEYBOARD_TEST
- /* Use simulated keyscan sequence instead if testing active */
- r = keyscan_seq_get_scan(c, r);
-#endif
-
-#ifdef OR_WITH_CURRENT_STATE_FOR_TESTING
- /* KLUDGE - or current state in, so we can make sure
- * all the lines are hooked up */
- r |= state[c];
-#endif
-
- state[c] = r;
- pressed |= r;
- }
- keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE);
+ CPRINTF("clearing keyboard fifo\n");
- return pressed ? 1 : 0;
+ kb_fifo_start = 0;
+ kb_fifo_end = 0;
+ kb_fifo_entries = 0;
+ for (i = 0; i < KB_FIFO_DEPTH; i++)
+ memset(kb_fifo[i], 0, KEYBOARD_COLS);
}
-/**
- * Update keyboard state using low-level interface to read keyboard.
- *
- * @param state Keyboard state to update.
- *
- * @return 1 if any key is still pressed, 0 if no key is pressed.
- */
-static int check_keys_changed(uint8_t *state)
+int keyboard_fifo_add(const uint8_t *buffp)
{
- int any_pressed = 0;
- int c, i;
- int any_change = 0;
- uint8_t new_state[KEYBOARD_COLS];
- uint32_t tnow = get_time().le.lo;
-
- /* Save the current scan time */
- if (++scan_time_index >= SCAN_TIME_COUNT)
- scan_time_index = 0;
- scan_time[scan_time_index] = tnow;
-
- /* Read the raw key state */
- any_pressed = read_matrix(new_state);
-
- /* Check for changes between previous scan and this one */
- for (c = 0; c < KEYBOARD_COLS; c++) {
- int diff = new_state[c] ^ prev_state[c];
-
- if (!diff)
- continue;
-
- for (i = 0; i < KEYBOARD_ROWS; i++) {
- if (diff & (1 << i))
- scan_edge_index[c][i] = scan_time_index;
- }
-
- debouncing[c] |= diff;
- prev_state[c] = new_state[c];
- }
-
- /* Check for keys which are done debouncing */
- for (c = 0; c < KEYBOARD_COLS; c++) {
- int debc = debouncing[c];
-
- if (!debc)
- continue;
-
- for (i = 0; i < KEYBOARD_ROWS; i++) {
- int mask = 1 << i;
- int new_mask = new_state[c] & mask;
-
- /* Are we done debouncing this key? */
- if (!(debc & mask))
- continue; /* Not debouncing this key */
- if (tnow - scan_time[scan_edge_index[c][i]] <
- (new_mask ? config.debounce_down_us :
- config.debounce_up_us))
- continue; /* Not done debouncing */
-
- debouncing[c] &= ~mask;
-
- /* Did the key change from its previous state? */
- if ((state[c] & mask) == new_mask)
- continue; /* No */
-
- state[c] ^= mask;
- any_change = 1;
- }
- }
-
- if (any_change) {
-#ifdef CONFIG_KEYBOARD_SUPPRESS_NOISE
- keyboard_suppress_noise();
-#endif
- print_state(state, "state");
-
-#ifdef PRINT_SCAN_TIMES
- /* Print delta times from now back to each previous scan */
- for (i = 0; i < SCAN_TIME_COUNT; i++) {
- int tnew = scan_time[
- (SCAN_TIME_COUNT + scan_time_index - i) %
- SCAN_TIME_COUNT];
- CPRINTF(" %d", tnow - tnew);
- }
- CPRINTF("\n");
-#endif
-
- /* Swallow special keys */
- if (check_runtime_keys(state))
- return 0;
- else if (keyboard_fifo_add(state) == EC_SUCCESS)
- set_host_interrupt(1);
- else
- CPRINTF("dropped keystroke\n");
- }
+ int ret = EC_SUCCESS;
- return any_pressed;
-}
+ /*
+ * If keyboard protocol is not enabled, don't save the state to the
+ * FIFO or trigger an interrupt.
+ */
+ if (!(config.flags & EC_MKBP_FLAGS_ENABLE))
+ return EC_SUCCESS;
-/*
- * Check if the user has triggered a recovery reset
- *
- * Pressing Power + Refresh + ESC. triggers a recovery reset. Here we check
- * for this.
- *
- * @param state Keyboard state to check
- * @return 1 if there is a recovery reset, else 0
- */
-static int check_recovery_key(const uint8_t *state)
-{
- int c;
-
- /* check the recovery key only if we're booting due to a
- * reset-pin-caused reset. */
- if (!(system_get_reset_flags() & RESET_FLAG_RESET_PIN))
- return 0;
-
- /* cold boot : Power + Refresh were pressed,
- * check if ESC is also pressed for recovery. */
- if (!(state[KEYBOARD_COL_ESC] & KEYBOARD_MASK_ESC))
- return 0;
-
- /* Make sure only other allowed keys are pressed. This protects
- * against accidentally triggering the special key when a cat sits on
- * your keyboard. Currently, only the requested key and ESC are
- * allowed. */
- for (c = 0; c < KEYBOARD_COLS; c++) {
- if (state[c] &&
- (c != KEYBOARD_COL_ESC || state[c] != KEYBOARD_MASK_ESC) &&
- (c != KEYBOARD_COL_REFRESH ||
- state[c] != KEYBOARD_MASK_REFRESH))
- return 0; /* Additional disallowed key pressed */
+ if (kb_fifo_entries >= config.fifo_max_depth) {
+ CPRINTF("[%T KB FIFO depth %d reached]\n",
+ config.fifo_max_depth);
+ ret = EC_ERROR_OVERFLOW;
+ goto kb_fifo_push_done;
}
- CPRINTF("Keyboard RECOVERY detected !\n");
-
- host_set_single_event(EC_HOST_EVENT_KEYBOARD_RECOVERY);
-
- return 1;
-}
-
-void keyboard_scan_init(void)
-{
- keyboard_raw_init();
-
- /* Tri-state (put into Hi-Z) the outputs */
- keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE);
-
- /* Initialize raw state */
- read_matrix(debounced_state);
- memcpy(prev_state, debounced_state, sizeof(prev_state));
-
- /* is recovery key pressed on cold startup ? */
- check_recovery_key(debounced_state);
-}
-
-/* Scan the keyboard until all keys are released */
-static void scan_keyboard(void)
-{
- timestamp_t poll_deadline, start;
- int keys_changed = 1;
+ mutex_lock(&fifo_mutex);
+ memcpy(kb_fifo[kb_fifo_end], buffp, KEYBOARD_COLS);
+ kb_fifo_end = (kb_fifo_end + 1) % KB_FIFO_DEPTH;
+ atomic_add(&kb_fifo_entries, 1);
+ mutex_unlock(&fifo_mutex);
- mutex_lock(&scanning_enabled);
- keyboard_raw_drive_column(KEYBOARD_COLUMN_ALL);
- keyboard_raw_enable_interrupt(1);
- mutex_unlock(&scanning_enabled);
+kb_fifo_push_done:
- /*
- * if a key was pressed after the last polling,
- * re-start immediatly polling instead of waiting
- * for the next interrupt.
- */
- if (!keyboard_raw_read_rows()) {
-#ifdef CONFIG_KEYBOARD_TEST
- task_wait_event(keyscan_seq_next_event_delay());
-#else
- task_wait_event(-1);
-#endif
- }
+ if (ret == EC_SUCCESS)
+ set_host_interrupt(1);
- keyboard_raw_enable_interrupt(0);
- keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE);
-
- /* Busy polling keyboard state. */
- while (1) {
- int wait_time;
-
- if (!(config.flags & EC_MKBP_FLAGS_ENABLE))
- break;
-
- /* If we saw any keys pressed, reset deadline */
- start = get_time();
- if (keys_changed)
- poll_deadline.val = start.val + config.poll_timeout_us;
- else if (timestamp_expired(poll_deadline, &start))
- break;
-
- /* Scan immediately, with no delay */
- mutex_lock(&scanning_enabled);
- keys_changed = check_keys_changed(debounced_state);
- mutex_unlock(&scanning_enabled);
-
- /* Wait a bit before scanning again */
- wait_time = config.scan_period_us -
- (get_time().val - start.val);
- if (wait_time < config.min_post_scan_delay_us)
- wait_time = config.min_post_scan_delay_us;
- task_wait_event(wait_time);
- }
+ return ret;
}
-void keyboard_scan_task(void)
+void keyboard_send_battery_key(void)
{
- print_state(debounced_state, "init state");
+ uint8_t state[KEYBOARD_COLS];
- keyboard_raw_task_start();
+ /* Copy debounced state and add battery pseudo-key */
+ memcpy(state, keyboard_scan_get_state(), sizeof(state));
+ state[BATTERY_KEY_COL] ^= BATTERY_KEY_ROW_MASK;
- while (1) {
- if (config.flags & EC_MKBP_FLAGS_ENABLE) {
- scan_keyboard();
- } else {
- keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE);
- task_wait_event(-1);
- }
- }
+ /* Add to FIFO */
+ keyboard_fifo_add(state);
}
-int keyboard_has_char(void)
-{
- /* TODO: needs to be implemented */
- return 0;
-}
-
-void keyboard_put_char(uint8_t chr, int send_irq)
-{
- /* TODO: needs to be implemented */
-}
+/*****************************************************************************/
+/* Host commands */
static int keyboard_get_scan(struct host_cmd_handler_args *args)
{
@@ -489,91 +189,13 @@ DECLARE_HOST_COMMAND(EC_CMD_MKBP_INFO,
keyboard_get_info,
EC_VER_MASK(0));
-void keyboard_scan_enable(int enable)
-{
- if (enable) {
- mutex_unlock(&scanning_enabled);
- task_wake(TASK_ID_KEYSCAN);
- } else {
- /*
- * TODO: using a mutex to control scanning isn't very
- * responsive. If we just started scanning the matrix, the
- * mutex will already be locked, and we'll finish the entire
- * matrix scan before we stop driving columns. We should
- * instead do something like link, where disabling scanning
- * immediately stops driving the columns.
- */
- mutex_lock(&scanning_enabled);
- keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE);
- }
-}
-
-/* Changes to col,row here need to also be reflected in kernel.
- * drivers/input/mkbp.c ... see KEY_BATTERY.
- */
-#define BATTERY_KEY_COL 0
-#define BATTERY_KEY_ROW 7
-#define BATTERY_KEY_ROW_MASK (1 << BATTERY_KEY_ROW)
-
-void keyboard_send_battery_key(void)
-{
- mutex_lock(&scanning_enabled);
- debounced_state[BATTERY_KEY_COL] ^= BATTERY_KEY_ROW_MASK;
- if (keyboard_fifo_add(debounced_state) == EC_SUCCESS)
- set_host_interrupt(1);
- else
- CPRINTF("dropped battery keystroke\n");
- mutex_unlock(&scanning_enabled);
-}
-
-static int command_keyboard_press(int argc, char **argv)
-{
- int r, c, p;
- char *e;
-
- if (argc != 4)
- return EC_ERROR_PARAM_COUNT;
-
- c = strtoi(argv[1], &e, 0);
- if (*e || c < 0 || c >= KEYBOARD_COLS)
- return EC_ERROR_PARAM1;
-
- r = strtoi(argv[2], &e, 0);
- if (*e || r < 0 || r >= KEYBOARD_ROWS)
- return EC_ERROR_PARAM2;
-
- p = strtoi(argv[3], &e, 0);
- if (*e || p < 0 || p > 1)
- return EC_ERROR_PARAM3;
-
- /*
- * TODO(sjg@chromium.org): This ignores debouncing, so is a bit
- * dodgy and might have strange side-effects on real key scans.
- */
- if (p)
- debounced_state[c] |= (1 << r);
- else
- debounced_state[c] &= ~(1 << r);
-
- if (keyboard_fifo_add(debounced_state) == EC_SUCCESS)
- set_host_interrupt(1);
- else
- ccprintf("dropped keystroke\n");
-
- return EC_SUCCESS;
-}
-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.
+ * TODO(sjg@chromium.org): Consider making this table driven as ectool.
*
* @param src Source config
* @param dst Destination config
@@ -584,35 +206,43 @@ DECLARE_CONSOLE_COMMAND(kbpress, command_keyboard_press,
* over to dst->flags
*/
static void keyscan_copy_config(const struct ec_mkbp_config *src,
- struct ec_mkbp_config *dst,
+ struct ec_mkbp_protocol_config *dst,
uint32_t valid_mask, uint8_t valid_flags)
{
+ struct keyboard_scan_config *ksc = keyboard_scan_get_config();
uint8_t new_flags;
if (valid_mask & EC_MKBP_VALID_SCAN_PERIOD)
- dst->scan_period_us = src->scan_period_us;
+ ksc->scan_period_us = src->scan_period_us;
+
if (valid_mask & EC_MKBP_VALID_POLL_TIMEOUT)
- dst->poll_timeout_us = src->poll_timeout_us;
+ ksc->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 =
+ ksc->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;
+ ksc->output_settle_us = src->output_settle_us;
+
if (valid_mask & EC_MKBP_VALID_DEBOUNCE_DOWN)
- dst->debounce_down_us = src->debounce_down_us;
+ ksc->debounce_down_us = src->debounce_down_us;
+
if (valid_mask & EC_MKBP_VALID_DEBOUNCE_UP)
- dst->debounce_up_us = src->debounce_up_us;
+ ksc->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;
@@ -636,21 +266,36 @@ static int host_command_mkbp_set_config(struct host_cmd_handler_args *args)
return EC_RES_SUCCESS;
}
+DECLARE_HOST_COMMAND(EC_CMD_MKBP_SET_CONFIG,
+ host_command_mkbp_set_config,
+ EC_VER_MASK(0));
static int host_command_mkbp_get_config(struct host_cmd_handler_args *args)
{
+ const struct keyboard_scan_config *ksc = keyboard_scan_get_config();
struct ec_response_mkbp_get_config *resp = args->response;
+ struct ec_mkbp_config *dst = &resp->config;
memcpy(&resp->config, &config, sizeof(config));
+
+ /* Copy fields from mkbp protocol config to mkbp config */
+ dst->valid_mask = config.valid_mask;
+ dst->flags = config.flags;
+ dst->valid_flags = config.valid_flags;
+ dst->fifo_max_depth = config.fifo_max_depth;
+
+ /* Copy fields from keyscan config to mkbp config */
+ dst->output_settle_us = ksc->output_settle_us;
+ dst->debounce_down_us = ksc->debounce_down_us;
+ dst->debounce_up_us = ksc->debounce_up_us;
+ dst->scan_period_us = ksc->scan_period_us;
+ dst->min_post_scan_delay_us = ksc->min_post_scan_delay_us;
+ dst->poll_timeout_us = ksc->poll_timeout_us;
+
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/common/keyboard_scan.c b/common/keyboard_scan.c
index c01326d956..45eb45a35a 100644
--- a/common/keyboard_scan.c
+++ b/common/keyboard_scan.c
@@ -23,42 +23,52 @@
#define CPUTS(outstr) cputs(CC_KEYSCAN, outstr)
#define CPRINTF(format, args...) cprintf(CC_KEYSCAN, format, ## args)
-/* Time constants */
-#define POLLING_MODE_TIMEOUT SECOND /* Max time to poll if no keys are down */
-#define DEBOUNCE_UP_US (30 * MSEC) /* Debounce time for key-up */
-#define DEBOUNCE_DOWN_US (6 * MSEC) /* Debounce time for key-down */
-#define SCAN_LOOP_DELAY MSEC /* Delay in scan loop */
-#define COLUMN_CHARGE_US 40 /* Column charge time in usec */
-
#define SCAN_TIME_COUNT 32 /* Number of last scan times to track */
+static struct keyboard_scan_config config = {
+#ifdef BOARD_link
+ .output_settle_us = 40,
+ .debounce_down_us = 6 * MSEC,
+ .debounce_up_us = 30 * MSEC,
+ .scan_period_us = 1500,
+ .min_post_scan_delay_us = 1000,
+ .poll_timeout_us = SECOND,
+#else
+ .output_settle_us = 50,
+ .debounce_down_us = 9 * MSEC,
+ .debounce_up_us = 30 * MSEC,
+ .scan_period_us = 3 * MSEC,
+ .min_post_scan_delay_us = 1000,
+ .poll_timeout_us = 100 * MSEC,
+#endif
+ .actual_key_mask = {
+ 0x14, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xff,
+ 0xa4, 0xff, 0xf6, 0x55, 0xfa, 0xc8 /* full set */
+ },
+};
+
/* Boot key list. Must be in same order as enum boot_key. */
struct boot_key_entry {
uint8_t mask_index;
uint8_t mask_value;
};
-const struct boot_key_entry boot_key_list[] = {
+static const struct boot_key_entry boot_key_list[] = {
{0, 0x00}, /* (none) */
{KEYBOARD_COL_ESC, KEYBOARD_MASK_ESC}, /* Esc */
{KEYBOARD_COL_DOWN, KEYBOARD_MASK_DOWN}, /* Down-arrow */
};
+static enum boot_key boot_key_value = BOOT_KEY_OTHER;
static uint8_t debounced_state[KEYBOARD_COLS]; /* Debounced key matrix */
static uint8_t prev_state[KEYBOARD_COLS]; /* Matrix from previous scan */
static uint8_t debouncing[KEYBOARD_COLS]; /* Mask of keys being debounced */
+static uint8_t simulated_key[KEYBOARD_COLS]; /* Keys simulated-pressed */
+
static uint32_t scan_time[SCAN_TIME_COUNT]; /* Times of last scans */
static int scan_time_index; /* Current scan_time[] index */
/* Index into scan_time[] when each key started debouncing */
static uint8_t scan_edge_index[KEYBOARD_COLS][KEYBOARD_ROWS];
-enum boot_key boot_key_value = BOOT_KEY_OTHER;
-
-/* Mask with 1 bits only for keys that actually exist */
-static const uint8_t actual_key_mask[KEYBOARD_COLS] = {
- 0x14, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xff,
- 0xa4, 0xff, 0xf6, 0x55, 0xfa, 0xc8 /* full set */
-};
-
/*
* Print all keyboard scan state changes? Off by default because it generates
* a lot of debug output, which makes the saved EC console data less useful.
@@ -67,27 +77,56 @@ static int print_state_changes;
static int enable_scanning = 1; /* Must init to 1 for scanning at boot */
-static void enable_interrupt(void)
+static int is_scanning_enabled(void)
{
- CPRINTF("[%T KB wait]\n");
-
- if (enable_scanning)
- keyboard_raw_drive_column(KEYBOARD_COLUMN_ALL);
+#ifdef BOARD_link
+ /* TODO: should apply to ARM too, but need standard lid API */
+ /* Scanning is never enabled when lid is closed */
+ if (!switch_get_lid_open())
+ return 0;
+#endif
- keyboard_raw_enable_interrupt(1);
+ return enable_scanning;
}
-static void enter_polling_mode(void)
+/**
+ * Print the keyboard state.
+ *
+ * @param state State array to print
+ * @param msg Description of state
+ */
+static void print_state(const uint8_t *state, const char *msg)
{
- CPRINTF("[%T KB poll]\n");
- keyboard_raw_enable_interrupt(0);
- keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE);
+ int c;
+
+ CPRINTF("[%T KB %s:", msg);
+ for (c = 0; c < KEYBOARD_COLS; c++) {
+ if (state[c])
+ CPRINTF(" %02x", state[c]);
+ else
+ CPUTS(" --");
+ }
+ CPUTS("]\n");
}
-static int is_scanning_enabled(void)
+/**
+ * Simulate a keypress.
+ *
+ * @param row Row of key
+ * @param col Column of key
+ * @param pressed Non-zero if pressed, zero if released
+ */
+static void simulate_key(int row, int col, int pressed)
{
- /* Scan only if enabled AND lid is open. */
- return enable_scanning && switch_get_lid_open();
+ if ((simulated_key[col] & (1 << row)) == ((pressed ? 1 : 0) << row))
+ return; /* No change */
+
+ simulated_key[col] ^= (1 << row);
+
+ print_state(simulated_key, "simulated ");
+
+ /* Wake the task to handle changes in simulated keys */
+ task_wake(TASK_ID_KEYSCAN);
}
/**
@@ -107,19 +146,29 @@ static int read_matrix(uint8_t *state)
int pressed = 0;
for (c = 0; c < KEYBOARD_COLS; c++) {
- /* Stop if scanning becomes disabled */
+ /*
+ * Stop if scanning becomes disabled. Check enable_cscanning
+ * instead of is_scanning_enabled() so that we can scan the
+ * matrix at boot time before the lid switch is readable.
+ */
if (!enable_scanning)
break;
/* Select column, then wait a bit for it to settle */
keyboard_raw_drive_column(c);
- udelay(COLUMN_CHARGE_US);
+ udelay(config.output_settle_us);
/* Read the row state */
r = keyboard_raw_read_rows();
- /* Mask off keys that don't exist so they never show
- * as pressed */
- r &= actual_key_mask[c];
+ /* Mask off keys that don't exist on the actual keyboard */
+ r &= config.actual_key_mask[c];
+ /* Add in simulated keypresses */
+ r |= simulated_key[c];
+
+#ifdef CONFIG_KEYBOARD_TEST
+ /* Use simulated keyscan sequence instead if testing active */
+ r = keyscan_seq_get_scan(c, r);
+#endif
state[c] = r;
pressed |= r;
@@ -131,31 +180,13 @@ static int read_matrix(uint8_t *state)
}
/**
- * Print the keyboard state.
- *
- * @param state State array to print
- * @param msg Description of state
- */
-static void print_state(const uint8_t *state, const char *msg)
-{
- int c;
-
- CPRINTF("[%T KB %s:", msg);
- for (c = 0; c < KEYBOARD_COLS; c++) {
- if (state[c])
- CPRINTF(" %02x", state[c]);
- else
- CPUTS(" --");
- }
- CPUTS("]\n");
-}
-
-/**
* Check special runtime key combinations.
*
* @param state Keyboard state to use when checking keys.
+ *
+ * @return 1 if a special key was pressed, 0 if not
*/
-static void check_runtime_keys(const uint8_t *state)
+static int check_runtime_keys(const uint8_t *state)
{
int num_press = 0;
int c;
@@ -165,10 +196,11 @@ static void check_runtime_keys(const uint8_t *state)
* key NOT on the same col as alt or volume up )
*/
if (state[KEYBOARD_COL_VOL_UP] != KEYBOARD_MASK_VOL_UP)
- return;
+ return 0;
+
if (state[KEYBOARD_COL_RIGHT_ALT] != KEYBOARD_MASK_RIGHT_ALT &&
state[KEYBOARD_COL_LEFT_ALT] != KEYBOARD_MASK_LEFT_ALT)
- return;
+ return 0;
/*
* Count number of columns with keys pressed. We know two columns are
@@ -179,24 +211,34 @@ static void check_runtime_keys(const uint8_t *state)
if (state[c])
num_press++;
}
+
if (num_press != 3)
- return;
+ return 0;
/* Check individual keys */
if (state[KEYBOARD_COL_KEY_R] == KEYBOARD_MASK_KEY_R) {
/* R = reboot */
CPRINTF("[%T KB warm reboot]\n");
+ keyboard_clear_buffer();
chipset_reset(0);
+ return 1;
} else if (state[KEYBOARD_COL_KEY_H] == KEYBOARD_MASK_KEY_H) {
/* H = hibernate */
CPRINTF("[%T KB hibernate]\n");
system_hibernate(0, 0);
+ return 1;
}
+
+ return 0;
}
/**
* Check for ghosting in the keyboard state.
*
+ * Assumes that the state has already been masked with the actual key mask, so
+ * that coords which don't correspond with actual keys don't trigger ghosting
+ * detection.
+ *
* @param state Keyboard state to check.
*
* @return 1 if ghosting detected, else 0.
@@ -262,6 +304,7 @@ static int check_keys_changed(uint8_t *state)
/* Check for changes between previous scan and this one */
for (c = 0; c < KEYBOARD_COLS; c++) {
int diff = new_state[c] ^ prev_state[c];
+
if (!diff)
continue;
@@ -277,6 +320,7 @@ static int check_keys_changed(uint8_t *state)
/* Check for keys which are done debouncing */
for (c = 0; c < KEYBOARD_COLS; c++) {
int debc = debouncing[c];
+
if (!debc)
continue;
@@ -288,7 +332,8 @@ static int check_keys_changed(uint8_t *state)
if (!(debc & mask))
continue; /* Not debouncing this key */
if (tnow - scan_time[scan_edge_index[c][i]] <
- (new_mask ? DEBOUNCE_DOWN_US : DEBOUNCE_UP_US))
+ (new_mask ? config.debounce_down_us :
+ config.debounce_up_us))
continue; /* Not done debouncing */
debouncing[c] &= ~mask;
@@ -300,13 +345,21 @@ static int check_keys_changed(uint8_t *state)
state[c] ^= mask;
any_change = 1;
+#ifdef CONFIG_KEYBOARD_PROTOCOL_8042
/* Inform keyboard module if scanning is enabled */
if (is_scanning_enabled())
keyboard_state_changed(i, c, new_mask ? 1 : 0);
+#endif
}
}
if (any_change) {
+
+#ifdef CONFIG_KEYBOARD_SUPPRESS_NOISE
+ /* Suppress keyboard noise */
+ keyboard_suppress_noise();
+#endif
+
if (print_state_changes)
print_state(state, "state");
@@ -321,7 +374,13 @@ static int check_keys_changed(uint8_t *state)
CPRINTF("\n");
#endif
- check_runtime_keys(state);
+ /* Swallow special keys */
+ if (check_runtime_keys(state))
+ return 0;
+
+#ifdef CONFIG_KEYBOARD_PROTOCOL_MKBP
+ keyboard_fifo_add(state);
+#endif
}
return any_pressed;
@@ -360,7 +419,7 @@ static int check_key(const uint8_t *state, int index, int mask)
* key combination is down or this isn't the right type of boot to look at
* boot keys.
*/
-static enum boot_key keyboard_scan_check_boot_key(const uint8_t *state)
+static enum boot_key check_boot_key(const uint8_t *state)
{
const struct boot_key_entry *k = boot_key_list;
int i;
@@ -389,11 +448,24 @@ static enum boot_key keyboard_scan_check_boot_key(const uint8_t *state)
return BOOT_KEY_OTHER;
}
+/*****************************************************************************/
+/* Interface */
+
+struct keyboard_scan_config *keyboard_scan_get_config(void)
+{
+ return &config;
+}
+
enum boot_key keyboard_scan_get_boot_key(void)
{
return boot_key_value;
}
+const uint8_t *keyboard_scan_get_state(void)
+{
+ return debounced_state;
+}
+
void keyboard_scan_init(void)
{
/* Configure GPIO */
@@ -407,7 +479,7 @@ void keyboard_scan_init(void)
memcpy(prev_state, debounced_state, sizeof(prev_state));
/* Check for keys held down at boot */
- boot_key_value = keyboard_scan_check_boot_key(debounced_state);
+ boot_key_value = check_boot_key(debounced_state);
/* Trigger event if recovery key was pressed */
if (boot_key_value == BOOT_KEY_ESC)
@@ -416,7 +488,8 @@ void keyboard_scan_init(void)
void keyboard_scan_task(void)
{
- int key_press_timer = 0;
+ timestamp_t poll_deadline, start;
+ int wait_time;
print_state(debounced_state, "init state");
@@ -424,7 +497,10 @@ void keyboard_scan_task(void)
while (1) {
/* Enable all outputs */
- enable_interrupt();
+ CPRINTF("[%T KB wait]\n");
+ if (is_scanning_enabled())
+ keyboard_raw_drive_column(KEYBOARD_COLUMN_ALL);
+ keyboard_raw_enable_interrupt(1);
/* Wait for scanning enabled and key pressed. */
do {
@@ -438,21 +514,31 @@ void keyboard_scan_task(void)
task_wait_event(-1);
} while (!is_scanning_enabled());
- enter_polling_mode();
+ /* Enter polling mode */
+ CPRINTF("[%T KB poll]\n");
+ keyboard_raw_enable_interrupt(0);
+ keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE);
+
/* Busy polling keyboard state. */
while (is_scanning_enabled()) {
+ start = get_time();
+
/* Check for keys down */
if (check_keys_changed(debounced_state)) {
- key_press_timer = 0;
- } else if (++key_press_timer >=
- (POLLING_MODE_TIMEOUT / SCAN_LOOP_DELAY)) {
- /* Stop polling */
- key_press_timer = 0;
+ poll_deadline.val = start.val
+ + config.poll_timeout_us;
+ } else if (timestamp_expired(poll_deadline, &start)) {
break;
}
/* Delay between scans */
- usleep(SCAN_LOOP_DELAY);
+ wait_time = config.scan_period_us -
+ (get_time().val - start.val);
+
+ if (wait_time < config.min_post_scan_delay_us)
+ wait_time = config.min_post_scan_delay_us;
+
+ usleep(wait_time);
}
}
}
@@ -475,6 +561,28 @@ void keyboard_scan_enable(int enable)
}
/*****************************************************************************/
+/* Host commands */
+
+static int mkbp_command_simulate_key(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_mkbp_simulate_key *p = args->params;
+
+ /* Only available on unlocked systems */
+ if (system_is_locked())
+ return EC_RES_ACCESS_DENIED;
+
+ if (p->col >= KEYBOARD_COLS || p->row >= KEYBOARD_ROWS)
+ return EC_RES_INVALID_PARAM;
+
+ simulate_key(p->row, p->col, p->pressed);
+
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_MKBP_SIMULATE_KEY,
+ mkbp_command_simulate_key,
+ EC_VER_MASK(0));
+
+/*****************************************************************************/
/* Console commands */
static int command_ksstate(int argc, char **argv)
@@ -500,3 +608,43 @@ DECLARE_CONSOLE_COMMAND(ksstate, command_ksstate,
"ksstate [on | off]",
"Show or toggle printing keyboard scan state",
NULL);
+
+static int command_keyboard_press(int argc, char **argv)
+{
+ if (argc == 1) {
+ int i, j;
+
+ ccputs("Simulated keys:\n");
+ for (i = 0; i < KEYBOARD_COLS; ++i) {
+ if (simulated_key[i] == 0)
+ continue;
+ for (j = 0; j < KEYBOARD_ROWS; ++j)
+ if (simulated_key[i] & (1 << j))
+ ccprintf("\t%d %d\n", i, j);
+ }
+
+ } else if (argc == 4) {
+ int r, c, p;
+ char *e;
+
+ c = strtoi(argv[1], &e, 0);
+ if (*e || c < 0 || c >= KEYBOARD_COLS)
+ return EC_ERROR_PARAM1;
+
+ r = strtoi(argv[2], &e, 0);
+ if (*e || r < 0 || r >= KEYBOARD_ROWS)
+ return EC_ERROR_PARAM2;
+
+ p = strtoi(argv[3], &e, 0);
+ if (*e || p < 0 || p > 1)
+ return EC_ERROR_PARAM3;
+
+ simulate_key(r, c, p);
+ }
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(kbpress, command_keyboard_press,
+ "[col] [row] [0 | 1]",
+ "Simulate keypress",
+ NULL);
diff --git a/include/keyboard_scan.h b/include/keyboard_scan.h
index 04a21838bb..e775477421 100644
--- a/include/keyboard_scan.h
+++ b/include/keyboard_scan.h
@@ -9,12 +9,40 @@
#define __CROS_EC_KEYBOARD_SCAN_H
#include "common.h"
+#include "keyboard_config.h"
+
+struct keyboard_scan_config {
+ /* Delay between setting up output and waiting for it to settle */
+ uint16_t output_settle_us;
+ /* Times for debouncing key-down and key-up */
+ uint16_t debounce_down_us;
+ uint16_t debounce_up_us;
+ /* Time between start of scans when in polling mode */
+ uint16_t scan_period_us;
+ /*
+ * Minimum time between end of one scan and start of the next one.
+ * This ensures keyboard scanning doesn't starve the rest of the system
+ * if the scan period is set too short, or if other higher-priority
+ * system activity is starving the keyboard scan task too.
+ */
+ uint16_t min_post_scan_delay_us;
+
+ /* Revert to interrupt mode after no keyboard activity for this long */
+ uint32_t poll_timeout_us;
+ /* Mask with 1 bits only for keys that actually exist */
+ uint8_t actual_key_mask[KEYBOARD_COLS];
+};
/**
* Initializes the module.
*/
void keyboard_scan_init(void);
+/**
+ * Return a pointer to the keyboard scan config.
+ */
+struct keyboard_scan_config *keyboard_scan_get_config(void);
+
/* Key held down at keyboard-controlled reset boot time. */
enum boot_key {
BOOT_KEY_NONE, /* No keys other than keyboard-controlled reset keys */
@@ -31,6 +59,12 @@ enum boot_key {
enum boot_key keyboard_scan_get_boot_key(void);
/**
+ * Return a pointer to the current debounced keyboard matrix state, which is
+ * KEYBOARD_COLS bytes long.
+ */
+const uint8_t *keyboard_scan_get_state(void);
+
+/**
* Enables/disables keyboard matrix scan.
*/
void keyboard_scan_enable(int enable);