Add support for white LEDs

Bug: 9079860
Change-Id: Icc981682a274546c1414bd7c0b0045b1293575bf
diff --git a/liblight/lights.c b/liblight/lights.c
index 2c62744..332a2ec 100644
--- a/liblight/lights.c
+++ b/liblight/lights.c
@@ -33,6 +33,8 @@
 
 /******************************************************************************/
 
+#define MAX_PATH_SIZE 80
+
 static pthread_once_t g_init = PTHREAD_ONCE_INIT;
 static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
 static struct light_state_t g_notification;
@@ -48,20 +50,23 @@
 char const*const BLUE_LED_FILE
         = "/sys/class/leds/blue/brightness";
 
+char const*const WHITE_LED_FILE
+        = "/sys/class/leds/white/brightness";
+
 char const*const LCD_FILE
         = "/sys/class/leds/lcd-backlight/brightness";
 
-char const*const RED_FREQ_FILE
-        = "/sys/class/leds/red/device/grpfreq";
+char const*const LED_FREQ_FILE
+        = "/sys/class/leds/%s/device/grpfreq";
 
-char const*const RED_PWM_FILE
-        = "/sys/class/leds/red/device/grppwm";
+char const*const LED_PWM_FILE
+        = "/sys/class/leds/%s/device/grppwm";
 
-char const*const RED_BLINK_FILE
-        = "/sys/class/leds/red/device/blink";
+char const*const LED_BLINK_FILE
+        = "/sys/class/leds/%s/device/blink";
 
 char const*const LED_LOCK_UPDATE_FILE
-        = "/sys/class/leds/red/device/lock";
+        = "/sys/class/leds/%s/device/lock";
 
 /**
  * device methods
@@ -96,6 +101,18 @@
 }
 
 static int
+is_avail(char const* path)
+{
+    int fd = open(path, O_RDWR);
+    if (fd >= 0) {
+        close(fd);
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static int
 is_lit(struct light_state_t const* state)
 {
     return state->color & 0x00ffffff;
@@ -126,7 +143,7 @@
         struct light_state_t const* state)
 {
     int len;
-    int alpha, red, green, blue;
+    int alpha, rgb;
     int blink, freq, pwm;
     int onMS, offMS;
     unsigned int colorRGB;
@@ -150,10 +167,6 @@
             state->flashMode, colorRGB, onMS, offMS);
 #endif
 
-    red = (colorRGB >> 16) & 0xFF;
-    green = (colorRGB >> 8) & 0xFF;
-    blue = colorRGB & 0xFF;
-
     if (onMS > 0 && offMS > 0) {
         int totalMS = onMS + offMS;
 
@@ -176,19 +189,39 @@
         pwm = 0;
     }
 
-    write_int(LED_LOCK_UPDATE_FILE, 1); // for LED On/Off synchronization
+    // Prefer RGB LEDs, fallback to white LED
+    rgb = is_avail(RED_LED_FILE) && is_avail(GREEN_LED_FILE) && is_avail(BLUE_LED_FILE);
 
-    write_int(RED_LED_FILE, red);
-    write_int(GREEN_LED_FILE, green);
-    write_int(BLUE_LED_FILE, blue);
+    char lock_update_file[MAX_PATH_SIZE];
+    char freq_file[MAX_PATH_SIZE];
+    char pwm_file[MAX_PATH_SIZE];
+    char blink_file[MAX_PATH_SIZE];
+    sprintf(lock_update_file, LED_LOCK_UPDATE_FILE, rgb ? "red" : "white");
+    sprintf(freq_file, LED_FREQ_FILE, rgb ? "red" : "white");
+    sprintf(pwm_file, LED_PWM_FILE, rgb ? "red" : "white");
+    sprintf(blink_file, LED_BLINK_FILE, rgb ? "red" : "white");
+
+    write_int(lock_update_file, 1); // for LED On/Off synchronization
+
+    if (rgb) {
+        write_int(RED_LED_FILE, (colorRGB >> 16) & 0xFF);
+        write_int(GREEN_LED_FILE, (colorRGB >> 8) & 0xFF);
+        write_int(BLUE_LED_FILE, colorRGB & 0xFF);
+    } else {
+        // See hardware/libhardware/include/hardware/lights.h
+        int brightness = ((77 * ((colorRGB >> 16) & 0xFF)) +
+                          (150 * ((colorRGB >> 8) & 0xFF)) +
+                          (29 * (colorRGB & 0xFF))) >> 8;
+        write_int(WHITE_LED_FILE, (int) brightness);
+    }
 
     if (blink) {
-        write_int(RED_FREQ_FILE, freq);
-        write_int(RED_PWM_FILE, pwm);
+        write_int(freq_file, freq);
+        write_int(pwm_file, pwm);
     }
-    write_int(RED_BLINK_FILE, blink);
+    write_int(blink_file, blink);
 
-    write_int(LED_LOCK_UPDATE_FILE, 0);
+    write_int(lock_update_file, 0);
 
     return 0;
 }