replace power_profile.xml with stock one
[GitHub/mt8127/android_device_alcatel_ttab.git] / liblights / lights.c
CommitLineData
f3fa1980
S
1/*
2 * Copyright (C) 2016 The M.A.D. Team
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
18#define LOG_TAG "lights"
19
20#include <cutils/log.h>
21
22#include <stdint.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <pthread.h>
29
30#include <sys/ioctl.h>
31#include <sys/types.h>
32
33#include <hardware/lights.h>
34
35/******************************************************************************/
36
37static pthread_once_t g_init = PTHREAD_ONCE_INIT;
38static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
39static struct light_state_t g_attention;
40static struct light_state_t g_notification;
41static struct light_state_t g_battery;
42
43char const*const RED_LED_FILE
44 = "/sys/class/leds/red/brightness";
45
46char const*const GREEN_LED_FILE
47 = "/sys/class/leds/green/brightness";
48
49char const*const BLUE_LED_FILE
50 = "/sys/class/leds/blue/brightness";
51
52char const*const LCD_FILE
53 = "/sys/class/leds/lcd-backlight/brightness";
54
55char const*const BUTTONS_FILE
56 = "/sys/class/leds/button-backlight/brightness";
57
58/**
59 * device methods
60 */
61
62void init_globals(void)
63{
64 // init the mutex
65 pthread_mutex_init(&g_lock, NULL);
66}
67
68static int
69write_int(char const* path, int value)
70{
71 int fd;
72 static int already_warned = 0;
73
74 fd = open(path, O_RDWR);
75 if (fd >= 0) {
76 char buffer[20];
77 int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
78 ssize_t amt = write(fd, buffer, (size_t)bytes);
79 close(fd);
80 return amt == -1 ? -errno : 0;
81 } else {
82 if (already_warned == 0) {
83 ALOGE("write_int failed to open %s\n", path);
84 already_warned = 1;
85 }
86 return -errno;
87 }
88}
89
90static int
91is_lit(struct light_state_t const* state)
92{
93 return state->color & 0x00ffffff;
94}
95
96static int
97rgb_to_brightness(struct light_state_t const* state)
98{
99 int color = state->color & 0x00ffffff;
100 return ((77*((color>>16)&0x00ff))
101 + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
102}
103
104static int
105set_light_backlight(struct light_device_t* dev,
106 struct light_state_t const* state)
107{
108 if (!dev) {
109 return -1;
110 }
111 int err = 0;
112 int brightness = rgb_to_brightness(state);
113 pthread_mutex_lock(&g_lock);
114 err = write_int(LCD_FILE, brightness);
115 pthread_mutex_unlock(&g_lock);
116 return err;
117}
118
119static int
120set_light_buttons(struct light_device_t* dev,
121 struct light_state_t const* state)
122{
123 if (!dev) {
124 return -1;
125 }
126 int err = 0;
127 int on = is_lit(state);
128 pthread_mutex_lock(&g_lock);
129 err = write_int(BUTTONS_FILE, on ? 255 : 0);
130 pthread_mutex_unlock(&g_lock);
131 return err;
132}
133
134static int
135set_speaker_light_locked(struct light_device_t* dev,
136 struct light_state_t const* state)
137{
138 int red, green, blue, blink;
139 int onMS, offMS;
140 unsigned int colorRGB;
141
142 if (!dev) {
143 return -1;
144 }
145
146 switch (state->flashMode) {
147 case LIGHT_FLASH_TIMED:
148 onMS = state->flashOnMS;
149 offMS = state->flashOffMS;
150 break;
151 case LIGHT_FLASH_NONE:
152 default:
153 onMS = 0;
154 offMS = 0;
155 break;
156 }
157
158 colorRGB = state->color;
159
160 ALOGV("set_speaker_light_locked mode %d, colorRGB=%08X, onMS=%d, offMS=%d\n",
161 state->flashMode, colorRGB, onMS, offMS);
162
163 red = (colorRGB >> 16) & 0xFF;
164 green = (colorRGB >> 8) & 0xFF;
165 blue = colorRGB & 0xFF;
166 blink = onMS > 0 && offMS > 0;
167
168 write_int(RED_LED_FILE, 0);
169 write_int(GREEN_LED_FILE, 0);
170 write_int(BLUE_LED_FILE, 0);
171
172 if (blink) {
173 if (red >= 128) {
174 write_int(RED_LED_FILE, 128);
175 }
176 if (green >= 128) {
177 write_int(GREEN_LED_FILE, 128);
178 }
179 if (blue >= 128) {
180 write_int(BLUE_LED_FILE, 128);
181 }
182 }
183 else {
184 if (red >= 128) {
185 write_int(RED_LED_FILE, 255);
186 }
187 if (green >= 128) {
188 write_int(GREEN_LED_FILE, 255);
189 }
190 if (blue >= 128) {
191 write_int(BLUE_LED_FILE, 255);
192 }
193 }
194
195 return 0;
196}
197
198static void
199handle_speaker_light_locked(struct light_device_t* dev)
200{
201 if (is_lit(&g_attention)) {
202 set_speaker_light_locked(dev, &g_attention);
203 } else if (is_lit(&g_notification)) {
204 set_speaker_light_locked(dev, &g_notification);
205 } else {
206 set_speaker_light_locked(dev, &g_battery);
207 }
208}
209
210static int
211set_light_battery(struct light_device_t* dev,
212 struct light_state_t const* state)
213{
214 pthread_mutex_lock(&g_lock);
215 g_battery = *state;
216 handle_speaker_light_locked(dev);
217 pthread_mutex_unlock(&g_lock);
218 return 0;
219}
220
221static int
222set_light_notifications(struct light_device_t* dev,
223 struct light_state_t const* state)
224{
225 pthread_mutex_lock(&g_lock);
226 g_notification = *state;
227 handle_speaker_light_locked(dev);
228 pthread_mutex_unlock(&g_lock);
229 return 0;
230}
231
232static int
233set_light_attention(struct light_device_t* dev,
234 struct light_state_t const* state)
235{
236 pthread_mutex_lock(&g_lock);
237 g_attention = *state;
238 handle_speaker_light_locked(dev);
239 pthread_mutex_unlock(&g_lock);
240 return 0;
241}
242
243
244/** Close the lights device */
245static int
246close_lights(struct light_device_t *dev)
247{
248 if (dev) {
249 free(dev);
250 }
251 return 0;
252}
253
254
255/******************************************************************************/
256
257/**
258 * module methods
259 */
260
261/** Open a new instance of a lights device using name */
262static int open_lights(const struct hw_module_t* module, char const* name,
263 struct hw_device_t** device)
264{
265 int (*set_light)(struct light_device_t* dev,
266 struct light_state_t const* state);
267
268 if (0 == strcmp(LIGHT_ID_BACKLIGHT, name))
269 set_light = set_light_backlight;
270 else if (0 == strcmp(LIGHT_ID_BUTTONS, name))
271 set_light = set_light_buttons;
272 else if (0 == strcmp(LIGHT_ID_BATTERY, name))
273 set_light = set_light_battery;
274 else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
275 set_light = set_light_notifications;
276 else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
277 set_light = set_light_attention;
278 else
279 return -EINVAL;
280
281 pthread_once(&g_init, init_globals);
282
283 struct light_device_t *dev = malloc(sizeof(struct light_device_t));
284
285 if (!dev)
286 return -ENOMEM;
287
288 memset(dev, 0, sizeof(*dev));
289
290 dev->common.tag = HARDWARE_DEVICE_TAG;
291 dev->common.version = 0;
292 dev->common.module = (struct hw_module_t*)module;
293 dev->common.close = (int (*)(struct hw_device_t*))close_lights;
294 dev->set_light = set_light;
295
296 *device = (struct hw_device_t*)dev;
297 return 0;
298}
299
300
301static struct hw_module_methods_t lights_module_methods = {
302 .open = open_lights,
303};
304
305/*
306 * The lights Module
307 */
308struct hw_module_t HAL_MODULE_INFO_SYM = {
309 .tag = HARDWARE_MODULE_TAG,
310 .version_major = 1,
311 .version_minor = 0,
312 .id = LIGHTS_HARDWARE_MODULE_ID,
313 .name = "M.A.D. Lights Module",
314 .author = "M.A.D. Team",
315 .methods = &lights_module_methods,
316};