1 /*
2  * Copyright (C) 2014, 2017 The  Linux Foundation. All rights reserved.
3  * Not a contribution
4  * 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
21 
22 #include <cutils/log.h>
23 
24 #include <stdint.h>
25 #include <stdlib.h>
26 #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 
37 #ifndef DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS
38 #define DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS 0x80
39 #endif
40 
41 /******************************************************************************/
42 
43 static pthread_once_t g_init = PTHREAD_ONCE_INIT;
44 static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
45 static struct light_state_t g_notification;
46 static struct light_state_t g_battery;
47 static int g_last_backlight_mode = BRIGHTNESS_MODE_USER;
48 static int g_attention = 0;
49 
50 char const*const RED_LED_FILE
51         = "/sys/class/leds/red/brightness";
52 
53 char const*const GREEN_LED_FILE
54         = "/sys/class/leds/green/brightness";
55 
56 char const*const BLUE_LED_FILE
57         = "/sys/class/leds/blue/brightness";
58 
59 char const*const LCD_FILE
60         = "/sys/class/leds/lcd-backlight/brightness";
61 
62 char const*const BUTTON_FILE
63         = "/sys/class/leds/button-backlight/brightness";
64 
65 char const*const RED_BLINK_FILE
66         = "/sys/class/leds/red/blink";
67 
68 char const*const GREEN_BLINK_FILE
69         = "/sys/class/leds/green/blink";
70 
71 char const*const BLUE_BLINK_FILE
72         = "/sys/class/leds/blue/blink";
73 
74 char const*const PERSISTENCE_FILE
75         = "/sys/class/graphics/fb0/msm_fb_persist_mode";
76 
77 /**
78  * device methods
79  */
80 
init_globals(void)81 void init_globals(void)
82 {
83     // init the mutex
84     pthread_mutex_init(&g_lock, NULL);
85 }
86 
87 static int
write_int(char const * path,int value)88 write_int(char const* path, int value)
89 {
90     int fd;
91     static int already_warned = 0;
92 
93     fd = open(path, O_RDWR);
94     if (fd >= 0) {
95         char buffer[20];
96         int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
97         ssize_t amt = write(fd, buffer, (size_t)bytes);
98         close(fd);
99         return amt == -1 ? -errno : 0;
100     } else {
101         if (already_warned == 0) {
102             ALOGE("write_int failed to open %s\n", path);
103             already_warned = 1;
104         }
105         return -errno;
106     }
107 }
108 
109 static int
is_lit(struct light_state_t const * state)110 is_lit(struct light_state_t const* state)
111 {
112     return state->color & 0x00ffffff;
113 }
114 
115 static int
rgb_to_brightness(struct light_state_t const * state)116 rgb_to_brightness(struct light_state_t const* state)
117 {
118     int color = state->color & 0x00ffffff;
119     return ((77*((color>>16)&0x00ff))
120             + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
121 }
122 
123 static int
set_light_backlight(struct light_device_t * dev,struct light_state_t const * state)124 set_light_backlight(struct light_device_t* dev,
125         struct light_state_t const* state)
126 {
127     int err = 0;
128     int brightness = rgb_to_brightness(state);
129     unsigned int lpEnabled =
130         state->brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE;
131     if(!dev) {
132         return -1;
133     }
134 
135     pthread_mutex_lock(&g_lock);
136     // Toggle low persistence mode state
137     if ((g_last_backlight_mode != state->brightnessMode && lpEnabled) ||
138         (!lpEnabled &&
139          g_last_backlight_mode == BRIGHTNESS_MODE_LOW_PERSISTENCE)) {
140         if ((err = write_int(PERSISTENCE_FILE, lpEnabled)) != 0) {
141             ALOGE("%s: Failed to write to %s: %s\n", __FUNCTION__,
142                    PERSISTENCE_FILE, strerror(errno));
143         }
144         if (lpEnabled != 0) {
145             brightness = DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS;
146         }
147     }
148 
149     g_last_backlight_mode = state->brightnessMode;
150 
151     if (!err) {
152         err = write_int(LCD_FILE, brightness);
153     }
154 
155     pthread_mutex_unlock(&g_lock);
156     return err;
157 }
158 
159 static int
set_speaker_light_locked(struct light_device_t * dev,struct light_state_t const * state)160 set_speaker_light_locked(struct light_device_t* dev,
161         struct light_state_t const* state)
162 {
163     int red, green, blue;
164     int blink;
165     int onMS, offMS;
166     unsigned int colorRGB;
167 
168     if(!dev) {
169         return -1;
170     }
171 
172     switch (state->flashMode) {
173         case LIGHT_FLASH_TIMED:
174             onMS = state->flashOnMS;
175             offMS = state->flashOffMS;
176             break;
177         case LIGHT_FLASH_NONE:
178         default:
179             onMS = 0;
180             offMS = 0;
181             break;
182     }
183 
184     colorRGB = state->color;
185 
186 #if 0
187     ALOGD("set_speaker_light_locked mode %d, colorRGB=%08X, onMS=%d, offMS=%d\n",
188             state->flashMode, colorRGB, onMS, offMS);
189 #endif
190 
191     red = (colorRGB >> 16) & 0xFF;
192     green = (colorRGB >> 8) & 0xFF;
193     blue = colorRGB & 0xFF;
194 
195     if (onMS > 0 && offMS > 0) {
196         /*
197          * if ON time == OFF time
198          *   use blink mode 2
199          * else
200          *   use blink mode 1
201          */
202         if (onMS == offMS)
203             blink = 2;
204         else
205             blink = 1;
206     } else {
207         blink = 0;
208     }
209 
210     if (blink) {
211         if (red) {
212             if (write_int(RED_BLINK_FILE, blink))
213                 write_int(RED_LED_FILE, 0);
214 	}
215         if (green) {
216             if (write_int(GREEN_BLINK_FILE, blink))
217                 write_int(GREEN_LED_FILE, 0);
218 	}
219         if (blue) {
220             if (write_int(BLUE_BLINK_FILE, blink))
221                 write_int(BLUE_LED_FILE, 0);
222 	}
223     } else {
224         write_int(RED_LED_FILE, red);
225         write_int(GREEN_LED_FILE, green);
226         write_int(BLUE_LED_FILE, blue);
227     }
228 
229     return 0;
230 }
231 
232 static void
handle_speaker_battery_locked(struct light_device_t * dev)233 handle_speaker_battery_locked(struct light_device_t* dev)
234 {
235     if (is_lit(&g_battery)) {
236         set_speaker_light_locked(dev, &g_battery);
237     } else {
238         set_speaker_light_locked(dev, &g_notification);
239     }
240 }
241 
242 static int
set_light_battery(struct light_device_t * dev,struct light_state_t const * state)243 set_light_battery(struct light_device_t* dev,
244         struct light_state_t const* state)
245 {
246     pthread_mutex_lock(&g_lock);
247     g_battery = *state;
248     handle_speaker_battery_locked(dev);
249     pthread_mutex_unlock(&g_lock);
250     return 0;
251 }
252 
253 static int
set_light_notifications(struct light_device_t * dev,struct light_state_t const * state)254 set_light_notifications(struct light_device_t* dev,
255         struct light_state_t const* state)
256 {
257     pthread_mutex_lock(&g_lock);
258     g_notification = *state;
259     handle_speaker_battery_locked(dev);
260     pthread_mutex_unlock(&g_lock);
261     return 0;
262 }
263 
264 static int
set_light_attention(struct light_device_t * dev,struct light_state_t const * state)265 set_light_attention(struct light_device_t* dev,
266         struct light_state_t const* state)
267 {
268     pthread_mutex_lock(&g_lock);
269     if (state->flashMode == LIGHT_FLASH_HARDWARE) {
270         g_attention = state->flashOnMS;
271     } else if (state->flashMode == LIGHT_FLASH_NONE) {
272         g_attention = 0;
273     }
274     handle_speaker_battery_locked(dev);
275     pthread_mutex_unlock(&g_lock);
276     return 0;
277 }
278 
279 static int
set_light_buttons(struct light_device_t * dev,struct light_state_t const * state)280 set_light_buttons(struct light_device_t* dev,
281         struct light_state_t const* state)
282 {
283     int err = 0;
284     if(!dev) {
285         return -1;
286     }
287     pthread_mutex_lock(&g_lock);
288     err = write_int(BUTTON_FILE, state->color & 0xFF);
289     pthread_mutex_unlock(&g_lock);
290     return err;
291 }
292 
293 /** Close the lights device */
294 static int
close_lights(struct light_device_t * dev)295 close_lights(struct light_device_t *dev)
296 {
297     if (dev) {
298         free(dev);
299     }
300     return 0;
301 }
302 
303 
304 /******************************************************************************/
305 
306 /**
307  * module methods
308  */
309 
310 /** Open a new instance of a lights device using name */
open_lights(const struct hw_module_t * module,char const * name,struct hw_device_t ** device)311 static int open_lights(const struct hw_module_t* module, char const* name,
312         struct hw_device_t** device)
313 {
314     int (*set_light)(struct light_device_t* dev,
315             struct light_state_t const* state);
316 
317     if (0 == strcmp(LIGHT_ID_BACKLIGHT, name))
318         set_light = set_light_backlight;
319     else if (0 == strcmp(LIGHT_ID_BATTERY, name))
320         set_light = set_light_battery;
321     else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
322         set_light = set_light_notifications;
323     else if (0 == strcmp(LIGHT_ID_BUTTONS, name))
324         set_light = set_light_buttons;
325     else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
326         set_light = set_light_attention;
327     else
328         return -EINVAL;
329 
330     pthread_once(&g_init, init_globals);
331 
332     struct light_device_t *dev = malloc(sizeof(struct light_device_t));
333 
334     if(!dev)
335         return -ENOMEM;
336 
337     memset(dev, 0, sizeof(*dev));
338 
339     dev->common.tag = HARDWARE_DEVICE_TAG;
340     dev->common.version = LIGHTS_DEVICE_API_VERSION_2_0;
341     dev->common.module = (struct hw_module_t*)module;
342     dev->common.close = (int (*)(struct hw_device_t*))close_lights;
343     dev->set_light = set_light;
344 
345     *device = (struct hw_device_t*)dev;
346     return 0;
347 }
348 
349 static struct hw_module_methods_t lights_module_methods = {
350     .open =  open_lights,
351 };
352 
353 /*
354  * The lights Module
355  */
356 struct hw_module_t HAL_MODULE_INFO_SYM = {
357     .tag = HARDWARE_MODULE_TAG,
358     .version_major = 1,
359     .version_minor = 0,
360     .id = LIGHTS_HARDWARE_MODULE_ID,
361     .name = "lights Module",
362     .author = "Google, Inc.",
363     .methods = &lights_module_methods,
364 };
365