display: Move set brightness with delay function from plugins to core display module
[platform/core/system/deviced.git] / plugins / wearable / 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 "display/display-lock.h"
47 #include "display/display-backlight.h"
48 #include "display/display-panel.h"
49 #include "battery-monitor.h"
50 #include "battery/power-supply.h"
51 #include "power/power-suspend.h"
52 #include "shared/plugin.h"
53
54 #define TOUCH_ON        1
55 #define TOUCH_OFF       0
56
57 #define LCD_PHASED_MAX_BRIGHTNESS       100
58 #define LCD_PHASED_DELAY                10000   /* microsecond */
59
60 #define DISPLAY_HAL_LIB_PATH "/usr/lib/libdisplay-hal.so"
61
62 #define GESTURE_STR                     "gesture"
63 #define POWERKEY_STR                    "powerkey"
64 #define EVENT_STR                       "event"
65 #define TOUCH_STR                       "touch"
66 #define BEZEL_STR                       "bezel"
67 #define TIMEOUT_STR                     "timeout"
68 #define PROXIMITY_STR                   "proximity"
69 #define PALM_STR                        "palm"
70 #define UNKNOWN_STR                     "unknown"
71
72 #define FREEZER_VITAL_WAKEUP_CGROUP "/sys/fs/cgroup/freezer/vital_wakeup/freezer.state"
73
74
75 static struct _backlight_ops backlight_ops;
76 static struct battery_plugin *battery_plgn;
77 static bool display_dev_available = false;
78 static int aod_max_level = -1;
79 static int aod_normal_level = -1;
80 static int aod_min_level = -1;
81 static int aod_charging_level = -1;
82 static const struct display_config *display_conf;
83 static struct battery_status *battery = NULL;
84 static struct battery_status* (*fp_get_var_battery_status)(void);
85
86 inline struct _backlight_ops *get_var_backlight_ops(void)
87 {
88         return &backlight_ops;
89 }
90
91 bool display_dev_ready(void)
92 {
93         return display_dev_available;
94 }
95
96 bool display_dimstay_check(void)
97 {
98         if (get_pm_status_flag() & DIM_FLAG)
99                 return true;
100
101         return false;
102 }
103
104 static void change_brightness(int start, int end, int step)
105 {
106         int diff, val;
107         int ret = -1;
108         int prev;
109
110         if (display_dimstay_check())
111                 return;
112
113         ret = backlight_ops.get_brightness(&prev);
114         if (ret < 0) {
115                 _E("Failed to get brightness: %d", ret);
116                 return;
117         }
118
119         if (prev == end)
120                 return;
121
122         if (get_pm_status_flag() & DIM_MASK)
123                 end = 0;
124
125         _I("start %d end %d step %d", start, end, step);
126
127         if (display_dev_available) {
128                 ret = hal_device_display_set_multi_brightness(end, step, LCD_PHASED_DELAY);
129                 if (ret != -ENODEV) {
130                         if (ret < 0)
131                                 _E("Failed to set_multi_brightness (%d)", ret);
132
133                         backlight_ops.set_brightness(end);
134
135                         return;
136                 }
137         }
138
139         diff = end - start;
140
141         if (abs(diff) < step)
142                 val = (diff > 0 ? 1 : -1);
143         else
144                 val = (int)ceil((double)diff / step);
145
146         while (start != end) {
147                 if (val == 0) break;
148
149                 start += val;
150                 if ((val > 0 && start > end) ||
151                     (val < 0 && start < end))
152                         start = end;
153
154                 display_backlight_set_brightness_with_delay(start, LCD_PHASED_DELAY);
155         }
156 }
157
158 static int set_brightness(int val)
159 {
160         int max, ret;
161         int default_brightness = 0, force_brightness = 0;
162
163         display_backlight_get_default_brightness(&default_brightness);
164         display_backlight_get_force_brightness(&force_brightness);
165
166         if (!display_dev_available) {
167                 _E("There is no display device.");
168                 return -ENOENT;
169         }
170
171         ret = display_backlight_get_max_brightness(&max);
172         if (ret < 0) {
173                 _E("Failed to get max brightness.");
174                 return ret;
175         }
176
177         if (force_brightness > 0 && val != PM_DIM_BRIGHTNESS) {
178                 _I("brightness(%d), force brightness(%d)",
179                     val, force_brightness);
180                 val = force_brightness;
181         }
182
183         if (get_pm_status_flag() & DIM_MASK)
184                 val = 0;
185
186         /* Maximum Brightness to users is 100.
187          * Thus real brightness need to be calculated */
188         val = val * max / 100;
189
190         update_bds_brightness_record(val);
191         _I("set brightness %d (default:%d)", val, default_brightness);
192         device_notify(DEVICE_NOTIFIER_DISPLAY_BRIGHTNESS, (void *)&val);
193
194         return hal_device_display_set_brightness(val);
195 }
196
197 static int get_brightness(int *val)
198 {
199         int brt, ret;
200
201         if (!display_dev_available) {
202                 _E("There is no display device.");
203                 return -ENOENT;
204         }
205
206         ret = hal_device_display_get_brightness(&brt);
207         if (ret < 0) {
208                 if (ret == -ENODEV)
209                         _E("Get brightness is not supported.");
210                 else
211                         _E("Failed to get brightness: %d", ret);
212
213                 return ret;
214         }
215
216         ret = display_backlight_get_normalized_brightness(brt, val);
217         if (ret < 0) {
218                 _E("Failed to get normalized brightness.");
219                 return ret;
220         }
221
222         return 0;
223 }
224
225 /* It was operated only AOD enter & leave */
226 static int backlight_transit_state(int state)
227 {
228         int brt, val;
229         int start, end;
230         static int aod_brightness_level;
231         int default_brightness = 0;
232
233         display_backlight_get_default_brightness(&default_brightness);
234
235         backlight_ops.get_brightness(&brt);
236
237         if (state == DPMS_OFF) {
238                 start = brt;
239
240                 /*
241                  * The value of backlight_ops.get_brightness is system brightness.
242                  * But when device is LBM, the value is not same with real brightness.
243                  * So it should be read exactly value for transit smooth effect
244                  */
245                 get_brightness(&val);
246
247                 /* AOD brightness
248                  *
249                  * Compare current brightness with threshold based on charger's charging state.
250                  * Charger charging state has 2 threshold: CHARGING, MIN
251                  * The other states has 3 threshold: MAX, NORMAL, MIN
252                  *
253                  * Select the highest threshold among the thresholds less then the current brightness.
254                  * If current brightness is less then MIN threshold, do not transit brightness.
255                  *
256                  * e.g.
257                  * threshold for    | threshold for
258                  * charger CHARGING | the other charger states
259                  *                  |
260                  *                  |
261                  *                  |-----MAX(50)
262                  *                  |
263                  *                  |-----NORMAL(40)
264                  *                  |
265                  *                  |
266                  * CHARGING(20)-----|
267                  *                  |
268                  *      MIN(10)-----|-----MIN(10)
269                  *  if DISCHARGING and current brightness is 30, then AOD brightness will be 10.
270                  *  if DISCHARGING and current brightness is 45, then AOD brightness will be 40.
271                  *  if CHARGING and current brightness is 80, then AOD brightness will be 20.
272                  *  if current brightness is 5, do not transit brightness.
273                  */
274                 if (aod_min_level > 0 && val < aod_min_level) {
275                         _W("Current brightness is already lower than minimum threshold.");
276                         return 0;
277                 }
278
279                 if (battery && battery->charge_now == CHARGER_CHARGING) {
280                         if (aod_charging_level > 0 && val >= aod_charging_level)
281                                 aod_brightness_level = aod_charging_level;
282                         else if (aod_min_level > 0 && val >= aod_min_level)
283                                 aod_brightness_level = aod_min_level;
284                         else
285                                 aod_brightness_level = display_conf->aod_enter_level;
286                 } else {
287                         if (aod_max_level > 0 && val >= aod_max_level)
288                                 aod_brightness_level = aod_max_level;
289                         else if (aod_normal_level > 0 && val >= aod_normal_level)
290                                 aod_brightness_level = aod_normal_level;
291                         else if (aod_min_level > 0 && val >= aod_min_level)
292                                 aod_brightness_level = aod_min_level;
293                         else
294                                 aod_brightness_level = display_conf->aod_enter_level;
295                 }
296
297                 if (val > aod_brightness_level) {
298                         _D("backlight transit start %d end %d DPMS OFF", start, aod_brightness_level);
299                         backlight_ops.transit_brt(start, aod_brightness_level, display_conf->brightness_change_step);
300                 }
301         } else {
302                 /* prevent transit effect when another effect is already executed */
303                 if (brt != aod_brightness_level) {
304                         _W("effect is already executed brt(%d) aod_level(%d)",
305                                         brt, aod_brightness_level);
306                         return 0;
307                 }
308
309                 start = aod_brightness_level;
310                 end = default_brightness;
311                 _D("backlight transit start %d end %d DPMS ON", start, end);
312                 backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
313         }
314
315         return 0;
316 }
317
318 static void restore_brightness_func(void)
319 {
320         backlight_ops.set_brightness = set_brightness;
321         backlight_ops.get_brightness = get_brightness;
322         backlight_ops.transit_brt = change_brightness;
323 }
324
325 static struct _backlight_ops backlight_ops = {
326         .get_lcd_power = dpms_get_cached_state,
327         .set_brightness = set_brightness,
328         .get_brightness = get_brightness,
329         .restore_brightness_func = restore_brightness_func,
330         .transit_state = backlight_transit_state,
331         .transit_brt = change_brightness,
332         /* auto-test only function */
333         .get_brightness_raw = get_brightness, /* always fetch brightness from node even LBM mode */
334 };
335
336 int display_service_load(void)
337 {
338         int r;
339
340         if (display_dev_available)
341                 return 0;
342
343         r = hal_device_display_get_backend();
344         if (r < 0) {
345                 _E("There is no HAL for display.");
346                 display_dev_available = false;
347                 display_set_hal_backend_available(display_dev_available);
348                 return 0;
349         }
350
351         display_dev_available = true;
352         display_set_hal_backend_available(display_dev_available);
353         _D("Display device structure load success.");
354         return 0;
355 }
356
357 int display_service_free(void)
358 {
359         display_dev_available = false;
360         return hal_device_display_put_backend();
361 }
362
363 int is_lcdon_blocked(void)
364 {
365         int state = backlight_ops.get_lcd_power();
366
367         if ((state == DPMS_DETACH) || (state == -EINVAL))
368                 return LCDON_BLOCK_WHEN_DISPLAY_DETACHED;
369
370         return LCDON_BLOCK_NONE;
371 }
372
373 int init_sysfs(unsigned int flags)
374 {
375         register_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
376
377         if (battery_plgn->handle) {
378                 fp_get_var_battery_status = dlsym(battery_plgn->handle, "get_var_battery_status");
379                 if (fp_get_var_battery_status) {
380                         battery = fp_get_var_battery_status();
381                         if (!battery)
382                                 _E("Failed to get battery status.");
383                 } else
384                         _E("Failed to obtain address of get_var_battery_status, %s.", dlerror());
385         } else
386                  _I("There is no battery module.");
387
388         return 0;
389 }
390
391 int exit_sysfs(void)
392 {
393         const struct device_ops *ops = NULL;
394
395         display_backlight_update_by_default_brightness();
396
397         dpms_exit();
398
399         ops = find_device("touchscreen");
400         if (!check_default(ops))
401                 ops->start(NORMAL_MODE);
402
403         unregister_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
404
405         return 0;
406 }
407
408 static void __CONSTRUCTOR__ initialize(void)
409 {
410         display_conf = get_var_display_config();
411         if (!display_conf)
412                 _E("Failed to get display configuration variable.");
413
414         battery_plgn = get_var_battery_plugin();
415         if (!battery_plgn)
416                 _E("Failed to get battery plugin variable.");
417 }