summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2016-07-06 19:37:00 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2016-07-08 01:27:59 +0000
commit1a6bff615382c5e210eac3f5ba83b2c1b388f889 (patch)
tree145258fe0eda56bf88044fec5b5a7b495fe1dd52
parent9de5e5ff8646357eaec6e1d6a2ddf251b1f6c768 (diff)
downloadchrome-ec-1a6bff615382c5e210eac3f5ba83b2c1b388f889.tar.gz
mkbp: Add support for buttons and switches.
Currently, the matrix keyboard protocol does not have support for handling non-matrixed keys. This commit adds support for buttons which do not appear in the keyboard matrix as well as switches. The events will still share the same keyboard FIFO, however some of the events may simply be the new state of the buttons or switches on the system instead of the key matrix. BUG=chrome-os-partner:54988 BUG=chrome-os-partner:54976 BRANCH=None TEST=Flash kevin, and verify that keyboard is still functional. TEST=make -j buildall Change-Id: If4ada904cbd5d77823a0710d4671484b198c9d91 Signed-off-by: Aseda Aboagye <aaboagye@google.com> Reviewed-on: https://chromium-review.googlesource.com/359026 Reviewed-by: Bernie Thompson <bhthompson@chromium.org> Commit-Queue: Bernie Thompson <bhthompson@chromium.org> Tested-by: Bernie Thompson <bhthompson@chromium.org>
-rw-r--r--common/keyboard_mkbp.c153
-rw-r--r--common/mkbp_event.c61
-rw-r--r--include/ec_commands.h10
-rw-r--r--include/keyboard_mkbp.h36
4 files changed, 220 insertions, 40 deletions
diff --git a/common/keyboard_mkbp.c b/common/keyboard_mkbp.c
index 0e5f766a08..418fd71eab 100644
--- a/common/keyboard_mkbp.c
+++ b/common/keyboard_mkbp.c
@@ -7,10 +7,12 @@
#include "atomic.h"
#include "chipset.h"
+#include "common.h"
#include "console.h"
#include "gpio.h"
#include "host_command.h"
#include "keyboard_config.h"
+#include "keyboard_mkbp.h"
#include "keyboard_protocol.h"
#include "keyboard_raw.h"
#include "keyboard_scan.h"
@@ -30,8 +32,8 @@
* series of keys is pressed in rapid succession and the kernel is too busy
* to read them out right away.
*
- * RAM usage is (depth * #cols); see kb_fifo[][] below. A 16-entry FIFO will
- * consume 16x13=208 bytes, which is non-trivial but not horrible.
+ * RAM usage is (depth * #cols); A 16-entry FIFO will consume 16x13=208 bytes,
+ * which is non-trivial but not horrible.
*/
#define KB_FIFO_DEPTH 16
@@ -45,7 +47,7 @@
static uint32_t kb_fifo_start; /* first entry */
static uint32_t kb_fifo_end; /* last entry */
static uint32_t kb_fifo_entries; /* number of existing entries */
-static uint8_t kb_fifo[KB_FIFO_DEPTH][KEYBOARD_COLS];
+static union kb_fifo_data kb_fifo[KB_FIFO_DEPTH];
static struct mutex fifo_mutex;
/* Config for mkbp protocol; does not include fields from scan config */
@@ -78,7 +80,7 @@ static int kb_fifo_remove(uint8_t *buffp)
if (!kb_fifo_entries) {
/* no entry remaining in FIFO : return last known state */
int last = (kb_fifo_start + KB_FIFO_DEPTH - 1) % KB_FIFO_DEPTH;
- memcpy(buffp, kb_fifo[last], KEYBOARD_COLS);
+ memcpy(buffp, &kb_fifo[last], sizeof(union kb_fifo_data));
/*
* Bail out without changing any FIFO indices and let the
@@ -87,7 +89,8 @@ static int kb_fifo_remove(uint8_t *buffp)
*/
return EC_ERROR_UNKNOWN;
}
- memcpy(buffp, kb_fifo[kb_fifo_start], KEYBOARD_COLS);
+
+ memcpy(buffp, &kb_fifo[kb_fifo_start], sizeof(union kb_fifo_data));
kb_fifo_start = (kb_fifo_start + 1) % KB_FIFO_DEPTH;
@@ -118,18 +121,59 @@ void keyboard_clear_buffer(void)
kb_fifo_end = 0;
kb_fifo_entries = 0;
for (i = 0; i < KB_FIFO_DEPTH; i++)
- memset(kb_fifo[i], 0, KEYBOARD_COLS);
+ memset(&kb_fifo[i], 0, sizeof(union kb_fifo_data));
+}
+
+/**
+ * Check if cookie matches the event.
+ *
+ * @param evt MKBP event.
+ * @param p Pointer to location where cookie should reside.
+ * @return 1 if cookie is valid for the event, 0 if the cookie is invalid.
+ */
+static uint8_t check_cookie(enum ec_mkbp_event evt, const uint8_t *p)
+{
+ int differ = 1;
+
+ switch (evt) {
+ case EC_MKBP_EVENT_BUTTON:
+ differ = memcmp(p, (void *)MKBP_BUTTON_COOKIE,
+ MKBP_BUTTON_COOKIE_LEN);
+ break;
+
+ case EC_MKBP_EVENT_SWITCH:
+ differ = memcmp(p, (void *)MKBP_SWITCH_COOKIE,
+ MKBP_SWITCH_COOKIE_LEN);
+
+ default:
+ /* No cookie for other event types. */
+ break;
+ }
+
+ if (differ)
+ return 0;
+ else
+ return 1;
}
+#define BTN (1 << 0)
+#define SW (1 << 1)
test_mockable int keyboard_fifo_add(const uint8_t *buffp)
{
int ret = EC_SUCCESS;
+ uint8_t is_btn_or_switch = 0;
+
+ /* Determine if the data is a button or switch. */
+ if (check_cookie(EC_MKBP_EVENT_BUTTON, buffp))
+ is_btn_or_switch |= BTN;
+ if (check_cookie(EC_MKBP_EVENT_SWITCH, buffp))
+ is_btn_or_switch |= SW;
/*
- * If keyboard protocol is not enabled, don't save the state to the
- * FIFO or trigger an interrupt.
+ * If the data is a keyboard matrix and the keyboard protocol is not
+ * enabled, don't save the state to the FIFO or trigger an interrupt.
*/
- if (!(config.flags & EC_MKBP_FLAGS_ENABLE))
+ if (!(config.flags & EC_MKBP_FLAGS_ENABLE) && !is_btn_or_switch)
return EC_SUCCESS;
if (kb_fifo_entries >= config.fifo_max_depth) {
@@ -140,7 +184,7 @@ test_mockable int keyboard_fifo_add(const uint8_t *buffp)
}
mutex_lock(&fifo_mutex);
- memcpy(kb_fifo[kb_fifo_end], buffp, KEYBOARD_COLS);
+ memcpy(&kb_fifo[kb_fifo_end], buffp, sizeof(union kb_fifo_data));
kb_fifo_end = (kb_fifo_end + 1) % KB_FIFO_DEPTH;
atomic_add(&kb_fifo_entries, 1);
mutex_unlock(&fifo_mutex);
@@ -149,7 +193,12 @@ kb_fifo_push_done:
if (ret == EC_SUCCESS) {
#ifdef CONFIG_MKBP_EVENT
- mkbp_send_event(EC_MKBP_EVENT_KEY_MATRIX);
+ if (is_btn_or_switch & BTN)
+ mkbp_send_event(EC_MKBP_EVENT_BUTTON);
+ else if (is_btn_or_switch & SW)
+ mkbp_send_event(EC_MKBP_EVENT_SWITCH);
+ else
+ mkbp_send_event(EC_MKBP_EVENT_KEY_MATRIX);
#else
set_host_interrupt(1);
#endif
@@ -159,20 +208,94 @@ kb_fifo_push_done:
}
#ifdef CONFIG_MKBP_EVENT
-static int keyboard_get_next_event(uint8_t *out)
+static int get_next_event(uint8_t *out, enum ec_mkbp_event evt)
{
+ uint8_t elem;
+ uint8_t next_elem;
+ uint8_t val;
+
if (!kb_fifo_entries)
return -1;
+ /*
+ * We need to peek at the next event to check that we were called with
+ * the correct event.
+ */
+ next_elem = 0;
+ val = check_cookie(EC_MKBP_EVENT_BUTTON,
+ (uint8_t *)&kb_fifo[kb_fifo_start]);
+ if (val)
+ next_elem |= BTN;
+
+ val = check_cookie(EC_MKBP_EVENT_SWITCH,
+ (uint8_t*)&kb_fifo[kb_fifo_start]);
+ if (val)
+ next_elem |= SW;
+
+ if ((!next_elem && ((evt == EC_MKBP_EVENT_BUTTON) ||
+ (evt == EC_MKBP_EVENT_SWITCH))) ||
+ ((next_elem & BTN) && (evt != EC_MKBP_EVENT_BUTTON)) ||
+ ((next_elem & SW) && (evt != EC_MKBP_EVENT_SWITCH))) {
+ /*
+ * We were called with the wrong event. The next element in the
+ * keyboard FIFO doesn't match with what we were called with.
+ * Repost the event and return an error that we're busy. The
+ * caller will need to call us with the correct event first.
+ */
+ mkbp_send_event(evt);
+ return -EC_ERROR_BUSY;
+ }
+
kb_fifo_remove(out);
+ elem = next_elem;
/* Keep sending events if FIFO is not empty */
- if (kb_fifo_entries)
- mkbp_send_event(EC_MKBP_EVENT_KEY_MATRIX);
+ if (kb_fifo_entries) {
+ /*
+ * We need to check the cookie of the next element in the
+ * keyboard FIFO so that we can send the correct pending event.
+ */
+ if (check_cookie(EC_MKBP_EVENT_BUTTON,
+ (uint8_t *)&kb_fifo[kb_fifo_start]))
+ mkbp_send_event(EC_MKBP_EVENT_BUTTON);
+ else if (check_cookie(EC_MKBP_EVENT_SWITCH,
+ (uint8_t *)&kb_fifo[kb_fifo_start]))
+ mkbp_send_event(EC_MKBP_EVENT_SWITCH);
+ else
+ mkbp_send_event(EC_MKBP_EVENT_KEY_MATRIX);
+ }
- return KEYBOARD_COLS;
+ /* Adjust for the cookie if necessary. */
+ if (elem & BTN) {
+ out += MKBP_BUTTON_COOKIE_LEN;
+ return (sizeof(struct mkbp_btn_data) - MKBP_BUTTON_COOKIE_LEN);
+ } else if (elem & SW) {
+ out += MKBP_SWITCH_COOKIE_LEN;
+ return (sizeof(struct mkbp_sw_data) - MKBP_SWITCH_COOKIE_LEN);
+ } else {
+ return KEYBOARD_COLS;
+ }
+}
+#undef BTN
+#undef SW
+
+static int keyboard_get_next_event(uint8_t *out)
+{
+ return get_next_event(out, EC_MKBP_EVENT_KEY_MATRIX);
}
DECLARE_EVENT_SOURCE(EC_MKBP_EVENT_KEY_MATRIX, keyboard_get_next_event);
+
+static int button_get_next_event(uint8_t *out)
+{
+ return get_next_event(out, EC_MKBP_EVENT_BUTTON);
+}
+DECLARE_EVENT_SOURCE(EC_MKBP_EVENT_BUTTON, button_get_next_event);
+
+static int switch_get_next_event(uint8_t *out)
+{
+ return get_next_event(out, EC_MKBP_EVENT_SWITCH);
+}
+DECLARE_EVENT_SOURCE(EC_MKBP_EVENT_SWITCH, switch_get_next_event);
#endif
void keyboard_send_battery_key(void)
diff --git a/common/mkbp_event.c b/common/mkbp_event.c
index 60ca19d645..43c956ed33 100644
--- a/common/mkbp_event.c
+++ b/common/mkbp_event.c
@@ -75,35 +75,47 @@ static int mkbp_get_next_event(struct host_cmd_handler_args *args)
uint8_t *resp = args->response;
const struct mkbp_event_source *src;
- /*
- * Find the next event to service. We do this in a round-robin
- * way to make sure no event gets starved.
- */
- for (i = 0; i < EC_MKBP_EVENT_COUNT; ++i)
- if (event_is_set((last + i) % EC_MKBP_EVENT_COUNT))
- break;
-
- if (i == EC_MKBP_EVENT_COUNT)
- return EC_RES_ERROR;
+ do {
+ /*
+ * Find the next event to service. We do this in a round-robin
+ * way to make sure no event gets starved.
+ */
+ for (i = 0; i < EC_MKBP_EVENT_COUNT; ++i)
+ if (event_is_set((last + i) % EC_MKBP_EVENT_COUNT))
+ break;
- evt = (i + last) % EC_MKBP_EVENT_COUNT;
- last = evt + 1;
+ if (i == EC_MKBP_EVENT_COUNT)
+ return EC_RES_ERROR;
- /*
- * Clear the event before retrieving the event data in case the
- * event source wants to send the same event.
- */
- clear_event(evt);
+ evt = (i + last) % EC_MKBP_EVENT_COUNT;
+ last = evt + 1;
- for (src = __mkbp_evt_srcs; src < __mkbp_evt_srcs_end; ++src)
- if (src->event_type == evt)
- break;
+ /*
+ * Clear the event before retrieving the event data in case the
+ * event source wants to send the same event.
+ */
+ clear_event(evt);
- if (src == __mkbp_evt_srcs_end)
- return EC_RES_ERROR;
+ for (src = __mkbp_evt_srcs; src < __mkbp_evt_srcs_end; ++src)
+ if (src->event_type == evt)
+ break;
+
+ if (src == __mkbp_evt_srcs_end)
+ return EC_RES_ERROR;
+
+ resp[0] = evt; /* Event type */
+
+ /*
+ * get_data() can return -EC_ERROR_BUSY which indicates that the
+ * next element in the keyboard FIFO does not match what we were
+ * called with. For example, get_data is expecting a keyboard
+ * matrix, however the next element in the FIFO is a button
+ * event instead. Therefore, we have to service that button
+ * event first.
+ */
+ data_size = src->get_data(resp + 1);
+ } while (data_size == -EC_ERROR_BUSY);
- resp[0] = evt; /* Event type */
- data_size = src->get_data(resp + 1);
if (data_size < 0)
return EC_RES_ERROR;
args->response_size = 1 + data_size;
@@ -116,4 +128,3 @@ static int mkbp_get_next_event(struct host_cmd_handler_args *args)
DECLARE_HOST_COMMAND(EC_CMD_GET_NEXT_EVENT,
mkbp_get_next_event,
EC_VER_MASK(0));
-
diff --git a/include/ec_commands.h b/include/ec_commands.h
index f532dfe84b..f31d59c25b 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -2521,6 +2521,12 @@ enum ec_mkbp_event {
/* New Sensor FIFO data. The event data is fifo_info structure. */
EC_MKBP_EVENT_SENSOR_FIFO = 2,
+ /* The state of the non-matrixed buttons have changed. */
+ EC_MKBP_EVENT_BUTTON = 3,
+
+ /* The state of the switches have changed. */
+ EC_MKBP_EVENT_SWITCH = 4,
+
/* Number of MKBP events */
EC_MKBP_EVENT_COUNT,
};
@@ -2536,6 +2542,10 @@ union ec_response_get_next_data {
uint8_t rsvd[3];
struct ec_response_motion_sense_fifo_info info;
} sensor_fifo;
+
+ uint32_t buttons;
+
+ uint32_t switches;
} __packed;
struct ec_response_get_next_event {
diff --git a/include/keyboard_mkbp.h b/include/keyboard_mkbp.h
index 5ea3c54593..14b1bb1c34 100644
--- a/include/keyboard_mkbp.h
+++ b/include/keyboard_mkbp.h
@@ -9,6 +9,42 @@
#define __CROS_EC_KEYBOARD_MKBP_H
#include "common.h"
+#include "keyboard_config.h"
+
+#define MKBP_BUTTON_COOKIE "bTnZ" /* Buttons! */
+#define MKBP_BUTTON_COOKIE_LEN 4
+#define MKBP_SWITCH_COOKIE "SwTz" /* Switches! */
+#define MKBP_SWITCH_COOKIE_LEN 4
+/*
+ * These cookies contain enough 1s in the first 4 columns so that they shouldn't
+ * be a valid keypress combination.
+ */
+
+struct mkbp_btn_data {
+ char cookie[MKBP_BUTTON_COOKIE_LEN]; /* Must be MKBP_BUTTON_COOKIE */
+
+ /* State of non-matrixed buttons. */
+ uint32_t state;
+} __packed;
+
+struct mkbp_sw_data {
+ char cookie[MKBP_SWITCH_COOKIE_LEN]; /* Must be MKBP_SWITCH_COOKIE */
+
+ /* State of switches. */
+ uint32_t state;
+} __packed;
+
+union kb_fifo_data {
+ uint8_t key_matrix[KEYBOARD_COLS];
+
+ struct mkbp_btn_data b_data;
+
+ struct mkbp_sw_data sw_data;
+} __packed;
+
+#define POWER_BUTTON 0
+#define VOL_UP 1
+#define VOL_DOWN 2
/**
* Add keyboard state into FIFO