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>
27 #include <libsyscommon/libgdbus.h>
28 #include <linux/input.h>
30 #include "ambient-mode.h"
34 #include "display-actor.h"
35 #include "display-ops.h"
36 #include "shared/common.h"
37 #include "shared/devices.h"
38 #include "shared/device-notifier.h"
39 #include "shared/common.h"
40 #include "shared/plugin.h"
41 #include "shared/apps.h"
42 #include "power/power-off.h"
43 #include "power/power-suspend.h"
44 #include "led/touch-key.h"
45 #include "display/display-lock.h"
47 #ifndef KEY_SCREENLOCK
48 #define KEY_SCREENLOCK 0x98
54 #define PREDEF_LEAVESLEEP "leavesleep"
55 #define POWEROFF_ACT "poweroff"
56 #define USEC_PER_SEC 1000000
57 #define USEC_PER_MSEC 1000
58 #define CSC_CONFIG_MODE_RUNNING 1
60 #define CAPTURE_COMBINATION_INTERVAL 0.5 /* 0.5 second */
61 #define TORCH_COMBINATION_INTERVAL 0.1 /* 0.1 second */
62 #define DEFAULT_COMBINATION_INTERVAL 0.1 /* 0.1 second */
64 #define LONGKEY_PRESSED_TIME 4 /* 4 second */
66 #define KEY_MAX_DELAY_TIME 700 /* ms */
68 #define SIGNAL_CHANGE_HARDKEY "ChangeHardkey"
69 #define SIGNAL_LCDON_BY_POWERKEY "LCDOnByPowerkey"
70 #define SIGNAL_LCDOFF_BY_POWERKEY "LCDOffByPowerkey"
72 #define NORMAL_POWER 0
73 #define KEY_TEST_MODE_POWER 2
77 enum key_combination_flags {
78 KEY_COMBINATION_STOP = 0,
79 KEY_COMBINATION_POWERKEY = BIT(0),
80 KEY_COMBINATION_MENUKEY = BIT(1),
81 KEY_COMBINATION_VOLUMEUP = BIT(2),
82 KEY_COMBINATION_VOLUMEDOWN = BIT(3),
85 enum combination_process {
86 COMBINATION_STOP = KEY_COMBINATION_STOP,
87 COMBINATION_SCREENCAPTURE = KEY_COMBINATION_POWERKEY | KEY_COMBINATION_MENUKEY,
88 COMBINATION_TORCH = KEY_COMBINATION_POWERKEY | KEY_COMBINATION_VOLUMEUP,
89 COMBINATION_QUICKTALK = KEY_COMBINATION_POWERKEY | KEY_COMBINATION_VOLUMEDOWN,
92 static struct display_plugin *disp_plgn;
93 static struct _backlight_ops *backlight_ops;
94 static struct timeval pressed_time;
95 static guint longkey_timeout_id = 0;
96 static guint longkey_restore_id = 0;
97 static guint displayon_by_powerkey_timeout_id = 0;
98 static int cancel_lcdoff;
99 static int key_combination = KEY_COMBINATION_STOP;
100 static double combination_pressed_time;
101 static bool touch_pressed = false;
102 static int skip_lcd_off = false;
103 static int skip_combination = false;
104 static int bezel_wakeup = true;
105 static const struct device_ops *touchled;
106 static int booting_check = true;
108 static inline int current_state_in_on(void)
110 return ((get_pm_cur_state() == S_LCDDIM) || (get_pm_cur_state() == S_NORMAL));
113 static inline void restore_custom_brightness(void)
115 if ((get_pm_cur_state() == S_LCDDIM) &&
116 backlight_ops->get_custom_status())
117 backlight_ops->custom_update();
120 static void longkey_pressed(void)
124 _I("Power key long pressed!");
127 caps = display_get_caps(DISPLAY_ACTOR_POWER_KEY);
129 if (display_has_caps(caps, DISPLAY_CAPA_LCDON)) {
130 /* change state - LCD on */
131 if (disp_plgn->pm_change_internal)
132 disp_plgn->pm_change_internal(INTERNAL_LOCK_POWERKEY, LCD_NORMAL);
133 poll_callback(INPUT_POLL_EVENT, NULL);
136 if (!display_has_caps(caps, DISPLAY_CAPA_LCDOFF)) {
137 _D("No poweroff capability!");
142 static gboolean longkey_restore_cb(void *data)
144 device_notify(DEVICE_NOTIFIER_LONGKEY_RESTORE, (void *)NULL);
145 longkey_restore_id = 0;
147 return G_SOURCE_REMOVE;
150 static gboolean longkey_pressed_cb(void *data)
153 longkey_timeout_id = 0;
155 return G_SOURCE_REMOVE;
158 static unsigned long timediff_usec(struct timeval t1, struct timeval t2)
162 udiff = (t2.tv_sec - t1.tv_sec) * USEC_PER_SEC;
163 udiff += (t2.tv_usec - t1.tv_usec);
168 static inline void check_key_pair(int code, int new, int *old)
171 _E("key pair is not matched! (%d, %d)", code, new);
176 static inline void broadcast_lcdon_by_powerkey(void)
178 gdbus_signal_emit(NULL,
179 DEVICED_PATH_DISPLAY,
180 DEVICED_INTERFACE_DISPLAY,
181 SIGNAL_LCDON_BY_POWERKEY,
185 static inline void broadcast_lcdoff_by_powerkey(void)
187 gdbus_signal_emit(NULL,
188 DEVICED_PATH_DISPLAY,
189 DEVICED_INTERFACE_DISPLAY,
190 SIGNAL_LCDOFF_BY_POWERKEY,
194 static inline bool switch_on_lcd(enum device_flags flags)
196 if (current_state_in_on())
199 if (backlight_ops->get_lcd_power() == DPMS_ON) {
200 if (ambient_get_state() == false)
204 if (flags & LCD_ON_BY_POWER_KEY)
205 broadcast_lcdon_by_powerkey();
206 else if (flags & LCD_ON_BY_TOUCH)
207 _I("Display on by Touch_wakeup event");
209 lcd_on_direct(flags);
214 static inline void switch_off_lcd(void)
216 if (!current_state_in_on())
219 if (backlight_ops->get_lcd_power() == DPMS_OFF)
222 broadcast_lcdoff_by_powerkey();
224 lcd_off_procedure(LCD_OFF_BY_POWER_KEY);
227 static void check_key_combination(struct input_event *pinput)
229 double press_time, diff_time;
230 press_time = (pinput->time).tv_sec + USEC_TO_SEC((pinput->time).tv_usec);
231 diff_time = press_time - combination_pressed_time;
233 switch (key_combination) {
234 case COMBINATION_SCREENCAPTURE:
235 if (diff_time <= CAPTURE_COMBINATION_INTERVAL) {
236 _I("Combination key : SCREENCAPTURE mode");
237 skip_combination = true;
240 case COMBINATION_TORCH:
241 if (diff_time <= TORCH_COMBINATION_INTERVAL) {
242 /* When torch combination, display control should be not change. */
243 if (displayon_by_powerkey_timeout_id) {
244 g_source_remove(displayon_by_powerkey_timeout_id);
245 displayon_by_powerkey_timeout_id = 0;
247 _I("Combination key : TORCH mode");
248 skip_combination = true;
250 key_combination = COMBINATION_STOP;
252 case COMBINATION_QUICKTALK:
253 if (diff_time <= DEFAULT_COMBINATION_INTERVAL) {
254 _I("Combination key : QUICK-TALK mode");
255 skip_combination = true;
256 if (longkey_timeout_id) {
257 g_source_remove(longkey_timeout_id);
258 longkey_timeout_id = 0;
263 combination_pressed_time = press_time;
269 static void start_key_combination(struct input_event *pinput)
271 switch (pinput->code) {
273 key_combination |= KEY_COMBINATION_POWERKEY;
276 key_combination |= KEY_COMBINATION_MENUKEY;
279 key_combination |= KEY_COMBINATION_VOLUMEUP;
282 key_combination |= KEY_COMBINATION_VOLUMEDOWN;
288 check_key_combination(pinput);
291 static void stop_key_combination(struct input_event *pinput)
293 if (pinput == NULL) {
294 key_combination = KEY_COMBINATION_STOP;
298 switch (pinput->code) {
300 key_combination &= ~KEY_COMBINATION_POWERKEY;
303 key_combination &= ~KEY_COMBINATION_MENUKEY;
306 key_combination &= ~KEY_COMBINATION_VOLUMEUP;
309 key_combination &= ~KEY_COMBINATION_VOLUMEDOWN;
312 _E("This code(%d) is not combination type.", pinput->code);
317 static void process_combination_key(struct input_event *pinput)
319 if (pinput->value == KEY_PRESSED)
320 start_key_combination(pinput);
321 else if (pinput->value == KEY_RELEASED)
322 stop_key_combination(pinput);
325 static int process_menu_key(struct input_event *pinput)
329 caps = display_get_caps(DISPLAY_ACTOR_MENU_KEY);
331 if (!display_has_caps(caps, DISPLAY_CAPA_LCDON)) {
332 if (current_state_in_on())
334 _D("No lcd-on capability!");
336 } else if (pinput->value == KEY_PRESSED)
337 switch_on_lcd(LCD_ON_BY_POWER_KEY);
342 static int decide_lcdoff(void)
344 /* It's not needed if it's already LCD off state */
345 if (!current_state_in_on() &&
346 backlight_ops->get_lcd_power() != DPMS_ON)
350 * This flag is set at the moment
351 * that LCD is turned on by power key
352 * LCD has not to turned off in the situation.
357 /* LCD is not turned off when powerkey is pressed,not released */
358 if (key_combination == KEY_COMBINATION_POWERKEY)
361 /* LCD-off is blocked at the moment poweroff popup shows */
365 /* LCD-off is blocked when powerkey and volmedown key are pressed */
366 if (skip_combination)
369 /* At booting time, display must do not turn off */
376 static int lcdoff_powerkey(void)
380 if (decide_lcdoff() == true) {
381 check_processes(S_NORMAL);
382 check_processes(S_LCDDIM);
384 if (!check_holdkey_block(S_NORMAL) &&
385 !check_holdkey_block(S_LCDDIM)) {
386 if (display_info.update_auto_brightness)
387 display_info.update_auto_brightness(false);
389 delete_condition(S_NORMAL);
390 delete_condition(S_LCDDIM);
391 update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
392 if (disp_plgn->pm_change_internal)
393 disp_plgn->pm_change_internal(INTERNAL_LOCK_POWERKEY, LCD_OFF);
397 skip_combination = false;
404 static bool key_check_display_on(void)
406 if (current_state_in_on())
409 if (backlight_ops->get_lcd_power() == DPMS_ON) {
410 _W("display power was on");
417 static gboolean display_on_cb(void *data)
419 if (displayon_by_powerkey_timeout_id == 0)
420 return G_SOURCE_REMOVE;
422 displayon_by_powerkey_timeout_id = 0;
423 if (backlight_ops->get_lcd_power() != DPMS_ON ||
424 current_state_in_on() == false) {
425 broadcast_lcdon_by_powerkey();
426 lcd_on_direct(LCD_ON_BY_POWER_KEY);
428 poll_callback(INPUT_POLL_EVENT, NULL);
431 return G_SOURCE_REMOVE;
434 static int process_back_key(struct input_event *pinput)
438 if (pinput->value == KEY_PRESSED) {
439 switch_on_lcd(LCD_ON_BY_BACK_KEY);
440 _I("back key pressed");
447 static int process_power_key(struct input_event *pinput)
450 static int value = KEY_RELEASED;
452 const struct display_config *display_conf = get_var_display_config();
454 _E("Failed to get display configuration variable.");
458 caps = display_get_caps(DISPLAY_ACTOR_POWER_KEY);
460 switch (pinput->value) {
462 check_key_pair(pinput->code, pinput->value, &value);
464 if (!display_conf->powerkey_doublepress) {
465 if (display_has_caps(caps, DISPLAY_CAPA_LCDOFF))
468 _D("No lcdoff capability!");
469 } else if (skip_lcd_off)
472 if (!display_has_caps(caps, DISPLAY_CAPA_LCDON))
475 if (longkey_timeout_id > 0) {
476 g_source_remove(longkey_timeout_id);
477 longkey_timeout_id = 0;
480 if (longkey_restore_id > 0) {
481 g_source_remove(longkey_restore_id);
482 longkey_restore_id = 0;
487 if (display_has_caps(caps, DISPLAY_CAPA_LCDON)) {
489 * LCD does not turn on immediately at mobile.
490 * It will be turned on after 0.1 second because of torch concept.
492 skip_lcd_off = key_check_display_on();
495 if (!displayon_by_powerkey_timeout_id &&
496 backlight_ops->get_lcd_power() != DPMS_ON &&
497 key_combination != COMBINATION_TORCH) {
498 displayon_by_powerkey_timeout_id = g_timeout_add(
500 display_on_cb, NULL);
503 _D("No lcdon capability!");
504 skip_lcd_off = false;
506 check_key_pair(pinput->code, pinput->value, &value);
507 _I("power key pressed");
508 pressed_time.tv_sec = (pinput->time).tv_sec;
509 pressed_time.tv_usec = (pinput->time).tv_usec;
510 if (key_combination == KEY_COMBINATION_POWERKEY) {
511 /* add long key timer */
512 longkey_timeout_id = g_timeout_add(
513 display_conf->longpress_interval,
514 longkey_pressed_cb, NULL);
515 /* add long key restore timer */
516 longkey_restore_id = g_timeout_add_seconds(
517 LONGKEY_PRESSED_TIME,
518 longkey_restore_cb, NULL);
523 case KEY_BEING_PRESSED:
524 if (timediff_usec(pressed_time, pinput->time) >
525 (display_conf->longpress_interval * USEC_PER_MSEC))
532 static int process_screenlock_key(struct input_event *pinput)
534 if (pinput->value != KEY_RELEASED) {
535 stop_key_combination(NULL);
539 if (!current_state_in_on())
542 check_processes(S_NORMAL);
543 check_processes(S_LCDDIM);
545 if (!check_holdkey_block(S_NORMAL) && !check_holdkey_block(S_LCDDIM)) {
546 delete_condition(S_NORMAL);
547 delete_condition(S_LCDDIM);
548 update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
551 if (disp_plgn->pm_change_internal)
552 disp_plgn->pm_change_internal(-1, LCD_OFF);
558 static void sound_vibrate_hardkey(void)
560 /* device notify(vibrator) */
562 /* Need to notify to deviced-vibrator. deviced-vibrator receives ChangedHardKey signal */
563 gdbus_signal_emit(NULL,
565 DEVICED_INTERFACE_KEY,
566 SIGNAL_CHANGE_HARDKEY,
570 static void process_hardkey_backlight(struct input_event *pinput)
574 _E("pinput->value : %d", pinput->value);
575 if (pinput->value == KEY_PRESSED) {
576 /* Sound & Vibrate only in unlock state */
577 if (__get_lock_screen_state() == VCONFKEY_IDLE_UNLOCK
578 || get_lock_screen_bg_state())
579 sound_vibrate_hardkey();
581 if (touchled && touchled->execute) {
582 opt = TOUCHLED_PRESS;
583 touchled->execute(&opt);
585 } else if (pinput->value == KEY_RELEASED) {
586 /* if lockscreen is idle lock */
587 if (__get_lock_screen_state() == VCONFKEY_IDLE_LOCK) {
588 _D("Lock state, key backlight is off when phone is unlocked!");
592 if (touchled && touchled->execute) {
593 opt = TOUCHLED_RELEASE;
594 touchled->execute(&opt);
599 static void update_vital_state(struct input_event *pinput)
603 /* Change vital state to VITAL_EXIT only if vital mode is active */
607 /* Touch or Menu Key Release Event */
608 if (pinput->type == EV_ABS || (pinput->type == EV_KEY &&
609 pinput->value == KEY_RELEASED && pinput->code == KEY_MENU)) {
610 /* Enable all services upon receiving user input, else maintain same state */
612 device_notify(DEVICE_NOTIFIER_VITAL_STATE, &type);
616 static int check_key(struct input_event *pinput, int fd)
620 process_combination_key(pinput);
621 switch (pinput->code) {
623 ignore = process_menu_key(pinput);
626 ignore = process_power_key(pinput);
627 if (current_state_in_on())
631 ignore = process_screenlock_key(pinput);
634 ignore = process_back_key(pinput);
635 stop_key_combination(NULL);
636 if (current_state_in_on()) {
637 process_hardkey_backlight(pinput);
642 stop_key_combination(NULL);
643 if (current_state_in_on()) {
644 process_hardkey_backlight(pinput);
650 if (current_state_in_on())
663 case KEY_PREVIOUSSONG:
665 case KEY_FASTFORWARD:
666 stop_key_combination(NULL);
667 if (current_state_in_on())
674 stop_key_combination(NULL);
677 stop_key_combination(NULL);
681 if (pinput->value == KEY_PRESSED)
682 pm_history_save(PM_LOG_KEY_PRESS, pinput->code);
683 else if (pinput->value == KEY_RELEASED)
684 pm_history_save(PM_LOG_KEY_RELEASE, pinput->code);
689 static int check_key_filter(void *data, int fd)
691 struct input_event *pinput = data;
693 static int old_fd, code, value;
697 switch (pinput->type) {
699 if (pinput->code == BTN_TOUCH &&
700 pinput->value == KEY_RELEASED)
701 touch_pressed = false;
703 * Normally, touch press/release events don't occur
704 * in lcd off state. But touch release events can occur
705 * in the state abnormally. Then touch events are ignored
706 * when lcd is off state.
708 if (pinput->code == BTN_TOUCH && !current_state_in_on())
710 if (pinput->code == code && pinput->value == value) {
711 _E("Same key(%d, %d) is polled [%d,%d]",
712 code, value, old_fd, fd);
716 value = pinput->value;
718 update_vital_state(pinput);
719 ignore = check_key(pinput, fd);
720 restore_custom_brightness();
724 if ((get_pm_cur_state() == S_LCDOFF) && bezel_wakeup) {
725 switch_on_lcd(LCD_ON_BY_BEZEL);
727 } else if (get_pm_cur_state() != S_LCDOFF)
731 update_vital_state(pinput);
732 if (pinput->value == KEY_PRESSED) {
733 switch_on_lcd(LCD_ON_BY_TOUCH);
737 if (current_state_in_on())
740 restore_custom_brightness();
742 if (pinput->value == KEY_PRESSED)
743 touch_pressed = true;
744 else if (pinput->value == KEY_RELEASED)
745 touch_pressed = false;
757 static int delayed_init_done(void *data)
764 static int bezel_wakeup_cb(void *data)
766 bezel_wakeup = (int)((intptr_t)data);
773 * powerkey := LCDON | LCDOFF | POWEROFF
776 static struct display_actor_ops display_powerkey_actor = {
777 .id = DISPLAY_ACTOR_POWER_KEY,
778 .caps = DISPLAY_CAPA_LCDON |
779 DISPLAY_CAPA_LCDOFF |
780 DISPLAY_CAPA_POWEROFF,
783 static struct display_actor_ops display_menukey_actor = {
784 .id = DISPLAY_ACTOR_MENU_KEY,
785 .caps = DISPLAY_CAPA_LCDON,
788 static void keyfilter_init(void)
790 display_add_actor(&display_powerkey_actor);
791 display_add_actor(&display_menukey_actor);
793 touchled = find_device(TOUCHLED_NAME);
795 register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
796 register_notifier(DEVICE_NOTIFIER_BEZEL_WAKEUP, bezel_wakeup_cb);
799 static void key_backlight_enable(bool enable)
803 if (!touchled || !touchled->execute)
807 opt = TOUCHLED_DIRECT_ON;
809 opt = TOUCHLED_DIRECT_OFF;
811 touchled->execute(&opt);
814 static const struct display_keyfilter_ops normal_keyfilter_ops = {
815 .init = keyfilter_init,
816 .check = check_key_filter,
817 .set_powerkey_ignore = NULL,
818 .powerkey_lcdoff = NULL,
819 .backlight_enable = key_backlight_enable,
822 const struct display_keyfilter_ops *keyfilter_ops = &normal_keyfilter_ops;
824 static void __CONSTRUCTOR__ initialize(void)
826 disp_plgn = get_var_display_plugin();
828 _E("Failed to get display plugin variable.");
831 backlight_ops = get_var_backlight_ops();
833 _E("Failed to get backlight operator variable.");