diff options
-rw-r--r-- | cros_ec/lib/ec_keyboard.c | 107 |
1 files changed, 101 insertions, 6 deletions
diff --git a/cros_ec/lib/ec_keyboard.c b/cros_ec/lib/ec_keyboard.c index 7a5c43e0ef..fbaaf6cbad 100644 --- a/cros_ec/lib/ec_keyboard.c +++ b/cros_ec/lib/ec_keyboard.c @@ -7,13 +7,53 @@ #include "cros_ec/include/ec_common.h" #include "cros_ec/include/ec_keyboard.h" +#include "chip_interface/ec_uart.h" #include "chip_interface/keyboard.h" #include "host_interface/i8042.h" +/* + * i8042 global settings. + */ +static int i8042_enabled = 0; /* default the keyboard is disabled. */ +static uint8_t resend_command[MAX_I8042_OUTPUT_LEN]; +static uint8_t resend_command_len = 0; + +/* + * Scancode settings + */ static EcKeyboardMatrixCallback matrix_callback; static enum EcScancodeSet scancode_set = EC_SCANCODE_SET_2; +/* + * Typematic delay, rate and counter variables. + * + * 7 6 5 4 3 2 1 0 + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * |un- | delay | B | D | + * | used| 0 1 | 0 1 | 0 1 1 | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * Formula: + * the inter-char delay = (2 ** B) * (D + 8) / 240 (sec) + * Default: 500ms delay, 10.9 chars/sec. + */ +#define DEFAULT_TYPEMATIC_VALUE ((1 << 5) || (1 << 3) || (3 << 0)) +#define DEFAULT_FIRST_DELAY 500 +#define DEFAULT_INTER_DELAY 91 +static uint8_t typematic_value_from_host = DEFAULT_TYPEMATIC_VALUE; +static int refill_first_delay = DEFAULT_FIRST_DELAY; /* unit: ms */ +static int counter_first_delay; +static int refill_inter_delay = DEFAULT_INTER_DELAY; /* unit: ms */ +static int counter_inter_delay; + + +static void reset_rate_and_delay() { + typematic_value_from_host = DEFAULT_TYPEMATIC_VALUE; + refill_first_delay = DEFAULT_FIRST_DELAY; + refill_inter_delay = DEFAULT_INTER_DELAY; +} + + static void KeyboardStateChanged(int row, int col, int is_pressed) { uint8_t scan_code[MAX_SCAN_CODE_LEN]; int len; @@ -42,6 +82,8 @@ static int HandleHostCommand( uint8_t data, uint8_t *output) { int out_len = 0; + int save_for_resend = 1; + int i; switch (command) { case EC_I8042_CMD_GSCANSET: /* also EC_I8042_CMD_SSCANSET */ @@ -54,24 +96,77 @@ static int HandleHostCommand( } break; + case EC_I8042_CMD_SETLEDS: /* fall-thru */ + case EC_I8042_CMD_EX_SETLEDS: + /* We use screen indicator. Do thing in keyboard controller. */ + output[out_len++] = EC_I8042_RET_ACK; + break; + + case EC_I8042_CMD_GETID: /* fall-thru */ + case EC_I8042_CMD_OK_GETID: + output[out_len++] = 0xab; /* Regular keyboards */ + output[out_len++] = 0x83; + break; + case EC_I8042_CMD_SETREP: + typematic_value_from_host = data; + refill_first_delay = counter_first_delay + counter_inter_delay; + refill_first_delay = ((typematic_value_from_host & 0x60) >> 5) * 250; + refill_inter_delay = 1000 * /* ms */ + (1 << ((typematic_value_from_host & 0x18) >> 3)) * + ((typematic_value_from_host & 0x7) + 8) / + 240; + break; + case EC_I8042_CMD_ENABLE: + i8042_enabled = 1; + /* TODO: clean the underlying internal buffer */ + break; + case EC_I8042_CMD_RESET_DIS: + i8042_enabled = 0; + reset_rate_and_delay(); + /* TODO: clean the underlying internal buffer */ + break; + case EC_I8042_CMD_RESET_DEF: - case EC_I8042_CMD_SETALL_MB: - case EC_I8042_CMD_SETALL_MBR: + reset_rate_and_delay(); + /* TODO: clean the underlying internal buffer */ + break; + case EC_I8042_CMD_RESET_BAT: + i8042_enabled = 0; + output[out_len++] = EC_I8042_RET_BAT; + output[out_len++] = EC_I8042_RET_BAT; + /* TODO: clean the underlying internal buffer */ + break; + case EC_I8042_CMD_RESEND: + save_for_resend = 0; + for (i = 0; i < resend_command_len; ++i) { + output[out_len++] = resend_command[i]; + } + break; + + case EC_I8042_CMD_SETALL_MB: /* fall-thru below */ + case EC_I8042_CMD_SETALL_MBR: case EC_I8042_CMD_EX_ENABLE: - case EC_I8042_CMD_EX_SETLEDS: - case EC_I8042_CMD_OK_GETID: - case EC_I8042_CMD_GETID: - case EC_I8042_CMD_SETLEDS: default: output[out_len++] = EC_I8042_RET_ERR; + EcUartPrintf("Unsupported i8042 command 0x%02x.\n", command); break; } + /* For resend, keep output before leaving. */ + if (out_len && save_for_resend) { + EC_ASSERT(out_len <= MAX_I8042_OUTPUT_LEN); + for (i = 0; i < out_len; ++i) { + resend_command[i] = output[i]; + } + resend_command_len = out_len; + } + + EC_ASSERT(out_len <= MAX_I8042_OUTPUT_LEN); return out_len; } |