blob: e83be16f94af8406a1cc1fd5ef5eecea764cf068 [file] [log] [blame]
Sungmin Choib5148892012-07-02 17:00:07 -07001/*
Ch Ganesh Kumaraf75ef52018-03-14 16:51:43 +05302 * Copyright (C) 2014, 2017-2018 The Linux Foundation. All rights reserved.
Sathish Ambley4342f272017-01-04 10:57:05 -08003 * Not a contribution
Sungmin Choib5148892012-07-02 17:00:07 -07004 * 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
Sungmin Choib5148892012-07-02 17:00:07 -070021
Naseer Ahmed04a804a2018-03-06 20:41:14 -050022#include <log/log.h>
Xu Yang586c6d52016-09-19 17:54:16 +080023#include <cutils/properties.h>
Sungmin Choib5148892012-07-02 17:00:07 -070024#include <stdint.h>
Arun Kumar K.R62031612015-07-30 11:38:19 -070025#include <stdlib.h>
Sungmin Choib5148892012-07-02 17:00:07 -070026#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
Sathish Ambley4342f272017-01-04 10:57:05 -080037#ifndef DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS
38#define DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS 0x80
39#endif
40
Sungmin Choib5148892012-07-02 17:00:07 -070041/******************************************************************************/
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;
Sathish Ambley4342f272017-01-04 10:57:05 -080047static int g_last_backlight_mode = BRIGHTNESS_MODE_USER;
Sungmin Choib5148892012-07-02 17:00:07 -070048static int g_attention = 0;
Pullakavi Srinivasda0b3252017-10-12 17:50:41 +053049static bool g_has_persistence_node = false;
Sungmin Choib5148892012-07-02 17:00:07 -070050
51char const*const RED_LED_FILE
52 = "/sys/class/leds/red/brightness";
53
54char const*const GREEN_LED_FILE
55 = "/sys/class/leds/green/brightness";
56
57char const*const BLUE_LED_FILE
58 = "/sys/class/leds/blue/brightness";
59
60char const*const LCD_FILE
61 = "/sys/class/leds/lcd-backlight/brightness";
62
Saurabh Shah8b021cf2017-03-14 12:16:43 -070063char const*const LCD_FILE2
64 = "/sys/class/backlight/panel0-backlight/brightness";
65
HuiWangf73bc572013-07-31 10:48:36 +080066char const*const BUTTON_FILE
67 = "/sys/class/leds/button-backlight/brightness";
68
samin.ryud57c7d52012-08-03 23:59:41 +090069char const*const RED_BLINK_FILE
Yulian Shandorov784d7392013-06-20 04:28:59 -070070 = "/sys/class/leds/red/blink";
samin.ryud57c7d52012-08-03 23:59:41 +090071
Ameya Thakur192c8ac2013-08-12 16:50:01 -070072char const*const GREEN_BLINK_FILE
73 = "/sys/class/leds/green/blink";
74
75char const*const BLUE_BLINK_FILE
76 = "/sys/class/leds/blue/blink";
77
Sathish Ambley4342f272017-01-04 10:57:05 -080078char const*const PERSISTENCE_FILE
79 = "/sys/class/graphics/fb0/msm_fb_persist_mode";
80
Sungmin Choib5148892012-07-02 17:00:07 -070081/**
82 * device methods
83 */
84
85void init_globals(void)
86{
87 // init the mutex
88 pthread_mutex_init(&g_lock, NULL);
89}
90
91static int
92write_int(char const* path, int value)
93{
94 int fd;
95 static int already_warned = 0;
96
97 fd = open(path, O_RDWR);
98 if (fd >= 0) {
99 char buffer[20];
Manoj Kumar AVM001b3092014-04-29 22:08:51 -0700100 int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
Dileep Kumar Reddibf333c72014-02-25 14:32:51 +0530101 ssize_t amt = write(fd, buffer, (size_t)bytes);
Sungmin Choib5148892012-07-02 17:00:07 -0700102 close(fd);
103 return amt == -1 ? -errno : 0;
104 } else {
105 if (already_warned == 0) {
106 ALOGE("write_int failed to open %s\n", path);
107 already_warned = 1;
108 }
109 return -errno;
110 }
111}
112
113static int
114is_lit(struct light_state_t const* state)
115{
116 return state->color & 0x00ffffff;
117}
118
119static int
120rgb_to_brightness(struct light_state_t const* state)
121{
122 int color = state->color & 0x00ffffff;
123 return ((77*((color>>16)&0x00ff))
124 + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
125}
126
127static int
128set_light_backlight(struct light_device_t* dev,
129 struct light_state_t const* state)
130{
131 int err = 0;
132 int brightness = rgb_to_brightness(state);
Sathish Ambley4342f272017-01-04 10:57:05 -0800133 unsigned int lpEnabled =
134 state->brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE;
Arun Kumar K.R0efad602014-01-21 21:32:36 -0800135 if(!dev) {
136 return -1;
137 }
Sathish Ambley4342f272017-01-04 10:57:05 -0800138
Sungmin Choib5148892012-07-02 17:00:07 -0700139 pthread_mutex_lock(&g_lock);
Sathish Ambley4342f272017-01-04 10:57:05 -0800140 // Toggle low persistence mode state
Pullakavi Srinivasda0b3252017-10-12 17:50:41 +0530141 bool persistence_mode = ((g_last_backlight_mode != state->brightnessMode && lpEnabled) ||
142 (!lpEnabled &&
143 g_last_backlight_mode == BRIGHTNESS_MODE_LOW_PERSISTENCE));
144 bool cannot_handle_persistence = !g_has_persistence_node && persistence_mode;
145 if (g_has_persistence_node) {
146 if (persistence_mode) {
147 if ((err = write_int(PERSISTENCE_FILE, lpEnabled)) != 0) {
148 ALOGE("%s: Failed to write to %s: %s\n", __FUNCTION__,
149 PERSISTENCE_FILE, strerror(errno));
150 }
151 if (lpEnabled != 0) {
152 brightness = DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS;
153 }
Sathish Ambley4342f272017-01-04 10:57:05 -0800154 }
Pullakavi Srinivasda0b3252017-10-12 17:50:41 +0530155 g_last_backlight_mode = state->brightnessMode;
Sathish Ambley4342f272017-01-04 10:57:05 -0800156 }
157
Sathish Ambley4342f272017-01-04 10:57:05 -0800158 if (!err) {
Saurabh Shah8b021cf2017-03-14 12:16:43 -0700159 if (!access(LCD_FILE, F_OK)) {
160 err = write_int(LCD_FILE, brightness);
161 } else {
162 err = write_int(LCD_FILE2, brightness);
163 }
Sathish Ambley4342f272017-01-04 10:57:05 -0800164 }
165
Sungmin Choib5148892012-07-02 17:00:07 -0700166 pthread_mutex_unlock(&g_lock);
Pullakavi Srinivasda0b3252017-10-12 17:50:41 +0530167 return cannot_handle_persistence ? -ENOSYS : err;
Sungmin Choib5148892012-07-02 17:00:07 -0700168}
169
170static int
171set_speaker_light_locked(struct light_device_t* dev,
172 struct light_state_t const* state)
173{
Arun Kumar K.R0efad602014-01-21 21:32:36 -0800174 int red, green, blue;
Yulian Shandorov784d7392013-06-20 04:28:59 -0700175 int blink;
Sungmin Choib5148892012-07-02 17:00:07 -0700176 int onMS, offMS;
177 unsigned int colorRGB;
178
Arun Kumar K.R0efad602014-01-21 21:32:36 -0800179 if(!dev) {
180 return -1;
181 }
182
Sungmin Choib5148892012-07-02 17:00:07 -0700183 switch (state->flashMode) {
184 case LIGHT_FLASH_TIMED:
185 onMS = state->flashOnMS;
186 offMS = state->flashOffMS;
187 break;
188 case LIGHT_FLASH_NONE:
189 default:
190 onMS = 0;
191 offMS = 0;
192 break;
193 }
194
195 colorRGB = state->color;
196
197#if 0
samin.ryud57c7d52012-08-03 23:59:41 +0900198 ALOGD("set_speaker_light_locked mode %d, colorRGB=%08X, onMS=%d, offMS=%d\n",
199 state->flashMode, colorRGB, onMS, offMS);
Sungmin Choib5148892012-07-02 17:00:07 -0700200#endif
201
202 red = (colorRGB >> 16) & 0xFF;
203 green = (colorRGB >> 8) & 0xFF;
204 blue = colorRGB & 0xFF;
205
Sungmin Choib5148892012-07-02 17:00:07 -0700206 if (onMS > 0 && offMS > 0) {
Ashay Jaiswal26f0b532015-05-03 17:58:58 +0530207 /*
208 * if ON time == OFF time
209 * use blink mode 2
210 * else
211 * use blink mode 1
212 */
213 if (onMS == offMS)
214 blink = 2;
215 else
216 blink = 1;
Sungmin Choib5148892012-07-02 17:00:07 -0700217 } else {
218 blink = 0;
Sungmin Choib5148892012-07-02 17:00:07 -0700219 }
220
221 if (blink) {
Mao Li728ee0b2014-07-01 23:06:16 +0800222 if (red) {
223 if (write_int(RED_BLINK_FILE, blink))
224 write_int(RED_LED_FILE, 0);
Ch Ganesh Kumaraf75ef52018-03-14 16:51:43 +0530225 }
Mao Li728ee0b2014-07-01 23:06:16 +0800226 if (green) {
227 if (write_int(GREEN_BLINK_FILE, blink))
228 write_int(GREEN_LED_FILE, 0);
Ch Ganesh Kumaraf75ef52018-03-14 16:51:43 +0530229 }
Mao Li728ee0b2014-07-01 23:06:16 +0800230 if (blue) {
231 if (write_int(BLUE_BLINK_FILE, blink))
232 write_int(BLUE_LED_FILE, 0);
Ch Ganesh Kumaraf75ef52018-03-14 16:51:43 +0530233 }
Yulian Shandorov784d7392013-06-20 04:28:59 -0700234 } else {
235 write_int(RED_LED_FILE, red);
236 write_int(GREEN_LED_FILE, green);
237 write_int(BLUE_LED_FILE, blue);
Sungmin Choib5148892012-07-02 17:00:07 -0700238 }
Sungmin Choib5148892012-07-02 17:00:07 -0700239
240 return 0;
241}
242
243static void
244handle_speaker_battery_locked(struct light_device_t* dev)
245{
246 if (is_lit(&g_battery)) {
247 set_speaker_light_locked(dev, &g_battery);
248 } else {
249 set_speaker_light_locked(dev, &g_notification);
250 }
251}
252
253static int
Mao Lia4e053a2014-06-16 23:05:17 +0530254set_light_battery(struct light_device_t* dev,
255 struct light_state_t const* state)
256{
257 pthread_mutex_lock(&g_lock);
258 g_battery = *state;
259 handle_speaker_battery_locked(dev);
260 pthread_mutex_unlock(&g_lock);
261 return 0;
262}
263
264static int
Sungmin Choib5148892012-07-02 17:00:07 -0700265set_light_notifications(struct light_device_t* dev,
266 struct light_state_t const* state)
267{
268 pthread_mutex_lock(&g_lock);
269 g_notification = *state;
270 handle_speaker_battery_locked(dev);
271 pthread_mutex_unlock(&g_lock);
272 return 0;
273}
274
275static int
276set_light_attention(struct light_device_t* dev,
277 struct light_state_t const* state)
278{
279 pthread_mutex_lock(&g_lock);
280 if (state->flashMode == LIGHT_FLASH_HARDWARE) {
281 g_attention = state->flashOnMS;
282 } else if (state->flashMode == LIGHT_FLASH_NONE) {
283 g_attention = 0;
284 }
285 handle_speaker_battery_locked(dev);
286 pthread_mutex_unlock(&g_lock);
287 return 0;
288}
289
Arun Kumar K.Redd99982017-08-23 08:09:06 +0530290static int
291set_light_buttons(struct light_device_t* dev,
292 struct light_state_t const* state)
293{
294 int err = 0;
295 if(!dev) {
296 return -1;
297 }
298 pthread_mutex_lock(&g_lock);
299 err = write_int(BUTTON_FILE, state->color & 0xFF);
300 pthread_mutex_unlock(&g_lock);
301 return err;
302}
303
Sungmin Choib5148892012-07-02 17:00:07 -0700304/** Close the lights device */
305static int
306close_lights(struct light_device_t *dev)
307{
308 if (dev) {
309 free(dev);
310 }
311 return 0;
312}
313
314
315/******************************************************************************/
316
317/**
318 * module methods
319 */
320
321/** Open a new instance of a lights device using name */
322static int open_lights(const struct hw_module_t* module, char const* name,
323 struct hw_device_t** device)
324{
325 int (*set_light)(struct light_device_t* dev,
326 struct light_state_t const* state);
327
Xu Yang586c6d52016-09-19 17:54:16 +0800328 if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {
Ch Ganesh Kumaraf75ef52018-03-14 16:51:43 +0530329 g_has_persistence_node = !access(PERSISTENCE_FILE, F_OK);
330 set_light = set_light_backlight;
Xu Yang586c6d52016-09-19 17:54:16 +0800331 } else if (0 == strcmp(LIGHT_ID_BATTERY, name))
Mao Lia4e053a2014-06-16 23:05:17 +0530332 set_light = set_light_battery;
Sungmin Choib5148892012-07-02 17:00:07 -0700333 else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
334 set_light = set_light_notifications;
Arun Kumar K.R9ae5a342017-08-23 13:46:03 +0530335 else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) {
336 if (!access(BUTTON_FILE, F_OK)) {
337 // enable light button when the file is present
338 set_light = set_light_buttons;
339 } else {
340 return -EINVAL;
341 }
342 }
Sungmin Choib5148892012-07-02 17:00:07 -0700343 else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
344 set_light = set_light_attention;
345 else
346 return -EINVAL;
347
348 pthread_once(&g_init, init_globals);
349
350 struct light_device_t *dev = malloc(sizeof(struct light_device_t));
Manoj Kumar AVM001b3092014-04-29 22:08:51 -0700351
352 if(!dev)
353 return -ENOMEM;
354
Sungmin Choib5148892012-07-02 17:00:07 -0700355 memset(dev, 0, sizeof(*dev));
356
357 dev->common.tag = HARDWARE_DEVICE_TAG;
Sathish Ambley4342f272017-01-04 10:57:05 -0800358 dev->common.version = LIGHTS_DEVICE_API_VERSION_2_0;
Sungmin Choib5148892012-07-02 17:00:07 -0700359 dev->common.module = (struct hw_module_t*)module;
360 dev->common.close = (int (*)(struct hw_device_t*))close_lights;
361 dev->set_light = set_light;
362
363 *device = (struct hw_device_t*)dev;
364 return 0;
365}
366
367static struct hw_module_methods_t lights_module_methods = {
368 .open = open_lights,
369};
370
371/*
372 * The lights Module
373 */
374struct hw_module_t HAL_MODULE_INFO_SYM = {
375 .tag = HARDWARE_MODULE_TAG,
376 .version_major = 1,
377 .version_minor = 0,
378 .id = LIGHTS_HARDWARE_MODULE_ID,
379 .name = "lights Module",
380 .author = "Google, Inc.",
381 .methods = &lights_module_methods,
382};