Files
OpenCellular/util/lbplay.c
Bill Richardson 31190cf215 Create host-side lightbar bikeshedding tool.
BUG=chrome-os-partner:7839
TEST=manual

  cd src/platform/ec
  make BOARD=link

  copy ./build/link/util/lbplay to the host and run it as root.

Change-Id: I6a4a842b7500751185c8f4c2744f4389226bae9b
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
2012-04-26 13:57:19 -07:00

210 lines
5.4 KiB
C

/* 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;
}