4 * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
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.
21 #include <libsyscommon/list.h>
22 #include <libsyscommon/resource-manager.h>
23 #include <system/syscommon-plugin-deviced-power-interface.h>
24 #include <system/syscommon-plugin-deviced-common-interface.h>
25 #include <shared/devices.h>
27 #include "core/udev.h"
28 #include "shared/device-notifier.h"
29 #include "shared/log.h"
30 #include "power/power.h"
31 #include "power/power-suspend.h"
32 #include "device-interface.h"
34 #include "display-lock.h"
35 #include "display-plugin.h"
36 #include "display-config.h"
37 #include "display-misc.h"
38 #include "display-ops.h"
39 #include "display-signal.h"
40 #include "display-state-transition.h"
41 #include "lock-detector.h"
43 #define DELAYED_INIT_WATING_TIME 60000 /* 1 minute */
45 static const struct device_ops *display_plugin_device_ops;
46 static unsigned int pm_status_flag;
47 static enum display_init_direction_e g_display_init_direction;
48 static bool g_display_hal_backend_available = false;
49 static GList *display_dependent_device_ops;
50 static enum device_ops_status display_ops_status = DEVICE_OPS_STATUS_UNINIT;
52 extern void init_save_userlock(void);
54 inline unsigned int get_pm_status_flag(void)
56 return pm_status_flag;
59 inline void set_pm_status_flag(unsigned int status_flag)
61 pm_status_flag |= status_flag;
64 inline void clear_pm_status_flag(unsigned int status_flag)
66 pm_status_flag &= ~status_flag;
69 inline enum display_init_direction_e get_display_init_direction(void)
71 return g_display_init_direction;
74 inline void set_display_init_direction(enum display_init_direction_e display_init_direction)
76 g_display_init_direction = display_init_direction;
79 void lcd_direct_control(enum dpms_state dpms_state, int flags)
81 const struct device_ops *ops = NULL;
86 SYS_G_LIST_FOREACH(display_dependent_device_ops, l, ops)
90 SYS_G_LIST_FOREACH(display_dependent_device_ops, l, ops)
94 _E("state is wrong value %d", dpms_state);
99 bool display_is_hal_backend_available(void)
101 return g_display_hal_backend_available;
104 void display_start_dependent_device(unsigned long flags)
106 const struct device_ops *ops = NULL;
109 SYS_G_LIST_FOREACH(display_dependent_device_ops, l, ops)
113 void display_stop_dependent_device(unsigned long flags)
115 const struct device_ops *ops = NULL;
118 SYS_G_LIST_FOREACH(display_dependent_device_ops, l, ops)
122 void display_register_dependent_device(const struct device_ops *ops)
124 SYS_G_LIST_APPEND(display_dependent_device_ops, ops);
127 void display_unregister_dependent_device(void)
130 GList *l_next = NULL;;
131 const struct device_ops *ops = NULL;
133 SYS_G_LIST_FOREACH_SAFE(display_dependent_device_ops, l, l_next, ops)
134 SYS_G_LIST_REMOVE_LIST(display_dependent_device_ops, l);
137 /* FIXME: display_dimstay_check function should be changed to plugin api call.
138 * Only the wearable profile had the first condition only, checking DIM_FLAG. */
139 bool display_dimstay_check(void)
141 if (pm_status_flag & DIM_FLAG)
144 if ((pm_status_flag & PWRSV_FLAG) && !(pm_status_flag & BRTCH_FLAG))
150 int display_initialize_display_state_timeout_from_setting(void)
154 const char* state_name = NULL;
155 enum deviced_display_state state = DEVICED_DISPLAY_STATE_START;
157 for (i = 0; i < DEVICED_DISPLAY_STATE_END; i++) {
158 display_plugin_state_get_state_by_state_index(i, &state);
160 case DEVICED_DISPLAY_STATE_ON:
161 get_run_timeout(&val);
163 case DEVICED_DISPLAY_STATE_DIM:
164 get_dim_timeout(&val);
166 case DEVICED_DISPLAY_STATE_OFF:
167 display_plugin_config_get_lcdoff_timeout(&val);
170 /* This state doesn't need to set time out. */
175 display_plugin_state_set_timeout(i, val);
178 display_plugin_state_get_name(i, &state_name);
179 _I("State(%s) timeout(%d) ms", state_name, val);
185 /** FIXME: display_ops_status getter/setter will be removed after plugin-core separation
186 This work should be proceeded in the display core
188 bool display_is_display_ops_started_status(void)
190 return (display_ops_status == DEVICE_OPS_STATUS_START);
193 void display_set_display_ops_status(enum device_ops_status dev_ops_status)
195 display_ops_status = dev_ops_status;
198 int display_get_display_ops_status(enum device_ops_status *dev_ops_status)
203 *dev_ops_status = display_ops_status;
207 void display_set_power_save_mode_flag(int onoff)
210 enum deviced_display_state current;
212 if (display_plugin_set_power_save_mode_flag(onoff) == 0)
216 set_pm_status_flag(PWRSV_FLAG);
218 clear_pm_status_flag(PWRSV_FLAG);
220 ret = display_state_get_current(¤t);
224 if (current == DEVICED_DISPLAY_STATE_ON)
225 display_backlight_update_by_default_brightness();
228 static int power_resume_from_echomem_callback(void *data)
231 enum deviced_display_state current;
233 ret = display_state_get_current(¤t);
237 display_plugin_set_system_wakeup_flag(true);
238 if (check_wakeup_src() == EVENT_DEVICE)
239 /* system waked up by devices */
240 display_state_transition_do_state_transition(current, EVENT_DEVICE);
242 /* system waked up by user input */
243 display_state_transition_do_state_transition(current, EVENT_INPUT);
248 static int poweroff_triggered_callback(void *udata)
250 int val = (int)(intptr_t) udata;
253 case VCONFKEY_SYSMAN_POWER_OFF_NONE:
254 clear_pm_status_flag(PWROFF_FLAG);
256 case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
257 case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
258 set_pm_status_flag(PWROFF_FLAG);
265 static gboolean delayed_dpms_init_done(gpointer data)
268 bool timeout_enable = false;
269 int lcdoff_timeout = 0;
271 enum deviced_display_state current;
273 if (!display_panel_init_dpms())
274 return G_SOURCE_CONTINUE;
276 ret = display_state_get_current(¤t);
278 return G_SOURCE_REMOVE;
281 case DEVICED_DISPLAY_STATE_ON:
282 case DEVICED_DISPLAY_STATE_DIM:
283 display_panel_lcd_on_procedure(LCD_NORMAL, LCD_ON_BY_EVENT);
284 display_plugin_config_get_timeout_enable(&timeout_enable);
285 if (timeout_enable) {
286 display_plugin_state_get_timeout(DEVICED_DISPLAY_STATE_ON, &timeout);
287 /* check minimun lcd on time */
288 if (timeout < SEC_TO_MSEC(DEFAULT_NORMAL_TIMEOUT))
289 timeout = SEC_TO_MSEC(DEFAULT_NORMAL_TIMEOUT);
290 display_state_transition_reset_state_transition_timeout(timeout);
293 case DEVICED_DISPLAY_STATE_OFF:
294 display_panel_lcd_off_procedure(LCD_OFF_BY_EVENT);
295 display_plugin_config_get_lcdoff_timeout(&lcdoff_timeout);
296 display_state_transition_reset_state_transition_timeout(lcdoff_timeout);
302 return G_SOURCE_REMOVE;
305 void display_add_timer_for_waiting_dpms_init(void)
307 guint id = g_timeout_add(500/* milliseconds */, delayed_dpms_init_done, NULL);
309 _E("Failed to add display_panel_init_dpms timeout.");
312 void display_set_initial_brightness(void)
316 int default_brightness = 0;
318 ret = get_setting_brightness(&brightness);
319 if (ret != 0 || (brightness < PM_MIN_BRIGHTNESS || brightness > PM_MAX_BRIGHTNESS)) {
320 _I("Failed to read vconf value for brightness.");
321 display_plugin_config_get_pm_default_brightness(&default_brightness);
322 if (brightness < PM_MIN_BRIGHTNESS || brightness > PM_MAX_BRIGHTNESS) {
323 ret = vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, default_brightness);
325 _E("Failed to set vconf value for lcd brightness: %d", vconf_get_ext_errno());
327 brightness = default_brightness;
329 _I("Set brightness(%d) from setting app.", brightness);
330 display_backlight_set_default_brightness(brightness);
331 display_backlight_set_brightness(brightness);
334 /* FIXME: This function should be moved to battery module after battery plguin/module refactoring */
335 void display_set_initial_battery_flag(void)
338 int battery_state = 0;
340 ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &battery_state);
342 battery_state = VCONFKEY_SYSMAN_BAT_NORMAL;
343 _E("Failed to get vconf value for battery status low: %d", vconf_get_ext_errno());
346 if (display_misc_is_low_battery_state(battery_state)) {
347 if (!(get_pm_status_flag() & CHRGR_FLAG)) {
348 display_set_power_save_mode_flag(true);
349 set_pm_status_flag(LOWBT_FLAG);
354 void display_set_initial_lockscreen_status(void)
358 int lock_screen_timeout = 0;
360 ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
363 _E("Failed to get vconf value for idle lock state: %d", vconf_get_ext_errno());
365 set_lock_screen_state(lock_state);
366 display_state_transition_get_lock_screen_timeout(&lock_screen_timeout);
367 if (lock_state == VCONFKEY_IDLE_LOCK) {
368 display_plugin_state_set_timeout(DEVICED_DISPLAY_STATE_ON, lock_screen_timeout);
369 _I("LCD NORMAL timeout(%d ms) is set for lock screen.", lock_screen_timeout);
373 /** FIXME: below uevent functions usage and role are unclear, during refactoring
374 these can be removed.
376 static void esd_action(void)
378 const struct device_ops *touchscreen_ops = NULL;
382 touchscreen_ops = find_device("touchscreen");
384 if (!check_default(touchscreen_ops))
385 touchscreen_ops->stop(NORMAL_MODE);
386 display_panel_set_panel_state_by_off_state(NORMAL_MODE);
387 display_panel_set_panel_state_by_on_state(NORMAL_MODE);
388 if (!check_default(touchscreen_ops))
389 touchscreen_ops->start(NORMAL_MODE);
392 static void lcd_uevent_changed(struct udev_device *dev)
397 devpath = udev_device_get_devpath(dev);
401 if (!fnmatch(LCD_ESD_PATH, devpath, 0)) {
402 action = udev_device_get_action(dev);
403 if (!strcmp(action, UDEV_CHANGE))
408 static const struct uevent_handler lcd_uevent_ops = {
409 .subsystem = LCD_EVENT_SUBSYSTEM,
410 .uevent_func = lcd_uevent_changed,
414 static gboolean handle_sighup(gpointer data)
416 int signo = (int)(intptr_t) data;
417 _I("received sig hub %d", signo);
420 return G_SOURCE_REMOVE;
423 static int delayed_init_done(void *data)
425 static bool done = false;
434 _I("Booting done, release booting lock.");
435 display_lock_request_unlock_with_option(DEVICED_EVENT_MISC_BOOTING, LCD_NORMAL, PM_SLEEP_MARGIN);
436 display_lock_request_unlock_with_option(DEVICED_EVENT_MISC_BOOTING, LCD_OFF, PM_SLEEP_MARGIN);
441 static void init_lcd_operation(void)
443 const struct device_ops *ops = NULL;
445 ops = find_device("display");
446 if (!check_default(ops))
447 display_register_dependent_device(ops);
449 ops = find_device("touchkey");
450 if (!check_default(ops))
451 display_register_dependent_device(ops);
453 ops = find_device("touchscreen");
454 if (!check_default(ops))
455 display_register_dependent_device(ops);
458 static void load_display_hal_backend(void)
462 if (g_display_hal_backend_available)
465 ret = hal_device_display_get_backend();
467 _W("There is no HAL for display.");
468 g_display_hal_backend_available = false;
471 g_display_hal_backend_available = true;
472 _W("Display device structure load success.");
475 static int unload_display_hal_backend(void)
477 g_display_hal_backend_available = false;
478 return hal_device_display_put_backend();
481 static int display_probe(void *data)
485 display_plugin_device_ops = find_device("display-plugin");
486 if (!display_plugin_device_ops || !display_plugin_device_ops->probe)
489 ret = display_plugin_device_ops->probe(&g_display_plugin);
494 * load display hal backend
495 * if there is no display shared library,
496 * deviced does not provide any method and function of display.
498 load_display_hal_backend();
502 static int input_init_handler(void)
504 if (!g_display_plugin.config->input_support)
505 remove_device_by_devname("input");
510 static void display_init(void *data)
512 bool timeout_enable = false;
513 int lcd_always_on = 0;
516 unsigned int flags = (WITHOUT_STARTNOTI | FLAG_X_DPMS);
517 enum deviced_display_state current;
519 if (!display_plugin_device_ops || !display_plugin_device_ops->init)
522 g_unix_signal_add(SIGHUP, handle_sighup, (gpointer) SIGHUP);
523 /* FIMXE: display config load should be put here*/
524 display_plugin_device_ops->init(data);
526 register_kernel_uevent_control(&lcd_uevent_ops);
528 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_DELAYED_INIT, delayed_init_done);
529 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_APPLICATION_BACKGROUND, display_app_background);
530 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_APPLICATION_FOREGROUND, display_app_foreground);
531 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_APPLICATION_TERMINATED, display_app_terminated);
532 display_signal_register_display_brightness_notifier();
533 display_misc_register_battery_health_notifier();
534 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_POWER_RESUME_FROM_ECHO_MEM, power_resume_from_echomem_callback);
535 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_POWEROFF_TRIGGERED, poweroff_triggered_callback);
537 init_save_userlock();
539 ret = init_setting(NULL);
541 _W("Failed to init: setting init error");
543 display_plugin_config_get_timeout_enable(&timeout_enable);
545 display_initialize_display_state_timeout_from_setting();
547 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_VITAL_STATE, vital_state_changed);
550 ret = input_init_handler();
551 pm_lock_detector_init();
553 _W("Failed to init: input devices poll init error");
556 ret = init_pm_dbus();
558 _W("Failed to init: dbus initialization error");
560 display_ops_init(NULL);
564 init_lcd_operation();
565 display_set_initial_brightness();
566 display_set_initial_battery_flag();
567 display_set_initial_lockscreen_status();
569 /* In smd test, TSP should be turned off if display panel is not existed. */
570 if (display_panel_get_dpms_cached_state() == -ENOENT) {
571 _I("Display panel is not existed.");
572 lcd_direct_control(DPMS_OFF, NORMAL_MODE);
573 display_unregister_dependent_device();
576 /* wm_ready needs to be checked
577 * since display manager can be launched later than deviced.
578 * In the case, display cannot be turned on at the first booting */
579 // wm_ready = check_wm_ready();
580 if (display_panel_init_dpms()) {
581 if (display_plugin_is_lcd_on_blocked() != LCDON_BLOCK_NONE) {
582 display_panel_lcd_off_procedure(LCD_OFF_BY_EVENT);
584 display_panel_lcd_on_procedure(LCD_NORMAL, LCD_ON_BY_EVENT);
587 display_add_timer_for_waiting_dpms_init();
590 display_plugin_config_get_lcd_always_on(&lcd_always_on);
592 _I("LCD always on.");
593 display_state_transition_set_transition_table_display_state(DEVICED_DISPLAY_STATE_ON, DEVICED_DISPLAY_STATE_ON, EVENT_TIMEOUT);
596 if (flags & WITHOUT_STARTNOTI) { /* start without noti */
597 _I("Start Power managing without noti");
598 syscommon_resman_set_resource_attr_uint64_4(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_POWER),
599 DEVICED_POWER_ATTR_SET_UINT64_4_CURRENT_STATE,
600 DEVICED_POWER_STATE_SLEEP, DEVICED_POWER_STATE_NORMAL,
601 HAL_DEVICE_POWER_TRANSITION_REASON_UNKNOWN, 0);
604 * Lock lcd off until booting is done.
605 * deviced guarantees all booting script is executing.
606 * Last script of booting unlocks this suspend blocking state.
608 display_lock_request_lock_with_option(DEVICED_EVENT_MISC_BOOTING, LCD_OFF,
609 STAY_CUR_STATE, DELAYED_INIT_WATING_TIME);
611 /* Initial display state right after the booting done */
612 if (display_plugin_is_lcd_on_blocked())
613 set_pm_cur_state(DEVICED_DISPLAY_STATE_OFF);
615 set_pm_cur_state(DEVICED_DISPLAY_STATE_ON);
617 ret = display_state_get_current(¤t);
619 ret = vconf_set_int(VCONFKEY_PM_STATE, current);
621 _E("Failed to set vconf value for pm cur state: %d", vconf_get_ext_errno());
624 display_set_display_ops_status(DEVICE_OPS_STATUS_START);
625 if (timeout_enable) {
626 display_plugin_state_get_timeout(DEVICED_DISPLAY_STATE_ON, &timeout);
627 /* check minimun lcd on time */
628 if (timeout < SEC_TO_MSEC(DEFAULT_NORMAL_TIMEOUT)) {
629 timeout = SEC_TO_MSEC(DEFAULT_NORMAL_TIMEOUT);
631 display_lock_request_lock_with_option(DEVICED_EVENT_MISC_BOOTING, LCD_NORMAL,
632 STAY_CUR_STATE, timeout);
636 set_display_init_direction(g_display_plugin.config->display_init_direction);
639 static void display_exit(void *data)
641 const struct device_ops *ops = NULL;
643 if (!display_plugin_device_ops || !display_plugin_device_ops->exit)
646 display_plugin_device_ops->exit(data);
648 display_set_display_ops_status(DEVICE_OPS_STATUS_STOP);
650 /* Set current state to DEVICED_DISPLAY_STATE_ON */
651 set_pm_cur_state(DEVICED_DISPLAY_STATE_ON);
652 set_setting_pmstate(DEVICED_DISPLAY_STATE_ON);
653 /* timeout is not needed */
654 display_state_transition_reset_state_transition_timeout(TIMEOUT_NONE);
656 unregister_kernel_uevent_control(&lcd_uevent_ops);
658 display_ops_exit(NULL);
662 display_backlight_update_by_default_brightness();
664 display_panel_exit_dpms();
666 ops = find_device("touchscreen");
667 if (!check_default(ops))
668 ops->start(NORMAL_MODE);
670 ops = find_device("touchkey");
671 if (!check_default(ops))
672 ops->start(NORMAL_MODE);
674 syscommon_notifier_unsubscribe_notify(DEVICED_NOTIFIER_VITAL_STATE, vital_state_changed);
675 syscommon_notifier_unsubscribe_notify(DEVICED_NOTIFIER_DELAYED_INIT, delayed_init_done);
676 syscommon_notifier_unsubscribe_notify(DEVICED_NOTIFIER_APPLICATION_BACKGROUND, display_app_background);
677 syscommon_notifier_unsubscribe_notify(DEVICED_NOTIFIER_APPLICATION_FOREGROUND, display_app_foreground);
678 syscommon_notifier_unsubscribe_notify(DEVICED_NOTIFIER_APPLICATION_TERMINATED, display_app_terminated);
679 display_misc_unregister_battery_health_notifier();
680 display_signal_unregister_display_brightness_notifier();
681 syscommon_notifier_unsubscribe_notify(DEVICED_NOTIFIER_POWER_RESUME_FROM_ECHO_MEM, power_resume_from_echomem_callback);
682 syscommon_notifier_unsubscribe_notify(DEVICED_NOTIFIER_POWEROFF_TRIGGERED, poweroff_triggered_callback);
684 display_unregister_dependent_device();
685 free_lock_info_list();
687 unload_display_hal_backend();
690 static int display_start(enum device_flags flags)
692 if (!display_plugin_device_ops || !display_plugin_device_ops->start)
695 return display_plugin_device_ops->start(flags);
698 static int display_stop(enum device_flags flags)
700 if (!display_plugin_device_ops || !display_plugin_device_ops->stop)
703 return display_plugin_device_ops->stop(flags);
706 static int display_status(void)
708 if (!display_plugin_device_ops || !display_plugin_device_ops->status)
711 return display_plugin_device_ops->status();
714 static const struct device_ops display_device_ops = {
715 .priority = DEVICE_PRIORITY_HIGH,
716 DECLARE_NAME_LEN("display"),
717 .probe = display_probe,
718 .init = display_init,
719 .exit = display_exit,
720 .start = display_start,
721 .stop = display_stop,
722 .status = display_status,
725 DEVICE_OPS_REGISTER(&display_device_ops)