Add Red/Blue LED notification support
authorsbrissen <sbrissen@Hotmail.com>
Fri, 25 May 2012 13:40:54 +0000 (09:40 -0400)
committerDorian Snyder <dastin1015@gmail.com>
Sat, 31 Aug 2013 04:03:31 +0000 (21:03 -0700)
This will allow the use of the red/blue led's on the sph-d710
Uses BOARD_HAS_LED_NOTIF in boardconfig.

Change-Id: Ic217ed5b0ec673d03bb596fbde0ac725a5ca0887

exynos4/exynos4210/liblights/lights.c

index 5eedad41680888433b5825a1780f1e44c4b9754c..3c59011bf292965f77b7f4f215198f0e725a0d4d 100644 (file)
@@ -46,12 +46,22 @@ char const*const BUTTON_FILE
         = "/sys/class/sec/sec_touchkey/brightness";
 #endif
 
+#ifdef LED_NOTIFICATION
+static char const RED_LED_DIR[]   = "/sys/class/leds/red";
+static char const BLUE_LED_DIR[]  = "/sys/class/leds/blue";
+#endif // LED_NOTIFICATION
 void init_globals(void)
 {
     // init the mutex
     pthread_mutex_init(&g_lock, NULL);
 }
 
+#ifdef LED_NOTIFICATION
+static struct led_state {
+    unsigned int enabled;
+    int delay_on, delay_off;
+} battery_red, battery_blue, notifications_red, notifications_blue;
+#endif // LED_NOTIFICATION
 static int
 write_int(char const* path, int value)
 {
@@ -74,6 +84,45 @@ write_int(char const* path, int value)
     }
 }
 
+#ifdef LED_NOTIFICATION
+static int write_str(char const *path, char const *str)
+{
+    int fd;
+    static int already_warned = 0;
+
+    ALOGV("write_str: path=\"%s\", str=\"%s\".", path, str);
+    fd = open(path, O_RDWR);
+
+    if (fd >= 0) {
+        int amt = write(fd, str, strlen(str));
+        close(fd);
+        return amt == -1 ? -errno : 0;
+    } else {
+        if (already_warned == 0) {
+            ALOGE("write_str failed to open %s\n", path);
+            already_warned = 1;
+        }
+        return -errno;
+    }
+}
+
+/* Should check for snprintf truncation, but as these functions only use
+ * internal paths, meh. */
+static int write_df_int(char const *dir, char const *file, int value)
+{
+    char path[PATH_MAX];
+    snprintf(path, sizeof(path), "%s/%s", dir, file);
+    return write_int(path, value);
+}
+
+static int write_df_str(char const *dir, char const *file, char const *str)
+{
+    char path[PATH_MAX];
+    snprintf(path, sizeof(path), "%s/%s", dir, file);
+    return write_str(path, str);
+}
+#endif // LED_NOTIFICATION
+
 static int
 is_lit(struct light_state_t const* state)
 {
@@ -88,6 +137,75 @@ rgb_to_brightness(struct light_state_t const* state)
             + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
 }
 
+#ifdef LED_NOTIFICATION
+static void comp_led_states(struct led_state *red, struct led_state *blue,
+             struct light_state_t const* state)
+{
+    unsigned int color = state->color;
+    int delay_on, delay_off;
+
+    switch (state->flashMode) {
+    case LIGHT_FLASH_TIMED:
+        delay_on  = state->flashOnMS;
+        delay_off = state->flashOffMS;
+        break;
+    default:
+        ALOGI("Unsuported flashMode %d, default to NONE.", state->flashMode);
+    case LIGHT_FLASH_NONE:
+        delay_on = delay_off = 0;
+        break;
+    }
+
+    red->enabled   = !!(color >> 16 & 0xff);
+    red->delay_on  = delay_on;
+    red->delay_off = delay_off;
+
+    blue->enabled   = !!(color & 0xff);
+    blue->delay_on  = delay_on;
+    blue->delay_off = delay_off;
+
+    ALOGV("comp_led_states: red=(%u, %d, %d), blue=(%u, %d, %d).",
+         red->enabled, red->delay_on, red->delay_off, blue->enabled,
+            blue->delay_on, blue->delay_off);
+}
+
+static int set_led(char const *dir, struct led_state const *battery,
+            struct led_state const *notifications)
+{
+
+    struct led_state const *state = NULL;
+    int res;
+
+    if (notifications->enabled)
+        state = notifications;
+    else if (battery->enabled)
+        state = battery;
+
+    if (state != NULL) {
+        int delay_on  = state->delay_on;
+        int delay_off = state->delay_off;
+
+        if (delay_on > 0 && delay_off > 0) {
+             /* Handling of blink_count is wrong in the kernel, blinking indefinitely
+             * for any non-zero value.  TW lights just sets it to 1. */
+            if ((res = write_df_str(dir, "trigger",     "notification")) < 0) return res;
+            if ((res = write_df_str(dir, "brightness",  "255"         )) < 0) return res;
+            if ((res = write_df_str(dir, "blink_count", "1"           )) < 0) return res;
+            if ((res = write_df_int(dir, "delay_on",    delay_on      )) < 0) return res;
+            if ((res = write_df_int(dir, "delay_off",   delay_off     )) < 0) return res;
+        } else {
+            if ((res = write_df_str(dir, "trigger",    "none")) < 0) return res;
+            if ((res = write_df_str(dir, "brightness", "255" )) < 0) return res;
+        }
+    } else {
+        if ((res = write_df_str(dir, "trigger",    "none")) < 0) return res;
+        if ((res = write_df_str(dir, "brightness", "0"   )) < 0) return res;
+    }
+
+    return 0;
+}
+#endif // LED_NOTIFICATION
+
 static int
 set_light_backlight(struct light_device_t* dev,
         struct light_state_t const* state)
@@ -126,14 +244,46 @@ static int
 set_light_battery(struct light_device_t* dev,
         struct light_state_t const* state)
 {
-    return 0;
+   int res = 0;
+
+#ifdef LED_NOTIFICATION
+    ALOGD("set_light_battery: color=%#010x, fM=%u, fOnMS=%d, fOffMs=%d.",
+          state->color, state->flashMode, state->flashOnMS, state->flashOffMS);
+
+    pthread_mutex_lock(&g_lock);
+
+    comp_led_states(&battery_red, &battery_blue, state);
+
+    if ((res = set_led(RED_LED_DIR,  &battery_red,  &notifications_red)) >= 0)
+           res = set_led(BLUE_LED_DIR, &battery_blue, &notifications_blue);
+
+    pthread_mutex_unlock(&g_lock);
+#endif // LED_NOTIFICATION
+
+    return res;
 }
 
 static int
 set_light_notification(struct light_device_t* dev,
         struct light_state_t const* state)
 {
-    return 0;
+    int res = 0;
+
+#ifdef LED_NOTIFICATION
+     ALOGD("set_light_notification: color=%#010x, fM=%u, fOnMS=%d, fOffMs=%d.",
+         state->color, state->flashMode, state->flashOnMS, state->flashOffMS);
+
+    pthread_mutex_lock(&g_lock);
+
+    comp_led_states(&notifications_red, &notifications_blue, state);
+
+    if ((res = set_led(RED_LED_DIR,  &battery_red,  &notifications_red)) >= 0)
+           res = set_led(BLUE_LED_DIR, &battery_blue, &notifications_blue);
+
+    pthread_mutex_unlock(&g_lock);
+#endif // LED_NOTIFICATION
+
+    return res;
 }
 
 static int