blob: 6d04c76c87512708890e4ca1dcbed19278e000ba [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Keyboard handling, including the implementation of VbExKeyboardRead() and
* remapping of keys for the Fully-Automated Firmware Test (FAFT).
*
* Copyright 2018 Google LLC
*/
#include <common.h>
#include <cros/keyboard.h>
#include <cros/cros_ofnode.h>
#include <cros/vboot.h>
#include <dm/ofnode.h>
/* Control Sequence Introducer for arrow keys */
#define CSI_0 0x1B /* Escape */
#define CSI_1 0x5B /* '[' */
/* Types of keys to be overridden */
enum key_type_t {
KEY_TYPE_ASCII,
KEY_TYPE_SPECIAL,
KEY_TYPE_COUNT,
};
/* Each fdt key array holds three pairs of keys */
#define KEY_ARRAY_SIZE (2 * 3)
/**
* struct remap_key - Keys to remap
*
* @array: List of keys to remap, as pairs:
* - keycode to remap
* - new keycode to use
* @array_ptr: pointes to @array if it is initialised, elseNULL
*/
struct remap_key {
u32 array[KEY_ARRAY_SIZE];
u32 *array_ptr;
};
static struct remap_key remap_keys[KEY_TYPE_COUNT];
int vboot_keymap_init(struct vboot_info *vboot)
{
ofnode node = vboot->config;
if (!ofnode_valid(node))
return -ENOENT;
if (!ofnode_read_u32_array(node, "faft-key-remap-special",
remap_keys[KEY_TYPE_SPECIAL].array,
KEY_ARRAY_SIZE)) {
remap_keys[KEY_TYPE_SPECIAL].array_ptr =
remap_keys[KEY_TYPE_SPECIAL].array;
}
if (!ofnode_read_u32_array(node, "faft-key-remap-ascii",
remap_keys[KEY_TYPE_ASCII].array,
KEY_ARRAY_SIZE)) {
remap_keys[KEY_TYPE_ASCII].array_ptr =
remap_keys[KEY_TYPE_ASCII].array;
}
return 0;
}
/**
* faft_key_remap() - Remap a key if enabled
*
* This replaces normal ascii keys and special keys if the mainboard
* fdt has either an ascii or a special-key remap array.
*
* @keyp: pointer to key to be checked on entry; on exit the value of the
* remapped key on success, or the original key on failure
* @keytype: KEY_TYPE_ASCII or KEY_TYPE_SPECIAL
*
* @return 0 on success, -EPERM if overriding is not enabled, -ENOENT if
* no override found
*/
static int faft_key_remap(int *keyp, enum key_type_t keytype)
{
struct vboot_info *vboot = vboot_get();
u32 gbb_flags = vboot_get_gbb_flags(vboot);
int i;
if ((gbb_flags & VB2_GBB_FLAG_RUNNING_FAFT) == 0)
return -1;
if (remap_keys[keytype].array_ptr) {
for (i = 0; i < KEY_ARRAY_SIZE; i += 2) {
if (*keyp == remap_keys[keytype].array_ptr[i]) {
*keyp = remap_keys[keytype].array_ptr[i + 1];
return 0;
}
}
}
return -ENOENT;
}
u32 VbExKeyboardRead(void)
{
int ch = 0;
/* No input available */
if (!tstc())
goto out;
/* Read a non-Escape character or a standalone Escape character */
ch = getchar();
if (ch != CSI_0 || !tstc()) {
/* Handle normal asci keys for FAFT keyboard matrix */
if (faft_key_remap(&ch, KEY_TYPE_ASCII) >= 0)
goto out;
/*
* Special handle of Ctrl-Enter, which is converted into '\n'
* by i8042 driver.
*/
if (ch == '\n')
ch = VB_KEY_CTRL_ENTER;
goto out;
}
/* Filter out non- Escape-[ sequence */
if (getchar() != CSI_1) {
ch = 0;
goto out;
}
/* Get special keys */
ch = getchar();
/* Handle special keys for FAFT keyboard matrix */
if (faft_key_remap(&ch, KEY_TYPE_SPECIAL) >= 0)
goto out;
/* Special values for arrow up/down/left/right */
switch (ch) {
case 'A':
ch = VB_KEY_UP;
break;
case 'B':
ch = VB_KEY_DOWN;
break;
case 'C':
ch = VB_KEY_RIGHT;
break;
case 'D':
ch = VB_KEY_LEFT;
break;
default:
/* Filter out speical keys that we do not recognise */
ch = 0;
break;
}
out:
return ch;
}
u32 VbExKeyboardReadWithFlags(u32 *flags_ptr)
{
if (flags_ptr)
/* We trust keyboards on u-boot legacy devices */
*flags_ptr = VB_KEY_FLAG_TRUSTED_KEYBOARD;
return VbExKeyboardRead();
}