summaryrefslogtreecommitdiff
path: root/driver/touchpad_elan.c
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@chromium.org>2017-11-09 16:39:37 -0800
committerchrome-bot <chrome-bot@chromium.org>2017-12-14 18:11:52 -0800
commitb9939cf42b22f6e2a4fcaebd75e7520538afccd6 (patch)
tree63af61a2070411de9a33ebc9d7dead9d67cf5b2e /driver/touchpad_elan.c
parentd99b8722c9e6b221b95f3f3ff05df33e93c2182d (diff)
downloadchrome-ec-b9939cf42b22f6e2a4fcaebd75e7520538afccd6.tar.gz
touchpad_elan: Add support for debugging mode
We add 2 hashes that each map to a list of allowed commands (command list is secret, and provided by Elan). UPDATE_EXTRA_CMD_TOUCHPAD_DEBUG on the USB interface have the following format for the parameter: - param[0]: must be 0xff - param[1]: offset of the I2C command in data - param[2]: command length - param[3-4]: read-back length (MSB first) over I2C, can be 0 - param[5-49]: data, is verified using SHA-256 hash. The I2C command pointed at by param[1-2] is then sent over I2C, and the data is read back into a shared buffer of size param[3-4]. The data can be fetched over USB by a single byte USB update touchpad debug command (indicating an offset in 64-bytes unit), fetching data from the shared buffer in blocks of 64 bytes. BRANCH=none BUG=b:63993891 TEST=Elan can run debugging commands using their proprietary tool. Change-Id: Idb19bcb940b7f030c3b3aeaf39d6b725fcb9ef34 Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/763576 Reviewed-by: Chun-ta Lin <itspeter@chromium.org>
Diffstat (limited to 'driver/touchpad_elan.c')
-rw-r--r--driver/touchpad_elan.c127
1 files changed, 125 insertions, 2 deletions
diff --git a/driver/touchpad_elan.c b/driver/touchpad_elan.c
index d3f19275ff..ba0d543a4d 100644
--- a/driver/touchpad_elan.c
+++ b/driver/touchpad_elan.c
@@ -9,6 +9,8 @@
#include "hwtimer.h"
#include "hooks.h"
#include "i2c.h"
+#include "sha256.h"
+#include "shared_mem.h"
#include "task.h"
#include "timer.h"
#include "touchpad.h"
@@ -506,11 +508,132 @@ int touchpad_update_write(int offset, int size, const uint8_t *data)
return EC_SUCCESS;
}
-/* TODO(b:63993891): Implement debugging mode for Elan touchpad. */
+/* Debugging mode. */
+
+/* Allowed debug commands. We only store a hash of the allowed commands. */
+#define TOUCHPAD_ELAN_DEBUG_CMD_LENGTH 50
+#define TOUCHPAD_ELAN_DEBUG_NUM_CMD 2
+
+static const uint8_t
+allowed_command_hashes[TOUCHPAD_ELAN_DEBUG_NUM_CMD][SHA256_DIGEST_SIZE] = {
+ {
+ 0x0a, 0xf6, 0x37, 0x03, 0x93, 0xb2, 0xde, 0x8c,
+ 0x56, 0x7b, 0x86, 0xba, 0xa6, 0x79, 0xe3, 0xa3,
+ 0x8b, 0xc7, 0x15, 0xf2, 0x53, 0xcf, 0x71, 0x8b,
+ 0x3d, 0xe4, 0x81, 0xf9, 0xd9, 0xa8, 0x78, 0x48
+ },
+ {
+ 0xac, 0xe5, 0xbf, 0x17, 0x1f, 0xde, 0xce, 0x76,
+ 0x0c, 0x0e, 0xf8, 0xa2, 0xe9, 0x67, 0x2d, 0xc9,
+ 0x1b, 0xd4, 0xba, 0x34, 0x51, 0xca, 0xf6, 0x6d,
+ 0x7b, 0xb2, 0x1f, 0x14, 0x82, 0x1c, 0x0b, 0x74
+ },
+};
+
int touchpad_debug(const uint8_t *param, unsigned int param_size,
uint8_t **data, unsigned int *data_size)
{
- return EC_RES_INVALID_COMMAND;
+ static uint8_t *buffer;
+ static unsigned int buffer_size;
+ unsigned int offset;
+
+ /* Offset parameter is 1 byte. */
+ if (param_size < 1)
+ return EC_RES_INVALID_PARAM;
+
+ /*
+ * Debug command, compute SHA-256, check that it matches allowed hashes,
+ * and execute I2C command.
+ *
+ * param[0] must be 0xff
+ * param[1] is the offset of the command in the data
+ * param[2] is the command length
+ * param[3-4] is the read-back length (MSB first), can be 0
+ * param[5-49] is verified using SHA-256 hash.
+ */
+ if (param[0] == 0xff && param_size == TOUCHPAD_ELAN_DEBUG_CMD_LENGTH) {
+ struct sha256_ctx ctx;
+ uint8_t *command_hash;
+ unsigned int offset = param[1];
+ unsigned int write_length = param[2];
+ unsigned int read_length =
+ ((unsigned int)param[3] << 8) | param[4];
+ int i;
+ int match;
+ int rv;
+
+ if (offset < 5 || write_length == 0 ||
+ (offset + write_length) >= TOUCHPAD_ELAN_DEBUG_CMD_LENGTH)
+ return EC_RES_INVALID_PARAM;
+
+ SHA256_init(&ctx);
+ SHA256_update(&ctx, param+5, TOUCHPAD_ELAN_DEBUG_CMD_LENGTH-5);
+ command_hash = SHA256_final(&ctx);
+
+ match = 0;
+ for (i = 0; i < TOUCHPAD_ELAN_DEBUG_NUM_CMD; i++) {
+ if (!memcmp(command_hash, allowed_command_hashes[i],
+ sizeof(allowed_command_hashes[i]))) {
+ match = 1;
+ break;
+ }
+ }
+
+ if (!match)
+ return EC_RES_INVALID_PARAM;
+
+ if (buffer) {
+ shared_mem_release(buffer);
+ buffer = NULL;
+ }
+
+ buffer_size = read_length;
+
+ if (read_length > 0) {
+ if (shared_mem_acquire(buffer_size,
+ (char **)&buffer) != EC_SUCCESS) {
+ buffer = NULL;
+ buffer_size = 0;
+ return EC_RES_BUSY;
+ }
+
+ memset(buffer, 0, buffer_size);
+ }
+
+ i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 1);
+ rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT,
+ CONFIG_TOUCHPAD_I2C_ADDR,
+ &param[offset], write_length,
+ buffer, read_length, I2C_XFER_SINGLE);
+ i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 0);
+
+ if (rv)
+ return EC_RES_BUS_ERROR;
+
+ return EC_RES_SUCCESS;
+ }
+
+ /*
+ * Data request: Retrieve previously read data from buffer, in blocks of
+ * 64 bytes.
+ */
+ offset = param[0] * 64;
+
+ if (!buffer)
+ return EC_RES_UNAVAILABLE;
+
+ if (offset >= buffer_size) {
+ shared_mem_release(buffer);
+ buffer = NULL;
+ *data = NULL;
+ *data_size = 0;
+ return EC_RES_OVERFLOW;
+ }
+
+ *data = buffer + offset;
+ *data_size = MIN(64, buffer_size - offset);
+
+ return EC_RES_SUCCESS;
}
#endif