tizen 2.3 release
[framework/system/deviced.git] / src / display / hbm.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 #include <stdbool.h>
20 #include <fcntl.h>
21 #include <Ecore.h>
22
23 #include "hbm.h"
24 #include "util.h"
25 #include "core.h"
26 #include "display-ops.h"
27 #include "core/common.h"
28 #include "core/device-notifier.h"
29 #include "core/edbus-handler.h"
30 #include "core/config-parser.h"
31
32 #define BOARD_CONF_FILE "/etc/deviced/display.conf"
33
34 #define ON              "on"
35 #define OFF             "off"
36
37 #define ON_LUX          39768
38 #define OFF_LUX         10000
39 #define ON_COUNT        1
40 #define OFF_COUNT       1
41
42 #define SIGNAL_HBM_OFF  "HBMOff"
43
44 #define DEFAULT_BRIGHTNESS_LEVEL        80
45
46 struct hbm_config hbm_conf = {
47         .on             = ON_LUX,
48         .off            = OFF_LUX,
49         .on_count       = ON_COUNT,
50         .off_count      = OFF_COUNT,
51 };
52
53 static Ecore_Timer *timer = NULL;
54 static struct timespec offtime;
55 static char *hbm_path;
56
57 static void broadcast_hbm_off(void)
58 {
59         broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
60             SIGNAL_HBM_OFF, NULL, NULL);
61 }
62
63 static void hbm_set_offtime(int timeout)
64 {
65         struct timespec now;
66
67         if (timeout <= 0) {
68                 offtime.tv_sec = 0;
69                 return;
70         }
71
72         clock_gettime(CLOCK_REALTIME, &now);
73         offtime.tv_sec = now.tv_sec + timeout;
74 }
75
76 static Eina_Bool hbm_off_cb(void *data)
77 {
78         int ret;
79
80         timer = NULL;
81
82         if (pm_cur_state != S_NORMAL) {
83                 _D("hbm timeout! but it's not lcd normal");
84                 return EINA_FALSE;
85         }
86         hbm_set_offtime(0);
87
88         ret = sys_set_str(hbm_path, OFF);
89         if (ret < 0)
90                 _E("Failed to off hbm");
91
92         vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS,
93             DEFAULT_BRIGHTNESS_LEVEL);
94         backlight_ops.set_default_brt(DEFAULT_BRIGHTNESS_LEVEL);
95         backlight_ops.update();
96         broadcast_hbm_off();
97
98         return EINA_FALSE;
99 }
100
101 static void hbm_start_timer(int timeout)
102 {
103         if (timer) {
104                 ecore_timer_del(timer);
105                 timer = NULL;
106         }
107         if (!timer) {
108                 timer = ecore_timer_add(timeout,
109                     hbm_off_cb, NULL);
110         }
111 }
112
113 static void hbm_end_timer(void)
114 {
115         if (timer) {
116                 ecore_timer_del(timer);
117                 timer = NULL;
118         }
119 }
120
121 int hbm_get_state(void)
122 {
123         char state[4];
124         int ret, hbm;
125
126         if (!hbm_path)
127                 return -ENODEV;
128
129         ret = sys_get_str(hbm_path, state);
130         if (ret < 0)
131                 return ret;
132
133         if (!strncmp(state, ON, strlen(ON)))
134                 hbm = true;
135         else if (!strncmp(state, OFF, strlen(OFF)))
136                 hbm = false;
137         else
138                 hbm = -EINVAL;
139
140         return hbm;
141 }
142
143 int hbm_set_state(int hbm)
144 {
145         if (!hbm_path)
146                 return -ENODEV;
147
148         return sys_set_str(hbm_path, (hbm ? ON : OFF));
149 }
150
151 int hbm_set_state_with_timeout(int hbm, int timeout)
152 {
153         int ret;
154
155         if (hbm && (timeout <= 0))
156                 return -EINVAL;
157
158         ret = hbm_set_state(hbm);
159         if (ret < 0)
160                 return ret;
161
162         _D("timeout is %d", timeout);
163
164         if (hbm) {
165                 /*
166                  * hbm is turned off after timeout.
167                  */
168                 hbm_set_offtime(timeout);
169                 hbm_start_timer(timeout);
170         } else {
171                 hbm_set_offtime(0);
172                 hbm_end_timer();
173                 broadcast_hbm_off();
174         }
175
176         return 0;
177 }
178
179 void hbm_check_timeout(void)
180 {
181         struct timespec now;
182         int ret;
183
184         if (timer) {
185                 ecore_timer_del(timer);
186                 timer = NULL;
187         }
188
189         if (offtime.tv_sec == 0) {
190                 if (hbm_get_state() == true) {
191                         _E("It's invalid state. hbm is off");
192                         hbm_set_state(false);
193                 }
194                 return;
195         }
196
197         clock_gettime(CLOCK_REALTIME, &now);
198         _D("now %d, offtime %d", now.tv_sec, offtime.tv_sec);
199
200         /* check it's timeout */
201         if (now.tv_sec >= offtime.tv_sec) {
202                 hbm_set_offtime(0);
203
204                 ret = sys_set_str(hbm_path, OFF);
205                 if (ret < 0)
206                         _E("Failed to off hbm");
207                 vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS,
208                     DEFAULT_BRIGHTNESS_LEVEL);
209                 backlight_ops.set_default_brt(DEFAULT_BRIGHTNESS_LEVEL);
210                 backlight_ops.update();
211                 broadcast_hbm_off();
212         } else {
213                 _D("hbm state is restored!");
214                 hbm_set_state(true);
215                 hbm_start_timer(offtime.tv_sec - now.tv_sec);
216         }
217 }
218
219 static int lcd_state_changed(void *data)
220 {
221         int state = (int)data;
222         int ret;
223
224         switch (state) {
225         case S_NORMAL:
226                 /* restore hbm when old state is dim */
227                 if (pm_old_state == S_LCDDIM)
228                         hbm_check_timeout();
229                 break;
230         case S_LCDDIM:
231                 if (hbm_get_state() == true) {
232                         ret = hbm_set_state(false);
233                         if (ret < 0)
234                                 _E("Failed to off hbm!");
235                 }
236                 /* fall through */
237         case S_LCDOFF:
238         case S_SLEEP:
239                 hbm_end_timer();
240                 break;
241         }
242
243         return 0;
244 }
245
246 static int hbm_load_config(struct parse_result *result, void *user_data)
247 {
248         struct hbm_config *c = user_data;
249
250         _D("%s,%s,%s", result->section, result->name, result->value);
251
252         if (!c)
253                 return -EINVAL;
254
255         if (!MATCH(result->section, "HBM"))
256                 return 0;
257
258         if (MATCH(result->name, "on")) {
259                 SET_CONF(c->on, atoi(result->value));
260                 _D("on lux is %d", c->on);
261         } else if (MATCH(result->name, "off")) {
262                 SET_CONF(c->off, atoi(result->value));
263                 _D("off lux is %d", c->off);
264         } else if (MATCH(result->name, "on_count")) {
265                 SET_CONF(c->on_count, atoi(result->value));
266                 _D("on count is %d", c->on_count);
267         } else if (MATCH(result->name, "off_count")) {
268                 SET_CONF(c->off_count, atoi(result->value));
269                 _D("off count is %d", c->off_count);
270         }
271
272         return 0;
273 }
274
275 static void hbm_init(void *data)
276 {
277         int fd, ret;
278
279         hbm_path = getenv("HBM_NODE");
280
281         /* Check HBM node is valid */
282         fd = open(hbm_path, O_RDONLY);
283         if (fd < 0) {
284                 hbm_path = NULL;
285                 return;
286         }
287         close(fd);
288
289         /* load configutation */
290         ret = config_parse(BOARD_CONF_FILE, hbm_load_config, &hbm_conf);
291         if (ret < 0)
292                 _W("Failed to load %s, %s Use default value!",
293                     BOARD_CONF_FILE, ret);
294
295         /* register notifier */
296         register_notifier(DEVICE_NOTIFIER_LCD, lcd_state_changed);
297 }
298
299 static void hbm_exit(void *data)
300 {
301         /* unregister notifier */
302         unregister_notifier(DEVICE_NOTIFIER_LCD, lcd_state_changed);
303
304         /*
305          * set default brightness
306          * if display logic is stopped in hbm state.
307          */
308         if (hbm_get_state() == true) {
309                 hbm_set_offtime(0);
310                 vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS,
311                     DEFAULT_BRIGHTNESS_LEVEL);
312                 _I("set brightness to default value!");
313         }
314 }
315
316 static const struct display_ops display_hbm_ops = {
317         .name     = "hbm",
318         .init     = hbm_init,
319         .exit     = hbm_exit,
320 };
321
322 DISPLAY_OPS_REGISTER(&display_hbm_ops)
323