3e7144ff2492665cd4508e8edfbeaaee0141037b
[platform/core/system/deviced.git] / src / 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 <hw/display.h>
33
34 #include "ambient-mode.h"
35 #include "core/log.h"
36 #include "core/devices.h"
37 #include "core/list.h"
38 #include "core/common.h"
39 #include "util.h"
40 #include "device-interface.h"
41 #include "vconf.h"
42 #include "core.h"
43 #include "device-node.h"
44
45 #define TOUCH_ON        1
46 #define TOUCH_OFF       0
47
48 #define LCD_PHASED_MIN_BRIGHTNESS       1
49 #define LCD_PHASED_MAX_BRIGHTNESS       100
50 #define LCD_PHASED_CHANGE_STEP          5
51 #define LCD_PHASED_DELAY                35000 /* microsecond */
52
53 #define POWER_AUTOSLEEP_PATH    "/sys/power/autosleep"
54 #define POWER_LOCK_PATH         "/sys/power/wake_lock"
55 #define POWER_UNLOCK_PATH       "/sys/power/wake_unlock"
56 #define POWER_WAKEUP_PATH       "/sys/power/wakeup_count"
57 #define POWER_STATE_PATH        "/sys/power/state"
58
59 enum {
60         POWER_UNLOCK = 0,
61         POWER_LOCK,
62 };
63
64 struct _backlight_ops backlight_ops;
65 struct _power_ops power_ops;
66
67 static bool custom_status;
68 static int custom_brightness;
69 static int force_brightness;
70 static int default_brightness;
71
72 static struct display_device *display_dev;
73
74 static int bl_onoff(int on)
75 {
76         enum display_state val;
77
78         if (!display_dev || !display_dev->set_state)
79                 return dpms_set_power(on);
80
81         switch (on) {
82         case DPMS_ON:
83                 val = DISPLAY_ON;
84                 break;
85         case DPMS_STANDBY:
86                 val = DISPLAY_STANDBY;
87                 break;
88         case DPMS_SUSPEND:
89                 val = DISPLAY_SUSPEND;
90                 break;
91         case DPMS_OFF:
92                 val = DISPLAY_OFF;
93                 break;
94         default:
95                 return -EINVAL;
96         }
97
98         return display_dev->set_state(val);
99 }
100
101 static int bl_brt(int brightness, int delay)
102 {
103         int ret = -1;
104
105         if (delay > 0)
106                 usleep(delay);
107
108         if (force_brightness > 0) {
109                 _I("brightness(%d), force brightness(%d)",
110                     brightness, force_brightness);
111                 brightness = force_brightness;
112         }
113
114         /* Update device brightness */
115         ret = backlight_ops.set_brightness(brightness);
116
117         _I("set brightness %d, %d", brightness, ret);
118
119         return ret;
120 }
121
122 static int system_suspend(void)
123 {
124         int ret;
125
126         _I("system suspend");
127         ret = sys_set_str(POWER_STATE_PATH, "mem");
128         _I("system resume (result : %d)", ret);
129         return 0;
130 }
131
132 static int system_enable_autosleep(void)
133 {
134         _I("system autosleep enabled");
135         return sys_set_str(POWER_AUTOSLEEP_PATH, "mem");
136 }
137
138 static int system_power_lock(void)
139 {
140         dd_list *elem, *elem_n;
141         const struct device_ops *dev;
142         int ret;
143
144         _I("system power lock");
145         ret = sys_set_str(POWER_LOCK_PATH, "mainlock");
146
147         /* Devices Resume */
148         DD_LIST_FOREACH_SAFE(dev_head, elem, elem_n, dev) {
149                 if (dev->resume)
150                         dev->resume();
151         }
152
153         return ret;
154 }
155
156 static int system_power_unlock(void)
157 {
158         dd_list *elem, *elem_n;
159         const struct device_ops *dev;
160
161         /* Devices Suspend */
162         DD_LIST_FOREACH_SAFE(dev_head, elem, elem_n, dev) {
163                 if (dev->suspend)
164                         dev->suspend();
165         }
166
167         _I("system power unlock");
168         return sys_set_str(POWER_UNLOCK_PATH, "mainlock");
169 }
170
171 static int system_get_power_lock_support(void)
172 {
173         static int power_lock_support = -1;
174         int ret;
175
176         if (power_lock_support >= 0)
177                 goto out;
178
179         ret = sys_check_node(POWER_LOCK_PATH);
180         if (ret < 0)
181                 power_lock_support = false;
182         else
183                 power_lock_support = true;
184
185         _I("system power lock : %s",
186                         (power_lock_support ? "support" : "not support"));
187
188 out:
189         return power_lock_support;
190 }
191
192 static int get_lcd_power(void)
193 {
194         enum dpms_state state;
195         enum display_state val;
196         int ret;
197
198         if (ambient_get_state())
199                 return DPMS_OFF;
200
201         if (!display_dev || !display_dev->get_state) {
202                 ret = dpms_get_power(&state);
203                 if (ret < 0)
204                         return ret;
205                 return state;
206         }
207
208         ret = display_dev->get_state(&val);
209         if (ret < 0)
210                 return ret;
211
212         switch (val) {
213         case DISPLAY_ON:
214                 return DPMS_ON;
215         case DISPLAY_STANDBY:
216                 return DPMS_STANDBY;
217         case DISPLAY_SUSPEND:
218                 return DPMS_SUSPEND;
219         case DISPLAY_OFF:
220                 return DPMS_OFF;
221         default:
222                 return -EINVAL;
223         }
224 }
225
226 void change_brightness(int start, int end, int step)
227 {
228         int diff, val;
229         int ret = -1;
230         int prev;
231
232         if ((pm_status_flag & PWRSV_FLAG) &&
233             !(pm_status_flag & BRTCH_FLAG))
234                 return;
235
236         ret = backlight_ops.get_brightness(&prev);
237         if (ret < 0) {
238                 _E("fail to get brightness : %d", ret);
239                 return;
240         }
241
242         if (prev == end)
243                 return;
244
245         _D("start %d end %d step %d", start, end, step);
246
247         diff = end - start;
248
249         if (abs(diff) < step)
250                 val = (diff > 0 ? 1 : -1);
251         else
252                 val = (int)ceil((double)diff / step);
253
254         while (start != end) {
255                 if (val == 0) break;
256
257                 start += val;
258                 if ((val > 0 && start > end) ||
259                     (val < 0 && start < end))
260                         start = end;
261
262                 bl_brt(start, LCD_PHASED_DELAY);
263         }
264 }
265
266 static int backlight_on(enum device_flags flags)
267 {
268         int ret = -1;
269
270         _D("LCD on %x", flags);
271
272         ret = bl_onoff(DPMS_ON);
273         if (ret < 0)
274                 _E("Failed to turn on backlight");
275
276         if (flags & LCD_PHASED_TRANSIT_MODE)
277                 change_brightness(LCD_PHASED_MIN_BRIGHTNESS,
278                     default_brightness, LCD_PHASED_CHANGE_STEP);
279
280         return ret;
281 }
282
283 static int backlight_off(enum device_flags flags)
284 {
285         int ret = -1;
286
287         _D("LCD off %x", flags);
288
289         if (flags & LCD_PHASED_TRANSIT_MODE)
290                 change_brightness(default_brightness,
291                     LCD_PHASED_MIN_BRIGHTNESS, LCD_PHASED_CHANGE_STEP);
292
293         if (flags & AMBIENT_MODE)
294                 return 0;
295
296         ret = bl_onoff(DPMS_OFF);
297         if (ret < 0)
298                 _E("Failed to turn off backlight");
299
300         return ret;
301 }
302
303 static int backlight_dim(void)
304 {
305         int ret;
306         int brightness;
307
308         if (vconf_get_int(VCONFKEY_SETAPPL_LCD_DIM_BRIGHTNESS, &brightness) != 0) {
309                 _E("Failed to get VCONFKEY_SETAPPL_LCD_DIM_BRIGHTNESS value");
310                 return -EPERM;
311         }
312
313         ret = bl_brt(brightness, 0);
314 #ifdef ENABLE_PM_LOG
315         if (!ret)
316                 pm_history_save(PM_LOG_LCD_DIM, pm_cur_state);
317         else
318                 pm_history_save(PM_LOG_LCD_DIM_FAIL, pm_cur_state);
319 #endif
320         return ret;
321 }
322
323 static int set_custom_status(bool on)
324 {
325         custom_status = on;
326         return 0;
327 }
328
329 static bool get_custom_status(void)
330 {
331         return custom_status;
332 }
333
334 static int save_custom_brightness(void)
335 {
336         int ret, brightness;
337
338         ret = backlight_ops.get_brightness(&brightness);
339
340         custom_brightness = brightness;
341
342         return ret;
343 }
344
345 static int custom_backlight_update(void)
346 {
347         int ret = 0;
348
349         if (custom_brightness < PM_MIN_BRIGHTNESS ||
350             custom_brightness > PM_MAX_BRIGHTNESS)
351                 return -EINVAL;
352
353         if ((pm_status_flag & PWRSV_FLAG) && !(pm_status_flag & BRTCH_FLAG)) {
354                 ret = backlight_dim();
355         } else {
356                 _I("custom brightness restored! %d", custom_brightness);
357                 ret = bl_brt(custom_brightness, 0);
358         }
359
360         return ret;
361 }
362
363 static int set_force_brightness(int level)
364 {
365         if (level < 0 ||  level > PM_MAX_BRIGHTNESS)
366                 return -EINVAL;
367
368         force_brightness = level;
369
370         return 0;
371 }
372
373 static int backlight_update(void)
374 {
375         int ret = 0;
376
377         if (get_custom_status()) {
378                 _I("custom brightness mode! brt no updated");
379                 return 0;
380         }
381         if ((pm_status_flag & PWRSV_FLAG) && !(pm_status_flag & BRTCH_FLAG))
382                 ret = backlight_dim();
383         else
384                 ret = bl_brt(default_brightness, 0);
385
386         return ret;
387 }
388
389 static int backlight_standby(int force)
390 {
391         int ret = -1;
392
393         if ((get_lcd_power() == DPMS_ON) || force) {
394                 _I("LCD standby");
395                 ret = bl_onoff(DPMS_STANDBY);
396         }
397
398         return ret;
399 }
400
401 static int set_default_brt(int level)
402 {
403         if (level < PM_MIN_BRIGHTNESS || level > PM_MAX_BRIGHTNESS)
404                 level = PM_DEFAULT_BRIGHTNESS;
405
406         default_brightness = level;
407
408         return 0;
409 }
410
411 static int check_wakeup_src(void)
412 {
413         /*  TODO if nedded.
414          * return wackeup source. user input or device interrupts? (EVENT_DEVICE or EVENT_INPUT)
415          */
416         return EVENT_DEVICE;
417 }
418
419 static int get_wakeup_count(int *cnt)
420 {
421         int ret;
422         int wakeup_count;
423
424         if (!cnt)
425                 return -EINVAL;
426
427         ret = sys_get_int(POWER_WAKEUP_PATH, &wakeup_count);
428         if (ret < 0)
429                 return ret;
430
431         *cnt = wakeup_count;
432         return 0;
433 }
434
435 static int set_wakeup_count(int cnt)
436 {
437         int ret;
438
439         ret = sys_set_int(POWER_WAKEUP_PATH, cnt);
440         if (ret < 0)
441                 return ret;
442
443         return 0;
444 }
445
446 static int get_max_brightness(void)
447 {
448         static int max = -1;
449         int ret;
450
451         if (max > 0)
452                 return max;
453
454         if (!display_dev) {
455                 _E("there is no display device");
456                 return -ENOENT;
457         }
458
459         if (!display_dev->get_max_brightness) {
460                 max = DEFAULT_DISPLAY_MAX_BRIGHTNESS;
461                 return max;
462         }
463
464         ret = display_dev->get_max_brightness(&max);
465         if (ret < 0) {
466                 _E("Failed to get max brightness (%d)", ret);
467                 return ret;
468         }
469
470         return max;
471 }
472
473 static int set_brightness(int val)
474 {
475         int max;
476
477         if (!display_dev || !display_dev->set_brightness) {
478                 _E("there is no display device");
479                 return -ENOENT;
480         }
481
482         max = get_max_brightness();
483         if (max < 0) {
484                 _E("Failed to get max brightness");
485                 return max;
486         }
487
488         /* Maximum Brightness to users is 100.
489          * Thus real brightness need to be calculated */
490         val = val * max / 100;
491
492         return display_dev->set_brightness(val);
493 }
494
495 static int get_brt_normalized(int brt_raw)
496 {
497         int quotient, remainder;
498         int max;
499
500         max = get_max_brightness();
501         if (max < 0) {
502                 _E("Failed to get max brightness");
503                 return max;
504         }
505
506         /* Maximum Brightness to users is 100.
507          * Thus the brightness value need to be calculated using real brightness.
508          *    ex) Let's suppose that the maximum brightness of driver is 255.
509          *      case 1) When the user sets the brightness to 41,
510          *              real brightness is
511          *                 41 * 255 / 100 = 104.55 = 104 (rounded off)
512          *      case 2) When the user gets the brightness,
513          *              the driver returns the brightness 104.
514          *              Thus the brightness to users is
515          *                 104 * 100 / 255 = 40.7843.... = 41 (rounded up)
516          */
517         quotient = brt_raw * 100 / max;
518         remainder = brt_raw * 100 % max;
519         if (remainder > 0)
520                 quotient++;
521
522         return quotient;
523 }
524
525 static int get_brightness(int *val)
526 {
527         int brt, ret;
528
529         if (!display_dev || !display_dev->get_brightness) {
530                 _E("there is no display device");
531                 return -ENOENT;
532         }
533
534         ret = display_dev->get_brightness(&brt);
535         if (ret < 0) {
536                 _E("failed to get brightness (%d)", ret);
537                 return ret;
538         }
539
540         *val = get_brt_normalized(brt);
541         return 0;
542 }
543
544 static int get_brightness_by_light_sensor(float lmax, float lmin, float light, int *brt)
545 {
546         int brt_raw;
547         int ret;
548
549         if (!display_dev || !display_dev->get_auto_brightness)
550                 return -ENOTSUP;
551
552         ret = display_dev->get_auto_brightness(lmax, lmin, light, &brt_raw);
553         if (ret < 0) {
554                 _E("failed to get brightness by light sensor(%d)", ret);
555                 return ret;
556         }
557
558         *brt = get_brt_normalized(brt_raw);
559         return 0;
560 }
561
562 static int get_frame_rate(int *rate)
563 {
564         if (!rate)
565                 return -EINVAL;
566
567         if (!display_dev || !display_dev->get_frame_rate)
568                 return -ENOTSUP;
569
570         return display_dev->get_frame_rate(rate);
571 }
572
573 static int set_frame_rate(int rate)
574 {
575         int ret;
576         static int fmin = -1, fmax = -1;
577
578         if (!display_dev ||
579                 !display_dev->set_frame_rate)
580                 return -ENOTSUP;
581
582         if (display_dev->get_min_frame_rate) {
583                 if (fmin < 0) {
584                         ret = display_dev->get_min_frame_rate(&fmin);
585                         if (ret < 0) {
586                                 _E("Failed to get min frate rate (%d)", ret);
587                                 return ret;
588                         }
589                 }
590                 if (rate < fmin) {
591                         _E("Invalid rate(%d)! (Valid rate: %d <= rate)", rate, fmin);
592                         return -EINVAL;
593                 }
594         }
595
596         if (display_dev->get_max_frame_rate) {
597                 if (fmax < 0) {
598                         ret = display_dev->get_max_frame_rate(&fmax);
599                         if (ret < 0) {
600                                 _E("Failed to get max frate rate (%d)", ret);
601                                 return ret;
602                         }
603                 }
604                 if (rate > fmax) {
605                         _E("Invalid rate(%d)! (Valid rate: rate <= %d)", rate, fmax);
606                         return -EINVAL;
607                 }
608         }
609
610         return display_dev->set_frame_rate(rate);
611 }
612
613 static void _init_ops(void)
614 {
615         backlight_ops.off = backlight_off;
616         backlight_ops.dim = backlight_dim;
617         backlight_ops.on = backlight_on;
618         backlight_ops.update = backlight_update;
619         backlight_ops.standby = backlight_standby;
620         backlight_ops.set_default_brt = set_default_brt;
621         backlight_ops.get_lcd_power = get_lcd_power;
622         backlight_ops.set_custom_status = set_custom_status;
623         backlight_ops.get_custom_status = get_custom_status;
624         backlight_ops.save_custom_brightness = save_custom_brightness;
625         backlight_ops.custom_update = custom_backlight_update;
626         backlight_ops.set_force_brightness = set_force_brightness;
627         backlight_ops.set_brightness = set_brightness;
628         backlight_ops.get_brightness = get_brightness;
629         backlight_ops.get_brightness_by_light_sensor = get_brightness_by_light_sensor;
630         backlight_ops.get_frame_rate = get_frame_rate;
631         backlight_ops.set_frame_rate = set_frame_rate;
632
633         power_ops.suspend = system_suspend;
634         power_ops.enable_autosleep = system_enable_autosleep;
635         power_ops.power_lock = system_power_lock;
636         power_ops.power_unlock = system_power_unlock;
637         power_ops.get_power_lock_support = system_get_power_lock_support;
638         power_ops.check_wakeup_src = check_wakeup_src;
639         power_ops.get_wakeup_count = get_wakeup_count;
640         power_ops.set_wakeup_count = set_wakeup_count;
641 }
642
643 int display_service_load(void)
644 {
645         struct hw_info *info;
646         int r;
647
648         if (display_dev)
649                 return 0;
650
651         r = hw_get_info(DISPLAY_HARDWARE_DEVICE_ID,
652                         (const struct hw_info **)&info);
653         if (r < 0) {
654                 _I("display shared library is not supported: %d", r);
655                 return -ENODEV;
656         }
657
658         if (!info->open) {
659                 _E("fail to open display device : open(NULL)");
660                 return -EPERM;
661         }
662
663         r = info->open(info, NULL, (struct hw_common **)&display_dev);
664         if (r < 0) {
665                 _E("fail to get display device structure : %d", r);
666                 return -EPERM;
667         }
668
669         _D("display device structure load success");
670         return 0;
671 }
672
673 int display_service_free(void)
674 {
675         struct hw_info *info;
676
677         if (!display_dev)
678                 return -ENOENT;
679
680         info = display_dev->common.info;
681
682         assert(info);
683
684         info->close((struct hw_common *)display_dev);
685         display_dev = NULL;
686
687         return 0;
688 }
689
690 int init_sysfs()
691 {
692         _init_ops();
693         return 0;
694 }
695
696 int exit_sysfs(void)
697 {
698         const struct device_ops *ops = NULL;
699
700         backlight_update();
701
702         ops = find_device("touchscreen");
703         if (!check_default(ops))
704                 ops->start(NORMAL_MODE);
705
706         ops = find_device("touchkey");
707         if (!check_default(ops))
708                 ops->start(NORMAL_MODE);
709
710         return 0;
711 }