mkbp: Implement ChromeOS EC keyboard support.

This change implements ChromeOS EC keyboard (mkbp) support. There are two
layers of translation between the data returned by the EC.

1. Map bits in the bit vector into scancodes.
2. Map scancodes into ASCII characters.

There is currently no support for multicharacter escape sequences which will
probably be necessary because the arrow keys use it, and they're used to
select languages on various vboot screens.

There is also no support for key repeat delay or key repeat frequency. Every
key that's pressed which wasn't pressed during the last scan is registered
every time a scan is done, barring running out of space in the output FIFO.
Ignoring whether a key was pressed during the last scan almost works in our
use case, but it fails if it matters how many times a key is pressed, for
instance when cycling through languages on the recovery screen.

Only the Snow supported keymatrix is supported currently. Two keyboard layouts
are supported, US and German, both copied from libpayload. The default layout
is US, possibly (and historically) the only one that we'll use.

The more generic layout support could be backported into libpayload, and it
would be nice to share it with the PS/2 keyboard driver. That can be a
different change.

In the read_scancodes function, the array which keeps track of all pressed
keys is maximally sized based on the total number of keys in the key matrix.
It's allocated on the stack, and while the data structure is fairly small and
the stack should be big enough to handle it, it's something to be aware of.

Flow of the driver:

When the system runs either of the two input related callbacks, if there are
no characters currently queued up to return, the driver sends a message to the
EC asking it to scan the matrix.

The bit vector which represents the pressed keys in the matrix is scanned,
skipping any bytes which have no set bits (which will be most of them). Those
are translated through the selectable keymatrix table into 16 bit scancodes
which are either zero extended 8 bit scancodes if there's a valid mapping, or
0xffff. If any of the keys were pressed during the last scan, they're set to
0xffff as well. The state of the modifiers is accumulated in this loop as
well.

Once the scancodes have been collected, the whole set is checked for ghosting.
Ghosting is if, due to the way the keymatrix is wired, a key looks like it was
pressed when it wasn't because it shares a row and a column with two other keys
which were pressed. The check is two nested loops which check each
key against all the others one by one.

Quadratic performance is acceptable here for two reasons. First, the number of
keys is bounded to a manageable number in an absolute sense, and practically
speaking there should be at most 3 or 4 pressed at any one time. Second, we're
already talking with hardware which is fairly slow, and getting input from a
human user which is extremely slow, relatively speaking.

During that loop, all the valid keys are copied into the output buffer and the
invalide ones are ignored. The invalid keys are kept up to this point so that
they can be part of the ghosting check.

Now we use the modifiers to select a keyboard layout, and map all the
non-modifier keys through it. When Ctrl is pressed we don't use a seperate
map, we just apply a mask to the alphabetic characters.

BUG=chrome-os-partner:18633
TEST=Built for Snow with the Snow scancodes and US layout turned on. Used
gbb_utility to force dev mode. Booted into dev mode and pressed lots of keys
to verify that ghosting detection was working. If it's not, pressing D, ;,
and ' will make the F4 key ghost which, for some reason, manifests as
Ctrl + L. That's the key combination for legacy mode which, because it isn't
supported, causes beeping and a warning message. Pressed Ctrl + D at the dev
screen (not currently visible) and verified that vboot recognized the Ctrl + D
and continued on to boot into the kernel. Verified that keys were only
recognized once per press.
BRANCH=None

Change-Id: Ic1534e4f851c83cbb9d037d2ab14f0acd461a6f7
Signed-off-by: Gabe Black <gabeblack@google.com>
Reviewed-on: https://gerrit.chromium.org/gerrit/48072
Reviewed-by: Gabe Black <gabeblack@chromium.org>
Reviewed-by: Stefan Reinauer <reinauer@google.com>
Commit-Queue: Gabe Black <gabeblack@chromium.org>
Tested-by: Gabe Black <gabeblack@chromium.org>
15 files changed
tree: 39a5f93a861f8cc7d216a2567c272951c0240503
  1. board/
  2. src/
  3. util/
  4. .gitignore
  5. Kconfig
  6. Makefile
  7. Makefile.inc
  8. PRESUBMIT.cfg