mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-08 16:41:55 +00:00
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>
This commit is contained in:
committed by
chrome-bot
parent
d99b8722c9
commit
b9939cf42b
@@ -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,
|
||||
¶m[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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user