summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorParth Malkan <parthmalkan@google.com>2022-02-15 08:15:39 -0800
committerCommit Bot <commit-bot@chromium.org>2022-02-24 06:41:29 +0000
commitb141fbd2258745409f135b5e94b27b407dd68f0a (patch)
treeb15c5e18b4e1d89f7b0c56743a5a66031d4ff170
parenta93bf9c122ff7bb6651c8a6bdadce37169964622 (diff)
downloadchrome-ec-b141fbd2258745409f135b5e94b27b407dd68f0a.tar.gz
KB: Implement antighost keyboard scanner
This change adds the code that avoids detecting ghost key presses thus supporting anti-ghost feature for gaming kb. It includes configuring KSI pins as gpios to identify key press interrupt and then reading adc channels connected to KSI to read voltage level to identify actual key presses. BUG=b:208773873 TEST=make run-kb_scan BRANCH=none Cq-Depend: chromium:3465515, chromium:3464454, chromium:3460338 Signed-off-by: Parth Malkan <parthmalkan@google.com> Change-Id: I563fb118d8d3023ab0f82ab42909203fc50cb0ef Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3464274 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r--common/keyboard_scan.c117
-rw-r--r--common/main.c16
2 files changed, 119 insertions, 14 deletions
diff --git a/common/keyboard_scan.c b/common/keyboard_scan.c
index 8d59fb0a33..f56d5985d3 100644
--- a/common/keyboard_scan.c
+++ b/common/keyboard_scan.c
@@ -5,6 +5,7 @@
/* Keyboard scanner module for Chrome EC */
+#include "adc.h"
#include "chipset.h"
#include "clock.h"
#include "common.h"
@@ -79,15 +80,15 @@ __overridable struct keyboard_scan_config keyscan_config = {
/* Boot key list. Must be in same order as enum boot_key. */
struct boot_key_entry {
- uint8_t mask_index;
- uint8_t mask_value;
+ uint8_t col;
+ uint8_t row;
};
#ifdef CONFIG_KEYBOARD_BOOT_KEYS
static const struct boot_key_entry boot_key_list[] = {
- {KEYBOARD_COL_ESC, KEYBOARD_MASK_ESC}, /* Esc */
- {KEYBOARD_COL_DOWN, KEYBOARD_MASK_DOWN}, /* Down-arrow */
- {KEYBOARD_COL_LEFT_SHIFT, KEYBOARD_MASK_LEFT_SHIFT}, /* Left-Shift */
+ {KEYBOARD_COL_ESC, KEYBOARD_ROW_ESC}, /* Esc */
+ {KEYBOARD_COL_DOWN, KEYBOARD_ROW_DOWN}, /* Down-arrow */
+ {KEYBOARD_COL_LEFT_SHIFT, KEYBOARD_ROW_LEFT_SHIFT}, /* Left-Shift */
};
static uint32_t boot_key_value = BOOT_KEY_NONE;
#endif
@@ -194,6 +195,45 @@ static void ensure_keyboard_scanned(int old_polls)
usleep(keyscan_config.scan_period_us);
}
+#ifdef CONFIG_KEYBOARD_SCAN_ADC
+/**
+ * Read KSI ADC rows
+ *
+ * Read each adc channel and look for voltage crossing threshold level
+ */
+static int keyboard_read_adc_rows(void)
+{
+ uint8_t kb_row = 0;
+
+ /* Read each adc channel to build row byte */
+ for (int i = 0; i < KEYBOARD_ROWS; i++) {
+ if (adc_read_channel(ADC_KSI_00 + i) >
+ keyscan_config.ksi_threshold_mv)
+ kb_row |= (1 << i);
+ }
+
+ return kb_row;
+}
+
+/**
+ * Read refresh key
+ *
+ * Refresh key is detached from rest of the matrix in ADC based
+ * keyboard, so needs to be read through GPIO
+ *
+ * @param state Destination for new state (must be KEYBOARD_COLS_MAX
+ * long).
+ */
+static void keyboard_read_refresh_key(uint8_t *state)
+{
+ if (!gpio_get_level(GPIO_RFR_KEY_L))
+ state[KEYBOARD_COL_REFRESH] |= BIT(KEYBOARD_ROW_REFRESH);
+ else
+ state[KEYBOARD_COL_REFRESH] &= ~BIT(KEYBOARD_ROW_REFRESH);
+}
+#endif
+
+
/**
* Simulate a keypress.
*
@@ -266,13 +306,26 @@ static int read_matrix(uint8_t *state)
udelay(keyscan_config.output_settle_us);
/* Read the row state */
+#ifdef CONFIG_KEYBOARD_SCAN_ADC
+ state[c] = keyboard_read_adc_rows();
+#else
state[c] = keyboard_raw_read_rows();
+#endif
/* Use simulated keyscan sequence instead if testing active */
if (IS_ENABLED(CONFIG_KEYBOARD_TEST))
state[c] = keyscan_seq_get_scan(c, state[c]);
}
+#ifdef CONFIG_KEYBOARD_SCAN_ADC
+ /* Account for the refresh key */
+ keyboard_read_refresh_key(state);
+
+ /*
+ * KB with ADC support doesn't have transitional ghost,
+ * this check isn't required
+ */
+#else
/* 2. Detect transitional ghost */
for (c = 0; c < keyboard_cols; c++) {
int c2;
@@ -296,6 +349,7 @@ static int read_matrix(uint8_t *state)
}
}
}
+#endif
/* 3. Fix result */
for (c = 0; c < keyboard_cols; c++) {
@@ -488,9 +542,11 @@ static int check_keys_changed(uint8_t *state)
/* Read the raw key state */
any_pressed = read_matrix(new_state);
- /* Ignore if so many keys are pressed that we're ghosting. */
- if (has_ghosting(new_state))
- return any_pressed;
+ if (!IS_ENABLED(CONFIG_KEYBOARD_SCAN_ADC)) {
+ /* Ignore if so many keys are pressed that we're ghosting. */
+ if (has_ghosting(new_state))
+ return any_pressed;
+ }
/* Check for changes between previous scan and this one */
for (c = 0; c < keyboard_cols; c++) {
@@ -629,9 +685,9 @@ static uint32_t check_key_list(const uint8_t *state)
/* Update mask with all boot keys that were pressed. */
k = boot_key_list;
for (c = 0; c < ARRAY_SIZE(boot_key_list); c++, k++) {
- if (curr_state[k->mask_index] & k->mask_value) {
+ if (curr_state[k->col] & BIT(k->row)) {
boot_key_mask |= BIT(c);
- curr_state[k->mask_index] &= ~k->mask_value;
+ curr_state[k->col] &= ~BIT(k->row);
}
}
@@ -645,6 +701,31 @@ static uint32_t check_key_list(const uint8_t *state)
return boot_key_mask;
}
+#ifdef CONFIG_KEYBOARD_SCAN_ADC
+static void read_adc_boot_keys(uint8_t *state)
+{
+ int k;
+
+ for (k = 0; k < ARRAY_SIZE(boot_key_list); k++) {
+ int c = boot_key_list[k].col;
+ int r = boot_key_list[k].row;
+
+ /* Select column, then wait a bit for it to settle */
+ keyboard_raw_drive_column(c);
+ udelay(keyscan_config.output_settle_us);
+
+ if (adc_read_channel(ADC_KSI_00 + r) >
+ keyscan_config.ksi_threshold_mv)
+ state[c] |= BIT(r);
+ }
+
+ /* Read refresh key */
+ keyboard_read_refresh_key(state);
+
+ keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE);
+}
+#endif
+
/**
* Check what boot key is down, if any.
*
@@ -715,14 +796,19 @@ void keyboard_scan_init(void)
keyboard_mask_refresh = KEYBOARD_ROW_TO_MASK(
board_keyboard_row_refresh());
- /* Configure GPIO */
- keyboard_raw_init();
+ if (!IS_ENABLED(CONFIG_KEYBOARD_SCAN_ADC))
+ /* Configure GPIO */
+ keyboard_raw_init();
/* Tri-state the columns */
keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE);
/* Initialize raw state */
+#ifndef CONFIG_KEYBOARD_SCAN_ADC
read_matrix(debounced_state);
+#else
+ read_adc_boot_keys(debounced_state);
+#endif
#ifdef CONFIG_KEYBOARD_LANGUAGE_ID
/* Check keyboard ID state */
@@ -817,9 +903,16 @@ void keyboard_scan_task(void *u)
* user pressing a key and enable_interrupt()
* starting to pay attention to edges.
*/
+#ifndef CONFIG_KEYBOARD_SCAN_ADC
if (!local_disable_scanning &&
(keyboard_raw_read_rows() || force_poll))
break;
+#else
+ if (!local_disable_scanning &&
+ (keyboard_read_adc_rows() || force_poll ||
+ !gpio_get_level(GPIO_RFR_KEY_L)))
+ break;
+#endif
else
task_wait_event(-1);
}
diff --git a/common/main.c b/common/main.c
index 2cc1594eff..93e68fb1ca 100644
--- a/common/main.c
+++ b/common/main.c
@@ -6,6 +6,9 @@
*/
#include "board_config.h"
+#ifdef CONFIG_KEYBOARD_SCAN_ADC
+#include "adc.h"
+#endif
#include "button.h"
#include "chipset.h"
#include "clock.h"
@@ -207,10 +210,19 @@ test_mockable __keep int main(void)
}
}
-
#ifdef HAS_TASK_KEYSCAN
- keyboard_scan_init();
+
+#ifdef CONFIG_KEYBOARD_SCAN_ADC
+ /*
+ * Initialize adc here as we need to use it during keyboard_scan_init
+ * to scan boot keys
+ */
+ adc_init();
#endif
+
+ keyboard_scan_init();
+#endif /* HAS_TASK_KEYSCAN */
+
#if defined(CONFIG_DEDICATED_RECOVERY_BUTTON) || defined(CONFIG_VOLUME_BUTTONS)
button_init();
#endif /* defined(CONFIG_DEDICATED_RECOVERY_BUTTON | CONFIG_VOLUME_BUTTONS) */