Matt Delco has uploaded this change for review.

View Change

libpayload/drivers/i8042: ignore special keys on keyboard

Some keyboards have a fn-key (and/or fn-mode lock) that can generate
0xe0-prefixed scan codes for certain keys. Previously the 0xe0 prefix
state wasn't tracked (it was ignored), so these scan codes could be
misinterpreted as non-0xe0 presses (e.g., 'mute' generates 0xe0 0x20
but this would get interpreted as 0x20 and be treated as a 'D' press).
Most 0xe0-prefixed codes (besides those for the 10-key) are irrelevant
for firmware so we'll ignore them.

BUG=none
BRANCH=none
TEST=local build and flash. Verified that special keys are no longer
interpreted as other keystrokes.

Change-Id: Ie6a828b6a0a3ab47456d6db2db504aa0d7aefc28
Signed-off-by: Matt Delco <delco@chromium.org>
---
M payloads/libpayload/drivers/i8042/keyboard.c
1 file changed, 23 insertions(+), 5 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/03/33303/1
diff --git a/payloads/libpayload/drivers/i8042/keyboard.c b/payloads/libpayload/drivers/i8042/keyboard.c
index 3e5f988..bca916f 100644
--- a/payloads/libpayload/drivers/i8042/keyboard.c
+++ b/payloads/libpayload/drivers/i8042/keyboard.c
@@ -235,12 +235,30 @@
unsigned char ch;
int shift;
int ret = 0;
-
- while (!keyboard_havechar()) ;
+ static int prior_special = 0;

ch = keyboard_get_scancode();

- if (!(ch & 0x80) && ch < 0x59) {
+ if (prior_special) {
+ if (ch == 0x5e)
+ ret = POWER_BUTTON;
+ /*
+ * For now 0xe0 with 0x1c, 0x35, or 0x47 - 0x53 is the same as
+ * non-0xe0. For 10-key scan codes 0x47-0x53 it's probably more
+ * accurate for the non-0xe0 presses to use the numeric
+ * interpretation of the key (i.e., when num lock is on) and
+ * the 0xe0 prefixed versions should use the non-numeric
+ * interpretation (i.e., num lock off). However, the existing
+ * tables are using the non-numeric interpretation so for now
+ * the 0xe0 presses can use what's in the table for non-0xe0
+ * presses. The main exception is that shift+'/' on the keypad
+ * (0xe0 0x35) should still produce a '/' (vs. a '?' like on
+ * the key that's to the left of the right-shift on English
+ * keyboards) so we'll ignore the shift status.
+ */
+ else if (ch == 0x1c || ch == 0x35 || (ch >= 0x47 && ch <= 0x53))
+ ret = map->map[0][ch];
+ } else if (ch < 0x59) { /* implies !(ch & 0x80), i.e., key press */
shift =
(modifier & KB_MOD_SHIFT) ^ (modifier & KB_MOD_CAPSLOCK) ? 1 : 0;

@@ -265,8 +283,8 @@
}
}

- if (ch == 0x5e)
- ret = POWER_BUTTON;
+ /* sequence 0xe0 0xe0 should not leave prior_special set. */
+ prior_special = !prior_special && ch == 0xe0;

return ret;
}

To view, visit change 33303. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ie6a828b6a0a3ab47456d6db2db504aa0d7aefc28
Gerrit-Change-Number: 33303
Gerrit-PatchSet: 1
Gerrit-Owner: Matt Delco <delco@chromium.org>
Gerrit-MessageType: newchange