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