lights.c revision 6e71b7f95e9fdc03147c5f235060dd4ed4f23b86
1/* 2 * Copyright (C) 2014, 2017 The Linux Foundation. All rights reserved. 3 * Not a contribution 4 * Copyright (C) 2008 The Android Open Source Project 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 20// #define LOG_NDEBUG 0 21 22#include <cutils/log.h> 23 24#include <stdint.h> 25#include <stdlib.h> 26#include <string.h> 27#include <unistd.h> 28#include <errno.h> 29#include <fcntl.h> 30#include <pthread.h> 31 32#include <sys/ioctl.h> 33#include <sys/types.h> 34 35#include <hardware/lights.h> 36 37#ifndef DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS 38#define DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS 0x80 39#endif 40 41/******************************************************************************/ 42 43static pthread_once_t g_init = PTHREAD_ONCE_INIT; 44static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER; 45static struct light_state_t g_notification; 46static struct light_state_t g_battery; 47static int g_last_backlight_mode = BRIGHTNESS_MODE_USER; 48static int g_attention = 0; 49 50char const*const RED_LED_FILE 51 = "/sys/class/leds/red/brightness"; 52 53char const*const GREEN_LED_FILE 54 = "/sys/class/leds/green/brightness"; 55 56char const*const BLUE_LED_FILE 57 = "/sys/class/leds/blue/brightness"; 58 59char const*const LCD_FILE 60 = "/sys/class/leds/lcd-backlight/brightness"; 61 62char const*const BUTTON_FILE 63 = "/sys/class/leds/button-backlight/brightness"; 64 65char const*const RED_BLINK_FILE 66 = "/sys/class/leds/red/blink"; 67 68char const*const GREEN_BLINK_FILE 69 = "/sys/class/leds/green/blink"; 70 71char const*const BLUE_BLINK_FILE 72 = "/sys/class/leds/blue/blink"; 73 74char const*const PERSISTENCE_FILE 75 = "/sys/class/graphics/fb0/msm_fb_persist_mode"; 76 77/** 78 * device methods 79 */ 80 81void init_globals(void) 82{ 83 // init the mutex 84 pthread_mutex_init(&g_lock, NULL); 85} 86 87static int 88write_int(char const* path, int value) 89{ 90 int fd; 91 static int already_warned = 0; 92 93 fd = open(path, O_RDWR); 94 if (fd >= 0) { 95 char buffer[20]; 96 int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value); 97 ssize_t amt = write(fd, buffer, (size_t)bytes); 98 close(fd); 99 return amt == -1 ? -errno : 0; 100 } else { 101 if (already_warned == 0) { 102 ALOGE("write_int failed to open %s\n", path); 103 already_warned = 1; 104 } 105 return -errno; 106 } 107} 108 109static int 110is_lit(struct light_state_t const* state) 111{ 112 return state->color & 0x00ffffff; 113} 114 115static int 116rgb_to_brightness(struct light_state_t const* state) 117{ 118 int color = state->color & 0x00ffffff; 119 return ((77*((color>>16)&0x00ff)) 120 + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8; 121} 122 123static int 124set_light_backlight(struct light_device_t* dev, 125 struct light_state_t const* state) 126{ 127 int err = 0; 128 int brightness = rgb_to_brightness(state); 129 unsigned int lpEnabled = 130 state->brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE; 131 if(!dev) { 132 return -1; 133 } 134 135 pthread_mutex_lock(&g_lock); 136 // Toggle low persistence mode state 137 if ((g_last_backlight_mode != state->brightnessMode && lpEnabled) || 138 (!lpEnabled && 139 g_last_backlight_mode == BRIGHTNESS_MODE_LOW_PERSISTENCE)) { 140 if ((err = write_int(PERSISTENCE_FILE, lpEnabled)) != 0) { 141 ALOGE("%s: Failed to write to %s: %s\n", __FUNCTION__, 142 PERSISTENCE_FILE, strerror(errno)); 143 } 144 if (lpEnabled != 0) { 145 brightness = DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS; 146 } 147 } 148 149 g_last_backlight_mode = state->brightnessMode; 150 151 if (!err) { 152 err = write_int(LCD_FILE, brightness); 153 } 154 155 pthread_mutex_unlock(&g_lock); 156 return err; 157} 158 159static int 160set_speaker_light_locked(struct light_device_t* dev, 161 struct light_state_t const* state) 162{ 163 int red, green, blue; 164 int blink; 165 int onMS, offMS; 166 unsigned int colorRGB; 167 168 if(!dev) { 169 return -1; 170 } 171 172 switch (state->flashMode) { 173 case LIGHT_FLASH_TIMED: 174 onMS = state->flashOnMS; 175 offMS = state->flashOffMS; 176 break; 177 case LIGHT_FLASH_NONE: 178 default: 179 onMS = 0; 180 offMS = 0; 181 break; 182 } 183 184 colorRGB = state->color; 185 186#if 0 187 ALOGD("set_speaker_light_locked mode %d, colorRGB=%08X, onMS=%d, offMS=%d\n", 188 state->flashMode, colorRGB, onMS, offMS); 189#endif 190 191 red = (colorRGB >> 16) & 0xFF; 192 green = (colorRGB >> 8) & 0xFF; 193 blue = colorRGB & 0xFF; 194 195 if (onMS > 0 && offMS > 0) { 196 /* 197 * if ON time == OFF time 198 * use blink mode 2 199 * else 200 * use blink mode 1 201 */ 202 if (onMS == offMS) 203 blink = 2; 204 else 205 blink = 1; 206 } else { 207 blink = 0; 208 } 209 210 if (blink) { 211 if (red) { 212 if (write_int(RED_BLINK_FILE, blink)) 213 write_int(RED_LED_FILE, 0); 214 } 215 if (green) { 216 if (write_int(GREEN_BLINK_FILE, blink)) 217 write_int(GREEN_LED_FILE, 0); 218 } 219 if (blue) { 220 if (write_int(BLUE_BLINK_FILE, blink)) 221 write_int(BLUE_LED_FILE, 0); 222 } 223 } else { 224 write_int(RED_LED_FILE, red); 225 write_int(GREEN_LED_FILE, green); 226 write_int(BLUE_LED_FILE, blue); 227 } 228 229 return 0; 230} 231 232static void 233handle_speaker_battery_locked(struct light_device_t* dev) 234{ 235 if (is_lit(&g_battery)) { 236 set_speaker_light_locked(dev, &g_battery); 237 } else { 238 set_speaker_light_locked(dev, &g_notification); 239 } 240} 241 242static int 243set_light_battery(struct light_device_t* dev, 244 struct light_state_t const* state) 245{ 246 pthread_mutex_lock(&g_lock); 247 g_battery = *state; 248 handle_speaker_battery_locked(dev); 249 pthread_mutex_unlock(&g_lock); 250 return 0; 251} 252 253static int 254set_light_notifications(struct light_device_t* dev, 255 struct light_state_t const* state) 256{ 257 pthread_mutex_lock(&g_lock); 258 g_notification = *state; 259 handle_speaker_battery_locked(dev); 260 pthread_mutex_unlock(&g_lock); 261 return 0; 262} 263 264static int 265set_light_attention(struct light_device_t* dev, 266 struct light_state_t const* state) 267{ 268 pthread_mutex_lock(&g_lock); 269 if (state->flashMode == LIGHT_FLASH_HARDWARE) { 270 g_attention = state->flashOnMS; 271 } else if (state->flashMode == LIGHT_FLASH_NONE) { 272 g_attention = 0; 273 } 274 handle_speaker_battery_locked(dev); 275 pthread_mutex_unlock(&g_lock); 276 return 0; 277} 278 279static int 280set_light_buttons(struct light_device_t* dev, 281 struct light_state_t const* state) 282{ 283 int err = 0; 284 if(!dev) { 285 return -1; 286 } 287 pthread_mutex_lock(&g_lock); 288 err = write_int(BUTTON_FILE, state->color & 0xFF); 289 pthread_mutex_unlock(&g_lock); 290 return err; 291} 292 293/** Close the lights device */ 294static int 295close_lights(struct light_device_t *dev) 296{ 297 if (dev) { 298 free(dev); 299 } 300 return 0; 301} 302 303 304/******************************************************************************/ 305 306/** 307 * module methods 308 */ 309 310/** Open a new instance of a lights device using name */ 311static int open_lights(const struct hw_module_t* module, char const* name, 312 struct hw_device_t** device) 313{ 314 int (*set_light)(struct light_device_t* dev, 315 struct light_state_t const* state); 316 317 if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) 318 set_light = set_light_backlight; 319 else if (0 == strcmp(LIGHT_ID_BATTERY, name)) 320 set_light = set_light_battery; 321 else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) 322 set_light = set_light_notifications; 323 else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) 324 set_light = set_light_buttons; 325 else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) 326 set_light = set_light_attention; 327 else 328 return -EINVAL; 329 330 pthread_once(&g_init, init_globals); 331 332 struct light_device_t *dev = malloc(sizeof(struct light_device_t)); 333 334 if(!dev) 335 return -ENOMEM; 336 337 memset(dev, 0, sizeof(*dev)); 338 339 dev->common.tag = HARDWARE_DEVICE_TAG; 340 dev->common.version = LIGHTS_DEVICE_API_VERSION_2_0; 341 dev->common.module = (struct hw_module_t*)module; 342 dev->common.close = (int (*)(struct hw_device_t*))close_lights; 343 dev->set_light = set_light; 344 345 *device = (struct hw_device_t*)dev; 346 return 0; 347} 348 349static struct hw_module_methods_t lights_module_methods = { 350 .open = open_lights, 351}; 352 353/* 354 * The lights Module 355 */ 356struct hw_module_t HAL_MODULE_INFO_SYM = { 357 .tag = HARDWARE_MODULE_TAG, 358 .version_major = 1, 359 .version_minor = 0, 360 .id = LIGHTS_HARDWARE_MODULE_ID, 361 .name = "lights Module", 362 .author = "Google, Inc.", 363 .methods = &lights_module_methods, 364}; 365