166 lines
3.8 KiB
C
166 lines
3.8 KiB
C
/* Copyright 2014 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 <strings.h>
|
|
#include <sys/file.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#define LIGHTBAR "/sys/devices/virtual/chromeos/cros_ec/lightbar"
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int major, minor, fd_v;
|
|
int i, tries, fd_s, fd_l;
|
|
char buf[80];
|
|
int ret = 1;
|
|
|
|
/* Check version */
|
|
fd_v = open(LIGHTBAR "/version", O_RDONLY);
|
|
if (fd_v < 0) {
|
|
perror("can't open version file");
|
|
goto out;
|
|
}
|
|
ret = read(fd_v, buf, sizeof(buf) - 1);
|
|
if (ret <= 0) {
|
|
perror("can't read version");
|
|
close(fd_v);
|
|
goto out;
|
|
}
|
|
buf[ret] = '\0';
|
|
close(fd_v);
|
|
|
|
errno = 0;
|
|
/* Expect "MAJOR MINOR" */
|
|
if (2 != sscanf(buf, "%d %d", &major, &minor)) {
|
|
if (errno)
|
|
perror("can't parse version string");
|
|
else
|
|
fprintf(stderr, "can't parse version string\n");
|
|
goto out;
|
|
}
|
|
/* Pixel is "0 0". Minor change will be compatible, Major may not */
|
|
if (major != 0) {
|
|
fprintf(stderr, "Don't know how to handle version %d.%d\n",
|
|
major, minor);
|
|
goto out;
|
|
}
|
|
|
|
/* Take over lightbar sequencing. */
|
|
fd_s = open(LIGHTBAR "/sequence", O_RDWR | O_SYNC);
|
|
if (fd_s < 0) {
|
|
perror("can't open sequence control");
|
|
goto out;
|
|
}
|
|
|
|
/* NOTE: Cooperative locking only. Rude programs may not play nice. */
|
|
if (flock(fd_s, LOCK_EX | LOCK_NB) < 0) {
|
|
perror("can't lock sequence control");
|
|
goto out_close;
|
|
}
|
|
|
|
/*
|
|
* If power events are changing the sequence our request to stop may
|
|
* be missed, so try a few times before giving up.
|
|
*
|
|
* Note that every write to a control file should be prefaced with an
|
|
* lseek() to the beginning. sysfs files don't work quite like normal
|
|
* files.
|
|
*/
|
|
tries = 3;
|
|
while (1) {
|
|
lseek(fd_s, 0, SEEK_SET);
|
|
if (read(fd_s, buf, sizeof(buf)) <= 0) {
|
|
perror("can't read sequence control");
|
|
goto out_unlock;
|
|
}
|
|
|
|
if (!strncasecmp(buf, "stop", 4))
|
|
break;
|
|
|
|
if (!tries--) {
|
|
fprintf(stderr, "couldn't get EC to stop\n");
|
|
goto out_unlock;
|
|
}
|
|
|
|
lseek(fd_s, 0, SEEK_SET);
|
|
strcpy(buf, "stop");
|
|
if (write(fd_s, buf, strlen(buf) + 1) <= 0) {
|
|
perror("can't write sequence control");
|
|
goto out_unlock;
|
|
}
|
|
}
|
|
|
|
/* Turn the brightness all the way up */
|
|
fd_l = open(LIGHTBAR "/brightness", O_WRONLY | O_SYNC);
|
|
if (fd_l < 0) {
|
|
perror("can't open brightness control");
|
|
goto out_run;
|
|
}
|
|
strcpy(buf, "255");
|
|
if (write(fd_l, buf, strlen(buf) + 1) < 0) {
|
|
perror("can't write brightness control");
|
|
goto out_led;
|
|
}
|
|
close(fd_l);
|
|
|
|
/* Now let's drive the colors. */
|
|
fd_l = open(LIGHTBAR "/led_rgb", O_WRONLY | O_SYNC);
|
|
if (fd_l < 0) {
|
|
perror("can't open led control");
|
|
goto out_run;
|
|
}
|
|
|
|
/* Cycle through some colors. We can update multiple LEDs at once,
|
|
* but there's a limit on how often we can send commands to the
|
|
* lightbar. Going too fast will block, although buffering combined
|
|
* with lseek() may just cause data to be lost. Read "/interval_msec"
|
|
* to see what the limit is. The default is 50msec (20Hz).
|
|
*/
|
|
for (i = 0; i < 256; i += 4) {
|
|
sprintf(buf, "0 %d %d %d 1 %d %d %d 2 %d %d %d 3 %d %d %d",
|
|
i, 0, 0,
|
|
0, 0, i,
|
|
255-i, 255, 0,
|
|
0, 255, 255-i);
|
|
lseek(fd_l, 0, SEEK_SET);
|
|
if (write(fd_l, buf, strlen(buf) + 1) < 0)
|
|
perror("write to led control");
|
|
|
|
usleep(100000);
|
|
}
|
|
|
|
/* all white */
|
|
strcpy(buf, "4 255 255 255");
|
|
lseek(fd_l, 0, SEEK_SET);
|
|
if (write(fd_l, buf, strlen(buf) + 1) < 0)
|
|
perror("write to led control");
|
|
|
|
usleep(400000);
|
|
|
|
/* Done. */
|
|
ret = 0;
|
|
out_led:
|
|
close(fd_l);
|
|
out_run:
|
|
/* Let EC drive lightbar again */
|
|
strcpy(buf, "run");
|
|
lseek(fd_s, 0, SEEK_SET);
|
|
if (write(fd_s, buf, strlen(buf) + 1) < 0)
|
|
perror("write to sequence control");
|
|
out_unlock:
|
|
flock(fd_s, LOCK_UN);
|
|
out_close:
|
|
close(fd_s);
|
|
out:
|
|
return ret;
|
|
}
|