summaryrefslogtreecommitdiff
path: root/driver/touchpad_elan.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /driver/touchpad_elan.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-release-R102-14695.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'driver/touchpad_elan.c')
-rw-r--r--driver/touchpad_elan.c847
1 files changed, 0 insertions, 847 deletions
diff --git a/driver/touchpad_elan.c b/driver/touchpad_elan.c
deleted file mode 100644
index 6df4f0f7de..0000000000
--- a/driver/touchpad_elan.c
+++ /dev/null
@@ -1,847 +0,0 @@
-/* Copyright 2016 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "byteorder.h"
-#include "common.h"
-#include "console.h"
-#include "gpio.h"
-#include "hwtimer.h"
-#include "hooks.h"
-#include "i2c.h"
-#include "math_util.h"
-#include "sha256.h"
-#include "shared_mem.h"
-#include "task.h"
-#include "tablet_mode.h"
-#include "timer.h"
-#include "touchpad.h"
-#include "update_fw.h"
-#include "util.h"
-#include "usb_api.h"
-#include "usb_hid_touchpad.h"
-#include "watchdog.h"
-
-/* Console output macros */
-#define CPUTS(outstr) cputs(CC_TOUCHPAD, outstr)
-#define CPRINTF(format, args...) cprintf(CC_TOUCHPAD, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_TOUCHPAD, format, ## args)
-
-#define TASK_EVENT_POWER TASK_EVENT_CUSTOM_BIT(0)
-
-/******************************************************************************/
-/* How to talk to the controller */
-/******************************************************************************/
-
-#define ELAN_VENDOR_ID 0x04f3
-
-#define ETP_I2C_RESET 0x0100
-#define ETP_I2C_WAKE_UP 0x0800
-#define ETP_I2C_SLEEP 0x0801
-
-#define ETP_I2C_STAND_CMD 0x0005
-#define ETP_I2C_UNIQUEID_CMD 0x0101
-#define ETP_I2C_FW_VERSION_CMD 0x0102
-#define ETP_I2C_OSM_VERSION_CMD 0x0103
-#define ETP_I2C_XY_TRACENUM_CMD 0x0105
-#define ETP_I2C_MAX_X_AXIS_CMD 0x0106
-#define ETP_I2C_MAX_Y_AXIS_CMD 0x0107
-#define ETP_I2C_RESOLUTION_CMD 0x0108
-#define ETP_I2C_IAP_VERSION_CMD 0x0110
-#define ETP_I2C_PRESSURE_CMD 0x010A
-#define ETP_I2C_SET_CMD 0x0300
-#define ETP_I2C_IAP_TYPE_CMD 0x0304
-#define ETP_I2C_POWER_CMD 0x0307
-#define ETP_I2C_FW_CHECKSUM_CMD 0x030F
-
-#define ETP_ENABLE_ABS 0x0001
-
-#define ETP_DISABLE_POWER 0x0001
-
-#define ETP_I2C_REPORT_LEN 34
-
-#define ETP_MAX_FINGERS 5
-#define ETP_FINGER_DATA_LEN 5
-
-#define ETP_PRESSURE_OFFSET 25
-#define ETP_FWIDTH_REDUCE 90
-
-#define ETP_REPORT_ID 0x5D
-#define ETP_REPORT_ID_OFFSET 2
-#define ETP_TOUCH_INFO_OFFSET 3
-#define ETP_FINGER_DATA_OFFSET 4
-#define ETP_HOVER_INFO_OFFSET 30
-#define ETP_MAX_REPORT_LEN 34
-
-#define ETP_IAP_START_ADDR 0x0083
-
-#define ETP_I2C_IAP_RESET_CMD 0x0314
-#define ETP_I2C_IAP_RESET 0xF0F0
-#define ETP_I2C_IAP_CTRL_CMD 0x0310
-#define ETP_I2C_MAIN_MODE_ON BIT(9)
-#define ETP_I2C_IAP_CMD 0x0311
-#define ETP_I2C_IAP_PASSWORD 0x1EA5
-
-#define ETP_I2C_IAP_REG_L 0x01
-#define ETP_I2C_IAP_REG_H 0x06
-
-#define ETP_FW_IAP_PAGE_ERR BIT(5)
-#define ETP_FW_IAP_INTF_ERR BIT(4)
-
-#ifdef CONFIG_USB_UPDATE
-/* The actual FW_SIZE depends on IC. */
-#define FW_SIZE CONFIG_TOUCHPAD_VIRTUAL_SIZE
-#endif
-
-struct {
- /* Max X/Y position */
- uint16_t max_x;
- uint16_t max_y;
- /* Scaling factor for finger width/height */
- uint16_t width_x;
- uint16_t width_y;
- /* Pressure adjustment */
- uint8_t pressure_adj;
- uint16_t ic_type;
- uint16_t page_count;
- uint16_t page_size;
- uint16_t iap_version;
-} elan_tp_params;
-
-/*
- * Report a more reasonable pressure value, so that no adjustment is necessary
- * on Chrome OS side. 3216/1024 ~= 3.1416.
- */
-const int pressure_mult = 3216;
-const int pressure_div = 1024;
-
-static int elan_tp_read_cmd(uint16_t reg, uint16_t *val)
-{
- uint8_t buf[2];
-
- buf[0] = reg;
- buf[1] = reg >> 8;
-
- return i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT,
- CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
- buf, sizeof(buf), (uint8_t *)val, sizeof(*val));
-}
-
-static int elan_tp_write_cmd(uint16_t reg, uint16_t val)
-{
- uint8_t buf[4];
-
- buf[0] = reg;
- buf[1] = reg >> 8;
- buf[2] = val;
- buf[3] = val >> 8;
-
- return i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT,
- CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
- buf, sizeof(buf), NULL, 0);
-}
-
-/* Power is on by default. */
-static int elan_tp_power = 1;
-
-static int elan_tp_set_power(int enable)
-{
- int rv;
- uint16_t val;
-
- if ((enable && elan_tp_power) || (!enable && !elan_tp_power))
- return EC_SUCCESS;
-
- CPRINTS("elan TP power %s", enable ? "on" : "off");
-
- rv = elan_tp_read_cmd(ETP_I2C_POWER_CMD, &val);
- if (rv)
- goto out;
-
- if (enable)
- val &= ~ETP_DISABLE_POWER;
- else
- val |= ETP_DISABLE_POWER;
-
- rv = elan_tp_write_cmd(ETP_I2C_POWER_CMD, val);
-
- elan_tp_power = enable;
-out:
- return rv;
-}
-
-static int finger_status[ETP_MAX_FINGERS] = {0};
-
-/*
- * Timestamp of last interrupt (32 bits are enough as we divide the value by 100
- * and then put it in a 16-bit field).
- */
-static uint32_t irq_ts;
-
-/*
- * Read touchpad report.
- * Returns 0 on success, positive (EC_RES_*) value on I2C error, and a negative
- * value if the I2C transaction is successful but the data is invalid (fairly
- * common).
- */
-static int elan_tp_read_report(void)
-{
- int rv;
- uint8_t tp_buf[ETP_I2C_REPORT_LEN];
- int i, ri;
- uint8_t touch_info;
- uint8_t hover_info;
- uint8_t *finger = tp_buf+ETP_FINGER_DATA_OFFSET;
- struct usb_hid_touchpad_report report;
- uint16_t timestamp;
-
- /* Compute and save timestamp early in case another interrupt comes. */
- timestamp = irq_ts / USB_HID_TOUCHPAD_TIMESTAMP_UNIT;
-
- rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT,
- CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
- NULL, 0, tp_buf, ETP_I2C_REPORT_LEN);
-
- if (rv) {
- CPRINTS("read report error (%d)", rv);
- return rv;
- }
-
- if (tp_buf[ETP_REPORT_ID_OFFSET] != ETP_REPORT_ID) {
- CPRINTS("Invalid report id (%x)", tp_buf[ETP_REPORT_ID_OFFSET]);
- return -1;
- }
-
- memset(&report, 0, sizeof(report));
- report.id = 0x01;
- ri = 0; /* Next finger index in HID report */
-
- touch_info = tp_buf[ETP_TOUCH_INFO_OFFSET];
- hover_info = tp_buf[ETP_HOVER_INFO_OFFSET];
-
- for (i = 0; i < ETP_MAX_FINGERS; i++) {
- int valid = touch_info & (1 << (3+i));
-
- if (valid) {
- int width = finger[3] & 0x0f;
- int height = (finger[3] & 0xf0) >> 4;
- int pressure = finger[4] + elan_tp_params.pressure_adj;
- pressure = DIV_ROUND_NEAREST(pressure * pressure_mult,
- pressure_div);
-
- width = MIN(4095, width * elan_tp_params.width_x);
- height = MIN(4095, height * elan_tp_params.width_y);
- pressure = MIN(1023, pressure);
-
- report.finger[ri].confidence = 1;
- report.finger[ri].tip = 1;
- report.finger[ri].inrange = 1;
- report.finger[ri].id = i;
- report.finger[ri].width = width;
- report.finger[ri].height = height;
- report.finger[ri].x =
- ((finger[0] & 0xf0) << 4) | finger[1];
- report.finger[ri].y =
- elan_tp_params.max_y -
- (((finger[0] & 0x0f) << 8) | finger[2]);
- report.finger[ri].pressure = pressure;
- finger += ETP_FINGER_DATA_LEN;
- ri++;
- finger_status[i] = 1;
- } else if (finger_status[i]) {
- report.finger[ri].id = i;
- /* When a finger is leaving, it's not a plam */
- report.finger[ri].confidence = 1;
- ri++;
- finger_status[i] = 0;
- }
- }
-
- report.count = ri;
- report.timestamp = timestamp;
-
- if (touch_info & 0x01) {
- /* Do not report zero-finger click events */
- if (report.count > 0)
- report.button = 1;
- }
-
- if (hover_info & 0x40) {
- /* TODO(b/35582031): Report hover event */
- CPRINTF("[TP] hover!\n");
- }
-
- set_touchpad_report(&report);
-
- return 0;
-}
-
-static void elan_get_fwinfo(void)
-{
- uint16_t ic_type = elan_tp_params.ic_type;
- uint16_t iap_version = elan_tp_params.iap_version;
-
- switch (ic_type) {
- case 0x09:
- elan_tp_params.page_count = 768;
- break;
- case 0x0D:
- elan_tp_params.page_count = 896;
- break;
- case 0x00:
- case 0x10:
- case 0x14:
- case 0x15:
- elan_tp_params.page_count = 1024;
- break;
- default:
- elan_tp_params.page_count = -1;
- CPRINTS("unknown ic_type: %d", ic_type);
- }
-
- if ((ic_type == 0x14 || ic_type == 0x15) && iap_version >= 2) {
- elan_tp_params.page_count /= 8;
- elan_tp_params.page_size = 512;
- } else if (ic_type >= 0x0D && iap_version >= 1) {
- elan_tp_params.page_count /= 2;
- elan_tp_params.page_size = 128;
- } else {
- elan_tp_params.page_size = 64;
- }
-}
-
-/*
- * - dpi == logical dimension / physical dimension (inches)
- * (254 tenths of mm per inch)
- */
-__maybe_unused static int calc_physical_dimension(int dpi, int logical_dim)
-{
- return round_divide(254 * logical_dim, dpi);
-}
-
-/* Initialize the controller ICs after reset */
-static void elan_tp_init(void)
-{
- int rv;
- uint8_t val[2];
- int dpi_x, dpi_y;
-
- CPRINTS("%s", __func__);
-
- elan_tp_write_cmd(ETP_I2C_STAND_CMD, ETP_I2C_RESET);
- msleep(100);
- rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT,
- CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
- NULL, 0, val, sizeof(val));
-
- CPRINTS("reset rv %d buf=%04x", rv, *((uint16_t *)val));
- if (rv)
- goto out;
-
- /* Read IC type, IAP version */
- rv = elan_tp_read_cmd(ETP_I2C_OSM_VERSION_CMD, &elan_tp_params.ic_type);
- CPRINTS("%s: ic_type:%04X.", __func__, elan_tp_params.ic_type);
- elan_tp_params.ic_type >>= 8;
- if (rv)
- goto out;
-
- rv = elan_tp_read_cmd(ETP_I2C_IAP_VERSION_CMD,
- &elan_tp_params.iap_version);
- CPRINTS("%s: iap_version:%04X.", __func__, elan_tp_params.iap_version);
- elan_tp_params.iap_version >>= 8;
- if (rv)
- goto out;
-
- elan_get_fwinfo();
-
- /* Read min/max */
- rv = elan_tp_read_cmd(ETP_I2C_MAX_X_AXIS_CMD, &elan_tp_params.max_x);
- if (rv)
- goto out;
- rv = elan_tp_read_cmd(ETP_I2C_MAX_Y_AXIS_CMD, &elan_tp_params.max_y);
- if (rv)
- goto out;
-
- /* Read min/max */
- rv = elan_tp_read_cmd(ETP_I2C_XY_TRACENUM_CMD, (uint16_t *)val);
- if (rv)
- goto out;
- if (val[0] == 0 || val[1] == 0) {
- CPRINTS("Invalid XY_TRACENUM");
- goto out;
- }
-
- /* ETP_FWIDTH_REDUCE reduces the apparent width to avoid treating large
- * finger as palm. Multiply value by 2 as HID multitouch divides it.
- */
- elan_tp_params.width_x =
- 2 * ((elan_tp_params.max_x / val[0]) - ETP_FWIDTH_REDUCE);
- elan_tp_params.width_y =
- 2 * ((elan_tp_params.max_y / val[1]) - ETP_FWIDTH_REDUCE);
-
- rv = elan_tp_read_cmd(ETP_I2C_PRESSURE_CMD, (uint16_t *)val);
- if (rv)
- goto out;
- elan_tp_params.pressure_adj = (val[0] & 0x10) ? 0 : ETP_PRESSURE_OFFSET;
-
- rv = elan_tp_read_cmd(ETP_I2C_RESOLUTION_CMD, (uint16_t *)val);
- if (rv)
- goto out;
-
- dpi_x = 10*val[0] + 790;
- dpi_y = 10*val[1] + 790;
-
- CPRINTS("max=%d/%d width=%d/%d adj=%d dpi=%d/%d",
- elan_tp_params.max_x, elan_tp_params.max_y,
- elan_tp_params.width_x, elan_tp_params.width_y,
- elan_tp_params.pressure_adj, dpi_x, dpi_y);
-
-#ifdef CONFIG_USB_HID_TOUCHPAD
- /* Validity check dimensions provided at build time. */
- if (elan_tp_params.max_x != CONFIG_USB_HID_TOUCHPAD_LOGICAL_MAX_X ||
- elan_tp_params.max_y != CONFIG_USB_HID_TOUCHPAD_LOGICAL_MAX_Y ||
- calc_physical_dimension(dpi_x, elan_tp_params.max_x) !=
- CONFIG_USB_HID_TOUCHPAD_PHYSICAL_MAX_X ||
- calc_physical_dimension(dpi_y, elan_tp_params.max_y) !=
- CONFIG_USB_HID_TOUCHPAD_PHYSICAL_MAX_Y) {
- CPRINTS("*** TP mismatch!");
- }
-#endif
-
- /* Switch to absolute mode */
- rv = elan_tp_write_cmd(ETP_I2C_SET_CMD, ETP_ENABLE_ABS);
- if (rv)
- goto out;
-
- /* Sleep control off */
- rv = elan_tp_write_cmd(ETP_I2C_STAND_CMD, ETP_I2C_WAKE_UP);
-
- /* Enable interrupt to fetch reports */
- gpio_enable_interrupt(GPIO_TOUCHPAD_INT);
-
-out:
- CPRINTS("%s:%d", __func__, rv);
-
- return;
-}
-DECLARE_DEFERRED(elan_tp_init);
-
-#ifdef CONFIG_USB_UPDATE
-int touchpad_get_info(struct touchpad_info *tp)
-{
- int rv;
- uint16_t val;
-
- tp->status = EC_RES_SUCCESS;
- tp->vendor = ELAN_VENDOR_ID;
-
- /* Get unique ID, FW, SM version. */
- rv = elan_tp_read_cmd(ETP_I2C_UNIQUEID_CMD, &val);
- if (rv)
- return -1;
- tp->elan.id = val;
-
- rv = elan_tp_read_cmd(ETP_I2C_FW_VERSION_CMD, &val);
- if (rv)
- return -1;
- tp->elan.fw_version = val & 0xff;
-
- rv = elan_tp_read_cmd(ETP_I2C_FW_CHECKSUM_CMD, &val);
- if (rv)
- return -1;
- tp->elan.fw_checksum = val;
-
- return sizeof(*tp);
-}
-
-static int elan_in_main_mode(void)
-{
- uint16_t val;
-
- elan_tp_read_cmd(ETP_I2C_IAP_CTRL_CMD, &val);
- return val & ETP_I2C_MAIN_MODE_ON;
-}
-
-static int elan_read_write_iap_type(void)
-{
- for (int retry = 0; retry < 3; ++retry) {
- uint16_t val;
-
- if (elan_tp_write_cmd(ETP_I2C_IAP_TYPE_CMD,
- elan_tp_params.page_size / 2))
- return EC_ERROR_UNKNOWN;
-
- if (elan_tp_read_cmd(ETP_I2C_IAP_TYPE_CMD, &val))
- return EC_ERROR_UNKNOWN;
-
- if (val == elan_tp_params.page_size / 2)
- return EC_SUCCESS;
-
- }
- return EC_ERROR_UNKNOWN;
-}
-
-static int elan_prepare_for_update(void)
-{
- uint16_t rx_buf;
- int initial_mode;
-
- initial_mode = elan_in_main_mode();
- if (!initial_mode) {
- CPRINTS("%s: In IAP mode, reset IC.", __func__);
- elan_tp_write_cmd(ETP_I2C_IAP_RESET_CMD, ETP_I2C_IAP_RESET);
- msleep(30);
- }
- /* Send the passphrase */
- elan_tp_write_cmd(ETP_I2C_IAP_CMD, ETP_I2C_IAP_PASSWORD);
- msleep(initial_mode ? 100 : 30);
-
- /* We should be in the IAP mode now */
- if (elan_in_main_mode()) {
- CPRINTS("%s: Failure to enter IAP mode.", __func__);
- return EC_ERROR_UNKNOWN;
- }
-
- if (elan_tp_params.ic_type >= 0x0D && elan_tp_params.iap_version >= 1) {
- if (elan_read_write_iap_type())
- return EC_ERROR_UNKNOWN;
- }
-
- /* Send the passphrase again */
- elan_tp_write_cmd(ETP_I2C_IAP_CMD, ETP_I2C_IAP_PASSWORD);
- msleep(30);
-
- /* Verify the password */
- if (elan_tp_read_cmd(ETP_I2C_IAP_CMD, &rx_buf)) {
- CPRINTS("%s: Cannot read IAP password.", __func__);
- return EC_ERROR_UNKNOWN;
- }
- if (rx_buf != ETP_I2C_IAP_PASSWORD) {
- CPRINTS("%s: Got an unexpected IAP password %0x4x.", __func__,
- rx_buf);
- return EC_ERROR_UNKNOWN;
- }
- return EC_SUCCESS;
-}
-
-static int touchpad_update_page(const uint8_t *data)
-{
- const uint8_t cmd[2] = {ETP_I2C_IAP_REG_L, ETP_I2C_IAP_REG_H};
- uint16_t checksum = 0;
- uint16_t rx_buf;
- int i, rv;
-
- for (i = 0; i < elan_tp_params.page_size; i += 2)
- checksum += ((uint16_t)(data[i + 1]) << 8) | (data[i]);
- checksum = htole16(checksum);
-
- i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 1);
-
- rv = i2c_xfer_unlocked(CONFIG_TOUCHPAD_I2C_PORT,
- CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
- cmd, sizeof(cmd), NULL, 0, I2C_XFER_START);
- if (rv)
- goto fail;
- rv = i2c_xfer_unlocked(CONFIG_TOUCHPAD_I2C_PORT,
- CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
- data, elan_tp_params.page_size, NULL, 0, 0);
- if (rv)
- goto fail;
- rv = i2c_xfer_unlocked(CONFIG_TOUCHPAD_I2C_PORT,
- CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
- (uint8_t *)&checksum, sizeof(checksum), NULL, 0,
- I2C_XFER_STOP);
- if (rv)
- goto fail;
-
-fail:
- i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 0);
- if (rv)
- return rv;
- msleep(elan_tp_params.page_size >= 512 ? 50 : 35);
-
- rv = elan_tp_read_cmd(ETP_I2C_IAP_CTRL_CMD, &rx_buf);
-
- if (rv || (rx_buf & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR))) {
- CPRINTS("%s: IAP reports failed write : %x.",
- __func__, rx_buf);
- return EC_ERROR_UNKNOWN;
- }
- return 0;
-}
-
-int touchpad_update_write(int offset, int size, const uint8_t *data)
-{
- static int iap_addr = -1;
- int addr, rv;
-
- CPRINTS("%s %08x %d", __func__, offset, size);
-
- if (offset == 0) {
- /* Verify the IC type is aligned with defined firmware size */
- if (elan_tp_params.page_size * elan_tp_params.page_count
- != FW_SIZE) {
- CPRINTS("%s: IC(%d*%d) size and FW_SIZE(%d) mismatch",
- __func__, elan_tp_params.page_count,
- elan_tp_params.page_size, FW_SIZE);
- return EC_ERROR_UNKNOWN;
- }
-
- gpio_disable_interrupt(GPIO_TOUCHPAD_INT);
- CPRINTS("%s: prepare fw update.", __func__);
- rv = elan_prepare_for_update();
- if (rv)
- return rv;
- iap_addr = 0;
- }
-
- if (offset <= (ETP_IAP_START_ADDR * 2) &&
- (ETP_IAP_START_ADDR * 2) < (offset + size)) {
- iap_addr = ((data[ETP_IAP_START_ADDR * 2 - offset + 1] << 8) |
- data[ETP_IAP_START_ADDR * 2 - offset]) << 1;
- CPRINTS("%s: payload starts from 0x%x.", __func__, iap_addr);
- }
-
- /* Data that comes in must align with page_size */
- if (offset % elan_tp_params.page_size)
- return EC_ERROR_INVAL;
-
- for (addr = offset; addr < (offset + size);
- addr += elan_tp_params.page_size) {
- if (iap_addr > addr) /* Skip chunk */
- continue;
- rv = touchpad_update_page(data + addr - offset);
- if (rv)
- return rv;
- CPRINTF("/p%d", addr / elan_tp_params.page_size);
- watchdog_reload();
- }
- CPRINTF("\n");
-
- if (offset + size == FW_SIZE) {
- CPRINTS("%s: End update, wait for reset.", __func__);
- hook_call_deferred(&elan_tp_init_data, 600 * MSEC);
- }
- return EC_SUCCESS;
-}
-
-/* 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
- },
-};
-
-/* Debugging commands need to allocate a <=1k buffer. */
-SHARED_MEM_CHECK_SIZE(1024);
-
-int touchpad_debug(const uint8_t *param, unsigned int param_size,
- uint8_t **data, unsigned int *data_size)
-{
- 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);
- }
-
- rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT,
- CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
- &param[offset], write_length,
- buffer, read_length);
-
- 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
-
-/*
- * Try to read touchpad report up to 3 times, reset the touchpad if we still
- * fail.
- */
-void elan_tp_read_report_retry(void)
-{
- int ret;
- int retry = 3;
-
- while (retry--) {
- ret = elan_tp_read_report();
-
- if (ret <= 0)
- return;
-
- /* Try again */
- msleep(1);
- }
-
- /* Failed to read data, reset the touchpad. */
- CPRINTF("Resetting TP.\n");
- board_touchpad_reset();
- elan_tp_init();
-}
-
-void touchpad_interrupt(enum gpio_signal signal)
-{
- irq_ts = __hw_clock_source_read();
-
- task_wake(TASK_ID_TOUCHPAD);
-}
-
-/* Make a decision on touchpad power, based on USB and tablet mode status. */
-static void touchpad_power_control(void)
-{
- static int enabled = 1;
- int enable = 1;
-
-#ifdef CONFIG_USB_SUSPEND
- enable = enable &&
- (!usb_is_suspended() || usb_is_remote_wakeup_enabled());
-#endif
-
-#ifdef CONFIG_TABLET_MODE
- enable = enable && !tablet_get_mode();
-#endif
-
- if (enabled == enable)
- return;
-
- elan_tp_set_power(enable);
-
- enabled = enable;
-}
-
-void touchpad_task(void *u)
-{
- uint32_t event;
-
- elan_tp_init();
- touchpad_power_control();
-
- while (1) {
- event = task_wait_event(-1);
-
- if (event & TASK_EVENT_WAKE)
- elan_tp_read_report_retry();
-
- if (event & TASK_EVENT_POWER)
- touchpad_power_control();
- }
-}
-
-/*
- * When USB PM status changes, or tablet mode changes, call in the main task to
- * decide whether to turn touchpad on or off.
- */
-#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_TABLET_MODE)
-static void touchpad_power_change(void)
-{
- task_set_event(TASK_ID_TOUCHPAD, TASK_EVENT_POWER);
-}
-#endif
-#ifdef CONFIG_USB_SUSPEND
-DECLARE_HOOK(HOOK_USB_PM_CHANGE, touchpad_power_change, HOOK_PRIO_DEFAULT);
-#endif
-#ifdef CONFIG_TABLET_MODE
-DECLARE_HOOK(HOOK_TABLET_MODE_CHANGE, touchpad_power_change, HOOK_PRIO_DEFAULT);
-#endif