diff options
-rw-r--r-- | Makefile.toolchain | 2 | ||||
-rw-r--r-- | include/lightbar_msg_list.h | 26 | ||||
-rw-r--r-- | util/build.mk | 2 | ||||
-rw-r--r-- | util/lbplay.c | 209 |
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, + ¶m, lb_command_paramcount[param.in.cmd].insize, + ¶m, 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, + ¶m, lb_command_paramcount[param.in.cmd].insize, + ¶m, 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, + ¶m, lb_command_paramcount[param.in.cmd].insize, + ¶m, 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, + ¶m, lb_command_paramcount[param.in.cmd].insize, + ¶m, 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, + ¶m, lb_command_paramcount[param.in.cmd].insize, + ¶m, 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; +} |