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