summaryrefslogtreecommitdiff
path: root/extra/touchpad_updater/touchpad_updater.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 /extra/touchpad_updater/touchpad_updater.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14633.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 'extra/touchpad_updater/touchpad_updater.c')
-rw-r--r--extra/touchpad_updater/touchpad_updater.c669
1 files changed, 0 insertions, 669 deletions
diff --git a/extra/touchpad_updater/touchpad_updater.c b/extra/touchpad_updater/touchpad_updater.c
deleted file mode 100644
index 716ded00f5..0000000000
--- a/extra/touchpad_updater/touchpad_updater.c
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Copyright 2017 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 <errno.h>
-#include <getopt.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/select.h>
-#include <unistd.h>
-
-#include <libusb.h>
-
-/* Command line options */
-static uint16_t vid = 0x18d1; /* Google */
-static uint16_t pid = 0x5022; /* Hammer */
-static uint8_t ep_num = 4; /* console endpoint */
-static uint8_t extended_i2c_exercise; /* non-zero to exercise */
-static char *firmware_binary = "144.0_2.0.bin"; /* firmware blob */
-
-/* Firmware binary blob related */
-#define MAX_FW_PAGE_SIZE 512
-#define MAX_FW_PAGE_COUNT 1024
-#define MAX_FW_SIZE (128 * 1024)
-
-static uint8_t fw_data[MAX_FW_SIZE];
-int fw_page_count;
-int fw_page_size;
-int fw_size;
-uint8_t ic_type;
-int iap_version;
-
-/* Utility functions */
-static int le_bytes_to_int(uint8_t *buf)
-{
- return buf[0] + (int)(buf[1] << 8);
-}
-
-/* Command line parsing related */
-static char *progname;
-static char *short_opts = ":f:v:p:e:hd";
-static const struct option long_opts[] = {
- /* name hasarg *flag val */
- {"file", 1, NULL, 'f'},
- {"vid", 1, NULL, 'v'},
- {"pid", 1, NULL, 'p'},
- {"ep", 1, NULL, 'e'},
- {"help", 0, NULL, 'h'},
- {"debug", 0, NULL, 'd'},
- {NULL, 0, NULL, 0},
-};
-
-static void usage(int errs)
-{
- printf("\nUsage: %s [options]\n"
- "\n"
- "Firmware updater over USB for trackpad under hammer\n"
- "\n"
- "Options:\n"
- "\n"
- " -f,--file STR Firmware binary (default %s)\n"
- " -v,--vid HEXVAL Vendor ID (default %04x)\n"
- " -p,--pid HEXVAL Product ID (default %04x)\n"
- " -e,--ep NUM Endpoint (default %d)\n"
- " -d,--debug Exercise extended read I2C over USB\n"
- " and print verbose debug messages.\n"
- " -h,--help Show this message\n"
- "\n", progname, firmware_binary, vid, pid, ep_num);
-
- exit(!!errs);
-}
-
-static void parse_cmdline(int argc, char *argv[])
-{
- char *e = 0;
- int i, errorcnt = 0;
-
- progname = strrchr(argv[0], '/');
- if (progname)
- progname++;
- else
- progname = argv[0];
-
- opterr = 0; /* quiet, you */
- while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
- switch (i) {
- case 'f':
- firmware_binary = optarg;
- break;
- case 'p':
- pid = (uint16_t) strtoull(optarg, &e, 16);
- if (!*optarg || (e && *e)) {
- printf("Invalid argument: \"%s\"\n", optarg);
- errorcnt++;
- }
- break;
- case 'v':
- vid = (uint16_t) strtoull(optarg, &e, 16);
- if (!*optarg || (e && *e)) {
- printf("Invalid argument: \"%s\"\n", optarg);
- errorcnt++;
- }
- break;
- case 'e':
- ep_num = (uint8_t) strtoull(optarg, &e, 0);
- if (!*optarg || (e && *e)) {
- printf("Invalid argument: \"%s\"\n", optarg);
- errorcnt++;
- }
- break;
- case 'd':
- extended_i2c_exercise = 1;
- break;
- case 'h':
- usage(errorcnt);
- break;
- case 0: /* auto-handled option */
- break;
- case '?':
- if (optopt)
- printf("Unrecognized option: -%c\n", optopt);
- else
- printf("Unrecognized option: %s\n",
- argv[optind - 1]);
- errorcnt++;
- break;
- case ':':
- printf("Missing argument to %s\n", argv[optind - 1]);
- errorcnt++;
- break;
- default:
- printf("Internal error at %s:%d\n", __FILE__, __LINE__);
- exit(1);
- }
- }
-
- if (errorcnt)
- usage(errorcnt);
-
-}
-
-/* USB transfer related */
-static uint8_t rx_buf[1024];
-static uint8_t tx_buf[1024];
-
-static struct libusb_device_handle *devh;
-static struct libusb_transfer *rx_transfer;
-static struct libusb_transfer *tx_transfer;
-
-static int claimed_iface;
-static int iface_num = -1;
-static int do_exit;
-
-static void request_exit(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- vfprintf(stderr, format, ap);
- va_end(ap);
- do_exit++; /* Why need this ? */
-
- if (tx_transfer)
- libusb_free_transfer(tx_transfer);
- if (rx_transfer)
- libusb_free_transfer(rx_transfer);
- if (devh) {
- if (claimed_iface)
- libusb_release_interface(devh, iface_num);
- libusb_close(devh);
- }
- libusb_exit(NULL);
- exit(1);
-}
-
-#define DIE(msg, r) \
- request_exit("%s: line %d, %s\n", msg, __LINE__, \
- libusb_error_name(r))
-
-static void sighandler(int signum)
-{
- request_exit("caught signal %d: %s\n", signum, strsignal(signum));
-}
-
-static int find_interface_with_endpoint(int want_ep_num)
-{
- int iface_num = -1;
- int r, i, j, k;
- struct libusb_device *dev;
- struct libusb_config_descriptor *conf = 0;
- const struct libusb_interface *iface0;
- const struct libusb_interface_descriptor *iface;
- const struct libusb_endpoint_descriptor *ep;
-
- dev = libusb_get_device(devh);
- r = libusb_get_active_config_descriptor(dev, &conf);
- if (r < 0) {
- DIE("get_active_config", r);
- return -1;
- }
-
- for (i = 0; i < conf->bNumInterfaces; i++) {
- iface0 = &conf->interface[i];
- for (j = 0; j < iface0->num_altsetting; j++) {
- iface = &iface0->altsetting[j];
- for (k = 0; k < iface->bNumEndpoints; k++) {
- ep = &iface->endpoint[k];
- if (ep->bEndpointAddress == want_ep_num) {
- iface_num = i;
- break;
- }
- }
- }
- }
-
- libusb_free_config_descriptor(conf);
- return iface_num;
-}
-
-static void init_with_libusb(void)
-{
- int r = 1;
-
- printf("init usb interface\n");
- r = libusb_init(NULL);
- if (r < 0)
- DIE("init", r);
-
- printf("open_device %04x:%04x\n", vid, pid);
- devh = libusb_open_device_with_vid_pid(NULL, vid, pid);
- if (!devh)
- request_exit("can't find device\n");
-
- iface_num = find_interface_with_endpoint(ep_num);
- if (iface_num < 0)
- request_exit("can't find interface owning EP %d\n", ep_num);
-
- printf("claim_interface %d to use endpoint %d\n", iface_num, ep_num);
- r = libusb_claim_interface(devh, iface_num);
- if (r < 0)
- DIE("claim interface", r);
- claimed_iface = 1;
-}
-
-static void register_sigaction(void)
-{
- struct sigaction sigact;
- sigact.sa_handler = sighandler;
- sigemptyset(&sigact.sa_mask);
- sigact.sa_flags = 0;
- sigaction(SIGINT, &sigact, NULL);
- sigaction(SIGTERM, &sigact, NULL);
- sigaction(SIGQUIT, &sigact, NULL);
-}
-
-/* Transfer over libusb */
-#define I2C_PORT_ON_HAMMER 0x00
-#define I2C_ADDRESS_ON_HAMMER 0x15
-
-static int check_read_status(int r, int expected, int actual)
-{
- int i;
- if (r)
- printf("Warning: libusb_bulk_transfer return error : %d\n", r);
- if (actual != (expected + 4)) {
- printf("Warning: Not reading back %d bytes.\n", expected);
- r = 1;
- }
-
- /* Check transaction status as defined in usb_i2c.h */
- for (i = 0; i < 4; ++i)
- if (rx_buf[i] != 0)
- break;
-
- if (i != 4) {
- r = le_bytes_to_int(rx_buf);
- printf("Warning: Defined error code (%d) returned.\n", r);
- }
-
- if (r || extended_i2c_exercise) {
- printf("\nDumping the receive buffer:\n");
- printf(" Recv %d bytes from USB hosts.\n", actual);
- for (i = 0; i < actual; ++i)
- printf(" [%2d]bytes: 0x%0x\n", i, rx_buf[i]);
- }
- return r;
-}
-
-#define MAX_USB_PACKET_SIZE 64
-#define PRIMITIVE_READING_SIZE 60
-
-static int libusb_single_write_and_read(
- const uint8_t *to_write, uint16_t write_length,
- uint8_t *to_read, uint16_t read_length)
-{
- int r;
- int tx_ready;
- int remains;
- int sent_bytes = 0;
- int actual_length = -1;
- int offset = read_length > PRIMITIVE_READING_SIZE ? 6 : 4;
- tx_transfer = rx_transfer = 0;
-
- memmove(tx_buf + offset, to_write, write_length);
- tx_buf[0] = I2C_PORT_ON_HAMMER | ((write_length >> 8) << 4);
- tx_buf[1] = I2C_ADDRESS_ON_HAMMER;
- tx_buf[2] = write_length & 0xff;
- if (read_length > PRIMITIVE_READING_SIZE) {
- tx_buf[3] = (read_length & 0x7f) | (1 << 7);
- tx_buf[4] = read_length >> 7;
- if (extended_i2c_exercise) {
- printf("Triggering extended reading."
- "rc:%0x, rc1:%0x\n",
- tx_buf[3], tx_buf[4]);
- printf("Expecting %d Bytes.\n",
- (tx_buf[3] & 0x7f) | (tx_buf[4] << 7));
- }
- } else {
- tx_buf[3] = read_length;
- }
-
- /*
- * TODO: This loop is probably not required as we write the whole block
- * in one transaction.
- */
- while (sent_bytes < (offset + write_length)) {
- tx_ready = remains = (offset + write_length) - sent_bytes;
-
- r = libusb_bulk_transfer(devh,
- (ep_num | LIBUSB_ENDPOINT_OUT),
- tx_buf + sent_bytes, tx_ready,
- &actual_length, 5000);
- if (r == 0 && actual_length == tx_ready) {
- r = libusb_bulk_transfer(devh,
- (ep_num | LIBUSB_ENDPOINT_IN),
- rx_buf, sizeof(rx_buf),
- &actual_length, 5000);
- }
- r = check_read_status(
- r, (remains == tx_ready) ? read_length : 0,
- actual_length);
- if (r)
- break;
- sent_bytes += tx_ready;
- }
- return r;
-}
-
-/* Control Elan trackpad I2C over USB */
-#define ETP_I2C_INF_LENGTH 2
-
-static int elan_write_and_read(
- int reg, uint8_t *buf, int read_length,
- int with_cmd, int cmd)
-{
-
- tx_buf[0] = (reg >> 0) & 0xff;
- tx_buf[1] = (reg >> 8) & 0xff;
- if (with_cmd) {
- tx_buf[2] = (cmd >> 0) & 0xff;
- tx_buf[3] = (cmd >> 8) & 0xff;
- }
- return libusb_single_write_and_read(
- tx_buf, with_cmd ? 4 : 2, rx_buf, read_length);
-}
-
-static int elan_read_block(int reg, uint8_t *buf, int read_length)
-{
- return elan_write_and_read(reg, buf, read_length, 0, 0);
-}
-
-static int elan_read_cmd(int reg)
-{
- return elan_read_block(reg, rx_buf, ETP_I2C_INF_LENGTH);
-}
-
-static int elan_write_cmd(int reg, int cmd)
-{
- return elan_write_and_read(reg, rx_buf, 0, 1, cmd);
-}
-
-/* Elan trackpad firmware information related */
-#define ETP_I2C_IAP_VERSION_CMD 0x0110
-#define ETP_I2C_FW_VERSION_CMD 0x0102
-#define ETP_I2C_IAP_CHECKSUM_CMD 0x0315
-#define ETP_I2C_FW_CHECKSUM_CMD 0x030F
-#define ETP_I2C_OSM_VERSION_CMD 0x0103
-
-static int elan_get_version(int is_iap)
-{
- elan_read_cmd(
- is_iap ? ETP_I2C_IAP_VERSION_CMD : ETP_I2C_FW_VERSION_CMD);
- return le_bytes_to_int(rx_buf + 4);
-}
-
-static void elan_get_ic_page_count(void)
-{
- elan_read_cmd(ETP_I2C_OSM_VERSION_CMD);
-
- ic_type = rx_buf[5];
- printf("ic_type: %02x\n", ic_type);
-
- switch (ic_type) {
- case 0x09:
- fw_page_count = 768;
- break;
- case 0x0D:
- fw_page_count = 896;
- break;
- case 0x00:
- case 0x10:
- case 0x14:
- fw_page_count = 1024;
- break;
- default:
- request_exit("The IC type is not supported.\n");
- }
-
- iap_version = elan_get_version(1);
- if (ic_type == 0x14 && iap_version >= 2) {
- fw_page_count /= 8;
- fw_page_size = 512;
- } else if (ic_type >= 0x0D && iap_version >= 1) {
- fw_page_count /= 2;
- fw_page_size = 128;
- } else {
- fw_page_size = 64;
- }
-}
-
-static int elan_get_checksum(int is_iap)
-{
- elan_read_cmd(
- is_iap ? ETP_I2C_IAP_CHECKSUM_CMD : ETP_I2C_FW_CHECKSUM_CMD);
- return le_bytes_to_int(rx_buf + 4);
-}
-
-static uint16_t elan_get_fw_info(void)
-{
- int fw_version = -1;
- uint16_t iap_checksum = 0xffff;
- uint16_t fw_checksum = 0xffff;
-
- printf("Querying device info...\n");
- fw_checksum = elan_get_checksum(0);
- iap_checksum = elan_get_checksum(1);
- fw_version = elan_get_version(0);
- iap_version = elan_get_version(1);
- printf("IAP version: %4x, FW version: %4x\n",
- iap_version, fw_version);
- printf("IAP checksum: %4x, FW checksum: %4x\n",
- iap_checksum, fw_checksum);
- return fw_checksum;
-}
-
-/* Update preparation */
-#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 (1 << 9)
-#define ETP_I2C_IAP_CMD 0x0311
-#define ETP_I2C_IAP_PASSWORD 0x1EA5
-#define ETP_I2C_IAP_TYPE_CMD 0x0304
-
-static int elan_in_main_mode(void)
-{
- elan_read_cmd(ETP_I2C_IAP_CTRL_CMD);
- return le_bytes_to_int(rx_buf + 4) & 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_write_cmd(ETP_I2C_IAP_TYPE_CMD,
- fw_page_size / 2))
- return -1;
-
- if (elan_read_cmd(ETP_I2C_IAP_TYPE_CMD))
- return -1;
-
- val = le_bytes_to_int(rx_buf + 4);
- if (val == fw_page_size / 2) {
- printf("%s: OK\n", __func__);
- return 0;
- }
-
- }
- return -1;
-}
-
-static void elan_prepare_for_update(void)
-{
- printf("%s\n", __func__);
-
- int initial_mode = elan_in_main_mode();
- if (!initial_mode) {
- printf("In IAP mode, reset IC.\n");
- elan_write_cmd(ETP_I2C_IAP_RESET_CMD, ETP_I2C_IAP_RESET);
- usleep(30 * 1000);
- }
-
- /* Send the passphrase */
- elan_write_cmd(ETP_I2C_IAP_CMD, ETP_I2C_IAP_PASSWORD);
- usleep((initial_mode ? 100 : 30) * 1000);
-
- /* We should be in the IAP mode now */
- if (elan_in_main_mode())
- request_exit("Failure to enter IAP mode, still in main mode\n");
-
- if (ic_type >= 0x0D && iap_version >= 1) {
- if (elan_read_write_iap_type())
- request_exit("Failure to set IAP mode\n");
- }
-
- /* Send the passphrase again */
- elan_write_cmd(ETP_I2C_IAP_CMD, ETP_I2C_IAP_PASSWORD);
- usleep(30 * 1000);
-
- /* Verify the password */
- if (elan_read_cmd(ETP_I2C_IAP_CMD))
- request_exit("cannot read iap password.\n");
- if (le_bytes_to_int(rx_buf + 4) != ETP_I2C_IAP_PASSWORD)
- request_exit("Got an unexpected IAP password %4x\n",
- le_bytes_to_int(rx_buf + 4));
-}
-
-/* Firmware block update */
-#define ETP_IAP_START_ADDR 0x0083
-
-static uint16_t elan_calc_checksum(uint8_t *data, int length)
-{
- uint16_t checksum = 0;
- for (int i = 0; i < length; i += 2)
- checksum += ((uint16_t)(data[i+1]) << 8) | (data[i]);
- return checksum;
-}
-
-static int elan_get_iap_addr(void)
-{
- return le_bytes_to_int(fw_data + ETP_IAP_START_ADDR * 2) * 2;
-}
-
-#define ETP_I2C_IAP_REG_L 0x01
-#define ETP_I2C_IAP_REG_H 0x06
-
-#define ETP_FW_IAP_PAGE_ERR (1 << 5)
-#define ETP_FW_IAP_INTF_ERR (1 << 4)
-
-static int elan_write_fw_block(uint8_t *raw_data, uint16_t checksum)
-{
- uint8_t page_store[MAX_FW_PAGE_SIZE + 4];
- int rv;
-
- page_store[0] = ETP_I2C_IAP_REG_L;
- page_store[1] = ETP_I2C_IAP_REG_H;
- memcpy(page_store + 2, raw_data, fw_page_size);
- page_store[fw_page_size + 2 + 0] = (checksum >> 0) & 0xff;
- page_store[fw_page_size + 2 + 1] = (checksum >> 8) & 0xff;
-
- rv = libusb_single_write_and_read(
- page_store, fw_page_size + 4, rx_buf, 0);
- if (rv)
- return rv;
- usleep((fw_page_size >= 512 ? 50 : 35) * 1000);
- elan_read_cmd(ETP_I2C_IAP_CTRL_CMD);
- rv = le_bytes_to_int(rx_buf + 4);
- if (rv & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) {
- printf("IAP reports failed write : %x\n", rv);
- return rv;
- }
- return 0;
-}
-
-
-static uint16_t elan_update_firmware(void)
-{
- uint16_t checksum = 0, block_checksum;
- int rv;
-
- printf("%s\n", __func__);
-
- for (int i = elan_get_iap_addr(); i < fw_size; i += fw_page_size) {
- printf("\rUpdating page %3d...", i / fw_page_size);
- fflush(stdout);
- block_checksum = elan_calc_checksum(fw_data + i, fw_page_size);
- rv = elan_write_fw_block(fw_data + i, block_checksum);
- if (rv)
- request_exit("Failed to update.\n");
- checksum += block_checksum;
- printf(" Updated, checksum: %d", checksum);
- fflush(stdout);
- }
- return checksum;
-}
-
-static void pretty_print_buffer(uint8_t *buf, int len)
-{
- int i;
-
- printf("Buffer = 0x");
- for (i = 0; i < len; ++i)
- printf("%02X", buf[i]);
- printf("\n");
-}
-
-int main(int argc, char *argv[])
-{
- uint16_t local_checksum;
- uint16_t remote_checksum;
-
- parse_cmdline(argc, argv);
- init_with_libusb();
- register_sigaction();
-
- /*
- * Judge IC type and get page count first.
- * Then check the FW file.
- */
- elan_get_ic_page_count();
- fw_size = fw_page_count * fw_page_size;
- printf("FW has %d bytes x %d pages\n", fw_page_size, fw_page_count);
-
- /* Read the FW file */
- FILE *f = fopen(firmware_binary, "rb");
- if (!f)
- request_exit("Cannot find binary: %s\n", firmware_binary);
- if (fread(fw_data, 1, fw_size, f) != (unsigned int)fw_size)
- request_exit("binary size mismatch, expect %d\n", fw_size);
-
- /*
- * It is possible that you are not able to get firmware info. This
- * might due to an incomplete update last time
- */
- elan_get_fw_info();
-
- /* Trigger an I2C transaction of expecting reading of 633 bytes. */
- if (extended_i2c_exercise) {
- tx_buf[0] = 0x05;
- tx_buf[1] = 0x00;
- tx_buf[2] = 0x3C;
- tx_buf[3] = 0x02;
- tx_buf[4] = 0x06;
- tx_buf[5] = 0x00;
- libusb_single_write_and_read(tx_buf, 6, rx_buf, 633);
- pretty_print_buffer(rx_buf, 637);
- }
-
- /* Get the trackpad ready for receiving update */
- elan_prepare_for_update();
-
- local_checksum = elan_update_firmware();
- /* Wait for a reset */
- usleep(600 * 1000);
- remote_checksum = elan_get_checksum(1);
- if (remote_checksum != local_checksum)
- printf("checksum diff local=[%04X], remote=[%04X]\n",
- local_checksum, remote_checksum);
-
- /* Print the updated firmware information */
- elan_get_fw_info();
- return 0;
-}