tizen 2.3 release
[framework/system/deviced.git] / src / display / device-interface.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 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 <journal/display.h>
31
32 #include "core/log.h"
33 #include "core/devices.h"
34 #include "util.h"
35 #include "device-interface.h"
36 #include "vconf.h"
37 #include "core.h"
38 #include "device-node.h"
39 #include "weaks.h"
40
41 #define TOUCH_ON        1
42 #define TOUCH_OFF       0
43
44 #define LCD_PHASED_MIN_BRIGHTNESS       1
45 #define LCD_PHASED_MAX_BRIGHTNESS       100
46 #define LCD_PHASED_CHANGE_STEP          5
47 #define LCD_PHASED_DELAY                35000 /* microsecond */
48
49 typedef struct _PMSys PMSys;
50 struct _PMSys {
51         int def_brt;
52         int dim_brt;
53
54         int (*sys_power_state) (PMSys *, int);
55         int (*sys_power_lock) (PMSys *, int);
56         int (*sys_get_power_lock_support) (PMSys *);
57         int (*sys_get_lcd_power) (PMSys *);
58         int (*bl_onoff) (PMSys *, int);
59         int (*bl_brt) (PMSys *, int, int);
60 };
61
62 static PMSys *pmsys;
63 struct _backlight_ops backlight_ops;
64 struct _power_ops power_ops;
65
66 #ifdef ENABLE_X_LCD_ONOFF
67 #include "x-lcd-on.c"
68 static bool x_dpms_enable = false;
69 #endif
70
71 static int power_lock_support = -1;
72 static bool custom_status = false;
73 static int custom_brightness = 0;
74 static int force_brightness = 0;
75
76 static int _bl_onoff(PMSys *p, int on)
77 {
78         int cmd;
79
80         cmd = DISP_CMD(PROP_DISPLAY_ONOFF, DEFAULT_DISPLAY);
81         return device_set_property(DEVICE_TYPE_DISPLAY, cmd, on);
82 }
83
84 static int _bl_brt(PMSys *p, int brightness, int delay)
85 {
86         int ret = -1;
87         int cmd;
88         int prev;
89
90         if (delay > 0)
91                 usleep(delay);
92
93         if (force_brightness > 0 && brightness != p->dim_brt) {
94                 _I("brightness(%d), force brightness(%d)",
95                     brightness, force_brightness);
96                 brightness = force_brightness;
97         }
98
99         cmd = DISP_CMD(PROP_DISPLAY_BRIGHTNESS, DEFAULT_DISPLAY);
100         ret = device_get_property(DEVICE_TYPE_DISPLAY, cmd, &prev);
101
102         /* Update new brightness to vconf */
103         if (!ret && (brightness != prev)) {
104                 vconf_set_int(VCONFKEY_PM_CURRENT_BRIGHTNESS, brightness);
105         }
106
107         /* Update device brightness */
108         ret = device_set_property(DEVICE_TYPE_DISPLAY, cmd, brightness);
109
110         _I("set brightness %d, %d", brightness, ret);
111
112         return ret;
113 }
114
115 static int _sys_power_state(PMSys *p, int state)
116 {
117         if (state < POWER_STATE_SUSPEND || state > POWER_STATE_POST_RESUME)
118                 return 0;
119         return device_set_property(DEVICE_TYPE_POWER, PROP_POWER_STATE, state);
120 }
121
122 static int _sys_power_lock(PMSys *p, int state)
123 {
124         if (state != POWER_LOCK && state != POWER_UNLOCK)
125                 return -1;
126         return device_set_property(DEVICE_TYPE_POWER, PROP_POWER_LOCK, state);
127 }
128
129 static int _sys_get_power_lock_support(PMSys *p)
130 {
131         int value = 0;
132         int ret = -1;
133
134         ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_LOCK_SUPPORT,
135             &value);
136
137         if (ret < 0)
138                 return -1;
139
140         if (value < 0)
141                 return 0;
142
143         return value;
144 }
145
146 static int _sys_get_lcd_power(PMSys *p)
147 {
148         int value = -1;
149         int ret = -1;
150         int cmd;
151
152         cmd = DISP_CMD(PROP_DISPLAY_ONOFF, DEFAULT_DISPLAY);
153         ret = device_get_property(DEVICE_TYPE_DISPLAY, cmd, &value);
154
155         if (ret < 0 || value < 0)
156                 return -1;
157
158         return value;
159 }
160
161 static void _init_bldev(PMSys *p, unsigned int flags)
162 {
163         int ret;
164         //_update_curbrt(p);
165         p->bl_brt = _bl_brt;
166         p->bl_onoff = _bl_onoff;
167 #ifdef ENABLE_X_LCD_ONOFF
168         if (flags & FLAG_X_DPMS) {
169                 p->bl_onoff = pm_x_set_lcd_backlight;
170                 x_dpms_enable = true;
171         }
172 #endif
173 }
174
175 static void _init_pmsys(PMSys *p)
176 {
177         char *val;
178
179         val = getenv("PM_SYS_DIMBRT");
180         p->dim_brt = (val ? atoi(val) : 0);
181         p->sys_power_state = _sys_power_state;
182         p->sys_power_lock = _sys_power_lock;
183         p->sys_get_power_lock_support = _sys_get_power_lock_support;
184         p->sys_get_lcd_power = _sys_get_lcd_power;
185 }
186
187 static void *_system_suspend_cb(void *data)
188 {
189         int ret;
190
191         _I("enter system suspend");
192         if (pmsys && pmsys->sys_power_state)
193                 ret = pmsys->sys_power_state(pmsys, POWER_STATE_SUSPEND);
194         else
195                 ret = -EFAULT;
196
197         if (ret < 0)
198                 _E("Failed to system suspend! %d", ret);
199
200         return (void *)ret;
201 }
202
203 static int system_suspend(void)
204 {
205         pthread_t pth;
206         int ret;
207
208         ret = pthread_create(&pth, 0, _system_suspend_cb, (void*)NULL);
209         if (ret < 0) {
210                 _E("pthread creation failed!, suspend directly!");
211                 _system_suspend_cb((void*)NULL);
212         } else {
213                 pthread_join(pth, NULL);
214         }
215
216         return 0;
217 }
218
219 static int system_pre_suspend(void)
220 {
221         _I("enter system pre suspend");
222         if (pmsys && pmsys->sys_power_state)
223                 return pmsys->sys_power_state(pmsys, POWER_STATE_PRE_SUSPEND);
224
225         return 0;
226 }
227
228 static int system_post_resume(void)
229 {
230         _I("enter system post resume");
231         if (pmsys && pmsys->sys_power_state)
232                 return pmsys->sys_power_state(pmsys, POWER_STATE_POST_RESUME);
233
234         return 0;
235 }
236
237 static int system_power_lock(void)
238 {
239         _I("system power lock");
240         if (pmsys && pmsys->sys_power_lock)
241                 return pmsys->sys_power_lock(pmsys, POWER_LOCK);
242
243         return 0;
244 }
245
246 static int system_power_unlock(void)
247 {
248         _I("system power unlock");
249         if (pmsys && pmsys->sys_power_lock)
250                 return pmsys->sys_power_lock(pmsys, POWER_UNLOCK);
251
252         return 0;
253 }
254
255 static int system_get_power_lock_support(void)
256 {
257         int value = -1;
258
259         if (power_lock_support == -1) {
260                 if (pmsys && pmsys->sys_get_power_lock_support) {
261                         value = pmsys->sys_get_power_lock_support(pmsys);
262                         if (value == 1) {
263                                         _I("system power lock : support");
264                                         power_lock_support = 1;
265                         } else {
266                                 _E("system power lock : not support");
267                                 power_lock_support = 0;
268                         }
269                 } else {
270                         _E("system power lock : read fail");
271                         power_lock_support = 0;
272                 }
273         }
274
275         return power_lock_support;
276 }
277
278 static int get_lcd_power(void)
279 {
280         if (pmsys && pmsys->sys_get_lcd_power) {
281                 return pmsys->sys_get_lcd_power(pmsys);
282         }
283
284         return -1;
285 }
286
287 static int backlight_hbm_off(void)
288 {
289 #ifdef MICRO_DD
290         return -EINVAL;
291 #else
292         int ret, state;
293
294         ret = device_get_property(DEVICE_TYPE_DISPLAY,
295             PROP_DISPLAY_HBM_CONTROL, &state);
296         if (ret < 0)
297                 return ret;
298
299         if (state) {
300                 ret = device_set_property(DEVICE_TYPE_DISPLAY,
301                     PROP_DISPLAY_HBM_CONTROL, 0);
302                 if (ret < 0)
303                         return ret;
304                 _D("hbm is off!");
305         }
306         return 0;
307 #endif
308 }
309 void change_brightness(int start, int end, int step)
310 {
311         int diff, val;
312         int ret = -1;
313         int cmd;
314         int prev;
315
316         if ((pm_status_flag & PWRSV_FLAG) &&
317             !(pm_status_flag & BRTCH_FLAG))
318                 return;
319
320         cmd = DISP_CMD(PROP_DISPLAY_BRIGHTNESS, DEFAULT_DISPLAY);
321         ret = device_get_property(DEVICE_TYPE_DISPLAY, cmd, &prev);
322
323         if (prev == end)
324                 return;
325
326         _D("start %d end %d step %d", start, end, step);
327
328         diff = end - start;
329
330         if (abs(diff) < step)
331                 val = (diff > 0 ? 1 : -1);
332         else
333                 val = (int)ceil(diff / step);
334
335         while (start != end) {
336                 if (val == 0) break;
337
338                 start += val;
339                 if ((val > 0 && start > end) ||
340                     (val < 0 && start < end))
341                         start = end;
342
343                 pmsys->bl_brt(pmsys, start, LCD_PHASED_DELAY);
344         }
345 }
346
347 static int backlight_on(enum device_flags flags)
348 {
349         int ret = -1;
350         int i;
351
352         _D("LCD on %x", flags);
353
354         if (!pmsys || !pmsys->bl_onoff)
355                 return -1;
356
357         for (i = 0; i < PM_LCD_RETRY_CNT; i++) {
358                 ret = pmsys->bl_onoff(pmsys, STATUS_ON);
359                 if (get_lcd_power() == PM_LCD_POWER_ON) {
360 #ifdef ENABLE_PM_LOG
361                         pm_history_save(PM_LOG_LCD_ON, pm_cur_state);
362 #endif
363                         journal_display_on(pmsys->def_brt);
364                         break;
365                 } else {
366 #ifdef ENABLE_PM_LOG
367                         pm_history_save(PM_LOG_LCD_ON_FAIL, pm_cur_state);
368 #endif
369 #ifdef ENABLE_X_LCD_ONOFF
370                         _E("Failed to LCD on, through xset");
371 #else
372                         _E("Failed to LCD on, through OAL");
373 #endif
374                         ret = -1;
375                 }
376         }
377
378         if (flags & LCD_PHASED_TRANSIT_MODE)
379                 change_brightness(LCD_PHASED_MIN_BRIGHTNESS,
380                     pmsys->def_brt, LCD_PHASED_CHANGE_STEP);
381
382         return ret;
383 }
384
385 static int backlight_off(enum device_flags flags)
386 {
387         int ret = -1;
388         int i;
389
390         _D("LCD off %x", flags);
391
392         if (!pmsys || !pmsys->bl_onoff)
393                 return -1;
394
395         if (flags & LCD_PHASED_TRANSIT_MODE)
396                 change_brightness(pmsys->def_brt,
397                     LCD_PHASED_MIN_BRIGHTNESS, LCD_PHASED_CHANGE_STEP);
398
399         if (flags & AMBIENT_MODE)
400                 return 0;
401
402         for (i = 0; i < PM_LCD_RETRY_CNT; i++) {
403 #ifdef ENABLE_X_LCD_ONOFF
404                 if (x_dpms_enable == false)
405 #endif
406                         usleep(30000);
407                 ret = pmsys->bl_onoff(pmsys, STATUS_OFF);
408                 if (get_lcd_power() == PM_LCD_POWER_OFF) {
409 #ifdef ENABLE_PM_LOG
410                         pm_history_save(PM_LOG_LCD_OFF, pm_cur_state);
411 #endif
412                         journal_display_off();
413                         break;
414                 } else {
415 #ifdef ENABLE_PM_LOG
416                         pm_history_save(PM_LOG_LCD_OFF_FAIL, pm_cur_state);
417 #endif
418 #ifdef ENABLE_X_LCD_ONOFF
419                         _E("Failed to LCD off, through xset");
420 #else
421                         _E("Failed to LCD off, through OAL");
422 #endif
423                         ret = -1;
424                 }
425         }
426         return ret;
427 }
428
429 static int backlight_dim(void)
430 {
431         int ret = 0;
432         if (pmsys && pmsys->bl_brt) {
433                 ret = pmsys->bl_brt(pmsys, pmsys->dim_brt, 0);
434 #ifdef ENABLE_PM_LOG
435                 if (!ret)
436                         pm_history_save(PM_LOG_LCD_DIM, pm_cur_state);
437                 else
438                         pm_history_save(PM_LOG_LCD_DIM_FAIL, pm_cur_state);
439 #endif
440         }
441         return ret;
442 }
443
444 static int set_custom_status(bool on)
445 {
446         custom_status = on;
447         return 0;
448 }
449
450 static bool get_custom_status(void)
451 {
452         return custom_status;
453 }
454
455 static int save_custom_brightness(void)
456 {
457         int cmd, ret, brightness;
458
459         cmd = DISP_CMD(PROP_DISPLAY_BRIGHTNESS, DEFAULT_DISPLAY);
460         ret = device_get_property(DEVICE_TYPE_DISPLAY, cmd, &brightness);
461
462         custom_brightness = brightness;
463
464         return ret;
465 }
466
467 static int custom_backlight_update(void)
468 {
469         int ret = 0;
470
471         if (custom_brightness < PM_MIN_BRIGHTNESS ||
472             custom_brightness > PM_MAX_BRIGHTNESS)
473                 return -EINVAL;
474
475         if ((pm_status_flag & PWRSV_FLAG) && !(pm_status_flag & BRTCH_FLAG)) {
476                 ret = backlight_dim();
477         } else if (pmsys && pmsys->bl_brt) {
478                 _I("custom brightness restored! %d", custom_brightness);
479                 ret = pmsys->bl_brt(pmsys, custom_brightness, 0);
480         }
481
482         return ret;
483 }
484
485 static int set_force_brightness(int level)
486 {
487         if (level < 0 ||  level > PM_MAX_BRIGHTNESS)
488                 return -EINVAL;
489
490         force_brightness = level;
491
492         return 0;
493 }
494
495 static int backlight_update(void)
496 {
497         int ret = 0;
498
499         if (hbm_get_state != NULL && hbm_get_state() == true) {
500                 _I("HBM is on, backlight is not updated!");
501                 return 0;
502         }
503
504         if (get_custom_status()) {
505                 _I("custom brightness mode! brt no updated");
506                 return 0;
507         }
508         if ((pm_status_flag & PWRSV_FLAG) && !(pm_status_flag & BRTCH_FLAG)) {
509                 ret = backlight_dim();
510         } else if (pmsys && pmsys->bl_brt) {
511                 ret = pmsys->bl_brt(pmsys, pmsys->def_brt, 0);
512         }
513         return ret;
514 }
515
516 static int backlight_standby(int force)
517 {
518         int ret = -1;
519         if (!pmsys || !pmsys->bl_onoff)
520                 return -1;
521
522         if ((get_lcd_power() == PM_LCD_POWER_ON) || force) {
523                 _I("LCD standby");
524                 ret = pmsys->bl_onoff(pmsys, STATUS_STANDBY);
525         }
526
527         return ret;
528 }
529
530 static int set_default_brt(int level)
531 {
532         if (!pmsys)
533                 return -EFAULT;
534
535         if (level < PM_MIN_BRIGHTNESS || level > PM_MAX_BRIGHTNESS)
536                 level = PM_DEFAULT_BRIGHTNESS;
537         pmsys->def_brt = level;
538
539         return 0;
540 }
541
542
543
544 static int check_wakeup_src(void)
545 {
546         /*  TODO if nedded.
547          * return wackeup source. user input or device interrupts? (EVENT_DEVICE or EVENT_INPUT)
548          */
549         return EVENT_DEVICE;
550 }
551
552 void _init_ops(void)
553 {
554         backlight_ops.off = backlight_off;
555         backlight_ops.dim = backlight_dim;
556         backlight_ops.on = backlight_on;
557         backlight_ops.update = backlight_update;
558         backlight_ops.standby = backlight_standby;
559         backlight_ops.hbm_off = backlight_hbm_off;
560         backlight_ops.set_default_brt = set_default_brt;
561         backlight_ops.get_lcd_power = get_lcd_power;
562         backlight_ops.set_custom_status = set_custom_status;
563         backlight_ops.get_custom_status = get_custom_status;
564         backlight_ops.save_custom_brightness = save_custom_brightness;
565         backlight_ops.custom_update = custom_backlight_update;
566         backlight_ops.set_force_brightness = set_force_brightness;
567
568         power_ops.suspend = system_suspend;
569         power_ops.pre_suspend = system_pre_suspend;
570         power_ops.post_resume = system_post_resume;
571         power_ops.power_lock = system_power_lock;
572         power_ops.power_unlock = system_power_unlock;
573         power_ops.get_power_lock_support = system_get_power_lock_support;
574         power_ops.check_wakeup_src = check_wakeup_src;
575 }
576
577 int init_sysfs(unsigned int flags)
578 {
579         int ret;
580
581         pmsys = (PMSys *) malloc(sizeof(PMSys));
582         if (pmsys == NULL) {
583                 _E("Not enough memory to alloc PM Sys");
584                 return -1;
585         }
586
587         memset(pmsys, 0x0, sizeof(PMSys));
588
589         _init_pmsys(pmsys);
590         _init_bldev(pmsys, flags);
591
592         if (pmsys->bl_onoff == NULL || pmsys->sys_power_state == NULL) {
593                 _E("We have no managable resource to reduce the power consumption");
594                 return -1;
595         }
596
597         _init_ops();
598
599         return 0;
600 }
601
602 int exit_sysfs(void)
603 {
604         int fd;
605         const struct device_ops *ops = NULL;
606
607         fd = open("/tmp/sem.pixmap_1", O_RDONLY);
608         if (fd == -1) {
609                 _E("X server disable");
610                 backlight_on(NORMAL_MODE);
611         }
612
613         backlight_update();
614
615         ops = find_device("touchscreen");
616         if (!check_default(ops))
617                 ops->start(NORMAL_MODE);
618
619         ops = find_device("touchkey");
620         if (!check_default(ops))
621                 ops->start(NORMAL_MODE);
622
623         free(pmsys);
624         pmsys = NULL;
625         if(fd != -1)
626                 close(fd);
627
628         return 0;
629 }