4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <sys/types.h>
34 #include "display-ops.h"
36 #include "shared/device-notifier.h"
37 #include <libsyscommon/ini-parser.h>
39 #define METHOD_CHECK_SUPPORTED "CheckSupported"
41 #define DISP_FORCE_SHIFT 12
42 #define DISP_FORCE_CMD(prop, force) (((force) << DISP_FORCE_SHIFT) | prop)
44 #define SAMPLING_INTERVAL 1 /* 1 sec */
45 #define MAX_SAMPLING_COUNT 3
47 #define DEFAULT_AUTOMATIC_BRT 5
48 #define AUTOMATIC_DEVIDE_VAL 10
49 #define AUTOMATIC_DELAY_TIME 500 /* 0.5 sec */
51 #define RADIAN_VALUE (57.2957)
52 #define ROTATION_90 90
53 #define WORKING_ANGLE_MIN 0
54 #define WORKING_ANGLE_MAX 20
56 #define BOARD_CONF_FILE "/etc/deviced/display.conf"
63 static struct _backlight_ops *backlight_ops;
64 static int (*_default_action) (int);
65 static guint alc_timeout_id = 0;
66 static guint update_timeout;
67 static sensor_listener_h light_listener;
68 static sensor_listener_h accel_listener;
69 static int fault_count;
70 static int automatic_brt = DEFAULT_AUTOMATIC_BRT;
71 static int min_brightness = PM_MIN_BRIGHTNESS;
72 static char *min_brightness_name = 0;
75 static float lmax, lmin;
76 static const struct display_config *display_conf;
78 static bool update_working_position(void)
82 float x, y, z, pitch, realg;
84 if (!display_conf->accel_sensor_on)
87 ret = sensor_listener_read_data(accel_listener, &data);
88 if (ret != SENSOR_ERROR_NONE) {
89 _E("Failed to get accelerometer data: %d", ret);
97 realg = (float)sqrt((x * x) + (y * y) + (z * z));
98 pitch = ROTATION_90 - abs((int) (asin(z / realg) * RADIAN_VALUE));
100 _D("Accel data x=%f y=%f z=%f pitch=%f", x, y, z, pitch);
102 if (pitch >= WORKING_ANGLE_MIN && pitch <= WORKING_ANGLE_MAX)
107 static void alc_set_brightness(int setting, int value, float light)
110 int position, tmp_value = 0, ret;
112 ret = backlight_ops->get_brightness(&tmp_value);
114 _E("Failed to get display brightness.");
118 if (value < min_brightness)
119 value = min_brightness;
121 if (tmp_value != value) {
122 if (!setting && min_brightness == PM_MIN_BRIGHTNESS &&
123 display_conf->accel_sensor_on == true) {
124 position = update_working_position();
125 if (!position && (old > light)) {
126 _D("It's not working position, "
127 "LCD isn't getting dark.");
133 diff = value - tmp_value;
134 if (abs(diff) < display_conf->brightness_change_step)
135 step = (diff > 0 ? 1 : -1);
137 step = (int)ceil(diff /
138 (float)display_conf->brightness_change_step);
141 while (tmp_value != value) {
142 if (step == 0) break;
145 if ((step > 0 && tmp_value > value) ||
146 (step < 0 && tmp_value < value))
149 backlight_ops->set_default_brt(tmp_value);
150 backlight_ops->update();
152 _I("Load light data(%f) auto brt=%d min brightness=%d "
153 "brightness=%d", light, automatic_brt, min_brightness, value);
158 static bool check_brightness_changed(int value)
161 static int values[MAX_SAMPLING_COUNT], count = 0;
163 if (count >= MAX_SAMPLING_COUNT || count < 0)
166 values[count++] = value;
168 for (i = 0; i < MAX_SAMPLING_COUNT - 1; i++)
169 if (values[i] != values[i+1])
174 static bool alc_update_brt(bool setting)
178 sensor_event_s light_data;
182 ret = sensor_listener_read_data(light_listener, &light_data);
183 if (ret != SENSOR_ERROR_NONE) {
184 _E("Failed to read light sensor data: %d", ret);
188 index = light_data.value_count - 1;
189 if (index < 0 || light_data.values[index] < 0) {
190 _E("Invalid light sensor data.");
194 light = light_data.values[index];
195 ret = backlight_ops->get_brightness_by_light_sensor(
196 lmax, lmin, light, &value);
197 if (ret == -ENOTSUP) {
198 _E("Not supported to handle the light data.");
202 if (ret < 0 || value < PM_MIN_BRIGHTNESS || value > PM_MAX_BRIGHTNESS) {
203 _E("Failed to load light data. light=%f value=%d: %d", light, value, ret);
209 if (display_conf->continuous_sampling &&
210 !check_brightness_changed(value) &&
214 alc_set_brightness(setting, value, light);
221 if ((fault_count > MAX_FAULT) && !(get_pm_status_flag() & PWROFF_FLAG)) {
222 if (alc_timeout_id) {
223 g_source_remove(alc_timeout_id);
226 ret = vconf_set_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT,
227 SETTING_BRIGHTNESS_AUTOMATIC_OFF);
229 _E("Failed to set vconf value for automatic brightness: %d", vconf_get_ext_errno());
230 _E("Fault counts is over %d, disable automatic brightness.", MAX_FAULT);
236 static gboolean alc_handler(void *data)
238 if (get_pm_cur_state() != S_NORMAL) {
239 if (alc_timeout_id > 0)
240 g_source_remove(alc_timeout_id);
242 return G_SOURCE_REMOVE;
245 if (!alc_update_brt(false))
246 return G_SOURCE_REMOVE;
248 if (alc_timeout_id != 0)
249 return G_SOURCE_CONTINUE;
251 return G_SOURCE_REMOVE;
254 static int alc_action(int timeout)
256 /* sampling timer add */
257 if (alc_timeout_id == 0 && !(get_pm_status_flag() & PWRSV_FLAG)) {
258 display_info.update_auto_brightness(true);
261 g_timeout_add_seconds(display_conf->lightsensor_interval,
265 if (_default_action != NULL)
266 return _default_action(timeout);
268 /* unreachable code */
272 static int connect_sensor(void)
276 sensor_h *list = NULL;
279 _I("Connect with sensor fw.");
281 ret = sensor_get_sensor_list(SENSOR_LIGHT, &list, &cnt);
282 if (ret != SENSOR_ERROR_NONE) {
283 _E("Failed to get light sensor list: %d", ret);
288 * Sensor apis will be fixed
289 * to provide which sensor is effective among sensors */
290 if (cnt == 3) /* three light sensors exist */
297 ret = sensor_get_min_range(sensor, &lmin);
298 if (ret != SENSOR_ERROR_NONE) {
299 _E("Failed to get light sensor min range: %d", ret);
302 ret = sensor_get_max_range(sensor, &lmax);
303 if (ret != SENSOR_ERROR_NONE) {
304 _E("Failed to get light sensor max range: %d", ret);
307 _I("Light sensor min=%f max=%f", lmin, lmax);
309 ret = sensor_create_listener(sensor, &light_listener);
310 if (ret != SENSOR_ERROR_NONE) {
311 _E("Failed to create listener(light).");
314 sensor_listener_set_option(light_listener, SENSOR_OPTION_ALWAYS_ON);
315 ret = sensor_listener_start(light_listener);
316 if (ret != SENSOR_ERROR_NONE) {
317 _E("Failed to start light sensor.");
318 sensor_destroy_listener(light_listener);
323 if (!display_conf->accel_sensor_on)
326 /* accelerometer sensor */
327 ret = sensor_get_default_sensor(SENSOR_ACCELEROMETER, &sensor);
328 if (ret != SENSOR_ERROR_NONE) {
329 _E("Failed to get default accel sensor.");
332 ret = sensor_create_listener(&sensor, &accel_listener);
333 if (ret != SENSOR_ERROR_NONE) {
334 _E("Failed to create listener(accel).");
337 sensor_listener_set_option(accel_listener, SENSOR_OPTION_ALWAYS_ON);
338 ret = sensor_listener_start(accel_listener);
339 if (ret != SENSOR_ERROR_NONE) {
340 _E("Failed to start accel sensor.");
341 sensor_destroy_listener(accel_listener);
351 if (light_listener > 0) {
352 sensor_listener_stop(light_listener);
353 sensor_destroy_listener(light_listener);
356 if (display_conf->accel_sensor_on && accel_listener > 0) {
357 sensor_listener_stop(accel_listener);
358 sensor_destroy_listener(accel_listener);
364 static int disconnect_sensor(void)
366 _I("Disconnect with sensor fw.");
368 if (light_listener > 0) {
369 sensor_listener_stop(light_listener);
370 sensor_destroy_listener(light_listener);
374 /* accelerometer sensor*/
375 if (display_conf->accel_sensor_on && accel_listener > 0) {
376 sensor_listener_stop(accel_listener);
377 sensor_destroy_listener(accel_listener);
381 if (_default_action != NULL) {
382 state_st(S_NORMAL)->action = _default_action;
383 _default_action = NULL;
385 if (alc_timeout_id > 0) {
386 g_source_remove(alc_timeout_id);
393 void set_brightness_changed_state(void)
395 if (get_pm_status_flag() & PWRSV_FLAG) {
396 set_pm_status_flag(BRTCH_FLAG);
397 _D("Brightness changed in low battery,"
398 "escape dim state (light).");
402 static int set_autobrightness_state(int status)
406 int default_brt = -1;
408 if (status == SETTING_BRIGHTNESS_AUTOMATIC_ON) {
409 if (connect_sensor() < 0)
412 /* escape dim state if it's in low battery.*/
413 set_brightness_changed_state();
415 /* change alc action func */
416 if (_default_action == NULL)
417 _default_action = state_st(S_NORMAL)->action;
418 state_st(S_NORMAL)->action = alc_action;
420 display_info.update_auto_brightness(true);
423 g_timeout_add_seconds(display_conf->lightsensor_interval,
425 } else if (status == SETTING_BRIGHTNESS_AUTOMATIC_PAUSE) {
426 _I("Auto brightness paused.");
430 /* escape dim state if it's in low battery.*/
431 set_brightness_changed_state();
433 ret = get_setting_brightness(&default_brt);
434 if (ret != 0 || (default_brt < PM_MIN_BRIGHTNESS || default_brt > PM_MAX_BRIGHTNESS)) {
435 _I("Failed to read vconf value for brightness.");
436 brt = display_conf->pm_default_brightness;
437 if (default_brt < PM_MIN_BRIGHTNESS || default_brt > PM_MAX_BRIGHTNESS) {
438 ret = vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, brt);
440 _E("Failed to set vconf value for lcd brightness: %d", vconf_get_ext_errno());
445 backlight_ops->set_default_brt(default_brt);
446 backlight_ops->update();
452 static void set_alc_function(keynode_t *key_nodes, void *data)
456 if (key_nodes == NULL) {
457 _E("Wrong parameter, key_nodes is null.");
461 status = vconf_keynode_get_int(key_nodes);
464 case SETTING_BRIGHTNESS_AUTOMATIC_OFF:
465 case SETTING_BRIGHTNESS_AUTOMATIC_ON:
466 case SETTING_BRIGHTNESS_AUTOMATIC_PAUSE:
467 ret = set_autobrightness_state(status);
468 _D("Set auto brightness: %d", ret);
471 _E("Invalid value(%d)", status);
475 static void set_alc_automatic_brt(keynode_t *key_nodes, void *data)
477 if (key_nodes == NULL) {
478 _E("Wrong parameter, key_nodes is null.");
481 automatic_brt = vconf_keynode_get_int(key_nodes) / AUTOMATIC_DEVIDE_VAL;
482 _D("Automatic brt(%d)", automatic_brt);
484 alc_update_brt(true);
487 static gboolean update_handler(void *data)
493 if (get_pm_cur_state() != S_NORMAL)
494 return G_SOURCE_REMOVE;
496 ret = vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &on);
497 if (ret < 0 || on != SETTING_BRIGHTNESS_AUTOMATIC_ON) {
499 _E("Failed to get vconf value for automatic brightness: %d", vconf_get_ext_errno());
500 return G_SOURCE_REMOVE;
503 _D("Auto brightness is working.");
504 alc_update_brt(true);
506 return G_SOURCE_REMOVE;
509 static void update_auto_brightness(bool update)
511 if (update_timeout) {
512 g_source_remove(update_timeout);
517 update_timeout = g_timeout_add(AUTOMATIC_DELAY_TIME,
518 update_handler, NULL);
522 static int prepare_lsensor(void *data)
527 ret = vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &status);
529 if (ret == 0 && status == SETTING_BRIGHTNESS_AUTOMATIC_ON)
530 set_autobrightness_state(status);
532 _E("Failed to get vconf value for automatic brightness: %d", vconf_get_ext_errno());
534 /* add auto_brt_setting change handler */
535 vconf_notify_key_changed(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT,
536 set_alc_function, NULL);
538 ret = vconf_get_int(VCONFKEY_SETAPPL_LCD_AUTOMATIC_BRIGHTNESS, &brt);
541 _E("Failed to get vconf value for automatic lcd brightness: %d", vconf_get_ext_errno());
543 if (brt < PM_MIN_BRIGHTNESS || brt > PM_MAX_BRIGHTNESS) {
544 _E("Failed to get automatic brightness.");
546 automatic_brt = brt / AUTOMATIC_DEVIDE_VAL;
547 _I("Automatic brt(%d) init success.", automatic_brt);
550 vconf_notify_key_changed(VCONFKEY_SETAPPL_LCD_AUTOMATIC_BRIGHTNESS,
551 set_alc_automatic_brt, NULL);
556 static void update_brightness_direct(void)
560 ret = vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &status);
561 if (ret == 0 && status == SETTING_BRIGHTNESS_AUTOMATIC_ON)
562 alc_update_brt(true);
564 _E("Failed to get vconf value for automatic brightness: %d", vconf_get_ext_errno());
567 static int set_autobrightness_min(int val, char *name)
572 if (val < PM_MIN_BRIGHTNESS || val > PM_MAX_BRIGHTNESS)
575 min_brightness = val;
577 if (min_brightness_name) {
578 free(min_brightness_name);
579 min_brightness_name = 0;
581 min_brightness_name = strndup(name, strlen(name));
583 update_brightness_direct();
585 _I("Auto brightness min value changed. min_brightness=%d min_brightness_name=%s",
586 min_brightness, min_brightness_name);
591 static void reset_autobrightness_min(GDBusConnection *conn,
593 const gchar *unique_name,
599 if (!min_brightness_name)
602 if (strcmp(sender, min_brightness_name))
605 _I("Change to default min brightness. before=%d changed=%d brightness_name=%s", min_brightness,
606 PM_MIN_BRIGHTNESS, min_brightness_name);
607 min_brightness = PM_MIN_BRIGHTNESS;
608 if (min_brightness_name) {
609 free(min_brightness_name);
610 min_brightness_name = 0;
613 update_brightness_direct();
616 static int lcd_changed_cb(void *data)
622 lcd_state = *(int *)data;
623 if (lcd_state == S_LCDOFF && alc_timeout_id > 0) {
624 g_source_remove(alc_timeout_id);
631 static int delayed_init_done(void *data)
638 state = *(int *)data;
642 /* get light data from sensor fw */
643 prepare_lsensor(NULL);
648 static void exit_lsensor(void)
650 vconf_ignore_key_changed(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT,
653 vconf_ignore_key_changed(VCONFKEY_SETAPPL_LCD_AUTOMATIC_BRIGHTNESS,
654 set_alc_automatic_brt);
656 set_autobrightness_state(SETTING_BRIGHTNESS_AUTOMATIC_OFF);
659 static void auto_brightness_init(void *data)
661 display_info.update_auto_brightness = update_auto_brightness;
662 display_info.set_autobrightness_min = set_autobrightness_min;
663 display_info.reset_autobrightness_min = reset_autobrightness_min;
665 register_notifier(DEVICE_NOTIFIER_LCD, lcd_changed_cb);
666 register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
669 static void auto_brightness_exit(void *data)
673 unregister_notifier(DEVICE_NOTIFIER_LCD, lcd_changed_cb);
674 unregister_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
677 static const struct display_ops display_autobrightness_ops = {
678 .name = "auto-brightness",
679 .init = auto_brightness_init,
680 .exit = auto_brightness_exit,
683 DISPLAY_OPS_REGISTER(&display_autobrightness_ops)
685 static void __CONSTRUCTOR__ initialize(void)
687 backlight_ops = get_var_backlight_ops();
689 _E("Failed to get backlight operator variable.");
691 display_conf = get_var_display_config();
693 _E("Failed to get display configuration variable.");