From 898047abc2e04fe34e325cc097ccaecf1c0d405a Mon Sep 17 00:00:00 2001 From: sbrissen Date: Fri, 25 May 2012 09:40:54 -0400 Subject: [PATCH] Add Red/Blue LED notification support 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 | 154 +++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/exynos4/exynos4210/liblights/lights.c b/exynos4/exynos4210/liblights/lights.c index 5eedad4..3c59011 100644 --- a/exynos4/exynos4210/liblights/lights.c +++ b/exynos4/exynos4210/liblights/lights.c @@ -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, ¬ifications_red)) >= 0) + res = set_led(BLUE_LED_DIR, &battery_blue, ¬ifications_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(¬ifications_red, ¬ifications_blue, state); + + if ((res = set_led(RED_LED_DIR, &battery_red, ¬ifications_red)) >= 0) + res = set_led(BLUE_LED_DIR, &battery_blue, ¬ifications_blue); + + pthread_mutex_unlock(&g_lock); +#endif // LED_NOTIFICATION + + return res; } static int -- 2.20.1