4 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <libsyscommon/ini-parser.h>
23 #include "auto-brightness-sensorhub.h"
25 #include "display-info.h"
27 #include "display-ops.h"
28 #include "display-panel.h"
29 #include "shared/common.h"
30 #include "shared/device-notifier.h"
31 #include "shared/log.h"
33 #define BOARD_CONF_FILE "/etc/deviced/display.conf"
38 #define SIGNAL_HBM_ON "HBMOn"
39 #define SIGNAL_HBM_OFF "HBMOff"
43 #define LCD_PATH "sys/class/lcd/"
44 #define HBM_PATH "/hbm"
45 #define DEVICE_PATH "/device"
46 #define PATH_BUFFER_MAX 512
49 static struct timespec offtime;
50 static char *hbm_path;
52 static void broadcast_hbm_state(char *state)
54 gdbus_signal_emit(NULL,
56 DEVICED_INTERFACE_DISPLAY,
61 static void hbm_set_offtime(int timeout)
70 clock_gettime(CLOCK_REALTIME, &now);
71 offtime.tv_sec = now.tv_sec + timeout;
74 static gboolean hbm_off_cb(void *data)
78 if (get_pm_cur_state() != DEVICED_DISPLAY_STATE_ON) {
79 _D("Hbm timeout, but it's not display normal.");
80 return G_SOURCE_REMOVE;
84 auto_brightness_control(BR_HBM_OFF, BR_IMPLICIT);
86 return G_SOURCE_REMOVE;
89 static void hbm_start_timer(int timeout)
92 g_source_remove(timer);
96 timer = g_timeout_add_seconds(timeout, hbm_off_cb, NULL);
100 static void hbm_end_timer(void)
103 g_source_remove(timer);
108 int hbm_get_state(void)
116 ret = sys_get_str(hbm_path, state, sizeof(state));
120 if (!strncmp(state, ON, strlen(ON)))
122 else if (!strncmp(state, OFF, strlen(OFF)))
130 int hbm_set_state(int hbm)
137 broadcast_hbm_state(SIGNAL_HBM_ON);
139 broadcast_hbm_state(SIGNAL_HBM_OFF);
141 ret = sys_set_str(hbm_path, (hbm ? ON : OFF));
143 _E("Failed to HBM %s.", hbm ? "ON" : " OFF");
148 static int hbm_set_state_with_timeout(int hbm, int timeout)
152 if (hbm && (timeout <= 0))
156 ret = auto_brightness_control(BR_HBM_ON, BR_IMPLICIT);
158 ret = auto_brightness_control(BR_HBM_OFF, BR_IMPLICIT);
163 _D("timeout is %d", timeout);
167 * hbm is turned off after timeout.
169 hbm_set_offtime(timeout);
170 hbm_start_timer(timeout);
179 static void hbm_check_timeout(void)
184 g_source_remove(timer);
188 if (offtime.tv_sec == 0) {
189 _E("It's invalid state. HBM is turned off.");
190 auto_brightness_control(BR_HBM_OFF, BR_IMPLICIT);
194 clock_gettime(CLOCK_REALTIME, &now);
195 _D("now %ld, offtime %ld", now.tv_sec, offtime.tv_sec);
197 /* check it's timeout */
198 if (now.tv_sec >= offtime.tv_sec) {
200 auto_brightness_control(BR_HBM_OFF, BR_IMPLICIT);
202 _D("HBM state is restored.");
203 auto_brightness_control(BR_HBM_ON, BR_IMPLICIT);
204 hbm_start_timer(offtime.tv_sec - now.tv_sec);
208 static int display_state_changed(void *data)
213 state = DATA_VALUE_INT(data);
215 if (get_outdoor_setting)
216 if (get_outdoor_setting())
220 case DEVICED_DISPLAY_STATE_ON:
222 * outdoor-enhance-mode not supported
223 * : check & restore hbm always.
224 * outdoor-enhance-mode supported
225 * : check & restore hbm when old state is dim only.
227 if (!get_outdoor_setting || (get_pm_old_state() == DEVICED_DISPLAY_STATE_DIM))
230 case DEVICED_DISPLAY_STATE_DIM:
231 case DEVICED_DISPLAY_STATE_OFF:
232 case DEVICED_DISPLAY_STATE_SLEEP:
233 ret = auto_brightness_control(BR_HBM_OFF, BR_IMPLICIT);
235 _E("Failed to off hbm.");
243 static GVariant *dbus_gethbm(GDBusConnection *conn,
244 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
245 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
247 return g_variant_new("(i)", hbm_get_state());
250 static GVariant *dbus_sethbm_timeout(GDBusConnection *conn,
251 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
252 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
254 int hbm, timeout, ret;
256 g_variant_get(param, "(ii)", &hbm, &timeout);
259 _E("Timeout can not be setting(%d).", timeout);
264 ret = hbm_set_state_with_timeout(hbm, timeout);
267 _E("Failed to set HBM (ret=%d, hbm=%d, time=%d).", ret, hbm, timeout);
269 _I("Set hbm (ret=%d, hbm=%d, time=%d).", ret, hbm, timeout);
272 return g_variant_new("(i)", ret);
275 static const dbus_method_s dbus_methods[] = {
276 { "GetHBM", NULL, "i", dbus_gethbm },
277 { "SetHBMTimeout", "ii", "i", dbus_sethbm_timeout },
280 static const dbus_interface_u dbus_interface = {
282 .name = DEVICED_INTERFACE_DISPLAY,
283 .methods = dbus_methods,
284 .nr_methods = ARRAY_SIZE(dbus_methods),
287 static int hbm_func(unsigned int cmd, void *arg)
290 struct hbmsetstate *hss;
294 ret = hbm_get_state();
298 ret = auto_brightness_control(BR_HBM_ON, BR_IMPLICIT);
300 ret = auto_brightness_control(BR_HBM_OFF, BR_IMPLICIT);
303 ret = auto_brightness_control(BR_HBM_ON, BR_IMPLICIT);
306 case HBM_TURN_OFF_STATE:
307 ret = auto_brightness_control(BR_HBM_OFF, BR_IMPLICIT);
309 case HBM_SET_TIMEOUT_STATE:
310 hss = (struct hbmsetstate *)arg;
311 ret = hbm_set_state_with_timeout(hss->hbm, hss->timeout);
321 static char *check_and_copy_path(char *path)
326 fd = open(path, O_RDONLY);
328 buf = strndup(path, strlen(path));
331 _E("Failed to open HBM node.");
337 static char *find_hbm_node()
341 char buf[PATH_BUFFER_MAX];
344 d = opendir(LCD_PATH);
348 while ((dir = readdir(d))) {
349 if (dir->d_name[0] == '.')
352 snprintf(buf, sizeof(buf), "%s%s%s", LCD_PATH,
353 dir->d_name, HBM_PATH);
355 result = check_and_copy_path(buf);
359 snprintf(buf, sizeof(buf), "%s%s%s%s", LCD_PATH,
360 dir->d_name, DEVICE_PATH, HBM_PATH);
362 result = check_and_copy_path(buf);
371 static void dpms_check_hbm_off(void)
373 int real_hbm = hbm_get_state();
375 if (real_hbm == true) {
376 _W("HBM still enabled right before DPMS OFF, turn off HBM.");
377 auto_brightness_control(BR_HBM_OFF, BR_IMPLICIT);
379 /* check once more whether the HBM is really OFFed by auto_brightness_control */
380 real_hbm = hbm_get_state();
382 /* hbm state, flag mismatch occured. Force HBMOFF */
383 if (real_hbm == true) {
384 _E("HBM state, flag mismatch occured. Force HBMOFF.");
385 hbm_set_state(false);
390 static void hbm_init(void *data)
394 hbm_path = find_hbm_node();
397 _E("Failed to find HBM node.");
400 _I("HBM node: %s.", hbm_path);
403 ret = gdbus_add_object(NULL, DEVICED_PATH_DISPLAY, &dbus_interface);
405 _E("Failed to register dbus object.");
407 /* register notifier */
408 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_LCD, display_state_changed);
410 /* double check to guarantee HBMOFF before DPMS OFF */
411 display_panel_register_dpms_checklist(DPMS_OFF, dpms_check_hbm_off);
414 static void hbm_exit(void *data)
416 /* unregister notifier */
417 syscommon_notifier_unsubscribe_notify(DEVICED_NOTIFIER_LCD, display_state_changed);
420 * set default brightness
421 * if display logic is stopped in hbm state.
423 if (hbm_get_state() == true) {
425 _I("set brightness to default value!");
429 static const struct display_ops display_hbm_ops = {
436 DISPLAY_OPS_REGISTER(&display_hbm_ops)