summaryrefslogtreecommitdiff
path: root/util/ectool_keyscan.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/ectool_keyscan.c')
-rw-r--r--util/ectool_keyscan.c679
1 files changed, 0 insertions, 679 deletions
diff --git a/util/ectool_keyscan.c b/util/ectool_keyscan.c
deleted file mode 100644
index 4f5393157d..0000000000
--- a/util/ectool_keyscan.c
+++ /dev/null
@@ -1,679 +0,0 @@
-/* Copyright 2012 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 <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <endian.h>
-
-#include "comm-host.h"
-#include "keyboard_config.h"
-#include "ectool.h"
-
-enum {
- /* Alloc this many more scans when needed */
- KEYSCAN_ALLOC_STEP = 64,
- KEYSCAN_MAX_TESTS = 10, /* Maximum number of tests supported */
- KEYSCAN_MAX_INPUT_LEN = 20, /* Maximum characters we can receive */
-};
-
-/* A single entry of the key matrix */
-struct matrix_entry {
- int row; /* key matrix row */
- int col; /* key matrix column */
- int keycode; /* corresponding linux key code */
-};
-
-struct keyscan_test_item {
- uint32_t beat; /* Beat number */
- uint8_t scan[KEYBOARD_COLS_MAX]; /* Scan data */
-};
-
-/* A single test, consisting of a list of key scans and expected ascii input */
-struct keyscan_test {
- char *name; /* name of test */
- char *expect; /* resulting input we expect to see */
- int item_count; /* number of items in data */
- int item_alloced; /* number of items alloced in data */
- struct keyscan_test_item *items; /* key data for EC */
-};
-
-/* A list of tests that we can run */
-struct keyscan_info {
- unsigned int beat_us; /* length of each beat in microseconds */
- struct keyscan_test tests[KEYSCAN_MAX_TESTS]; /* the tests */
- int test_count; /* number of tests */
- struct matrix_entry *matrix; /* the key matrix info */
- int matrix_count; /* number of keys in matrix */
-};
-
-/**
- * Read the key matrix from the device tree
- *
- * Keymap entries in the fdt take the form of 0xRRCCKKKK where
- * RR=Row CC=Column KKKK=Key Code
- *
- * @param keyscan keyscan information
- * @param path path to device tree file containing data
- * @return 0 if ok, -1 on error
- */
-static int keyscan_read_fdt_matrix(struct keyscan_info *keyscan,
- const char *path)
-{
- struct stat buf;
- uint32_t word;
- int upto;
- FILE *f;
- int err;
-
- /* Allocate memory for key matrix */
- if (stat(path, &buf)) {
- fprintf(stderr, "Cannot stat key matrix file '%s'\n", path);
- return -1;
- }
- keyscan->matrix_count = buf.st_size / 4;
- keyscan->matrix = (struct matrix_entry *)(calloc(
- keyscan->matrix_count, sizeof(*keyscan->matrix)));
- if (!keyscan->matrix) {
- fprintf(stderr, "Out of memory for key matrix\n");
- return -1;
- }
-
- f = fopen(path, "rb");
- if (!f) {
- fprintf(stderr, "Cannot open key matrix file '%s'\n", path);
- return -1;
- }
-
- /* Now read the data */
- upto = err = 0;
- while (fread(&word, 1, sizeof(word), f) == sizeof(word)) {
- struct matrix_entry *matrix = &keyscan->matrix[upto++];
-
- word = be32toh(word);
- matrix->row = word >> 24;
- matrix->col = (word >> 16) & 0xff;
- matrix->keycode = word & 0xffff;
-
- /* Hard-code some limits for now */
- if (matrix->row >= KEYBOARD_ROWS ||
- matrix->col >= KEYBOARD_COLS_MAX) {
- fprintf(stderr, "Matrix pos out of range (%d,%d)\n",
- matrix->row, matrix->col);
- fclose(f);
- return -1;
- }
- }
- fclose(f);
- if (!err && upto != keyscan->matrix_count) {
- fprintf(stderr, "Read mismatch from matrix file '%s'\n", path);
- err = -1;
- }
-
- return err;
-}
-
-/*
- * translate Linux's KEY_... values into ascii. We change space into 0xfe
- * since we use the numeric value (&32) for space. That avoids ambiguity
- * when we see a space in a key sequence file.
- */
-static const unsigned char kbd_plain_xlate[] = {
- 0xff, 0x1b, '1', '2', '3', '4', '5', '6',
- '7', '8', '9', '0', '-', '=', '\b', '\t', /* 0x00 - 0x0f */
- 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
- 'o', 'p', '[', ']', '\r', 0xff, 'a', 's', /* 0x10 - 0x1f */
- 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
- '\'', '`', 0xff, '\\', 'z', 'x', 'c', 'v', /* 0x20 - 0x2f */
- 'b', 'n', 'm', ',' , '.', '/', 0xff, 0xff, 0xff,
- 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 - 0x3f */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7',
- '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
- '2', '3', '0', '.', 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 - 0x5F */
- '\r', 0xff, 0xff, '\0'
-};
-
-/**
- * Add a new key to a scan
- *
- * Given a new key, this looks it up in the matrix and adds it to the scan,
- * so that if this scan were reported by the EC, the AP would the given key.
- *
- * The format of keys is a list of ascii characters, or & followed by a numeric
- * ascii value, or * followed by a numeric keycode value. Spaces are ignored
- * (use '*32' for space).
- *
- * Examples:
- * a - a
- * &20 - space
- * *58 - KEY_CAPSLOCK
- *
- * @param keyscan keyscan information
- * @param keysp point to the current key string on entry; on exit it
- * is updated to point to just after the string, plus any
- * following space
- * @param path path to device tree file containing data
- * @return 0 if ok, -1 on error
- */
-static int keyscan_add_to_scan(struct keyscan_info *keyscan, char **keysp,
- uint8_t scan[])
-{
- const uint8_t *pos;
- struct matrix_entry *matrix;
- int keycode = -1, i;
- char *keys = *keysp;
- int key = ' ';
-
- if (*keys == '&') {
- /* Numeric ascii code */
- keys++;
- key = strtol(keys, &keys, 10);
- if (!key || keys == *keysp) {
- fprintf(stderr, "Invalid numeric ascii\n");
- return -1;
- }
- if (*keys == ' ')
- keys++;
- else if (*keys) {
- fprintf(stderr, "Expect space after numeric ascii\n");
- return -1;
- }
- } else if (*keys == '*') {
- /* Numeric ascii code */
- keys++;
- keycode = strtol(keys, &keys, 10);
- if (!keycode || keys == *keysp) {
- fprintf(stderr, "Invalid numeric keycode\n");
- return -1;
- }
- if (*keys == ' ')
- keys++;
- else if (*keys) {
- fprintf(stderr, "Expect space after num. keycode\n");
- return -1;
- }
- } else {
- key = *keys++;
- }
-
- /* Convert keycode to key if needed */
- if (keycode == -1) {
- pos = (uint8_t *)(strchr((char *)kbd_plain_xlate, key));
- if (!pos) {
- fprintf(stderr, "Key '%c' not found in xlate table\n",
- key);
- return -1;
- }
- keycode = pos - kbd_plain_xlate;
- }
-
- /* Look up keycode in matrix */
- for (i = 0, matrix = keyscan->matrix; i < keyscan->matrix_count;
- i++, matrix++) {
- if (matrix->keycode == keycode) {
-#ifdef DEBUG
- printf("%d: %d,%d\n", matrix->keycode, matrix->row,
- matrix->col);
-#endif
- scan[matrix->col] |= 1 << matrix->row;
- *keysp = keys;
- return 0;
- }
- }
- fprintf(stderr, "Key '%c' (keycode %d) not found in matrix\n", key,
- keycode);
-
- return -1;
-}
-
-/**
- * Add a new keyscan to the given test
- *
- * This processes a new keyscan, consisting of a beat number and a sequence
- * of keys.
- *
- * The format of keys is a beat number followed by a list of keys, each
- * either ascii characters, or & followed by a numeric ascii value, or *
- * followed by a numeric keycode value. Spaces are ignored (use '*32' for
- * space).
- *
- * Examples:
- * 0 abc - beat 0, press a, b and c
- * 4 a &20 - beat 4, press a and space
- * 8 *58 &13 - beat 8, press KEY_CAPSLOCK
- *
- * @param keyscan keyscan information
- * @param linenum line number we are reading from (for error reporting)
- * @param test test to add this scan to
- * @param keys key string to process
- * @return 0 if ok, -1 on error
- */
-static int keyscan_process_keys(struct keyscan_info *keyscan, int linenum,
- struct keyscan_test *test, char *keys)
-{
- struct keyscan_test_item *item;
- unsigned long int beat;
-
- /* Allocate more items if needed */
- if (!test->item_alloced || test->item_count == test->item_alloced) {
- int size, new_size;
-
- size = test->item_alloced * sizeof(struct keyscan_test_item);
- new_size = size + KEYSCAN_ALLOC_STEP *
- sizeof(struct keyscan_test_item);
- test->items = (struct keyscan_test_item *)(realloc(test->items,
- new_size));
- if (!test->items) {
- fprintf(stderr, "Out of memory realloc()\n");
- return -1;
- }
- memset((char *)test->items + size, '\0', new_size - size);
- test->item_alloced += KEYSCAN_ALLOC_STEP;
- new_size = size;
- }
-
- /* read the beat number */
- item = &test->items[test->item_count];
- beat = strtol(keys, &keys, 10);
- item->beat = beat;
-
- /* Read keys and add them to our scan */
- if (*keys == ' ') {
- keys++;
- while (*keys) {
- if (keyscan_add_to_scan(keyscan, &keys, item->scan)) {
- fprintf(stderr, "Line %d: Cannot parse"
- " key input '%s'\n", linenum,
- keys);
- return -1;
- }
- }
- } else if (*keys) {
- fprintf(stderr, "Line %d: Need space after beat\n",
- linenum);
- return -1;
- }
- test->item_count++;
-
- return 0;
-}
-
-/* These are the commands we understand in a key sequence file */
-enum keyscan_cmd {
- KEYSCAN_CMD_TEST, /* start a new test */
- KEYSCAN_CMD_ENDTEST, /* end a test */
- KEYSCAN_CMD_SEQ, /* add a keyscan to a test sequence */
- KEYSCAN_CMD_EXPECT, /* indicate what input is expected */
-
- KEYSCAN_CMD_COUNT
-};
-
-/* Names for each of the keyscan commands */
-static const char *keyscan_cmd_name[KEYSCAN_CMD_COUNT] = {
- "test",
- "endtest",
- "seq",
- "expect",
-};
-
-/**
- * Read a command from a string and return it
- *
- * @param str String containing command
- * @param len Length of command string
- * @return detected command, or -1 if none
- */
-static enum keyscan_cmd keyscan_read_cmd(const char *str, int len)
-{
- int i;
-
- for (i = 0; i < KEYSCAN_CMD_COUNT; i++) {
- if (!strncmp(keyscan_cmd_name[i], str, len))
- return (enum keyscan_cmd)(i);
- }
-
- return (enum keyscan_cmd)(-1);
-}
-
-/**
- * Process a key sequence file a build up a list of tets from it
- *
- * @param f File containing keyscan info
- * @param keyscan keyscan information
- * @return 0 if ok, -1 on error
- */
-static int keyscan_process_file(FILE *f, struct keyscan_info *keyscan)
-{
- struct keyscan_test *cur_test;
- char line[256];
- char *str;
- int linenum;
-
- keyscan->test_count = 0;
-
- linenum = 0;
- cur_test = NULL;
- while (str = fgets(line, sizeof(line), f), str) {
- char *args, *end;
- int cmd, len;
-
- linenum++;
- len = strlen(str);
-
- /* chomp the trailing newline */
- if (len > 0 && str[len - 1] == '\n') {
- len--;
- str[len] = '\0';
- }
-
- /* deal with blank lines and comments */
- if (!len || *str == '#')
- continue;
-
- /* get the command */
- for (end = str; *end && *end != ' '; end++)
- ;
-
- cmd = keyscan_read_cmd(str, end - str);
- args = end + (*end != '\0');
- switch (cmd) {
- case KEYSCAN_CMD_TEST:
- /* Start a new test */
- if (keyscan->test_count == KEYSCAN_MAX_TESTS) {
- fprintf(stderr, "KEYSCAN_MAX_TESTS "
- "exceeded\n");
- return -1;
- }
- cur_test = &keyscan->tests[keyscan->test_count];
- cur_test->name = strdup(args);
- if (!cur_test->name) {
- fprintf(stderr, "Line %d: out of memory\n",
- linenum);
- }
- break;
- case KEYSCAN_CMD_EXPECT:
- /* Get expect string */
- if (!cur_test) {
- fprintf(stderr, "Line %d: expect should be "
- "inside test\n", linenum);
- return -1;
- }
- cur_test->expect = strdup(args);
- if (!cur_test->expect) {
- fprintf(stderr, "Line %d: out of memory\n",
- linenum);
- }
- break;
- case KEYSCAN_CMD_ENDTEST:
- /* End of a test */
- keyscan->test_count++;
- cur_test = NULL;
- break;
- case KEYSCAN_CMD_SEQ:
- if (keyscan_process_keys(keyscan, linenum, cur_test,
- args)) {
- fprintf(stderr, "Line %d: Cannot parse key "
- "input '%s'\n", linenum, args);
- return -1;
- }
- break;
- default:
- fprintf(stderr, "Line %d: Uknown command '%1.*s'\n",
- linenum, (int)(end - str), str);
- return -1;
- }
- }
-
- return 0;
-}
-
-/**
- * Print out a list of all tests
- *
- * @param keyscan keyscan information
- */
-static void keyscan_print(struct keyscan_info *keyscan)
-{
- int testnum;
- int i;
-
- for (testnum = 0; testnum < keyscan->test_count; testnum++) {
- struct keyscan_test *test = &keyscan->tests[testnum];
-
- printf("Test: %s\n", test->name);
- for (i = 0; i < test->item_count; i++) {
- struct keyscan_test_item *item;
- int j;
-
- item = &test->items[i];
- printf("%2d %7d: ", i, item->beat);
- for (j = 0; j < sizeof(item->scan); j++)
- printf("%02x ", item->scan[j]);
- printf("\n");
- }
- printf("\n");
- }
-}
-
-/**
- * Set the terminal to raw mode, or cooked
- *
- * @param tty_fd Terminal file descriptor to change
- * @Param raw 0 for cooked, non-zero for raw
- */
-static void set_to_raw(int tty_fd, int raw)
-{
- struct termios tty_attr;
- int value;
-
- value = fcntl(tty_fd, F_GETFL);
-
- tcgetattr(tty_fd, &tty_attr);
- if (raw) {
- tty_attr.c_lflag &= ~ICANON;
- value |= O_NONBLOCK;
- } else {
- tty_attr.c_lflag |= ICANON;
- value &= ~O_NONBLOCK;
- }
- tcsetattr(tty_fd, TCSANOW, &tty_attr);
- fcntl(tty_fd, F_SETFL, value);
-}
-
-/**
- * Read input for a whlie until wee see no more
- *
- * @param fd File descriptor for input
- * @param input Place to put input string
- * @param max_len Maximum length of input string
- * @param wait Number of microseconds to wait for input
- */
-static void keyscan_get_input(int fd, char *input, int max_len, int wait)
-{
- int len;
-
- usleep(wait);
- input[0] = '\0';
- len = read(fd, input, max_len - 1);
- if (len > 0)
- input[len] = '\0';
-}
-
-static int keyscan_send_sequence(struct keyscan_info *keyscan,
- struct keyscan_test *test)
-{
- struct ec_params_keyscan_seq_ctrl *req;
- struct keyscan_test_item *item;
- int upto, size, rv;
-
- size = sizeof(*req) + sizeof(item->scan);
- req = (struct ec_params_keyscan_seq_ctrl *)malloc(size);
- if (!req) {
- fprintf(stderr, "Out of memory for message\n");
- return -1;
- }
- for (upto = rv = 0, item = test->items; rv >= 0 &&
- upto < test->item_count; upto++, item++) {
- req->cmd = EC_KEYSCAN_SEQ_ADD;
- req->add.time_us = item->beat * keyscan->beat_us;
- memcpy(req->add.scan, item->scan, sizeof(item->scan));
- rv = ec_command(EC_CMD_KEYSCAN_SEQ_CTRL, 0, req, size, NULL, 0);
- }
- free(req);
- if (rv < 0)
- return rv;
-
- return 0;
-}
-
-/**
- * Run a single test
- *
- * @param keyscan keyscan information
- * @param test test to run
- * @return 0 if test passes, -ve if some error occurred
- */
-static int run_test(struct keyscan_info *keyscan, struct keyscan_test *test)
-{
- struct ec_params_keyscan_seq_ctrl ctrl;
- char input[KEYSCAN_MAX_INPUT_LEN];
- struct ec_result_keyscan_seq_ctrl *resp;
- int wait_us;
- int size;
- int rv;
- int fd = 0;
- int i;
-
- /* First clear the sequence */
- ctrl.cmd = EC_KEYSCAN_SEQ_CLEAR;
- rv = ec_command(EC_CMD_KEYSCAN_SEQ_CTRL, 0, &ctrl, sizeof(ctrl),
- NULL, 0);
- if (rv < 0)
- return rv;
-
- rv = keyscan_send_sequence(keyscan, test);
- if (rv < 0)
- return rv;
-
- /* Start it */
- set_to_raw(fd, 1);
- ctrl.cmd = EC_KEYSCAN_SEQ_START;
- rv = ec_command(EC_CMD_KEYSCAN_SEQ_CTRL, 0, &ctrl, sizeof(ctrl),
- NULL, 0);
- if (rv < 0)
- return rv;
-
- /* Work out how long we need to wait */
- wait_us = 100 * 1000; /* Wait 100ms to at least */
- if (test->item_count) {
- struct keyscan_test_item *ksi;
-
- ksi = &test->items[test->item_count - 1];
- wait_us += ksi->beat * keyscan->beat_us;
- }
-
- /* Wait for input */
- keyscan_get_input(fd, input, sizeof(input), wait_us);
- set_to_raw(fd, 0);
-
- /* Ask EC for results */
- size = sizeof(*resp) + test->item_count;
- resp = (struct ec_result_keyscan_seq_ctrl *)(malloc(size));
- if (!resp) {
- fprintf(stderr, "Out of memory for results\n");
- return -1;
- }
- ctrl.cmd = EC_KEYSCAN_SEQ_COLLECT;
- ctrl.collect.start_item = 0;
- ctrl.collect.num_items = test->item_count;
- rv = ec_command(EC_CMD_KEYSCAN_SEQ_CTRL, 0, &ctrl, sizeof(ctrl),
- resp, size);
- if (rv < 0)
- return rv;
-
- /* Check what scans were skipped */
- for (i = 0; i < resp->collect.num_items; i++) {
- struct ec_collect_item *item;
- struct keyscan_test_item *ksi;
-
- item = &resp->collect.item[i];
- ksi = &test->items[i];
- if (!(item->flags & EC_KEYSCAN_SEQ_FLAG_DONE))
- printf(" [skip %d at beat %u] ", i, ksi->beat);
- }
-
- if (strcmp(input, test->expect)) {
- printf("Expected '%s', got '%s' ", test->expect, input);
- return -1;
- }
-
- return 0;
-}
-
-/**
- * Run all tests
- *
- * @param keyscan keyscan information
- * @return 0 if ok, -1 on error
- */
-static int keyscan_run_tests(struct keyscan_info *keyscan)
-{
- int testnum;
- int any_err = 0;
-
- for (testnum = 0; testnum < keyscan->test_count; testnum++) {
- struct keyscan_test *test = &keyscan->tests[testnum];
- int err;
-
- fflush(stdout);
- err = run_test(keyscan, test);
- any_err |= err;
- if (err) {
- printf("%d: %s: : FAIL\n", testnum, test->name);
- }
- }
-
- return any_err ? -1 : 0;
-}
-
-int cmd_keyscan(int argc, char *argv[])
-{
- struct keyscan_info keyscan;
- FILE *f;
- int err;
-
- argc--;
- argv++;
- if (argc < 2) {
- fprintf(stderr, "Must specify beat period and filename\n");
- return -1;
- }
- memset(&keyscan, '\0', sizeof(keyscan));
- keyscan.beat_us = atoi(argv[0]);
- if (keyscan.beat_us < 100)
- fprintf(stderr, "Warning: beat period is normally > 100us\n");
- f = fopen(argv[1], "r");
- if (!f) {
- perror("Cannot open file\n");
- return -1;
- }
-
- /* TODO(crosbug.com/p/23826): Read key matrix from fdt */
- err = keyscan_read_fdt_matrix(&keyscan, "test/test-matrix.bin");
- if (!err)
- err = keyscan_process_file(f, &keyscan);
- if (!err)
- keyscan_print(&keyscan);
- if (!err)
- err = keyscan_run_tests(&keyscan);
- fclose(f);
-
- return err;
-}