diff options
author | Parth Malkan <parthmalkan@google.com> | 2022-02-15 08:15:39 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2022-02-24 06:41:29 +0000 |
commit | b141fbd2258745409f135b5e94b27b407dd68f0a (patch) | |
tree | b15c5e18b4e1d89f7b0c56743a5a66031d4ff170 | |
parent | a93bf9c122ff7bb6651c8a6bdadce37169964622 (diff) | |
download | chrome-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.c | 117 | ||||
-rw-r--r-- | common/main.c | 16 |
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) */ |