2 * Copyright (C) 2011 The Android Open Source Project
3 * Copyright (C) 2011 The CyanogenMod Project
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #define LOG_TAG "lights"
22 #include <cutils/log.h>
31 #include <sys/ioctl.h>
32 #include <sys/types.h>
34 #include <hardware/lights.h>
36 /******************************************************************************/
38 static pthread_once_t g_init
= PTHREAD_ONCE_INIT
;
39 static pthread_mutex_t g_lock
= PTHREAD_MUTEX_INITIALIZER
;
40 static int g_enable_touchlight
= -1;
42 char const*const PANEL_FILE
43 = "/sys/class/backlight/panel/brightness";
45 #ifndef EXYNOS4210_TABLET
46 char const*const BUTTON_FILE
47 = "/sys/class/sec/sec_touchkey/brightness";
50 #ifdef LED_NOTIFICATION
51 static char const RED_LED_DIR
[] = "/sys/class/leds/red";
52 static char const BLUE_LED_DIR
[] = "/sys/class/leds/blue";
53 #endif // LED_NOTIFICATION
54 void init_globals(void)
57 pthread_mutex_init(&g_lock
, NULL
);
63 FILE* fp
= fopen("/data/.disable_touchlight", "r");
65 g_enable_touchlight
= 1;
67 g_enable_touchlight
= (int)(fgetc(fp
));
68 if (g_enable_touchlight
== '1')
69 g_enable_touchlight
= 1;
71 g_enable_touchlight
= 0;
77 #ifdef LED_NOTIFICATION
78 static struct led_state
{
80 int delay_on
, delay_off
;
81 } battery_red
, battery_blue
, notifications_red
, notifications_blue
;
82 #endif // LED_NOTIFICATION
84 write_int(char const* path
, int value
)
87 static int already_warned
= 0;
89 fd
= open(path
, O_RDWR
);
92 int bytes
= sprintf(buffer
, "%d\n", value
);
93 int amt
= write(fd
, buffer
, bytes
);
95 return amt
== -1 ? -errno
: 0;
97 if (already_warned
== 0) {
98 ALOGE("write_int failed to open %s\n", path
);
105 #ifdef LED_NOTIFICATION
106 static int write_str(char const *path
, char const *str
)
109 static int already_warned
= 0;
111 ALOGV("write_str: path=\"%s\", str=\"%s\".", path
, str
);
112 fd
= open(path
, O_RDWR
);
115 int amt
= write(fd
, str
, strlen(str
));
117 return amt
== -1 ? -errno
: 0;
119 if (already_warned
== 0) {
120 ALOGE("write_str failed to open %s\n", path
);
127 /* Should check for snprintf truncation, but as these functions only use
128 * internal paths, meh. */
129 static int write_df_int(char const *dir
, char const *file
, int value
)
132 snprintf(path
, sizeof(path
), "%s/%s", dir
, file
);
133 return write_int(path
, value
);
136 static int write_df_str(char const *dir
, char const *file
, char const *str
)
139 snprintf(path
, sizeof(path
), "%s/%s", dir
, file
);
140 return write_str(path
, str
);
142 #endif // LED_NOTIFICATION
145 is_lit(struct light_state_t
const* state
)
147 return state
->color
& 0x00ffffff;
151 rgb_to_brightness(struct light_state_t
const* state
)
153 int color
= state
->color
& 0x00ffffff;
154 return ((77*((color
>>16)&0x00ff))
155 + (150*((color
>>8)&0x00ff)) + (29*(color
&0x00ff))) >> 8;
158 #ifdef LED_NOTIFICATION
159 static void comp_led_states(struct led_state
*red
, struct led_state
*blue
,
160 struct light_state_t
const* state
)
162 unsigned int color
= state
->color
;
163 int delay_on
, delay_off
;
165 switch (state
->flashMode
) {
166 case LIGHT_FLASH_TIMED
:
167 delay_on
= state
->flashOnMS
;
168 delay_off
= state
->flashOffMS
;
171 ALOGI("Unsuported flashMode %d, default to NONE.", state
->flashMode
);
172 case LIGHT_FLASH_NONE
:
173 delay_on
= delay_off
= 0;
177 red
->enabled
= !!(color
>> 16 & 0xff);
178 red
->delay_on
= delay_on
;
179 red
->delay_off
= delay_off
;
181 blue
->enabled
= !!(color
& 0xff);
182 blue
->delay_on
= delay_on
;
183 blue
->delay_off
= delay_off
;
185 ALOGV("comp_led_states: red=(%u, %d, %d), blue=(%u, %d, %d).",
186 red
->enabled
, red
->delay_on
, red
->delay_off
, blue
->enabled
,
187 blue
->delay_on
, blue
->delay_off
);
190 static int set_led(char const *dir
, struct led_state
const *battery
,
191 struct led_state
const *notifications
)
194 struct led_state
const *state
= NULL
;
197 if (notifications
->enabled
)
198 state
= notifications
;
199 else if (battery
->enabled
)
203 int delay_on
= state
->delay_on
;
204 int delay_off
= state
->delay_off
;
206 if (delay_on
> 0 && delay_off
> 0) {
207 /* Handling of blink_count is wrong in the kernel, blinking indefinitely
208 * for any non-zero value. TW lights just sets it to 1. */
209 if ((res
= write_df_str(dir
, "trigger", "notification")) < 0) return res
;
210 if ((res
= write_df_str(dir
, "brightness", "255" )) < 0) return res
;
211 if ((res
= write_df_str(dir
, "blink_count", "1" )) < 0) return res
;
212 if ((res
= write_df_int(dir
, "delay_on", delay_on
)) < 0) return res
;
213 if ((res
= write_df_int(dir
, "delay_off", delay_off
)) < 0) return res
;
215 if ((res
= write_df_str(dir
, "trigger", "none")) < 0) return res
;
216 if ((res
= write_df_str(dir
, "brightness", "255" )) < 0) return res
;
219 if ((res
= write_df_str(dir
, "trigger", "none")) < 0) return res
;
220 if ((res
= write_df_str(dir
, "brightness", "0" )) < 0) return res
;
225 #endif // LED_NOTIFICATION
228 set_light_backlight(struct light_device_t
* dev
,
229 struct light_state_t
const* state
)
232 static int s_previous_brightness
= -1;
233 int brightness
= rgb_to_brightness(state
);
235 pthread_mutex_lock(&g_lock
);
236 err
= write_int(PANEL_FILE
, brightness
);
238 #ifndef EXYNOS4210_TABLET
239 if (!s_previous_brightness
&& (brightness
> 0)) {
240 err
= write_int(BUTTON_FILE
, brightness
> 0 ? 1 : 2);
241 s_previous_brightness
= brightness
;
245 pthread_mutex_unlock(&g_lock
);
251 set_light_buttons(struct light_device_t
* dev
,
252 struct light_state_t
const* state
)
254 #ifdef EXYNOS4210_TABLET
262 pthread_mutex_lock(&g_lock
);
263 ALOGD("set_light_button on=%d\n", g_enable_touchlight
? 1 : 0);
264 err
= write_int(BUTTON_FILE
, g_enable_touchlight
? 1 : 0);
265 pthread_mutex_unlock(&g_lock
);
272 set_light_battery(struct light_device_t
* dev
,
273 struct light_state_t
const* state
)
277 #ifdef LED_NOTIFICATION
278 ALOGD("set_light_battery: color=%#010x, fM=%u, fOnMS=%d, fOffMs=%d.",
279 state
->color
, state
->flashMode
, state
->flashOnMS
, state
->flashOffMS
);
281 pthread_mutex_lock(&g_lock
);
283 comp_led_states(&battery_red
, &battery_blue
, state
);
285 if ((res
= set_led(RED_LED_DIR
, &battery_red
, ¬ifications_red
)) >= 0)
286 res
= set_led(BLUE_LED_DIR
, &battery_blue
, ¬ifications_blue
);
288 pthread_mutex_unlock(&g_lock
);
289 #endif // LED_NOTIFICATION
295 set_light_notification(struct light_device_t
* dev
,
296 struct light_state_t
const* state
)
300 #ifdef LED_NOTIFICATION
301 ALOGD("set_light_notification: color=%#010x, fM=%u, fOnMS=%d, fOffMs=%d.",
302 state
->color
, state
->flashMode
, state
->flashOnMS
, state
->flashOffMS
);
304 pthread_mutex_lock(&g_lock
);
306 comp_led_states(¬ifications_red
, ¬ifications_blue
, state
);
308 if ((res
= set_led(RED_LED_DIR
, &battery_red
, ¬ifications_red
)) >= 0)
309 res
= set_led(BLUE_LED_DIR
, &battery_blue
, ¬ifications_blue
);
311 pthread_mutex_unlock(&g_lock
);
312 #endif // LED_NOTIFICATION
318 close_lights(struct light_device_t
*dev
)
327 /******************************************************************************/
328 static int open_lights(const struct hw_module_t
* module
, char const* name
,
329 struct hw_device_t
** device
)
331 int (*set_light
)(struct light_device_t
* dev
,
332 struct light_state_t
const* state
);
334 if (0 == strcmp(LIGHT_ID_BACKLIGHT
, name
)) {
335 set_light
= set_light_backlight
;
337 else if (0 == strcmp(LIGHT_ID_BUTTONS
, name
)) {
338 set_light
= set_light_buttons
;
340 else if (0 == strcmp(LIGHT_ID_BATTERY
, name
)) {
341 set_light
= set_light_battery
;
343 else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS
, name
)) {
344 set_light
= set_light_notification
;
350 pthread_once(&g_init
, init_globals
);
352 struct light_device_t
*dev
= malloc(sizeof(struct light_device_t
));
353 memset(dev
, 0, sizeof(*dev
));
355 dev
->common
.tag
= HARDWARE_DEVICE_TAG
;
356 dev
->common
.version
= 0;
357 dev
->common
.module
= (struct hw_module_t
*)module
;
358 dev
->common
.close
= (int (*)(struct hw_device_t
*))close_lights
;
359 dev
->set_light
= set_light
;
361 *device
= (struct hw_device_t
*)dev
;
366 static struct hw_module_methods_t lights_module_methods
= {
370 struct hw_module_t HAL_MODULE_INFO_SYM
= {
371 .tag
= HARDWARE_MODULE_TAG
,
374 .id
= LIGHTS_HARDWARE_MODULE_ID
,
375 .name
= "Samsung Exynos4210 Lights Module",
376 .author
= "The CyanogenMod Project",
377 .methods
= &lights_module_methods
,