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