/* Copyright (c) 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 #include #include #include #include #include #include #include #include #include #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; }