[PATCH 1/2] lights hal: add support for LIGHT_FLASH_TIMED

BUG= 26852054

Change-Id: Ie6f20f370c5fc29c5e428e5fdc0cdba27b76134c
diff --git a/lights/lights.c b/lights/lights.c
index c8e4149..ceb6174 100644
--- a/lights/lights.c
+++ b/lights/lights.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (C) 2014 - 2015 The  Linux Foundation. All rights reserved.
+ * Copyright (C) 2014 - 2016 The  Linux Foundation. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,29 +29,59 @@
 
 /******************************************************************************/
 #define SET_LIGHT(color)    (color & 0xffffff ? 0x28 : 0)
+#define TRIG_MODE_NONE      "none"
+#define TRIG_MODE_TIMER     "timer"
+
+typedef enum {
+    HAL_LIGHT_ID_LED1 = 0,
+    HAL_LIGHT_ID_LED2,
+    HAL_LIGHT_ID_LED3,
+    HAL_LIGHT_ID_BT,
+    HAL_LIGHT_ID_WIFI,
+    HAL_LIGHT_ID_MAX
+} light_hal_device_id;
+
+typedef struct {
+    char const * const brightness;
+    char const * const delay_on;
+    char const * const delay_off;
+    char const * const trigger;
+} light_device_sysfs_nodes;
+
+static light_device_sysfs_nodes dev_nodes[] =
+{
+    {
+        "/sys/class/leds/led1/brightness", "/sys/class/leds/led1/delay_on",
+        "/sys/class/leds/led1/delay_off", "/sys/class/leds/led1/trigger"
+    },
+
+    {
+        "/sys/class/leds/led2/brightness", "/sys/class/leds/led2/delay_on",
+        "/sys/class/leds/led2/delay_off", "/sys/class/leds/led2/trigger"
+    },
+
+    {
+        "/sys/class/leds/led3/brightness", "/sys/class/leds/led3/delay_on",
+        "/sys/class/leds/led3/delay_off", "/sys/class/leds/led3/trigger"
+    },
+
+    {
+        "/sys/class/leds/bt/brightness", "/sys/class/leds/bt/delay_on",
+        "/sys/class/leds/bt/delay_off", "/sys/class/leds/bt/trigger"
+    },
+
+    {
+        "/sys/class/leds/wlan/brightness", "/sys/class/leds/wlan/delay_on",
+        "/sys/class/leds/wlan/delay_off", "/sys/class/leds/wlan/trigger"
+    },
+};
 
 static pthread_once_t g_init = PTHREAD_ONCE_INIT;
 static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
 
-char const* const LED1_LED_FILE
-        = "/sys/class/leds/led1/brightness";
-
-char const* const LED2_LED_FILE
-        = "/sys/class/leds/led2/brightness";
-
-char const* const LED3_LED_FILE
-        = "/sys/class/leds/led3/brightness";
-
-char const* const BLUETOOTH_LED_FILE
-        = "/sys/class/leds/bt/brightness";
-
-char const* const WIFI_LED_FILE
-        = "/sys/class/leds/wlan/brightness";
-
 /**
  * device methods
  */
-
 void init_globals(void)
 {
     // init the mutex
@@ -73,16 +103,91 @@
     }
 }
 
