summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.toolchain2
-rw-r--r--include/lightbar_msg_list.h26
-rw-r--r--util/build.mk2
-rw-r--r--util/lbplay.c209
4 files changed, 224 insertions, 15 deletions
diff --git a/Makefile.toolchain b/Makefile.toolchain
index 89977f5c78..4aae435863 100644
--- a/Makefile.toolchain
+++ b/Makefile.toolchain
@@ -7,7 +7,7 @@
# Toolchain configuration
CROSS_COMPILE ?= arm-none-eabi-
-HOST_CROSS_COMPILE ?= i686-pc-linux-gnu-
+HOST_CROSS_COMPILE ?= x86_64-pc-linux-gnu-
CC=$(CROSS_COMPILE)gcc
CPP=$(CROSS_COMPILE)cpp
diff --git a/include/lightbar_msg_list.h b/include/lightbar_msg_list.h
index f1c73a7f83..d4563ab348 100644
--- a/include/lightbar_msg_list.h
+++ b/include/lightbar_msg_list.h
@@ -7,16 +7,16 @@
* types.
*/
#define LIGHTBAR_MSG_LIST \
- LBMSG(ERROR), \
- LBMSG(S5), \
- LBMSG(S3), \
- LBMSG(S0), \
- LBMSG(S5S3), \
- LBMSG(S3S0), \
- LBMSG(S0S3), \
- LBMSG(S3S5), \
- LBMSG(STOP), \
- LBMSG(RUN), \
- LBMSG(PULSE), \
- LBMSG(TEST), \
- LBMSG(KONAMI),
+ LBMSG(ERROR), /* 0 */ \
+ LBMSG(S5), /* 1 */ \
+ LBMSG(S3), /* 2 */ \
+ LBMSG(S0), /* 3 */ \
+ LBMSG(S5S3), /* 4 */ \
+ LBMSG(S3S0), /* 5 */ \
+ LBMSG(S0S3), /* 6 */ \
+ LBMSG(S3S5), /* 7 */ \
+ LBMSG(STOP), /* 8 */ \
+ LBMSG(RUN), /* 9 */ \
+ LBMSG(PULSE), /* A */ \
+ LBMSG(TEST), /* B */ \
+ LBMSG(KONAMI), /* C */
diff --git a/util/build.mk b/util/build.mk
index 55db7177b8..e8a930ed78 100644
--- a/util/build.mk
+++ b/util/build.mk
@@ -5,5 +5,5 @@
# Host tools build
#
-host-util-bin=ectool
+host-util-bin=ectool lbplay
build-util-bin=ec_uartd stm32mon
diff --git a/util/lbplay.c b/util/lbplay.c
new file mode 100644
index 0000000000..33d8bb731e
--- /dev/null
+++ b/util/lbplay.c
@@ -0,0 +1,209 @@
+/* Copyright (c) 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/io.h>
+#include <unistd.h>
+
+#include "lightbar.h"
+#include "lpc_commands.h"
+
+
+/* Waits for the EC to be unbusy. Returns 0 if unbusy, non-zero if
+ * timeout. */
+static int wait_for_ec(int status_addr, int timeout_usec)
+{
+ int i;
+ for (i = 0; i < timeout_usec; i += 10) {
+ usleep(10); /* Delay first, in case we just sent a command */
+ if (!(inb(status_addr) & EC_LPC_STATUS_BUSY_MASK))
+ return 0;
+ }
+ return -1; /* Timeout */
+}
+
+
+/* Sends a command to the EC. Returns the command status code, or
+ * -1 if other error. */
+static int ec_command(int command, const void *indata, int insize,
+ void *outdata, int outsize) {
+ uint8_t *d;
+ int i;
+
+ /* TODO: add command line option to use kernel command/param window */
+ int cmd_addr = EC_LPC_ADDR_USER_CMD;
+ int data_addr = EC_LPC_ADDR_USER_DATA;
+ int param_addr = EC_LPC_ADDR_USER_PARAM;
+
+ if (insize > EC_LPC_PARAM_SIZE || outsize > EC_LPC_PARAM_SIZE) {
+ fprintf(stderr, "Data size too big\n");
+ return -1;
+ }
+
+ if (wait_for_ec(cmd_addr, 1000000)) {
+ fprintf(stderr, "Timeout waiting for EC ready\n");
+ return -1;
+ }
+
+ /* Write data, if any */
+ /* TODO: optimized copy using outl() */
+ for (i = 0, d = (uint8_t *)indata; i < insize; i++, d++)
+ outb(*d, param_addr + i);
+
+ outb(command, cmd_addr);
+
+ if (wait_for_ec(cmd_addr, 1000000)) {
+ fprintf(stderr, "Timeout waiting for EC response\n");
+ return -1;
+ }
+
+ /* Check result */
+ i = inb(data_addr);
+ if (i) {
+ fprintf(stderr, "EC returned error result code %d\n", i);
+ return i;
+ }
+
+ /* Read data, if any */
+ /* TODO: optimized copy using outl() */
+ for (i = 0, d = (uint8_t *)outdata; i < outsize; i++, d++)
+ *d = inb(param_addr + i);
+
+ return 0;
+}
+
+static const struct {
+ uint8_t insize;
+ uint8_t outsize;
+} lb_command_paramcount[LIGHTBAR_NUM_CMDS] = {
+ { sizeof(((struct lpc_params_lightbar_cmd *)0)->in.dump),
+ sizeof(((struct lpc_params_lightbar_cmd *)0)->out.dump) },
+ { sizeof(((struct lpc_params_lightbar_cmd *)0)->in.off),
+ sizeof(((struct lpc_params_lightbar_cmd *)0)->out.off) },
+ { sizeof(((struct lpc_params_lightbar_cmd *)0)->in.on),
+ sizeof(((struct lpc_params_lightbar_cmd *)0)->out.on) },
+ { sizeof(((struct lpc_params_lightbar_cmd *)0)->in.init),
+ sizeof(((struct lpc_params_lightbar_cmd *)0)->out.init) },
+ { sizeof(((struct lpc_params_lightbar_cmd *)0)->in.brightness),
+ sizeof(((struct lpc_params_lightbar_cmd *)0)->out.brightness) },
+ { sizeof(((struct lpc_params_lightbar_cmd *)0)->in.seq),
+ sizeof(((struct lpc_params_lightbar_cmd *)0)->out.seq) },
+ { sizeof(((struct lpc_params_lightbar_cmd *)0)->in.reg),
+ sizeof(((struct lpc_params_lightbar_cmd *)0)->out.reg) },
+ { sizeof(((struct lpc_params_lightbar_cmd *)0)->in.rgb),
+ sizeof(((struct lpc_params_lightbar_cmd *)0)->out.rgb) },
+};
+
+
+static void lb_cmd_noargs(enum lightbar_command cmd)
+{
+ struct lpc_params_lightbar_cmd param;
+ param.in.cmd = cmd;
+ ec_command(EC_LPC_COMMAND_LIGHTBAR_CMD,
+ &param, lb_command_paramcount[param.in.cmd].insize,
+ &param, lb_command_paramcount[param.in.cmd].outsize);
+}
+
+inline void lightbar_off(void)
+{
+ lb_cmd_noargs(LIGHTBAR_CMD_OFF);
+}
+
+inline void lightbar_on(void)
+{
+ lb_cmd_noargs(LIGHTBAR_CMD_ON);
+}
+
+inline void lightbar_init_vals(void)
+{
+ lb_cmd_noargs(LIGHTBAR_CMD_INIT);
+}
+
+void lightbar_brightness(int newval)
+{
+ struct lpc_params_lightbar_cmd param;
+ param.in.cmd = LIGHTBAR_CMD_BRIGHTNESS;
+ param.in.brightness.num = newval;
+ ec_command(EC_LPC_COMMAND_LIGHTBAR_CMD,
+ &param, lb_command_paramcount[param.in.cmd].insize,
+ &param, lb_command_paramcount[param.in.cmd].outsize);
+}
+
+void lightbar_sequence(enum lightbar_sequence num)
+{
+ struct lpc_params_lightbar_cmd param;
+ param.in.cmd = LIGHTBAR_CMD_SEQ;
+ param.in.seq.num = num;
+ ec_command(EC_LPC_COMMAND_LIGHTBAR_CMD,
+ &param, lb_command_paramcount[param.in.cmd].insize,
+ &param, lb_command_paramcount[param.in.cmd].outsize);
+}
+
+void lightbar_reg(uint8_t ctrl, uint8_t reg, uint8_t val)
+{
+ struct lpc_params_lightbar_cmd param;
+ param.in.cmd = LIGHTBAR_CMD_REG;
+ param.in.reg.ctrl = ctrl;
+ param.in.reg.reg = reg;
+ param.in.reg.value = val;
+ ec_command(EC_LPC_COMMAND_LIGHTBAR_CMD,
+ &param, lb_command_paramcount[param.in.cmd].insize,
+ &param, lb_command_paramcount[param.in.cmd].outsize);
+}
+
+void lightbar_rgb(int led, int red, int green, int blue)
+{
+ struct lpc_params_lightbar_cmd param;
+ param.in.cmd = LIGHTBAR_CMD_RGB;
+ param.in.rgb.led = led;
+ param.in.rgb.red = red;
+ param.in.rgb.green = green;
+ param.in.rgb.blue = blue;
+ ec_command(EC_LPC_COMMAND_LIGHTBAR_CMD,
+ &param, lb_command_paramcount[param.in.cmd].insize,
+ &param, lb_command_paramcount[param.in.cmd].outsize);
+}
+
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ /* Request I/O privilege */
+ if (iopl(3) < 0) {
+ perror("Error getting I/O privilege");
+ return -3;
+ }
+
+
+ /* Tell the EC to let us drive. */
+ lightbar_sequence(LIGHTBAR_STOP);
+
+ /* Initialize it */
+ lightbar_off();
+ lightbar_init_vals();
+ lightbar_brightness(0xff);
+ lightbar_on();
+
+ /* Play a bit */
+
+ for (i = 0; i <= 255; i += 4) {
+ lightbar_rgb(4, 0, i, 0);
+ usleep(100000);
+ }
+
+ for (; i >= 0; i -= 4) {
+ lightbar_rgb(4, i, 0, 0);
+ usleep(100000);
+ }
+
+ /* Let the EC drive again */
+ lightbar_sequence(LIGHTBAR_RUN);
+
+ return 0;
+}