summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2013-05-29 18:00:03 -0700
committerChromeBot <chrome-bot@google.com>2013-06-05 14:12:23 -0700
commitd0d1564434ae991ac99a6ce54f6f3360f47017a8 (patch)
tree68ce6707147fbf828fef543222fcde756da1acf2
parent26475135b551a742f2d148d426c4aa18b338f5ca (diff)
downloadchrome-ec-d0d1564434ae991ac99a6ce54f6f3360f47017a8.tar.gz
ectool prefers /dev/cros_ec, then falls back to i2c, lpc
This is preparation for the common userspace EC interface. If/when that appears, this will be ready. BUG=chromium:239197 BRANCH=all TEST=manual Build, install, run it. Shouldn't be any change. Change-Id: I9fa78515ec5443ba659f10a66bbaadcb7f4802b0 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/56131
-rw-r--r--include/ec_commands.h8
-rw-r--r--util/build.mk2
-rw-r--r--util/comm-dev.c82
-rw-r--r--util/comm-host.c77
-rw-r--r--util/comm-host.h27
-rw-r--r--util/comm-i2c.c151
-rw-r--r--util/comm-lpc.c155
-rw-r--r--util/cros_ec_dev.h53
-rw-r--r--util/ectool.c69
9 files changed, 412 insertions, 212 deletions
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 3390e3ab85..a2cc70ca8e 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -42,10 +42,16 @@
#define EC_LPC_ADDR_HOST_CMD 0x204
/* I/O addresses for host command args and params */
-#define EC_LPC_ADDR_HOST_ARGS 0x800
+#define EC_LPC_ADDR_HOST_ARGS 0x800 /* and 0x801, 0x802, 0x803 */
#define EC_LPC_ADDR_HOST_PARAM 0x804
#define EC_HOST_PARAM_SIZE 0x0fc /* Size of param area in bytes */
+/* The actual block is 0x800-0x8ff, but some BIOSes think it's 0x880-0x8ff
+ * and they tell the kernel that so we have to think of it as two parts. */
+#define EC_HOST_CMD_REGION0 0x800
+#define EC_HOST_CMD_REGION1 0x880
+#define EC_HOST_CMD_REGION_SIZE 0x80
+
/* EC command register bit functions */
#define EC_LPC_CMDR_DATA (1 << 0) /* Data ready for host to read */
#define EC_LPC_CMDR_PENDING (1 << 1) /* Write pending to EC */
diff --git a/util/build.mk b/util/build.mk
index 62b25b4e6b..062e34c708 100644
--- a/util/build.mk
+++ b/util/build.mk
@@ -7,7 +7,7 @@
#
host-util-bin=ectool lbplay burn_my_ec
-host-util-common=ectool_keyscan
+host-util-common=ectool_keyscan comm-host comm-dev
ifeq ($(CONFIG_LPC),y)
host-util-common+=comm-lpc
else
diff --git a/util/comm-dev.c b/util/comm-dev.c
new file mode 100644
index 0000000000..2802aeca24
--- /dev/null
+++ b/util/comm-dev.c
@@ -0,0 +1,82 @@
+/* Copyright (c) 2013 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 <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "cros_ec_dev.h"
+#include "comm-host.h"
+#include "ec_commands.h"
+
+static int fd = -1;
+
+static int ec_command_dev(int command, int version,
+ const void *outdata, int outsize,
+ void *indata, int insize)
+{
+ struct cros_ec_command s_cmd;
+
+ s_cmd.command = command;
+ s_cmd.version = version;
+ s_cmd.result = 0xff;
+ s_cmd.outsize = outsize;
+ s_cmd.outdata = (uint8_t *)outdata;
+ s_cmd.insize = insize;
+ s_cmd.indata = indata;
+
+ if (ioctl(fd, CROS_EC_DEV_IOCXCMD, &s_cmd))
+ return -1;
+
+ return s_cmd.insize;
+}
+
+static int ec_readmem_dev(int offset, int bytes, void *dest)
+{
+ struct cros_ec_readmem s_mem;
+
+ s_mem.offset = offset;
+ s_mem.bytes = bytes;
+ s_mem.buffer = dest;
+
+ return ioctl(fd, CROS_EC_DEV_IOCRDMEM, &s_mem);
+}
+
+int comm_init_dev(void)
+{
+ char version[80];
+ int r;
+ char *s;
+
+ fd = open("/dev/" CROS_EC_DEV_NAME, O_RDWR);
+ if (fd < 0)
+ return 1;
+
+ r = read(fd, version, sizeof(version)-1);
+ if (r <= 0) {
+ close(fd);
+ return 2;
+ }
+ version[r] = '\0';
+ s = strchr(version, '\n');
+ if (s)
+ *s = '\0';
+ if (strcmp(version, CROS_EC_DEV_VERSION)) {
+ close(fd);
+ return 3;
+ }
+
+ ec_command = ec_command_dev;
+ if (ec_readmem_dev(EC_MEMMAP_ID, 2, version) == 2)
+ ec_readmem = ec_readmem_dev;
+
+ return 0;
+}
diff --git a/util/comm-host.c b/util/comm-host.c
new file mode 100644
index 0000000000..bf94927361
--- /dev/null
+++ b/util/comm-host.c
@@ -0,0 +1,77 @@
+/* Copyright (c) 2013 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 <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "comm-host.h"
+#include "ec_commands.h"
+
+int (*ec_command)(int command, int version,
+ const void *outdata, int outsize,
+ void *indata, int insize);
+
+int (*ec_readmem)(int offset, int bytes, void *dest);
+
+int comm_init_dev(void) __attribute__((weak));
+int comm_init_lpc(void) __attribute__((weak));
+int comm_init_i2c(void) __attribute__((weak));
+
+static int fake_readmem(int offset, int bytes, void *dest)
+{
+ struct ec_params_read_memmap p;
+ int c;
+ char *buf;
+
+ p.offset = offset;
+
+ if (bytes) {
+ p.size = bytes;
+ c = ec_command(EC_CMD_READ_MEMMAP, 0, &p, sizeof(p),
+ dest, p.size);
+ if (c < 0)
+ return c;
+ return p.size;
+ }
+
+ p.size = EC_MEMMAP_TEXT_MAX;
+
+ c = ec_command(EC_CMD_READ_MEMMAP, 0, &p, sizeof(p), dest, p.size);
+ if (c < 0)
+ return c;
+
+ buf = dest;
+ for (c = 0; c < EC_MEMMAP_TEXT_MAX; c++) {
+ if (buf[c] == 0)
+ return c;
+ }
+
+ buf[EC_MEMMAP_TEXT_MAX - 1] = 0;
+ return EC_MEMMAP_TEXT_MAX - 1;
+}
+
+int comm_init(void)
+{
+ /* Default memmap access */
+ ec_readmem = fake_readmem;
+
+ /* Prefer new /dev method */
+ if (comm_init_dev && !comm_init_dev())
+ return 0;
+
+ /* Fallback to direct LPC on x86 */
+ if (comm_init_lpc && !comm_init_lpc())
+ return 0;
+
+ /* Fallback to direct i2c on ARM */
+ if (comm_init_i2c && !comm_init_i2c())
+ return 0;
+
+ /* Give up */
+ fprintf(stderr, "Unable to establish host communication\n");
+ return 1;
+}
diff --git a/util/comm-host.h b/util/comm-host.h
index a16057abf5..d890156af0 100644
--- a/util/comm-host.h
+++ b/util/comm-host.h
@@ -1,6 +1,9 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 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.
+ *
+ * For hysterical raisins, there are several mechanisms for communicating with
+ * the EC. This abstracts them.
*/
#ifndef COMM_HOST_H
@@ -16,24 +19,18 @@ int comm_init(void);
/*
* Send a command to the EC. Returns the length of output data returned (0 if
- * none), or a negative number if error; errors are -EC_RES_* constants from
- * ec_commands.h.
+ * none), or negative on error.
*/
-int ec_command(int command, int version, const void *indata, int insize,
- void *outdata, int outsize);
+extern int (*ec_command)(int command, int version,
+ const void *outdata, int outsize, /* to the EC */
+ void *indata, int insize); /* from the EC */
/*
* Return the content of the EC information area mapped as "memory".
- * The offsets are defined by the EC_MEMMAP_ constants.
- */
-uint8_t read_mapped_mem8(uint8_t offset);
-uint16_t read_mapped_mem16(uint8_t offset);
-uint32_t read_mapped_mem32(uint8_t offset);
-/*
- * Read a memory-mapped string at the specified offset and store into buf,
- * which must be at least size EC_MEMMAP_TEXT_MAX. Returns the length of
- * the copied string, not counting the terminating '\0', or <0 if error.
+ * The offsets are defined by the EC_MEMMAP_ constants. Returns the number
+ * of bytes read, or negative on error. Specifying bytes=0 will read a
+ * string (always including the trailing '\0').
*/
-int read_mapped_string(uint8_t offset, char *buf);
+extern int (*ec_readmem)(int offset, int bytes, void *dest);
#endif /* COMM_HOST_H */
diff --git a/util/comm-i2c.c b/util/comm-i2c.c
index d1471495c8..8f75320b48 100644
--- a/util/comm-i2c.c
+++ b/util/comm-i2c.c
@@ -40,44 +40,6 @@
static int i2c_fd = -1;
-int comm_init(void)
-{
- char *file_path;
- char buffer[64];
- FILE *f;
- int i;
-
- /* find the device number based on the adapter name */
- for (i = 0; i < I2C_MAX_ADAPTER; i++) {
- if (asprintf(&file_path, I2C_ADAPTER_NODE, i) < 0)
- return -1;
- f = fopen(file_path, "r");
- if (f) {
- if (fgets(buffer, sizeof(buffer), f) &&
- !strncmp(buffer, I2C_ADAPTER_NAME, 6)) {
- free(file_path);
- break;
- }
- fclose(f);
- }
- free(file_path);
- }
- if (i == I2C_MAX_ADAPTER) {
- fprintf(stderr, "Cannot find I2C adapter\n");
- return -1;
- }
-
- if (asprintf(&file_path, I2C_NODE, i) < 0)
- return -1;
- debug("using I2C adapter %s\n", file_path);
- i2c_fd = open(file_path, O_RDWR);
- if (i2c_fd < 0)
- fprintf(stderr, "Cannot open %s : %d\n", file_path, errno);
-
- free(file_path);
- return 0;
-}
-
/*
* Sends a command to the EC (protocol v2). Returns the command status code, or
@@ -86,8 +48,9 @@ int comm_init(void)
* Returns >= 0 for success, or negative if error.
*
*/
-int ec_command(int command, int version, const void *indata, int insize,
- void *outdata, int outsize)
+static int ec_command_i2c(int command, int version,
+ const void *outdata, int outsize,
+ void *indata, int insize)
{
struct i2c_rdwr_ioctl_data data;
int ret = -1;
@@ -127,7 +90,7 @@ int ec_command(int command, int version, const void *indata, int insize,
* allocate larger packet
* (version, command, size, ..., checksum)
*/
- req_len = insize + PROTO_V2_IN;
+ req_len = outsize + PROTO_V2_IN;
req_buf = calloc(1, req_len);
if (!req_buf)
goto done;
@@ -135,12 +98,12 @@ int ec_command(int command, int version, const void *indata, int insize,
i2c_msg[0].buf = (char *)req_buf;
req_buf[0] = version + EC_CMD_VERSION0;
req_buf[1] = command;
- req_buf[2] = insize;
+ req_buf[2] = outsize;
debug("i2c req %02x:", command);
sum = req_buf[0] + req_buf[1] + req_buf[2];
/* copy message payload and compute checksum */
- for (i = 0, c = indata; i < insize; i++, c++) {
+ for (i = 0, c = outdata; i < outsize; i++, c++) {
req_buf[i + 3] = *c;
sum += *c;
debug(" %02x", *c);
@@ -152,7 +115,7 @@ int ec_command(int command, int version, const void *indata, int insize,
* allocate larger packet
* (result, size, ..., checksum)
*/
- resp_len = outsize + PROTO_V2_OUT;
+ resp_len = insize + PROTO_V2_OUT;
resp_buf = calloc(1, resp_len);
if (!resp_buf)
goto done;
@@ -173,9 +136,9 @@ int ec_command(int command, int version, const void *indata, int insize,
/* TODO: handle EC_RES_IN_PROGRESS case. */
resp_len = resp_buf[1];
- if (resp_len > outsize) {
+ if (resp_len > insize) {
fprintf(stderr, "response size is too large %d > %d\n",
- resp_len, outsize);
+ resp_len, insize);
ret = -EC_RES_ERROR;
goto done;
}
@@ -185,11 +148,11 @@ int ec_command(int command, int version, const void *indata, int insize,
command, i2c_msg[1].buf[0]);
/* Translate ERROR to -ERROR */
ret = -ret;
- } else if (outsize) {
+ } else if (insize) {
debug("i2c resp :");
/* copy response packet payload and compute checksum */
sum = resp_buf[0] + resp_buf[1];
- for (i = 0, d = outdata; i < resp_len; i++, d++) {
+ for (i = 0, d = indata; i < resp_len; i++, d++) {
*d = resp_buf[i + 2];
sum += *d;
debug(" %02x", *d);
@@ -213,70 +176,42 @@ done:
return ret;
}
-uint8_t read_mapped_mem8(uint8_t offset)
+int comm_init_i2c(void)
{
- struct ec_params_read_memmap p;
- uint8_t val;
-
- p.offset = offset;
- p.size = sizeof(val);
-
- if (ec_command(EC_CMD_READ_MEMMAP, 0, &p, sizeof(p),
- &val, sizeof(val)) < 0)
- return 0xff;
-
- return val;
-}
-
-uint16_t read_mapped_mem16(uint8_t offset)
-{
- struct ec_params_read_memmap p;
- uint16_t val;
-
- p.offset = offset;
- p.size = sizeof(val);
-
- if (ec_command(EC_CMD_READ_MEMMAP, 0, &p, sizeof(p),
- &val, sizeof(val)) < 0)
- return 0xffff;
-
- return val;
-}
-
-uint32_t read_mapped_mem32(uint8_t offset)
-{
- struct ec_params_read_memmap p;
- uint32_t val;
-
- p.offset = offset;
- p.size = sizeof(val);
-
- if (ec_command(EC_CMD_READ_MEMMAP, 0, &p, sizeof(p),
- &val, sizeof(val)) < 0)
- return 0xffffffff;
-
- return val;
-}
-
-int read_mapped_string(uint8_t offset, char *buf)
-{
- struct ec_params_read_memmap p;
- int c;
-
- p.offset = offset;
- p.size = EC_MEMMAP_TEXT_MAX;
+ char *file_path;
+ char buffer[64];
+ FILE *f;
+ int i;
- if (ec_command(EC_CMD_READ_MEMMAP, 0, &p, sizeof(p),
- buf, EC_MEMMAP_TEXT_MAX) < 0) {
- *buf = 0;
+ /* find the device number based on the adapter name */
+ for (i = 0; i < I2C_MAX_ADAPTER; i++) {
+ if (asprintf(&file_path, I2C_ADAPTER_NODE, i) < 0)
+ return -1;
+ f = fopen(file_path, "r");
+ if (f) {
+ if (fgets(buffer, sizeof(buffer), f) &&
+ !strncmp(buffer, I2C_ADAPTER_NAME, 6)) {
+ free(file_path);
+ break;
+ }
+ fclose(f);
+ }
+ free(file_path);
+ }
+ if (i == I2C_MAX_ADAPTER) {
+ fprintf(stderr, "Cannot find I2C adapter\n");
return -1;
}
- for (c = 0; c < EC_MEMMAP_TEXT_MAX; c++) {
- if (buf[c] == 0)
- return c;
- }
+ if (asprintf(&file_path, I2C_NODE, i) < 0)
+ return -1;
+ debug("using I2C adapter %s\n", file_path);
+ i2c_fd = open(file_path, O_RDWR);
+ if (i2c_fd < 0)
+ fprintf(stderr, "Cannot open %s : %d\n", file_path, errno);
- buf[EC_MEMMAP_TEXT_MAX - 1] = 0;
- return EC_MEMMAP_TEXT_MAX - 1;
+ free(file_path);
+
+ ec_command = ec_command_i2c;
+ return 0;
}
diff --git a/util/comm-lpc.c b/util/comm-lpc.c
index dbae5a7ecc..3548f4eb29 100644
--- a/util/comm-lpc.c
+++ b/util/comm-lpc.c
@@ -14,59 +14,6 @@
#define INITIAL_UDELAY 5 /* 5 us */
#define MAXIMUM_UDELAY 10000 /* 10 ms */
-int comm_init(void)
-{
- int i;
- int byte = 0xff;
-
- /* Request I/O privilege */
- if (iopl(3) < 0) {
- perror("Error getting I/O privilege");
- return -3;
- }
-
- /*
- * Test if the I/O port has been configured for Chromium EC LPC
- * interface. If all the bytes are 0xff, very likely that Chromium EC
- * is not present.
- *
- * TODO: (crosbug.com/p/10963) Should only need to look at the command
- * byte, since we don't support ACPI burst mode and thus bit 4 should
- * be 0.
- */
- byte &= inb(EC_LPC_ADDR_HOST_CMD);
- byte &= inb(EC_LPC_ADDR_HOST_DATA);
- for (i = 0; i < EC_HOST_PARAM_SIZE && byte == 0xff; ++i)
- byte &= inb(EC_LPC_ADDR_HOST_PARAM + i);
- if (byte == 0xff) {
- fprintf(stderr, "Port 0x%x,0x%x,0x%x-0x%x are all 0xFF.\n",
- EC_LPC_ADDR_HOST_CMD, EC_LPC_ADDR_HOST_DATA,
- EC_LPC_ADDR_HOST_PARAM,
- EC_LPC_ADDR_HOST_PARAM + EC_HOST_PARAM_SIZE - 1);
- fprintf(stderr,
- "Very likely this board doesn't have a Chromium EC.\n");
- return -4;
- }
-
- /*
- * Test if LPC command args are supported.
- *
- * The cheapest way to do this is by looking for the memory-mapped
- * flag. This is faster than sending a new-style 'hello' command and
- * seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag
- * in args when it responds.
- */
- if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) != 'E' ||
- inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) != 'C' ||
- !(inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_HOST_CMD_FLAGS) &
- EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED)) {
- fprintf(stderr, "EC doesn't support command args.\n");
- return -5;
- }
-
- return 0;
-}
-
/*
* Wait for the EC to be unbusy. Returns 0 if unbusy, non-zero if
* timeout.
@@ -97,9 +44,10 @@ static int wait_for_ec(int status_addr, int timeout_usec)
return -1; /* Timeout */
}
-int ec_command(int command, int version, const void *indata, int insize,
- void *outdata, int outsize) {
-
+static int ec_command_lpc(int command, int version,
+ const void *outdata, int outsize,
+ void *indata, int insize)
+{
struct ec_lpc_host_args args;
const uint8_t *d;
uint8_t *dout;
@@ -109,13 +57,13 @@ int ec_command(int command, int version, const void *indata, int insize,
/* Fill in args */
args.flags = EC_HOST_ARGS_FLAG_FROM_HOST;
args.command_version = version;
- args.data_size = insize;
+ args.data_size = outsize;
/* Initialize checksum */
csum = command + args.flags + args.command_version + args.data_size;
/* Write data and update checksum */
- for (i = 0, d = (uint8_t *)indata; i < insize; i++, d++) {
+ for (i = 0, d = (uint8_t *)outdata; i < outsize; i++, d++) {
outb(*d, EC_LPC_ADDR_HOST_PARAM + i);
csum += *d;
}
@@ -153,7 +101,7 @@ int ec_command(int command, int version, const void *indata, int insize,
return -EC_RES_INVALID_RESPONSE;
}
- if (args.data_size > outsize) {
+ if (args.data_size > insize) {
fprintf(stderr, "EC returned too much data\n");
return -EC_RES_INVALID_RESPONSE;
}
@@ -162,7 +110,7 @@ int ec_command(int command, int version, const void *indata, int insize,
csum = command + args.flags + args.command_version + args.data_size;
/* Read response and update checksum */
- for (i = 0, dout = (uint8_t *)outdata; i < args.data_size;
+ for (i = 0, dout = (uint8_t *)indata; i < args.data_size;
i++, dout++) {
*dout = inb(EC_LPC_ADDR_HOST_PARAM + i);
csum += *dout;
@@ -179,31 +127,82 @@ int ec_command(int command, int version, const void *indata, int insize,
}
-uint8_t read_mapped_mem8(uint8_t offset)
+static int ec_readmem_lpc(int offset, int bytes, void *dest)
{
- return inb(EC_LPC_ADDR_MEMMAP + offset);
-}
+ int i = offset;
+ char *s = dest;
+ int cnt = 0;
+
+ if (offset >= EC_MEMMAP_SIZE - bytes)
+ return -1;
+
+ if (bytes) { /* fixed length */
+ for (; cnt < bytes; i++, s++, cnt++)
+ *s = inb(EC_LPC_ADDR_MEMMAP + i);
+ } else { /* string */
+ for (; i < EC_MEMMAP_SIZE; i++, s++) {
+ *s = inb(EC_LPC_ADDR_MEMMAP + i);
+ cnt++;
+ if (!*s)
+ break;
+ }
+ }
-uint16_t read_mapped_mem16(uint8_t offset)
-{
- return inw(EC_LPC_ADDR_MEMMAP + offset);
+ return cnt;
}
-uint32_t read_mapped_mem32(uint8_t offset)
+int comm_init_lpc(void)
{
- return inl(EC_LPC_ADDR_MEMMAP + offset);
-}
+ int i;
+ int byte = 0xff;
-int read_mapped_string(uint8_t offset, char *buf)
-{
- int c;
+ /* Request I/O privilege */
+ if (iopl(3) < 0) {
+ perror("Error getting I/O privilege");
+ return -3;
+ }
+
+ /*
+ * Test if the I/O port has been configured for Chromium EC LPC
+ * interface. If all the bytes are 0xff, very likely that Chromium EC
+ * is not present.
+ *
+ * TODO: (crosbug.com/p/10963) Should only need to look at the command
+ * byte, since we don't support ACPI burst mode and thus bit 4 should
+ * be 0.
+ */
+ byte &= inb(EC_LPC_ADDR_HOST_CMD);
+ byte &= inb(EC_LPC_ADDR_HOST_DATA);
+ for (i = 0; i < EC_HOST_PARAM_SIZE && byte == 0xff; ++i)
+ byte &= inb(EC_LPC_ADDR_HOST_PARAM + i);
+ if (byte == 0xff) {
+ fprintf(stderr, "Port 0x%x,0x%x,0x%x-0x%x are all 0xFF.\n",
+ EC_LPC_ADDR_HOST_CMD, EC_LPC_ADDR_HOST_DATA,
+ EC_LPC_ADDR_HOST_PARAM,
+ EC_LPC_ADDR_HOST_PARAM + EC_HOST_PARAM_SIZE - 1);
+ fprintf(stderr,
+ "Very likely this board doesn't have a Chromium EC.\n");
+ return -4;
+ }
- for (c = 0; c < EC_MEMMAP_TEXT_MAX; c++) {
- buf[c] = inb(EC_LPC_ADDR_MEMMAP + offset + c);
- if (buf[c] == 0)
- return c;
+ /*
+ * Test if LPC command args are supported.
+ *
+ * The cheapest way to do this is by looking for the memory-mapped
+ * flag. This is faster than sending a new-style 'hello' command and
+ * seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag
+ * in args when it responds.
+ */
+ if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) != 'E' ||
+ inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) != 'C' ||
+ !(inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_HOST_CMD_FLAGS) &
+ EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED)) {
+ fprintf(stderr, "EC doesn't support command args.\n");
+ return -5;
}
- buf[EC_MEMMAP_TEXT_MAX - 1] = 0;
- return EC_MEMMAP_TEXT_MAX - 1;
+ /* Okay, this works */
+ ec_command = ec_command_lpc;
+ ec_readmem = ec_readmem_lpc;
+ return 0;
}
diff --git a/util/cros_ec_dev.h b/util/cros_ec_dev.h
new file mode 100644
index 0000000000..f56c3ef67f
--- /dev/null
+++ b/util/cros_ec_dev.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2013 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.
+ */
+
+#ifndef _CROS_EC_DEV_H_
+#define _CROS_EC_DEV_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define CROS_EC_DEV_NAME "cros_ec"
+#define CROS_EC_DEV_VERSION "1.0.0"
+
+
+/*
+ * @version: Command version number (often 0)
+ * @command: Command to send (EC_CMD_...)
+ * @outdata: Outgoing data to EC
+ * @outsize: Outgoing length in bytes
+ * @indata: Where to put the incoming data from EC
+ * @insize: Incoming length in bytes (filled in by EC)
+ * @result: EC's response to the command (separate from communication failure)
+ * ioctl returns zero on success, negative on error
+ */
+struct cros_ec_command {
+ uint32_t version;
+ uint32_t command;
+ uint8_t *outdata;
+ uint32_t outsize;
+ uint8_t *indata;
+ uint32_t insize;
+ uint32_t result;
+};
+
+/*
+ * @offset: within EC_LPC_ADDR_MEMMAP region
+ * @bytes: number of bytes to read. zero means "read a string" (including '\0')
+ * (at most only EC_MEMMAP_SIZE bytes can be read)
+ * @buffer: where to store the result
+ * ioctl returns the number of bytes read, negative on error
+ */
+struct cros_ec_readmem {
+ uint32_t offset;
+ uint32_t bytes;
+ char *buffer;
+};
+
+#define CROS_EC_DEV_IOC ':'
+#define CROS_EC_DEV_IOCXCMD _IOWR(':', 0, struct cros_ec_command)
+#define CROS_EC_DEV_IOCRDMEM _IOWR(':', 1, struct cros_ec_readmem)
+
+#endif /* _CROS_EC_DEV_H_ */
diff --git a/util/ectool.c b/util/ectool.c
index 5deb582742..521ebea767 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -256,6 +256,56 @@ void print_help(const char *prog)
puts(help_str);
}
+static uint8_t read_mapped_mem8(uint8_t offset)
+{
+ int ret;
+ uint8_t val;
+
+ ret = ec_readmem(offset, sizeof(val), &val);
+ if (ret <= 0) {
+ fprintf(stderr, "failure in %s(): %d\n", __func__, ret);
+ exit(1);
+ }
+ return val;
+}
+
+static uint16_t read_mapped_mem16(uint8_t offset)
+{
+ int ret;
+ uint16_t val;
+
+ ret = ec_readmem(offset, sizeof(val), &val);
+ if (ret <= 0) {
+ fprintf(stderr, "failure in %s(): %d\n", __func__, ret);
+ exit(1);
+ }
+ return val;
+}
+
+static uint32_t read_mapped_mem32(uint8_t offset)
+{
+ int ret;
+ uint32_t val;
+
+ ret = ec_readmem(offset, sizeof(val), &val);
+ if (ret <= 0) {
+ fprintf(stderr, "failure in %s(): %d\n", __func__, ret);
+ exit(1);
+ }
+ return val;
+}
+
+static int read_mapped_string(uint8_t offset, char *buffer)
+{
+ int ret;
+
+ ret = ec_readmem(offset, 0, buffer);
+ if (ret <= 0) {
+ fprintf(stderr, "failure in %s(): %d\n", __func__, ret);
+ exit(1);
+ }
+ return ret;
+}
int cmd_hello(int argc, char *argv[])
{
@@ -2394,7 +2444,7 @@ int cmd_battery(int argc, char *argv[])
val = read_mapped_mem8(EC_MEMMAP_BATTERY_VERSION);
if (val < 1) {
- printf("Command not supported\n");
+ fprintf(stderr, "Battery version %d is not supported\n", val);
return -1;
}
@@ -2469,7 +2519,7 @@ int cmd_battery(int argc, char *argv[])
return 0;
cmd_error:
- fprintf(stderr, "Bad battery info value. Check protocol version.");
+ fprintf(stderr, "Bad battery info value. Check protocol version.\n");
return -1;
}
@@ -3031,23 +3081,25 @@ const struct command commands[] = {
int main(int argc, char *argv[])
{
const struct command *cmd;
- int rv;
+ int rv = 1;
BUILD_ASSERT(ARRAY_SIZE(lb_command_paramcount) == LIGHTBAR_NUM_CMDS);
if (argc < 2 || !strcasecmp(argv[1], "-?") ||
!strcasecmp(argv[1], "help")) {
print_help(argv[0]);
- return -2;
+ exit(1);
}
if (acquire_gec_lock(GEC_LOCK_TIMEOUT_SECS) < 0) {
fprintf(stderr, "Could not acquire GEC lock.\n");
- return 1;
+ exit(1);
}
- if (comm_init() < 0)
- return -3;
+ if (comm_init() < 0) {
+ fprintf(stderr, "Couldn't find EC\n");
+ goto out;
+ }
/* Handle commands */
for (cmd = commands; cmd->name; cmd++) {
@@ -3060,9 +3112,8 @@ int main(int argc, char *argv[])
/* If we're still here, command was unknown */
fprintf(stderr, "Unknown command '%s'\n\n", argv[1]);
print_help(argv[0]);
- rv = -2;
out:
release_gec_lock();
- return rv;
+ return !!rv;
}