+static int write_str(char const* path, char const* str)
+{
+    FILE *fd;
+
+    fd = fopen(path, "w+");
+    if (fd) {
+        int bytes = fprintf(fd, "%s", str);
+        fclose(fd);
+        return (bytes < 0 ? bytes : 0);
+    } else {
+        ALOGE("write_int failed to open %s\n", path);
+        return -errno;
+    }
+}
+
+static int disable_timed_blink(light_hal_device_id dev_id)
+{
+    int err = 0;
+
+    if (dev_id >= HAL_LIGHT_ID_MAX)
+        return -EINVAL;
+
+    pthread_mutex_lock(&g_lock);
+    err = write_str(dev_nodes[dev_id].trigger, TRIG_MODE_NONE);
+    pthread_mutex_unlock(&g_lock);
+    return err;
+}
+
+static int enable_timed_blink(light_hal_device_id dev_id,
+                              struct light_state_t const* state)
+{
+    int err = 0;
+
+    if (dev_id >= HAL_LIGHT_ID_MAX)
+        return -EINVAL;
+
+    pthread_mutex_lock(&g_lock);
+    if((err = write_str(dev_nodes[dev_id].trigger, TRIG_MODE_TIMER)))
+        goto exit;
+    if((err = write_int(dev_nodes[dev_id].delay_on, state->flashOnMS)))
+        goto exit;
+    err = write_int(dev_nodes[dev_id].delay_off, state->flashOffMS);
+
+exit:
+    pthread_mutex_unlock(&g_lock);
+    return err;
+}
+
+static int set_led(light_hal_device_id dev_id,
+                   struct light_state_t const* state)
+{
+    int err = 0;
+
+    if (dev_id >= HAL_LIGHT_ID_MAX)
+        return -EINVAL;
+
+    pthread_mutex_lock(&g_lock);
+    err = write_int(dev_nodes[dev_id].brightness, SET_LIGHT(state->color));
+    pthread_mutex_unlock(&g_lock);
+
+    return err;
+}
+
 static int set_light_notifications(struct light_device_t* dev,
         struct light_state_t const* state)
 {
     int err = 0;
-    if(!dev) {
+
+    if(!dev)
         return -1;
+
+    switch (state->flashMode) {
+        case LIGHT_FLASH_TIMED:
+            err = enable_timed_blink(HAL_LIGHT_ID_LED1, state);
+            break;
+
+        case LIGHT_FLASH_NONE:
+            err = disable_timed_blink(HAL_LIGHT_ID_LED1);
+            set_led(HAL_LIGHT_ID_LED1, state);
+            break;
+
+        default:
+            err = -EINVAL;
     }
-    pthread_mutex_lock(&g_lock);
-    err = write_int(LED1_LED_FILE, SET_LIGHT(state->color));
-    pthread_mutex_unlock(&g_lock);
+
     return err;
 }
 
@@ -90,12 +195,24 @@
         struct light_state_t const* state)
 {
     int err = 0;
-    if(!dev) {
+
+    if(!dev)
         return -1;
+
+    switch (state->flashMode) {
+        case LIGHT_FLASH_TIMED:
+            err = enable_timed_blink(HAL_LIGHT_ID_LED2, state);
+            break;
+
+        case LIGHT_FLASH_NONE:
+            err = disable_timed_blink(HAL_LIGHT_ID_LED2);
+            set_led(HAL_LIGHT_ID_LED2, state);
+            break;
+
+        default:
+            err = -EINVAL;
     }
-    pthread_mutex_lock(&g_lock);
-    err = write_int(LED2_LED_FILE, SET_LIGHT(state->color));
-    pthread_mutex_unlock(&g_lock);
+
     return err;
 }
 
@@ -106,9 +223,21 @@
     if(!dev) {
         return -1;
     }
-    pthread_mutex_lock(&g_lock);
-    err = write_int(LED3_LED_FILE, SET_LIGHT(state->color));
-    pthread_mutex_unlock(&g_lock);
+
+    switch (state->flashMode) {
+        case LIGHT_FLASH_TIMED:
+            err = enable_timed_blink(HAL_LIGHT_ID_LED3, state);
+            break;
+
+        case LIGHT_FLASH_NONE:
+            err = disable_timed_blink(HAL_LIGHT_ID_LED3);
+            set_led(HAL_LIGHT_ID_LED3, state);
+            break;
+
+        default:
+            err = -EINVAL;
+    }
+
     return err;
 }
 
@@ -119,9 +248,21 @@
     if(!dev) {
         return -1;
     }
-    pthread_mutex_lock(&g_lock);
-    err = write_int(BLUETOOTH_LED_FILE, SET_LIGHT(state->color));
-    pthread_mutex_unlock(&g_lock);
+
+    switch (state->flashMode) {
+        case LIGHT_FLASH_TIMED:
+            err = enable_timed_blink(HAL_LIGHT_ID_BT, state);
+            break;
+
+        case LIGHT_FLASH_NONE:
+            err = disable_timed_blink(HAL_LIGHT_ID_BT);
+            set_led(HAL_LIGHT_ID_BT, state);
+            break;
+
+        default:
+            err = -EINVAL;
+    }
+
     return err;
 }
 
@@ -132,9 +273,21 @@
     if(!dev) {
         return -1;
     }
-    pthread_mutex_lock(&g_lock);
-    err = write_int(WIFI_LED_FILE, SET_LIGHT(state->color));
-    pthread_mutex_unlock(&g_lock);
+
+    switch (state->flashMode) {
+        case LIGHT_FLASH_TIMED:
+            err = enable_timed_blink(HAL_LIGHT_ID_WIFI, state);
+            break;
+
+        case LIGHT_FLASH_NONE:
+            err = disable_timed_blink(HAL_LIGHT_ID_WIFI);
+            set_led(HAL_LIGHT_ID_WIFI, state);
+            break;
+
+        default:
+            err = -EINVAL;
+    }
+
     return err;
 }
 
@@ -204,6 +357,6 @@
     .version_minor = 0,
     .id = LIGHTS_HARDWARE_MODULE_ID,
     .name = "Lights Module",
-    .author = "Qualcomm",
+    .author = "Codeaurora Author",
     .methods = &lights_module_methods,
 };