power: elevate iot-headless power plugin to core
[platform/core/system/deviced.git] / plugins / tv / display / device-interface.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <limits.h>
29 #include <math.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <dlfcn.h>
33 #include <hal/device/hal-display.h>
34
35 #include "ambient-mode.h"
36 #include "core/log.h"
37 #include "shared/devices.h"
38 #include "shared/common.h"
39 #include "shared/device-notifier.h"
40 #include "util.h"
41 #include "device-interface.h"
42 #include "vconf.h"
43 #include "core.h"
44 #include "display/display-dpms.h"
45 #include "display/display.h"
46 #include "power/power-suspend.h"
47 #include "display/display-lock.h"
48
49 #define TOUCH_ON        1
50 #define TOUCH_OFF       0
51
52 #define LCD_PHASED_MIN_BRIGHTNESS       1
53 #define LCD_PHASED_MAX_BRIGHTNESS       100
54 #define LCD_PHASED_CHANGE_STEP          5
55 #define LCD_PHASED_DELAY                10000   /* microsecond */
56 #define DUMP_MODE_WAITING_TIME          600000  /* milisecond */
57
58 #define DISPLAY_HAL_LIB_PATH "/usr/lib/libdisplay-hal.so"
59
60 #define GESTURE_STR                     "gesture"
61 #define POWERKEY_STR                    "powerkey"
62 #define EVENT_STR                       "event"
63 #define TOUCH_STR                       "touch"
64 #define TIMEOUT_STR                     "timeout"
65 #define PROXIMITY_STR                   "proximity"
66 #define PALM_STR                        "palm"
67 #define UNKNOWN_STR                     "unknown"
68
69 #define FREEZER_VITAL_WAKEUP_CGROUP "/sys/fs/cgroup/freezer/vital_wakeup/freezer.state"
70
71 static struct _backlight_ops backlight_ops;
72 static bool custom_status;
73 static int custom_brightness;
74 static int force_brightness;
75 static int default_brightness;
76 static int dpms_running_state = DPMS_SETTING_DONE;
77 static bool display_dev_available = false;
78 static guint release_timer;
79 static struct display_config *display_conf;
80
81 inline struct _backlight_ops *get_var_backlight_ops(void)
82 {
83         return &backlight_ops;
84 }
85
86 bool display_dev_ready(void)
87 {
88         return display_dev_available;
89 }
90
91 void dpms_set_running_state(int val)
92 {
93         dpms_running_state = val;
94 }
95
96 static int bl_onoff(int on, enum device_flags flags)
97 {
98         dpms_set_state(on);
99
100 #ifdef ENABLE_PM_LOG
101         if (on == DPMS_ON)
102                 pm_history_save(PM_LOG_LCD_ON_COMPLETE, get_pm_cur_state());
103         else if (on == DPMS_OFF || on == DPMS_FORCE_OFF)
104                 pm_history_save(PM_LOG_LCD_OFF_COMPLETE, get_pm_cur_state());
105         else
106                 pm_history_save(PM_LOG_LCD_CONTROL_FAIL, on);
107 #endif
108
109         return 0;
110 }
111
112 static int bl_brt(int brightness, int delay)
113 {
114         int ret = -1;
115
116         if (delay > 0)
117                 usleep(delay);
118
119         /* Update device brightness */
120         ret = backlight_ops.set_brightness(brightness);
121
122         _I("Set brightness(%d): %d", brightness, ret);
123
124         return ret;
125 }
126
127 static int get_lcd_power_node(void)
128 {
129         int ret;
130         enum display_state val;
131
132         ret = hal_device_display_get_state(&val);
133         if (ret < 0)
134                 return ret;
135
136         if (val == DISPLAY_ON && ambient_get_state())
137                 return DPMS_OFF;
138
139         if (dpms_running_state != DPMS_SETTING_DONE)
140                 return dpms_running_state;
141
142         switch (val) {
143                 case DISPLAY_ON:
144                         return DPMS_ON;
145                 case DISPLAY_STANDBY:
146                         return DPMS_STANDBY;
147                 case DISPLAY_SUSPEND:
148                         return DPMS_SUSPEND;
149                 case DISPLAY_OFF:
150                         return DPMS_OFF;
151                 default:
152                         return -EINVAL;
153         }
154 }
155
156 bool display_dimstay_check(void)
157 {
158         if (get_pm_status_flag() & DIM_FLAG)
159                 return true;
160
161         if ((get_pm_status_flag() & PWRSV_FLAG) && !(get_pm_status_flag() & BRTCH_FLAG))
162                 return true;
163
164         return false;
165 }
166
167 static void change_brightness(int start, int end, int step)
168 {
169         int diff, val;
170         int ret = -1;
171         int prev;
172
173         if (display_dimstay_check())
174                 return;
175
176         ret = backlight_ops.get_brightness(&prev);
177         if (ret < 0) {
178                 _E("Failed to get brightness: %d", ret);
179                 return;
180         }
181
182         if (prev == end)
183                 return;
184
185         if (get_pm_status_flag() & DIM_MASK)
186                 end = 0;
187
188         _I("start %d end %d step %d", start, end, step);
189
190         if (display_dev_available) {
191                 ret = hal_device_display_set_multi_brightness(end, step, LCD_PHASED_DELAY);
192                 if (ret != -ENODEV) {
193                         if (ret < 0)
194                                 _E("Failed to set_multi_brightness (%d)", ret);
195
196                         backlight_ops.set_brightness(end);
197
198                         return;
199                 }
200         }
201
202         diff = end - start;
203
204         if (abs(diff) < step)
205                 val = (diff > 0 ? 1 : -1);
206         else
207                 val = (int)ceil((double)diff / step);
208
209         while (start != end) {
210                 if (val == 0) break;
211
212                 start += val;
213                 if ((val > 0 && start > end) ||
214                     (val < 0 && start < end))
215                         start = end;
216
217                 bl_brt(start, LCD_PHASED_DELAY);
218         }
219 }
220
221 static int backlight_on(enum device_flags flags)
222 {
223         int ret = -1;
224         static int cnt;
225
226         _I("[DPMS XLIB Backlight] LCD on %#x cnt:%d", flags, cnt);
227
228         cnt++;
229         ret = bl_onoff(DPMS_ON, flags);
230 #ifdef ENABLE_PM_LOG
231         pm_history_save(PM_LOG_LCD_ON, get_pm_cur_state());
232 #endif
233
234         return ret;
235 }
236
237 static int backlight_off(enum device_flags flags)
238 {
239         int ret = -1;
240         static int cnt, ambient_cnt;
241
242         if (flags & AMBIENT_MODE) {
243                 _I("[DPMS XLIB Backlight] LCD suspend %#x cnt:%d", flags, ambient_cnt);
244                 ambient_cnt++;
245
246                 return 0;
247         }
248
249         _I("[DPMS XLIB Backlight] LCD off %#x cnt:%d", flags, cnt);
250         cnt++;
251
252         if (flags & LCD_PHASED_TRANSIT_MODE)
253                 backlight_ops.transit_brt(default_brightness,
254                     LCD_PHASED_MIN_BRIGHTNESS, LCD_PHASED_CHANGE_STEP);
255
256         if (flags & FORCE_OFF_MODE)
257                 ret = bl_onoff(DPMS_FORCE_OFF, flags);
258         else
259                 ret = bl_onoff(DPMS_OFF, flags);
260
261 #ifdef ENABLE_PM_LOG
262         pm_history_save(PM_LOG_LCD_OFF, get_pm_cur_state());
263 #endif
264
265         return ret;
266 }
267
268 static int backlight_dim(void)
269 {
270         int ret;
271
272         ret = backlight_ops.set_brightness(PM_DIM_BRIGHTNESS);
273 #ifdef ENABLE_PM_LOG
274         if (!ret)
275                 pm_history_save(PM_LOG_LCD_DIM, get_pm_cur_state());
276         else
277                 pm_history_save(PM_LOG_LCD_DIM_FAIL, get_pm_cur_state());
278 #endif
279         return ret;
280 }
281
282 static int set_custom_status(bool on)
283 {
284         custom_status = on;
285         return 0;
286 }
287
288 static bool get_custom_status(void)
289 {
290         return custom_status;
291 }
292
293 static int save_custom_brightness(void)
294 {
295         int ret, brightness;
296
297         ret = backlight_ops.get_brightness(&brightness);
298
299         custom_brightness = brightness;
300
301         return ret;
302 }
303
304 static int custom_backlight_update(void)
305 {
306         int ret = 0;
307
308         if (custom_brightness < PM_MIN_BRIGHTNESS ||
309             custom_brightness > PM_MAX_BRIGHTNESS)
310                 return -EINVAL;
311
312         if (display_dimstay_check())
313                 ret = backlight_dim();
314         else {
315                 _I("custom brightness restored! %d", custom_brightness);
316                 ret = backlight_ops.set_brightness(custom_brightness);
317         }
318
319         return ret;
320 }
321
322 static int set_force_brightness(int level)
323 {
324         if (level < 0 ||  level > PM_MAX_BRIGHTNESS)
325                 return -EINVAL;
326
327         force_brightness = level;
328
329         return 0;
330 }
331
332 static int backlight_update(void)
333 {
334         int ret = 0;
335         int brt;
336
337         if (get_custom_status()) {
338                 _I("custom brightness mode! brt no updated");
339                 return 0;
340         }
341         if (display_dimstay_check())
342                 ret = backlight_dim();
343         else {
344                 brt = backlight_ops.get_default_brt();
345                 ret = backlight_ops.set_brightness(brt);
346         }
347         return ret;
348 }
349
350 static int backlight_standby(int force)
351 {
352         int ret = -1;
353
354         if ((dpms_get_cached_state() == DPMS_ON) || force) {
355                 _I("LCD standby");
356                 ret = bl_onoff(DPMS_STANDBY, 0);
357         }
358
359         return ret;
360 }
361
362 static int set_default_brt(int level)
363 {
364         if (level < PM_MIN_BRIGHTNESS || level > PM_MAX_BRIGHTNESS)
365                 level = display_conf->pm_default_brightness;
366
367         default_brightness = level;
368
369         return 0;
370 }
371
372 static int get_default_brt(void)
373 {
374         return default_brightness;
375 }
376
377 static int get_max_brightness(void)
378 {
379         static int max = -1;
380         int ret;
381
382         if (max > 0)
383                 return max;
384
385         if (!display_dev_available) {
386                 _E("There is no HAL for display device.");
387                 return -ENOENT;
388         }
389
390         ret = hal_device_display_get_max_brightness(&max);
391         if (ret < 0) {
392                 if (ret == -ENODEV) {
393                         _E("Get max brightness is not supported.");
394                         max = DEFAULT_DISPLAY_MAX_BRIGHTNESS;
395                         return max;
396                 } else {
397                         _E("Failed to get max brightness: %d", ret);
398                         return ret;
399                 }
400         }
401
402         return max;
403 }
404
405 static int set_brightness(int val)
406 {
407         int max;
408
409         if (!display_dev_available) {
410                 _E("There is no display device.");
411                 return -ENOENT;
412         }
413
414         max = get_max_brightness();
415         if (max < 0) {
416                 _E("Failed to get max brightness.");
417                 return max;
418         }
419
420         if (force_brightness > 0 && val != PM_DIM_BRIGHTNESS) {
421                 _I("brightness(%d), force brightness(%d)",
422                     val, force_brightness);
423                 val = force_brightness;
424         }
425
426         if (get_pm_status_flag() & DIM_MASK)
427                 val = 0;
428
429         /* Maximum Brightness to users is 100.
430          * Thus real brightness need to be calculated */
431         val = val * max / 100;
432
433         _I("set brightness %d (default:%d)", val, default_brightness);
434         device_notify(DEVICE_NOTIFIER_DISPLAY_BRIGHTNESS, (void *)&val);
435
436         return hal_device_display_set_brightness(val);
437 }
438
439 static int get_brt_normalized(int brt_raw)
440 {
441         int quotient, remainder;
442         int max;
443
444         max = get_max_brightness();
445         if (max < 0) {
446                 _E("Failed to get max brightness.");
447                 return max;
448         }
449
450         /* Maximum Brightness to users is 100.
451          * Thus the brightness value need to be calculated using real brightness.
452          *    ex) Let's suppose that the maximum brightness of driver is 255.
453          *      case 1) When the user sets the brightness to 41,
454          *              real brightness is
455          *                 41 * 255 / 100 = 104.55 = 104 (rounded off)
456          *      case 2) When the user gets the brightness,
457          *              the driver returns the brightness 104.
458          *              Thus the brightness to users is
459          *                 104 * 100 / 255 = 40.7843.... = 41 (rounded up)
460          */
461         quotient = brt_raw * 100 / max;
462         remainder = brt_raw * 100 % max;
463         if (remainder > 0)
464                 quotient++;
465
466         return quotient;
467 }
468
469 static int get_brightness(int *val)
470 {
471         int brt, ret;
472
473         if (!display_dev_available) {
474                 _E("There is no display device.");
475                 return -ENOENT;
476         }
477
478         ret = hal_device_display_get_brightness(&brt);
479         if (ret < 0) {
480                 if (ret == -ENODEV)
481                         _E("Get brightness is not supported.");
482                 else
483                         _E("Failed to get brightness: %d", ret);
484
485                 return ret;
486         }
487
488         *val = get_brt_normalized(brt);
489         return 0;
490 }
491
492 static int get_brightness_by_light_sensor(float lmax, float lmin, float light, int *brt)
493 {
494         int brt_raw;
495         int ret;
496
497         if (!display_dev_available)
498                 return -ENOTSUP;
499
500         ret = hal_device_display_get_auto_brightness(lmax, lmin, light, &brt_raw);
501         if (ret < 0) {
502                 if (ret == -ENODEV)
503                         _E("Get auto brightness is not supported.");
504                 else
505                         _E("Failed to get brightness by light sensor: %d", ret);
506
507                 return ret;
508         }
509
510         *brt = get_brt_normalized(brt_raw);
511         return 0;
512 }
513
514 static int get_image_effect(enum display_image_effect *effect)
515 {
516         int ret;
517         enum display_image_effect val;
518
519         if (!display_dev_available) {
520                 _E("There is no display device.");
521                 return -ENOENT;
522         }
523
524         ret = hal_device_display_get_image_effect(&val);
525         if (ret < 0) {
526                 if (ret == -ENODEV)
527                         _E("Get image effect is not supported.");
528                 else
529                         _E("Failed to get image effect: %d", ret);
530
531                 return ret;
532         }
533
534         *effect = val;
535
536         return 0;
537 }
538
539 static int set_image_effect(enum display_image_effect effect)
540 {
541         int ret;
542
543         if (!display_dev_available) {
544                 _E("There is no display device.");
545                 return -ENOENT;
546         }
547
548         ret = hal_device_display_set_image_effect(effect);
549         if (ret < 0) {
550                 if (ret == -ENODEV)
551                         _E("Set image effect is not supported.");
552                 else
553                         _E("Failed to set image effect: %d", ret);
554
555                 return ret;
556         }
557
558         return 0;
559 }
560
561 static int get_panel_mode(enum display_panel_mode *mode)
562 {
563         int ret;
564         enum display_panel_mode val;
565
566         if (!display_dev_available) {
567                 _E("There is no display device.");
568                 return -ENOENT;
569         }
570
571         ret = hal_device_display_get_panel_mode(&val);
572         if (ret < 0) {
573                 if (ret == -ENODEV)
574                         _E("Get panel mode is not supported.");
575                 else
576                         _E("Failed to get panel mode(%d)", ret);
577
578                 return ret;
579         }
580
581         *mode = val;
582
583         return 0;
584 }
585
586 static int set_panel_mode(enum display_panel_mode mode)
587 {
588         int ret;
589
590         if (!display_dev_available) {
591                 _E("There is no display device.");
592                 return -ENOENT;
593         }
594
595         ret = hal_device_display_set_panel_mode(mode);
596         if (ret < 0) {
597                 if (ret == -ENODEV)
598                         _E("Set panel mode is not supported.");
599                 else
600                         _E("Failed to set panel mode(%d)", ret);
601
602                 return ret;
603         }
604
605         return 0;
606 }
607
608 static int get_frame_rate(int *rate)
609 {
610         if (!rate)
611                 return -EINVAL;
612
613         if (!display_dev_available)
614                 return -ENOTSUP;
615
616         return hal_device_display_get_frame_rate(rate);
617 }
618
619 static int set_frame_rate(int rate)
620 {
621         int ret = 0;
622         static int fmin = -1, fmax = -1;
623
624         if (!display_dev_available)
625                 return -ENOTSUP;
626
627         if (fmin < 0) {
628                 ret = hal_device_display_get_min_frame_rate(&fmin);
629                 if (ret < 0) {
630                         _E("Failed to get min frate rate: %d", ret);
631                         return ret;
632                 }
633         }
634         if ((ret != -ENODEV) && (rate < fmin)) {
635                 _E("Invalid rate(%d). (Valid rate: %d <= rate)", rate, fmin);
636                 return -EINVAL;
637         }
638
639         if (fmax < 0) {
640                 ret = hal_device_display_get_max_frame_rate(&fmax);
641                 if (ret < 0) {
642                         _E("Failed to get max frate rate: %d", ret);
643                         return ret;
644                 }
645         }
646         if ((ret != -ENODEV) && (rate > fmax)) {
647                 _E("Invalid rate(%d). (Valid rate: rate <= %d)", rate, fmax);
648                 return -EINVAL;
649         }
650
651         return hal_device_display_set_frame_rate(rate);
652 }
653
654 /* It was operated only AOD enter & leave */
655 static int backlight_transit_state(int state)
656 {
657         int brt, val;
658         int start, end;
659
660         backlight_ops.get_brightness(&brt);
661
662         if (state == DPMS_OFF) {
663                 start = brt;
664                 end = display_conf->aod_enter_level;
665
666                 /*
667                  * The value of backlight_ops.get_brightness is system brightness.
668                  * But when device is LBM, the value is not same with real brightness.
669                  * So it should be read exactly value for transit smooth effect
670                  */
671                 get_brightness(&val);
672
673                 if (val > display_conf->aod_enter_level)
674                         backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
675         } else {
676                 /* prevent transit effect when another effect is already executed */
677                 if (brt != display_conf->aod_enter_level) {
678                         _W("effect is already executed brt(%d) aod_level(%d)",
679                                         brt, display_conf->aod_enter_level);
680                         return 0;
681                 }
682
683                 start = display_conf->aod_enter_level;
684                 end = default_brightness;
685                 backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
686         }
687
688         return 0;
689 }
690
691 static gboolean blink_cb(gpointer data)
692 {
693         static bool flag;
694
695         set_brightness(flag ? PM_MAX_BRIGHTNESS : PM_MIN_BRIGHTNESS);
696
697         flag = !flag;
698
699         return G_SOURCE_CONTINUE;
700 }
701
702 static void blink(int timeout)
703 {
704         static guint timer;
705
706         if (timer) {
707                 g_source_remove(timer);
708                 timer = 0;
709         }
710
711         if (timeout < 0) {
712                 _E("timeout value is invalid %d", timeout);
713                 return;
714         }
715
716         if (timeout == 0) {
717                 backlight_update();
718                 return;
719         }
720
721         timer = g_timeout_add(timeout, blink_cb, NULL);
722 }
723
724 static gboolean release_blink_cb(gpointer data)
725 {
726         blink(0);
727
728         release_timer = 0;
729         return G_SOURCE_REMOVE;
730 }
731
732 static void release_blink(void)
733 {
734         if (release_timer) {
735                 g_source_remove(release_timer);
736                 release_timer = 0;
737         }
738
739         release_timer = g_timeout_add(DUMP_MODE_WAITING_TIME, release_blink_cb, NULL);
740 }
741
742 static void restore_brightness_func(void)
743 {
744         backlight_ops.set_brightness = set_brightness;
745         backlight_ops.get_brightness = get_brightness;
746         backlight_ops.transit_brt = change_brightness;
747 }
748
749 static struct _backlight_ops backlight_ops = {
750         .off = backlight_off,
751         .dim = backlight_dim,
752         .on = backlight_on,
753         .update = backlight_update,
754         .standby = backlight_standby,
755         .set_default_brt = set_default_brt,
756         .get_default_brt = get_default_brt,
757         .get_lcd_power = dpms_get_cached_state,
758         .get_lcd_power_node = get_lcd_power_node,
759         .set_custom_status = set_custom_status,
760         .get_custom_status = get_custom_status,
761         .save_custom_brightness = save_custom_brightness,
762         .custom_update = custom_backlight_update,
763         .set_force_brightness = set_force_brightness,
764         .set_brightness = set_brightness,
765         .get_brightness = get_brightness,
766         .restore_brightness_func = restore_brightness_func,
767         .get_brightness_by_light_sensor = get_brightness_by_light_sensor,
768         .get_image_effect = get_image_effect,
769         .set_image_effect = set_image_effect,
770         .get_panel_mode = get_panel_mode,
771         .set_panel_mode = set_panel_mode,
772         .get_frame_rate = get_frame_rate,
773         .set_frame_rate = set_frame_rate,
774         .transit_state = backlight_transit_state,
775         .transit_brt = change_brightness,
776         .blink = blink,
777         .release_blink = release_blink,
778 };
779
780 int display_service_load(void)
781 {
782         int r;
783
784         if (display_dev_available)
785                 return 0;
786
787         r = hal_device_display_get_backend();
788         if (r < 0) {
789                 _E("There is no HAL for display.");
790                 display_dev_available = false;
791                 return 0;
792         }
793
794         display_dev_available = true;
795         _D("Display device structure load success.");
796         return 0;
797 }
798
799 int display_service_free(void)
800 {
801         display_dev_available = false;
802         return hal_device_display_put_backend();
803 }
804
805 /* Dummy. Do not consider detached display state */
806 int is_lcdon_blocked(void)
807 {
808         return LCDON_BLOCK_NONE;
809 }
810
811 int init_sysfs(unsigned int flags)
812 {
813         register_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
814
815         return 0;
816 }
817
818 int exit_sysfs(void)
819 {
820         const struct device_ops *ops = NULL;
821
822         backlight_update();
823
824         exit_dpms();
825
826         ops = find_device("touchscreen");
827         if (!check_default(ops))
828                 ops->start(NORMAL_MODE);
829
830         ops = find_device("touchkey");
831         if (!check_default(ops))
832                 ops->start(NORMAL_MODE);
833
834         unregister_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
835
836         return 0;
837 }
838
839 static void __CONSTRUCTOR__ initialize(void)
840 {
841         display_conf = get_var_display_config();
842         if (!display_conf)
843                 _E("Failed to get display configuration variable.");
844 }
845