blob: 1ca12323dc324080e119b4b9eeb52e6c22c9b40e [file] [log] [blame]
Sungmin Choib5148892012-07-02 17:00:07 -07001/*
Ch Ganesh Kumar71f50f32018-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 Ahmed79dc3b02018-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
yutingshih706133f2020-04-21 15:56:11 +080041/* #define ARIMA_DEBUG */
42
43#ifdef ARIMA_DEBUG
44#define LIGHT_DBG(fmt,args...) ALOGE("[ARIMA][%s] " fmt, __FUNCTION__, ##args)
45#else
46#define LIGHT_DBG(fmt,args...) do {} while (0)
47#endif
48
49#define LED_FIRST_NOTIFICATION 1
50
Sungmin Choib5148892012-07-02 17:00:07 -070051/******************************************************************************/
52
53static pthread_once_t g_init = PTHREAD_ONCE_INIT;
54static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
55static struct light_state_t g_notification;
56static struct light_state_t g_battery;
Sathish Ambley4342f272017-01-04 10:57:05 -080057static int g_last_backlight_mode = BRIGHTNESS_MODE_USER;
Sungmin Choib5148892012-07-02 17:00:07 -070058static int g_attention = 0;
59
60char const*const RED_LED_FILE
61 = "/sys/class/leds/red/brightness";
62
63char const*const GREEN_LED_FILE
64 = "/sys/class/leds/green/brightness";
65
66char const*const BLUE_LED_FILE
67 = "/sys/class/leds/blue/brightness";
68
69char const*const LCD_FILE
70 = "/sys/class/leds/lcd-backlight/brightness";
71
Saurabh Shah8b021cf2017-03-14 12:16:43 -070072char const*const LCD_FILE2
73 = "/sys/class/backlight/panel0-backlight/brightness";
74
HuiWangf73bc572013-07-31 10:48:36 +080075char const*const BUTTON_FILE
76 = "/sys/class/leds/button-backlight/brightness";
77
samin.ryud57c7d52012-08-03 23:59:41 +090078char const*const RED_BLINK_FILE
yutingshih706133f2020-04-21 15:56:11 +080079 = "/sys/class/leds/red/breath";
samin.ryud57c7d52012-08-03 23:59:41 +090080
Ameya Thakur192c8ac2013-08-12 16:50:01 -070081char const*const GREEN_BLINK_FILE
yutingshih706133f2020-04-21 15:56:11 +080082 = "/sys/class/leds/green/breath";
Ameya Thakur192c8ac2013-08-12 16:50:01 -070083
84char const*const BLUE_BLINK_FILE
yutingshih706133f2020-04-21 15:56:11 +080085 = "/sys/class/leds/blue/breath";
Ameya Thakur192c8ac2013-08-12 16:50:01 -070086
Sathish Ambley4342f272017-01-04 10:57:05 -080087char const*const PERSISTENCE_FILE
88 = "/sys/class/graphics/fb0/msm_fb_persist_mode";
89
Sungmin Choib5148892012-07-02 17:00:07 -070090/**
91 * device methods
92 */
93
94void init_globals(void)
95{
96 // init the mutex
97 pthread_mutex_init(&g_lock, NULL);
98}
99
100static int
101write_int(char const* path, int value)
102{
103 int fd;
104 static int already_warned = 0;
105
106 fd = open(path, O_RDWR);
107 if (fd >= 0) {
108 char buffer[20];
Manoj Kumar AVM001b3092014-04-29 22:08:51 -0700109 int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
Dileep Kumar Reddibf333c72014-02-25 14:32:51 +0530110 ssize_t amt = write(fd, buffer, (size_t)bytes);
Sungmin Choib5148892012-07-02 17:00:07 -0700111 close(fd);
112 return amt == -1 ? -errno : 0;
113 } else {
114 if (already_warned == 0) {
115 ALOGE("write_int failed to open %s\n", path);
116 already_warned = 1;
117 }
118 return -errno;
119 }
120}
121
122static int
123is_lit(struct light_state_t const* state)
124{
125 return state->color & 0x00ffffff;
126}
127
128static int
129rgb_to_brightness(struct light_state_t const* state)
130{
131 int color = state->color & 0x00ffffff;
132 return ((77*((color>>16)&0x00ff))
133 + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
134}
135
136static int
137set_light_backlight(struct light_device_t* dev,
138 struct light_state_t const* state)
139{
140 int err = 0;
141 int brightness = rgb_to_brightness(state);
Sathish Ambley4342f272017-01-04 10:57:05 -0800142 unsigned int lpEnabled =
143 state->brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE;
Arun Kumar K.R0efad602014-01-21 21:32:36 -0800144 if(!dev) {
145 return -1;
146 }
Sathish Ambley4342f272017-01-04 10:57:05 -0800147
Sungmin Choib5148892012-07-02 17:00:07 -0700148 pthread_mutex_lock(&g_lock);
Sathish Ambley4342f272017-01-04 10:57:05 -0800149 // Toggle low persistence mode state
150 if ((g_last_backlight_mode != state->brightnessMode && lpEnabled) ||
151 (!lpEnabled &&
152 g_last_backlight_mode == BRIGHTNESS_MODE_LOW_PERSISTENCE)) {
153 if ((err = write_int(PERSISTENCE_FILE, lpEnabled)) != 0) {
154 ALOGE("%s: Failed to write to %s: %s\n", __FUNCTION__,
155 PERSISTENCE_FILE, strerror(errno));
156 }
157 if (lpEnabled != 0) {
158 brightness = DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS;
159 }
160 }
161
162 g_last_backlight_mode = state->brightnessMode;
163
164 if (!err) {
Saurabh Shah8b021cf2017-03-14 12:16:43 -0700165 if (!access(LCD_FILE, F_OK)) {
166 err = write_int(LCD_FILE, brightness);
167 } else {
168 err = write_int(LCD_FILE2, brightness);
169 }
Sathish Ambley4342f272017-01-04 10:57:05 -0800170 }
171
Sungmin Choib5148892012-07-02 17:00:07 -0700172 pthread_mutex_unlock(&g_lock);
173 return err;
174}
175
176static int
177set_speaker_light_locked(struct light_device_t* dev,
178 struct light_state_t const* state)
179{
Arun Kumar K.R0efad602014-01-21 21:32:36 -0800180 int red, green, blue;
Yulian Shandorov784d7392013-06-20 04:28:59 -0700181 int blink;
Sungmin Choib5148892012-07-02 17:00:07 -0700182 int onMS, offMS;
183 unsigned int colorRGB;
184
Arun Kumar K.R0efad602014-01-21 21:32:36 -0800185 if(!dev) {
186 return -1;
187 }
188
Sungmin Choib5148892012-07-02 17:00:07 -0700189 switch (state->flashMode) {
190 case LIGHT_FLASH_TIMED:
191 onMS = state->flashOnMS;
192 offMS = state->flashOffMS;
193 break;
194 case LIGHT_FLASH_NONE:
195 default:
196 onMS = 0;
197 offMS = 0;
198 break;
199 }
200
201 colorRGB = state->color;
202
203#if 0
samin.ryud57c7d52012-08-03 23:59:41 +0900204 ALOGD("set_speaker_light_locked mode %d, colorRGB=%08X, onMS=%d, offMS=%d\n",
205 state->flashMode, colorRGB, onMS, offMS);
Sungmin Choib5148892012-07-02 17:00:07 -0700206#endif
207
208 red = (colorRGB >> 16) & 0xFF;
209 green = (colorRGB >> 8) & 0xFF;
210 blue = colorRGB & 0xFF;
211
Sungmin Choib5148892012-07-02 17:00:07 -0700212 if (onMS > 0 && offMS > 0) {
Ashay Jaiswal26f0b532015-05-03 17:58:58 +0530213 /*
214 * if ON time == OFF time
215 * use blink mode 2
216 * else
217 * use blink mode 1
218 */
219 if (onMS == offMS)
220 blink = 2;
221 else
222 blink = 1;
Sungmin Choib5148892012-07-02 17:00:07 -0700223 } else {
224 blink = 0;
Sungmin Choib5148892012-07-02 17:00:07 -0700225 }
226
yutingshih706133f2020-04-21 15:56:11 +0800227 LIGHT_DBG("red=%02X, green=%02X, blue=%02X, blink=%d\n", red, green, blue, blink);
228
Sungmin Choib5148892012-07-02 17:00:07 -0700229 if (blink) {
yutingshih706133f2020-04-21 15:56:11 +0800230 write_int(RED_BLINK_FILE, 0);
231 write_int(GREEN_BLINK_FILE, 0);
232 write_int(BLUE_BLINK_FILE, 0);
233 /* Delay 6ms for off effective and complete */
234 usleep(6000);
235
Mao Li728ee0b2014-07-01 23:06:16 +0800236 if (red) {
237 if (write_int(RED_BLINK_FILE, blink))
238 write_int(RED_LED_FILE, 0);
yutingshih706133f2020-04-21 15:56:11 +0800239 } else {
240 write_int(RED_LED_FILE, 0);
Ch Ganesh Kumar71f50f32018-03-14 16:51:43 +0530241 }
yutingshih706133f2020-04-21 15:56:11 +0800242
Mao Li728ee0b2014-07-01 23:06:16 +0800243 if (green) {
244 if (write_int(GREEN_BLINK_FILE, blink))
245 write_int(GREEN_LED_FILE, 0);
yutingshih706133f2020-04-21 15:56:11 +0800246 } else {
247 write_int(GREEN_LED_FILE, 0);
Ch Ganesh Kumar71f50f32018-03-14 16:51:43 +0530248 }
yutingshih706133f2020-04-21 15:56:11 +0800249
Mao Li728ee0b2014-07-01 23:06:16 +0800250 if (blue) {
251 if (write_int(BLUE_BLINK_FILE, blink))
252 write_int(BLUE_LED_FILE, 0);
yutingshih706133f2020-04-21 15:56:11 +0800253 } else {
254 write_int(BLUE_LED_FILE, 0);
Ch Ganesh Kumar71f50f32018-03-14 16:51:43 +0530255 }
Yulian Shandorov784d7392013-06-20 04:28:59 -0700256 } else {
yutingshih706133f2020-04-21 15:56:11 +0800257 write_int(RED_LED_FILE, 0);
258 write_int(GREEN_LED_FILE, 0);
259 write_int(BLUE_LED_FILE, 0);
260 /* Delay 6ms for off effective and complete */
261 usleep(6000);
262
Yulian Shandorov784d7392013-06-20 04:28:59 -0700263 write_int(RED_LED_FILE, red);
264 write_int(GREEN_LED_FILE, green);
265 write_int(BLUE_LED_FILE, blue);
Sungmin Choib5148892012-07-02 17:00:07 -0700266 }
yutingshih706133f2020-04-21 15:56:11 +0800267 usleep(5000); /* 5ms */
Sungmin Choib5148892012-07-02 17:00:07 -0700268
269 return 0;
270}
271
272static void
273handle_speaker_battery_locked(struct light_device_t* dev)
274{
yutingshih706133f2020-04-21 15:56:11 +0800275#if LED_FIRST_NOTIFICATION
276 if (is_lit(&g_notification)) {
277 LIGHT_DBG("Notification\n");
278 set_speaker_light_locked(dev, &g_notification);
279 } else {
280 LIGHT_DBG("Battery\n");
281 set_speaker_light_locked(dev, &g_battery);
282 }
283#else /* Default */
Sungmin Choib5148892012-07-02 17:00:07 -0700284 if (is_lit(&g_battery)) {
285 set_speaker_light_locked(dev, &g_battery);
286 } else {
287 set_speaker_light_locked(dev, &g_notification);
288 }
yutingshih706133f2020-04-21 15:56:11 +0800289#endif
Sungmin Choib5148892012-07-02 17:00:07 -0700290}
291
292static int
Mao Lia4e053a2014-06-16 23:05:17 +0530293set_light_battery(struct light_device_t* dev,
294 struct light_state_t const* state)
295{
yutingshih706133f2020-04-21 15:56:11 +0800296 LIGHT_DBG("Enter...\n");
Mao Lia4e053a2014-06-16 23:05:17 +0530297 pthread_mutex_lock(&g_lock);
298 g_battery = *state;
299 handle_speaker_battery_locked(dev);
300 pthread_mutex_unlock(&g_lock);
301 return 0;
302}
303
304static int
Sungmin Choib5148892012-07-02 17:00:07 -0700305set_light_notifications(struct light_device_t* dev,
306 struct light_state_t const* state)
307{
yutingshih706133f2020-04-21 15:56:11 +0800308 LIGHT_DBG("Enter...\n");
Sungmin Choib5148892012-07-02 17:00:07 -0700309 pthread_mutex_lock(&g_lock);
310 g_notification = *state;
311 handle_speaker_battery_locked(dev);
312 pthread_mutex_unlock(&g_lock);
313 return 0;
314}
315
316static int
317set_light_attention(struct light_device_t* dev,
318 struct light_state_t const* state)
319{
320 pthread_mutex_lock(&g_lock);
321 if (state->flashMode == LIGHT_FLASH_HARDWARE) {
322 g_attention = state->flashOnMS;
323 } else if (state->flashMode == LIGHT_FLASH_NONE) {
324 g_attention = 0;
325 }
326 handle_speaker_battery_locked(dev);
327 pthread_mutex_unlock(&g_lock);
328 return 0;
329}
330
HuiWangf73bc572013-07-31 10:48:36 +0800331static int
332set_light_buttons(struct light_device_t* dev,
333 struct light_state_t const* state)
334{
335 int err = 0;
Arun Kumar K.R0efad602014-01-21 21:32:36 -0800336 if(!dev) {
337 return -1;
338 }
HuiWangf73bc572013-07-31 10:48:36 +0800339 pthread_mutex_lock(&g_lock);
340 err = write_int(BUTTON_FILE, state->color & 0xFF);
341 pthread_mutex_unlock(&g_lock);
342 return err;
343}
Sungmin Choib5148892012-07-02 17:00:07 -0700344
345/** Close the lights device */
346static int
347close_lights(struct light_device_t *dev)
348{
349 if (dev) {
350 free(dev);
351 }
352 return 0;
353}
354
355
356/******************************************************************************/
357
358/**
359 * module methods
360 */
361
362/** Open a new instance of a lights device using name */
363static int open_lights(const struct hw_module_t* module, char const* name,
364 struct hw_device_t** device)
365{
366 int (*set_light)(struct light_device_t* dev,
367 struct light_state_t const* state);
368
yutingshih706133f2020-04-21 15:56:11 +0800369 LIGHT_DBG("Enter...\n");
Xu Yang586c6d52016-09-19 17:54:16 +0800370 if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {
Ch Ganesh Kumar71f50f32018-03-14 16:51:43 +0530371 set_light = set_light_backlight;
Xu Yang586c6d52016-09-19 17:54:16 +0800372 } else if (0 == strcmp(LIGHT_ID_BATTERY, name))
Mao Lia4e053a2014-06-16 23:05:17 +0530373 set_light = set_light_battery;
Sungmin Choib5148892012-07-02 17:00:07 -0700374 else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
375 set_light = set_light_notifications;
Arun Kumar K.R9e35f2b2017-08-23 13:46:03 +0530376 else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) {
377 if (!access(BUTTON_FILE, F_OK)) {
378 // enable light button when the file is present
379 set_light = set_light_buttons;
380 } else {
381 return -EINVAL;
382 }
383 }
Sungmin Choib5148892012-07-02 17:00:07 -0700384 else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
385 set_light = set_light_attention;
386 else
387 return -EINVAL;
388
389 pthread_once(&g_init, init_globals);
390
391 struct light_device_t *dev = malloc(sizeof(struct light_device_t));
Manoj Kumar AVM001b3092014-04-29 22:08:51 -0700392
393 if(!dev)
394 return -ENOMEM;
395
Sungmin Choib5148892012-07-02 17:00:07 -0700396 memset(dev, 0, sizeof(*dev));
397
398 dev->common.tag = HARDWARE_DEVICE_TAG;
Sathish Ambley4342f272017-01-04 10:57:05 -0800399 dev->common.version = LIGHTS_DEVICE_API_VERSION_2_0;
Sungmin Choib5148892012-07-02 17:00:07 -0700400 dev->common.module = (struct hw_module_t*)module;
401 dev->common.close = (int (*)(struct hw_device_t*))close_lights;
402 dev->set_light = set_light;
403
404 *device = (struct hw_device_t*)dev;
405 return 0;
406}
407
408static struct hw_module_methods_t lights_module_methods = {
409 .open = open_lights,
410};
411
412/*
413 * The lights Module
414 */
415struct hw_module_t HAL_MODULE_INFO_SYM = {
416 .tag = HARDWARE_MODULE_TAG,
417 .version_major = 1,
418 .version_minor = 0,
419 .id = LIGHTS_HARDWARE_MODULE_ID,
420 .name = "lights Module",
421 .author = "Google, Inc.",
422 .methods = &lights_module_methods,
423};