blob: b136b43ef60d25be28a2dfb139d5e888eb482136 [file] [log] [blame]
Dan Murphy8a7333a2010-05-27 07:47:59 -05001/*
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
Mike Lockwooda06fed22010-12-01 18:22:52 -050037#define LIGHT_ATTENTION 1
38#define LIGHT_NOTIFY 2
Dan Murphy8a7333a2010-05-27 07:47:59 -050039
40/******************************************************************************/
41
42
Mike Lockwooda06fed22010-12-01 18:22:52 -050043static struct light_state_t *g_notify;
44static struct light_state_t *g_attention;
45static pthread_once_t g_init = PTHREAD_ONCE_INIT;
Dan Murphy8a7333a2010-05-27 07:47:59 -050046static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
Dan Murphy8a7333a2010-05-27 07:47:59 -050047
Dan Murphy8a7333a2010-05-27 07:47:59 -050048/**
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 LOGE("write_int failed to open %s\n", path);
66 already_warned = 1;
67 }
68 return -errno;
69 }
70}
71
makarand.karvekarf82cb0e2010-09-17 11:08:47 -050072static 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 LOGE("write_int failed to open %s\n", path);
86 already_warned = 1;
87 }
88 return -errno;
89 }
90}
91
Mike Lockwooda06fed22010-12-01 18:22:52 -050092void 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
Dan Murphy8a7333a2010-05-27 07:47:59 -0500102static int rgb_to_brightness(struct light_state_t const *state)
103{
Mike Lockwooda06fed22010-12-01 18:22:52 -0500104 /* use max of the RGB components for brightness */
Dan Murphy8a7333a2010-05-27 07:47:59 -0500105 int color = state->color & 0x00ffffff;
Mike Lockwooda06fed22010-12-01 18:22:52 -0500106 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;
Dan Murphy8a7333a2010-05-27 07:47:59 -0500117}
118
119static int
120set_light_backlight(struct light_device_t *dev,
Mike Lockwooda06fed22010-12-01 18:22:52 -0500121 struct light_state_t const *state)
Dan Murphy8a7333a2010-05-27 07:47:59 -0500122{
123 int err = 0;
124 int brightness = rgb_to_brightness(state);
125
126 pthread_mutex_lock(&g_lock);
Dan Murphy8a7333a2010-05-27 07:47:59 -0500127 err = write_int("/sys/class/leds/lcd-backlight/brightness", brightness);
128 pthread_mutex_unlock(&g_lock);
129
130 return err;
131}
132
133static int
Mike Lockwooda06fed22010-12-01 18:22:52 -0500134set_notification_light(struct light_state_t const* state)
Dan Murphy8a7333a2010-05-27 07:47:59 -0500135{
Mike Lockwooda06fed22010-12-01 18:22:52 -0500136 unsigned int brightness = rgb_to_brightness(state);
137 int blink = state->flashOnMS;
Dan Murphy8a7333a2010-05-27 07:47:59 -0500138
Mike Lockwooda06fed22010-12-01 18:22:52 -0500139#if 0
140 LOGD("set_notification_light colorRGB=%08X, onMS=%d, offMS=%d\n",
141 state->color, state->flashOnMS, state->flashOffMS);
Dan Murphy8a7333a2010-05-27 07:47:59 -0500142#endif
143
Mike Lockwooda06fed22010-12-01 18:22:52 -0500144 write_int("/sys/class/leds/notification-led/brightness", brightness);
145 write_int("/sys/class/leds/notification-led/blink", blink);
Dan Murphy8a7333a2010-05-27 07:47:59 -0500146
Mike Lockwooda06fed22010-12-01 18:22:52 -0500147 return 0;
148}
Dan Murphy8a7333a2010-05-27 07:47:59 -0500149
Mike Lockwooda06fed22010-12-01 18:22:52 -0500150static void
151handle_notification_light_locked(int type)
152{
153 struct light_state_t *new_state = 0;
154 int attn_mode = 0;
Dan Murphy8a7333a2010-05-27 07:47:59 -0500155
Mike Lockwooda06fed22010-12-01 18:22:52 -0500156 if (g_attention->flashMode == LIGHT_FLASH_HARDWARE)
157 attn_mode = g_attention->flashOnMS;
158
159 switch (type) {
160 case LIGHT_ATTENTION: {
161 if (attn_mode == 0) {
162 /* go back to notify state */
163 new_state = g_notify;
164 } else {
165 new_state = g_attention;
166 }
167 break;
168 }
169 case LIGHT_NOTIFY: {
170 if (attn_mode != 0) {
171 /* attention takes priority over notify state */
172 new_state = g_attention;
173 } else {
174 new_state = g_notify;
175 }
176 break;
177 }
178 }
179 if (new_state == 0) {
180 LOGE("%s: unknown type (%d)\n", __func__, type);
181 return;
makarand.karvekarf82cb0e2010-09-17 11:08:47 -0500182 }
Dan Murphy8a7333a2010-05-27 07:47:59 -0500183
Mike Lockwooda06fed22010-12-01 18:22:52 -0500184 set_notification_light(new_state);
185}
Dan Murphy8a7333a2010-05-27 07:47:59 -0500186
Mike Lockwooda06fed22010-12-01 18:22:52 -0500187static int
188set_light_notifications(struct light_device_t* dev,
189 struct light_state_t const* state)
190{
191 pthread_mutex_lock(&g_lock);
192
193 g_notify->color = state->color;
194 if (state->flashMode != LIGHT_FLASH_NONE) {
195 g_notify->flashMode = LIGHT_FLASH_HARDWARE;
196 g_notify->flashOnMS = state->flashOnMS;
197 g_notify->flashOffMS = state->flashOffMS;
198 } else {
199 g_notify->flashOnMS = 0;
200 g_notify->flashOffMS = 0;
201 }
202 handle_notification_light_locked(LIGHT_NOTIFY);
203
204 pthread_mutex_unlock(&g_lock);
205 return 0;
206}
207
208static int
209set_light_attention(struct light_device_t* dev,
210 struct light_state_t const* state)
211{
212 pthread_mutex_lock(&g_lock);
213
214 g_attention->flashMode = state->flashMode;
215 g_attention->flashOnMS = state->flashOnMS;
216 g_attention->color = state->color;
217 g_attention->flashOffMS = 0;
218 handle_notification_light_locked(LIGHT_ATTENTION);
219
220 pthread_mutex_unlock(&g_lock);
Dan Murphy8a7333a2010-05-27 07:47:59 -0500221 return 0;
222}
223
224/** Close the lights device */
225static int close_lights(struct light_device_t *dev)
226{
227 if (dev)
228 free(dev);
229 return 0;
230}
231
232/******************************************************************************/
233
234/**
235 * module methods
236 */
237
238/** Open a new instance of a lights device using name */
239static int open_lights(const struct hw_module_t *module, char const *name,
240 struct hw_device_t **device)
241{
242 pthread_t lighting_poll_thread;
243
244 int (*set_light) (struct light_device_t *dev,
245 struct light_state_t const *state);
246
247 if (0 == strcmp(LIGHT_ID_BACKLIGHT, name))
248 set_light = set_light_backlight;
Dan Murphy8a7333a2010-05-27 07:47:59 -0500249 else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
Mike Lockwooda06fed22010-12-01 18:22:52 -0500250 set_light = set_light_notifications;
251 else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
252 set_light = set_light_attention;
Dan Murphy8a7333a2010-05-27 07:47:59 -0500253 else
254 return -EINVAL;
255
Mike Lockwooda06fed22010-12-01 18:22:52 -0500256 pthread_once(&g_init, init_globals);
Dan Murphy8a7333a2010-05-27 07:47:59 -0500257
258 struct light_device_t *dev = malloc(sizeof(struct light_device_t));
259 memset(dev, 0, sizeof(*dev));
260
261 dev->common.tag = HARDWARE_DEVICE_TAG;
262 dev->common.version = 0;
263 dev->common.module = (struct hw_module_t *)module;
264 dev->common.close = (int (*)(struct hw_device_t *))close_lights;
265 dev->set_light = set_light;
266
267 *device = (struct hw_device_t *)dev;
268
269 return 0;
270}
271
272static struct hw_module_methods_t lights_module_methods = {
273 .open = open_lights,
274};
275
276/*
277 * The lights Module
278 */
279const struct hw_module_t HAL_MODULE_INFO_SYM = {
280 .tag = HARDWARE_MODULE_TAG,
281 .version_major = 1,
282 .version_minor = 0,
283 .id = LIGHTS_HARDWARE_MODULE_ID,
284 .name = "Nvidia lights Module",
285 .author = "Motorola, Inc.",
286 .methods = &lights_module_methods,
287};