liblights: Scale brightness if necessary

Change-Id: Ia9fdbe0c0f709e8e2e16f9cd2fb757c6f53e7c50
diff --git a/liblights/include/samsung_lights.h b/liblights/include/samsung_lights.h
index b853b0e..ab0630e 100644
--- a/liblights/include/samsung_lights.h
+++ b/liblights/include/samsung_lights.h
@@ -25,6 +25,7 @@
  * device tree.
  */
 #define PANEL_BRIGHTNESS_NODE "/sys/class/backlight/panel/brightness"
+#define PANEL_MAX_BRIGHTNESS_NODE "/sys/class/backlight/panel/max_brightness"
 #define BUTTON_BRIGHTNESS_NODE "/sys/class/sec/sec_touchkey/brightness"
 #define LED_BLINK_NODE "/sys/class/sec/led/led_blink"
 
diff --git a/liblights/lights.c b/liblights/lights.c
index 6da32e2..14946c5 100644
--- a/liblights/lights.c
+++ b/liblights/lights.c
@@ -35,14 +35,21 @@
 
 #define COLOR_MASK 0x00ffffff
 
+#define MAX_INPUT_BRIGHTNESS 255
+
 static pthread_once_t g_init = PTHREAD_ONCE_INIT;
 static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
 
+struct backlight_config {
+    int cur_brightness, max_brightness;
+};
+
 struct led_config {
     unsigned int color;
     int delay_on, delay_off;
 };
 
+static struct backlight_config g_backlight; // For panel backlight
 static struct led_config g_leds[3]; // For battery, notifications, and attention.
 static int g_cur_led = -1;          // Presently showing LED of the above.
 
@@ -51,6 +58,38 @@
     pthread_mutex_init(&g_lock, NULL);
 }
 
+static int read_int(char const *path)
+{
+    int fd, len;
+    int num_bytes = 10;
+    char buf[11];
+    int retval;
+
+    fd = open(path, O_RDONLY);
+    if (fd < 0) {
+        ALOGE("%s: failed to open %s\n", __func__, path);
+        goto fail;
+    }
+
+    len = read(fd, buf, num_bytes - 1);
+    if (len < 0) {
+        ALOGE("%s: failed to read from %s\n", __func__, path);
+        goto fail;
+    }
+
+    buf[len] = '\0';
+    close(fd);
+
+    // no endptr, decimal base
+    retval = strtol(buf, NULL, 10);
+    return retval == 0 ? -1 : retval;
+
+fail:
+    if (fd >= 0)
+        close(fd);
+    return -1;
+}
+
 static int write_int(char const *path, int value)
 {
     int fd;
@@ -112,9 +151,23 @@
 {
     int err = 0;
     int brightness = rgb_to_brightness(state);
+    int max_brightness = g_backlight.max_brightness;
+
+    /*
+     * If our max panel brightness is > 255, apply linear scaling across the
+     * accepted range.
+     */
+    if (max_brightness > MAX_INPUT_BRIGHTNESS) {
+        int old_brightness = brightness;
+        brightness = brightness * max_brightness / MAX_INPUT_BRIGHTNESS;
+        ALOGV("%s: scaling brightness %d => %d\n", __func__,
+            old_brightness, brightness);
+    }
 
     pthread_mutex_lock(&g_lock);
     err = write_int(PANEL_BRIGHTNESS_NODE, brightness);
+    if (err == 0)
+        g_backlight.cur_brightness = brightness;
 
     pthread_mutex_unlock(&g_lock);
     return err;
@@ -306,6 +359,14 @@
     else
         return -EINVAL;
 
+    int max_brightness = read_int(PANEL_MAX_BRIGHTNESS_NODE);
+    if (max_brightness < 0) {
+        ALOGE("%s: failed to read max panel brightness, fallback to 255!",
+            __func__);
+        max_brightness = 255;
+    }
+    g_backlight.max_brightness = max_brightness;
+
     pthread_once(&g_init, init_g_lock);
 
     struct light_device_t *dev = malloc(sizeof(struct light_device_t));