display: Move set brightness with delay function from plugins to core display module
[platform/core/system/deviced.git] / plugins / iot-headed / 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 "power/power-suspend.h"
37 #include "core/log.h"
38 #include "shared/devices.h"
39 #include "shared/common.h"
40 #include "shared/device-notifier.h"
41 #include "util.h"
42 #include "device-interface.h"
43 #include "vconf.h"
44 #include "core.h"
45 #include "display/display-dpms.h"
46 #include "display/display.h"
47 #include "display/display-lock.h"
48 #include "display/display-backlight.h"
49 #include "display/display-panel.h"
50
51 #define TOUCH_ON        1
52 #define TOUCH_OFF       0
53
54 #define LCD_PHASED_MAX_BRIGHTNESS       100
55 #define LCD_PHASED_DELAY                10000   /* microsecond */
56
57 #define DISPLAY_HAL_LIB_PATH "/usr/lib/libdisplay-hal.so"
58
59 #define GESTURE_STR                     "gesture"
60 #define POWERKEY_STR                    "powerkey"
61 #define EVENT_STR                       "event"
62 #define TOUCH_STR                       "touch"
63 #define TIMEOUT_STR                     "timeout"
64 #define PROXIMITY_STR                   "proximity"
65 #define PALM_STR                        "palm"
66 #define UNKNOWN_STR                     "unknown"
67
68 #define FREEZER_VITAL_WAKEUP_CGROUP "/sys/fs/cgroup/freezer/vital_wakeup/freezer.state"
69
70 static struct _backlight_ops backlight_ops;
71 static bool display_dev_available = false;
72 static const struct display_config *display_conf;
73
74 inline struct _backlight_ops *get_var_backlight_ops(void)
75 {
76         return &backlight_ops;
77 }
78
79 bool display_dev_ready(void)
80 {
81         return display_dev_available;
82 }
83
84 bool display_dimstay_check(void)
85 {
86         if (get_pm_status_flag() & DIM_FLAG)
87                 return true;
88
89         if ((get_pm_status_flag() & PWRSV_FLAG) && !(get_pm_status_flag() & BRTCH_FLAG))
90                 return true;
91
92         return false;
93 }
94
95 static void change_brightness(int start, int end, int step)
96 {
97         int diff, val;
98         int ret = -1;
99         int prev;
100
101         if (display_dimstay_check())
102                 return;
103
104         ret = backlight_ops.get_brightness(&prev);
105         if (ret < 0) {
106                 _E("Failed to get brightness: %d", ret);
107                 return;
108         }
109
110         if (prev == end)
111                 return;
112
113         if (get_pm_status_flag() & DIM_MASK)
114                 end = 0;
115
116         _I("start %d end %d step %d", start, end, step);
117
118         if (display_dev_available) {
119                 ret = hal_device_display_set_multi_brightness(end, step, LCD_PHASED_DELAY);
120                 if (ret != -ENODEV) {
121                         if (ret < 0)
122                                 _E("Failed to set_multi_brightness (%d)", ret);
123
124                         backlight_ops.set_brightness(end);
125
126                         return;
127                 }
128         }
129
130         diff = end - start;
131
132         if (abs(diff) < step)
133                 val = (diff > 0 ? 1 : -1);
134         else
135                 val = (int)ceil((double)diff / step);
136
137         while (start != end) {
138                 if (val == 0) break;
139
140                 start += val;
141                 if ((val > 0 && start > end) ||
142                     (val < 0 && start < end))
143                         start = end;
144
145                 display_backlight_set_brightness_with_delay(start, LCD_PHASED_DELAY);
146         }
147 }
148
149 static int set_brightness(int val)
150 {
151         int max, ret;
152         int default_brightness = 0, force_brightness = 0;
153
154         display_backlight_get_default_brightness(&default_brightness);
155         display_backlight_get_force_brightness(&force_brightness);
156
157         if (!display_dev_available) {
158                 _E("There is no display device.");
159                 return -ENOENT;
160         }
161
162         ret = display_backlight_get_max_brightness(&max);
163         if (ret < 0) {
164                 _E("Failed to get max brightness.");
165                 return ret;
166         }
167
168         if (force_brightness > 0 && val != PM_DIM_BRIGHTNESS) {
169                 _I("brightness(%d), force brightness(%d)",
170                     val, force_brightness);
171                 val = force_brightness;
172         }
173
174         if (get_pm_status_flag() & DIM_MASK)
175                 val = 0;
176
177         /* Maximum Brightness to users is 100.
178          * Thus real brightness need to be calculated */
179         val = val * max / 100;
180
181         _I("set brightness %d (default:%d)", val, default_brightness);
182         device_notify(DEVICE_NOTIFIER_DISPLAY_BRIGHTNESS, (void *)&val);
183
184         return hal_device_display_set_brightness(val);
185 }
186
187 static int get_brightness(int *val)
188 {
189         int brt, ret;
190
191         if (!display_dev_available) {
192                 _E("There is no display device.");
193                 return -ENOENT;
194         }
195
196         ret = hal_device_display_get_brightness(&brt);
197         if (ret < 0) {
198                 if (ret == -ENODEV)
199                         _E("Get brightness is not supported.");
200                 else
201                         _E("Failed to get brightness: %d", ret);
202
203                 return ret;
204         }
205
206         ret = display_backlight_get_normalized_brightness(brt, val);
207         if (ret < 0) {
208                 _E("Failed to get normalized brightness.");
209                 return ret;
210         }
211
212         return 0;
213 }
214
215 /* It was operated only AOD enter & leave */
216 static int backlight_transit_state(int state)
217 {
218         int brt, val;
219         int start, end;
220         int default_brightness = 0;
221
222         display_backlight_get_default_brightness(&default_brightness);
223
224         backlight_ops.get_brightness(&brt);
225
226         if (state == DPMS_OFF) {
227                 start = brt;
228                 end = display_conf->aod_enter_level;
229
230                 /*
231                  * The value of backlight_ops.get_brightness is system brightness.
232                  * But when device is LBM, the value is not same with real brightness.
233                  * So it should be read exactly value for transit smooth effect
234                  */
235                 get_brightness(&val);
236
237                 if (val > display_conf->aod_enter_level)
238                         backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
239         } else {
240                 /* prevent transit effect when another effect is already executed */
241                 if (brt != display_conf->aod_enter_level) {
242                         _W("effect is already executed brt(%d) aod_level(%d)",
243                                         brt, display_conf->aod_enter_level);
244                         return 0;
245                 }
246
247                 start = display_conf->aod_enter_level;
248                 end = default_brightness;
249                 backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
250         }
251
252         return 0;
253 }
254
255 static void restore_brightness_func(void)
256 {
257         backlight_ops.set_brightness = set_brightness;
258         backlight_ops.get_brightness = get_brightness;
259         backlight_ops.transit_brt = change_brightness;
260 }
261
262 static struct _backlight_ops backlight_ops = {
263         .get_lcd_power = dpms_get_cached_state,
264         .set_brightness = set_brightness,
265         .get_brightness = get_brightness,
266         .restore_brightness_func = restore_brightness_func,
267         .transit_state = backlight_transit_state,
268         .transit_brt = change_brightness,
269 };
270
271 int display_service_load(void)
272 {
273         int r;
274
275         if (display_dev_available)
276                 return 0;
277
278         r = hal_device_display_get_backend();
279         if (r < 0) {
280                 _E("There is no HAL for display.");
281                 display_dev_available = false;
282                 display_set_hal_backend_available(display_dev_available);
283                 return 0;
284         }
285
286         display_dev_available = true;
287         display_set_hal_backend_available(display_dev_available);
288         _D("Display device structure load success.");
289         return 0;
290 }
291
292 int display_service_free(void)
293 {
294         display_dev_available = false;
295         return hal_device_display_put_backend();
296 }
297
298 /* Dummy. Do not consider detached display state */
299 int is_lcdon_blocked(void)
300 {
301         return LCDON_BLOCK_NONE;
302 }
303
304 int init_sysfs(unsigned int flags)
305 {
306         register_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
307
308         return 0;
309 }
310
311 int exit_sysfs(void)
312 {
313         const struct device_ops *ops = NULL;
314
315         display_backlight_update_by_default_brightness();
316
317         dpms_exit();
318
319         ops = find_device("touchscreen");
320         if (!check_default(ops))
321                 ops->start(NORMAL_MODE);
322
323         ops = find_device("touchkey");
324         if (!check_default(ops))
325                 ops->start(NORMAL_MODE);
326
327         unregister_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
328
329         return 0;
330 }
331
332 static void __CONSTRUCTOR__ initialize(void)
333 {
334         display_conf = get_var_display_config();
335         if (!display_conf)
336                 _E("Failed to get display configuration variable.");
337 }
338