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 = sprintf(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 write_int(RED_BLINK_FILE, blink); 173 if (green) 174 write_int(GREEN_BLINK_FILE, blink); 175 if (blue) 176 write_int(BLUE_BLINK_FILE, blink); 177 } else { 178 write_int(RED_LED_FILE, red); 179 write_int(GREEN_LED_FILE, green); 180 write_int(BLUE_LED_FILE, blue); 181 } 182 183 return 0; 184 } 185 186 static void 187 handle_speaker_battery_locked(struct light_device_t* dev) 188 { 189 if (is_lit(&g_battery)) { 190 set_speaker_light_locked(dev, &g_battery); 191 } else { 192 set_speaker_light_locked(dev, &g_notification); 193 } 194 } 195 196 static int 197 set_light_notifications(struct light_device_t* dev, 198 struct light_state_t const* state) 199 { 200 pthread_mutex_lock(&g_lock); 201 g_notification = *state; 202 handle_speaker_battery_locked(dev); 203 pthread_mutex_unlock(&g_lock); 204 return 0; 205 } 206 207 static int 208 set_light_attention(struct light_device_t* dev, 209 struct light_state_t const* state) 210 { 211 pthread_mutex_lock(&g_lock); 212 if (state->flashMode == LIGHT_FLASH_HARDWARE) { 213 g_attention = state->flashOnMS; 214 } else if (state->flashMode == LIGHT_FLASH_NONE) { 215 g_attention = 0; 216 } 217 handle_speaker_battery_locked(dev); 218 pthread_mutex_unlock(&g_lock); 219 return 0; 220 } 221 222 static int 223 set_light_buttons(struct light_device_t* dev, 224 struct light_state_t const* state) 225 { 226 int err = 0; 227 if(!dev) { 228 return -1; 229 } 230 pthread_mutex_lock(&g_lock); 231 err = write_int(BUTTON_FILE, state->color & 0xFF); 232 pthread_mutex_unlock(&g_lock); 233 return err; 234 } 235 236 /** Close the lights device */ 237 static int 238 close_lights(struct light_device_t *dev) 239 { 240 if (dev) { 241 free(dev); 242 } 243 return 0; 244 } 245 246 247 /******************************************************************************/ 248 249 /** 250 * module methods 251 */ 252 253 /** Open a new instance of a lights device using name */ 254 static int open_lights(const struct hw_module_t* module, char const* name, 255 struct hw_device_t** device) 256 { 257 int (*set_light)(struct light_device_t* dev, 258 struct light_state_t const* state); 259 260 if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) 261 set_light = set_light_backlight; 262 else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) 263 set_light = set_light_notifications; 264 else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) 265 set_light = set_light_buttons; 266 else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) 267 set_light = set_light_attention; 268 else 269 return -EINVAL; 270 271 pthread_once(&g_init, init_globals); 272 273 struct light_device_t *dev = malloc(sizeof(struct light_device_t)); 274 memset(dev, 0, sizeof(*dev)); 275 276 dev->common.tag = HARDWARE_DEVICE_TAG; 277 dev->common.version = 0; 278 dev->common.module = (struct hw_module_t*)module; 279 dev->common.close = (int (*)(struct hw_device_t*))close_lights; 280 dev->set_light = set_light; 281 282 *device = (struct hw_device_t*)dev; 283 return 0; 284 } 285 286 static struct hw_module_methods_t lights_module_methods = { 287 .open = open_lights, 288 }; 289 290 /* 291 * The lights Module 292 */ 293 struct hw_module_t HAL_MODULE_INFO_SYM = { 294 .tag = HARDWARE_MODULE_TAG, 295 .version_major = 1, 296 .version_minor = 0, 297 .id = LIGHTS_HARDWARE_MODULE_ID, 298 .name = "lights Module", 299 .author = "Google, Inc.", 300 .methods = &lights_module_methods, 301 }; 302