display: Move force_brightness getter and setter from plugin to core display module
[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-panel.h"
46 #include "display/display.h"
47 #include "display/display-backlight.h"
48 #include "power/power-suspend.h"
49 #include "display/display-lock.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 static int bl_brt(int brightness, int delay)
85 {
86         int ret = -1;
87
88         if (delay > 0)
89                 usleep(delay);
90
91         /* Update device brightness */
92         ret = backlight_ops.set_brightness(brightness);
93
94         _I("Set brightness(%d): %d", brightness, ret);
95
96         return ret;
97 }
98
99 bool display_dimstay_check(void)
100 {
101         if (get_pm_status_flag() & DIM_FLAG)
102                 return true;
103
104         if ((get_pm_status_flag() & PWRSV_FLAG) && !(get_pm_status_flag() & BRTCH_FLAG))
105                 return true;
106
107         return false;
108 }
109
110 static void change_brightness(int start, int end, int step)
111 {
112         int diff, val;
113         int ret = -1;
114         int prev;
115
116         if (display_dimstay_check())
117                 return;
118
119         ret = backlight_ops.get_brightness(&prev);
120         if (ret < 0) {
121                 _E("Failed to get brightness: %d", ret);
122                 return;
123         }
124
125         if (prev == end)
126                 return;
127
128         if (get_pm_status_flag() & DIM_MASK)
129                 end = 0;
130
131         _I("start %d end %d step %d", start, end, step);
132
133         if (display_dev_available) {
134                 ret = hal_device_display_set_multi_brightness(end, step, LCD_PHASED_DELAY);
135                 if (ret != -ENODEV) {
136                         if (ret < 0)
137                                 _E("Failed to set_multi_brightness (%d)", ret);
138
139                         backlight_ops.set_brightness(end);
140
141                         return;
142                 }
143         }
144
145         diff = end - start;
146
147         if (abs(diff) < step)
148                 val = (diff > 0 ? 1 : -1);
149         else
150                 val = (int)ceil((double)diff / step);
151
152         while (start != end) {
153                 if (val == 0) break;
154
155                 start += val;
156                 if ((val > 0 && start > end) ||
157                     (val < 0 && start < end))
158                         start = end;
159
160                 bl_brt(start, LCD_PHASED_DELAY);
161         }
162 }
163
164 static int set_brightness(int val)
165 {
166         int max, ret;
167         int default_brightness = 0, force_brightness = 0;
168
169         display_backlight_get_default_brightness(&default_brightness);
170         display_backlight_get_force_brightness(&force_brightness);
171
172         if (!display_dev_available) {
173                 _E("There is no display device.");
174                 return -ENOENT;
175         }
176
177         ret = display_backlight_get_max_brightness(&max);
178         if (ret < 0) {
179                 _E("Failed to get max brightness.");
180                 return ret;
181         }
182
183         if (force_brightness > 0 && val != PM_DIM_BRIGHTNESS) {
184                 _I("brightness(%d), force brightness(%d)",
185                     val, force_brightness);
186                 val = force_brightness;
187         }
188
189         if (get_pm_status_flag() & DIM_MASK)
190                 val = 0;
191
192         /* Maximum Brightness to users is 100.
193          * Thus real brightness need to be calculated */
194         val = val * max / 100;
195
196         _I("set brightness %d (default:%d)", val, default_brightness);
197         device_notify(DEVICE_NOTIFIER_DISPLAY_BRIGHTNESS, (void *)&val);
198
199         return hal_device_display_set_brightness(val);
200 }
201
202 static int get_brightness(int *val)
203 {
204         int brt, ret;
205
206         if (!display_dev_available) {
207                 _E("There is no display device.");
208                 return -ENOENT;
209         }
210
211         ret = hal_device_display_get_brightness(&brt);
212         if (ret < 0) {
213                 if (ret == -ENODEV)
214                         _E("Get brightness is not supported.");
215                 else
216                         _E("Failed to get brightness: %d", ret);
217
218                 return ret;
219         }
220
221         ret = display_backlight_get_normalized_brightness(brt, val);
222         if (ret < 0) {
223                 _E("Failed to get normalized brightness.");
224                 return ret;
225         }
226
227         return 0;
228 }
229
230 /* It was operated only AOD enter & leave */
231 static int backlight_transit_state(int state)
232 {
233         int brt, val;
234         int start, end;
235         int default_brightness = 0;
236
237         display_backlight_get_default_brightness(&default_brightness);
238
239         backlight_ops.get_brightness(&brt);
240
241         if (state == DPMS_OFF) {
242                 start = brt;
243                 end = display_conf->aod_enter_level;
244
245                 /*
246                  * The value of backlight_ops.get_brightness is system brightness.
247                  * But when device is LBM, the value is not same with real brightness.
248                  * So it should be read exactly value for transit smooth effect
249                  */
250                 get_brightness(&val);
251
252                 if (val > display_conf->aod_enter_level)
253                         backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
254         } else {
255                 /* prevent transit effect when another effect is already executed */
256                 if (brt != display_conf->aod_enter_level) {
257                         _W("effect is already executed brt(%d) aod_level(%d)",
258                                         brt, display_conf->aod_enter_level);
259                         return 0;
260                 }
261
262                 start = display_conf->aod_enter_level;
263                 end = default_brightness;
264                 backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
265         }
266
267         return 0;
268 }
269
270 static void restore_brightness_func(void)
271 {
272         backlight_ops.set_brightness = set_brightness;
273         backlight_ops.get_brightness = get_brightness;
274         backlight_ops.transit_brt = change_brightness;
275 }
276
277 static struct _backlight_ops backlight_ops = {
278         .get_lcd_power = dpms_get_cached_state,
279         .set_brightness = set_brightness,
280         .get_brightness = get_brightness,
281         .restore_brightness_func = restore_brightness_func,
282         .transit_state = backlight_transit_state,
283         .transit_brt = change_brightness,
284 };
285
286 int display_service_load(void)
287 {
288         int r;
289
290         if (display_dev_available)
291                 return 0;
292
293         r = hal_device_display_get_backend();
294         if (r < 0) {
295                 _E("There is no HAL for display.");
296                 display_dev_available = false;
297                 display_set_hal_backend_available(display_dev_available);
298                 return 0;
299         }
300
301         display_dev_available = true;
302         display_set_hal_backend_available(display_dev_available);
303         _D("Display device structure load success.");
304         return 0;
305 }
306
307 int display_service_free(void)
308 {
309         display_dev_available = false;
310         return hal_device_display_put_backend();
311 }
312
313 /* Dummy. Do not consider detached display state */
314 int is_lcdon_blocked(void)
315 {
316         return LCDON_BLOCK_NONE;
317 }
318
319 int init_sysfs(unsigned int flags)
320 {
321         register_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
322
323         return 0;
324 }
325
326 int exit_sysfs(void)
327 {
328         const struct device_ops *ops = NULL;
329
330         display_backlight_update_by_default_brightness();
331
332         dpms_exit();
333
334         ops = find_device("touchscreen");
335         if (!check_default(ops))
336                 ops->start(NORMAL_MODE);
337
338         ops = find_device("touchkey");
339         if (!check_default(ops))
340                 ops->start(NORMAL_MODE);
341
342         unregister_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
343
344         return 0;
345 }
346
347 static void __CONSTRUCTOR__ initialize(void)
348 {
349         display_conf = get_var_display_config();
350         if (!display_conf)
351                 _E("Failed to get display configuration variable.");
352 }
353