summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Yung-Chieh Lo <yjlou@chromium.org>2011-10-31 17:27:29 +0800
committerLouis Yung-Chieh Lo <yjlou@chromium.org>2011-10-31 17:27:29 +0800
commitafa146d0396fc5b77c411d103384da63a3e456d2 (patch)
treed6511a32a7bc1d967408703353965b2e0e112bcc
parentfd5d4b6e9e0a6833cd8685f068599117f5ab7ea8 (diff)
downloadchrome-ec-afa146d0396fc5b77c411d103384da63a3e456d2.tar.gz
Implement typematic delay and rate. Also other keyboard commands.
BUG=None TEST=make && make runtests Change-Id: Ia0013ddbb0300791b4667bf70c5d0fb78c9508b1
-rw-r--r--cros_ec/lib/ec_keyboard.c107
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;
}