1d645faeefd6dc6ce30ed2869d4064c46d943c2e
[platform/core/system/deviced.git] / src / touchscreen / touchscreen.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
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 <assert.h>
20 #include <stdbool.h>
21 #include <hal/device/hal-touchscreen.h>
22 #include <libsyscommon/libgdbus.h>
23 #include <vconf.h>
24 #include <dlfcn.h>
25 #include "shared/devices.h"
26 #include "shared/common.h"
27 #include "core/log.h"
28 #include "shared/device-notifier.h"
29 #include "battery/power-supply.h"
30 #include "core.h"
31 #include "display-ops.h"
32 #include "display-panel.h"
33 #include "display-plugin.h"
34 #include "display-config.h"
35 #include "power/power-boot.h"
36 #include "shared/plugin.h"
37
38 enum ps_mode {
39         POWERSAVING_OFF,
40         POWERSAVING_ON,
41 };
42
43 static struct battery_plugin *battery_plgn;
44 static bool touchscreen_dev_available = false;
45 static int touchscreen_enable = DEVICE_OPS_STATUS_START;
46 static int powersaving_support = true;
47
48 static int touchscreen_start(enum device_flags flags);
49 static int touchscreen_stop(enum device_flags flags);
50
51 static int delayed_init_done(void *data);
52
53 static struct battery_status *battery = NULL;
54
55 static struct battery_status* (*fp_get_var_battery_status)(void);
56
57 static void touchscreen_wakeup_status(keynode_t *key, void *data)
58 {
59         if (!key)
60                 return;
61
62         if (!g_display_plugin.config)
63                 return;
64
65         g_display_plugin.config->touch_wakeup = vconf_keynode_get_bool(key);
66
67         if (display_panel_get_dpms_cached_state() != DPMS_ON) {
68                 if (g_display_plugin.config->touch_wakeup)
69                         touchscreen_start(NORMAL_MODE);
70                 else
71                         touchscreen_stop(TOUCH_SCREEN_OFF_MODE);
72         }
73 }
74
75 static int touchscreen_powersaving(enum ps_mode mode)
76 {
77         bool state;
78         int ret;
79
80         if (!powersaving_support)
81                 return -ENOTSUP;
82
83         if (touchscreen_enable != DEVICE_OPS_STATUS_START)
84                 return 0;
85
86         if (mode == POWERSAVING_ON)
87                 state = true;
88         else if (mode == POWERSAVING_OFF)
89                 state = false;
90         else
91                 return -EINVAL;
92
93         ret = hal_device_touchscreen_set_powersaving(state);
94         if (touchscreen_dev_available && (ret != -ENODEV)) {
95                 if (ret < 0) {
96                         _E("Failed to set touch powersaving node.");
97                         return -EIO;
98                 }
99         }
100
101         _I("Set touch powersaving %s.", state ? "ON" : "OFF");
102
103         return 0;
104 }
105
106 static int touchscreen_probe(void *data)
107 {
108         int ret;
109
110         if (touchscreen_dev_available)
111                 return 0;
112
113         ret = hal_device_touchscreen_get_backend();
114         if (ret < 0) {
115                 _E("There is no HAL for touchscreen.");
116                 touchscreen_dev_available = false;
117
118                 return -ENODEV;
119         }
120
121         _I("Touchscreen device structure load success.");
122         touchscreen_dev_available = true;
123
124         return 0;
125 }
126
127 static void touchscreen_exit(void *data)
128 {
129         touchscreen_dev_available = false;
130         hal_device_touchscreen_put_backend();
131 }
132
133 static int touchscreen_set_state(enum touchscreen_state state)
134 {
135         int ret;
136         char *act;
137
138         if (!touchscreen_dev_available) {
139                 _E("Touchscreen device structure is not loaded.");
140                 return -ENOENT;
141         }
142
143         if (state != TOUCHSCREEN_ON && state != TOUCHSCREEN_OFF) {
144                 _E("Invalid parameter.");
145                 return -EINVAL;
146         }
147
148         act = (state == TOUCHSCREEN_ON) ? "enable" : "disable";
149
150         ret = hal_device_touchscreen_set_state(state);
151         if (ret == 0)
152                 _I("Success to %s touchscreen.", act);
153         else {
154                 if (ret == -ENODEV)
155                         _E("Touchscreen set state is not supported.");
156                 else
157                         _E("Failed to %s touchscreen: %d", act, ret);
158         }
159
160         return ret;
161 }
162
163 static int touchscreen_execute(void *data)
164 {
165         touchscreen_enable = (int)((intptr_t)data);
166         return 0;
167 }
168
169 static int touchscreen_start(enum device_flags flags)
170 {
171         int state = -1;
172         int ret;
173
174         if (touchscreen_enable != DEVICE_OPS_STATUS_START)
175                 return 0;
176
177         /* Do not enable touchscreen during silent boot mode */
178         if (silent_boot && !delayed_init_done(NULL))
179                 return -ENOTSUP;
180
181         /*
182          * It is safe to turn touchscreen on before powersaving on/off.
183          */
184         ret = touchscreen_set_state(TOUCHSCREEN_ON);
185
186         state = display_panel_get_dpms_cached_state();
187
188         if (state == DPMS_OFF)
189                 touchscreen_powersaving(POWERSAVING_ON);
190         else
191                 touchscreen_powersaving(POWERSAVING_OFF);
192
193         return ret;
194 }
195
196 static int touchscreen_stop(enum device_flags flags)
197 {
198         if (!g_display_plugin.config) {
199                 _I("Touchscreen is not initialized.");
200                 goto exit;
201         }
202
203         /*
204          * Touchscreen control priority
205          *  1. Touchscreen module control by execute(touchscreen_enable)
206          *  2. Device charger status by charging dock
207          *  3. Touch wakeup setting(touch_wakeup_enable) value
208          *  4. Normal mode(Basic request)
209          */
210         if (touchscreen_enable != DEVICE_OPS_STATUS_START)
211                 return 0;
212
213         if (flags & TOUCH_SCREEN_OFF_MODE) {
214                 touchscreen_powersaving(POWERSAVING_OFF);
215                 return touchscreen_set_state(TOUCHSCREEN_OFF);
216         }
217
218         if (battery && battery->charger_connected == 1) {
219                 _I("Battery charging one %d %d.", battery->charger_connected, battery->online_type);
220                 return touchscreen_powersaving(POWERSAVING_ON);
221         }
222
223         if (g_display_plugin.config->touch_wakeup) {
224                 _I("Touch wakeup enabled.");
225                 return touchscreen_powersaving(POWERSAVING_ON);
226         }
227
228 exit:
229         touchscreen_powersaving(POWERSAVING_OFF);
230         return touchscreen_set_state(TOUCHSCREEN_OFF);
231 }
232
233 static int touchscreen_dump(FILE *fp, int mode, void *dump_data)
234 {
235         enum touchscreen_state state;
236         int ret;
237
238         ret = hal_device_touchscreen_get_state(&state);
239         if (!touchscreen_dev_available || (ret == -ENODEV))
240                 return 0;
241
242         if (ret < 0) {
243                 _E("Failed to get touchscreen state: %d", ret);
244                 return ret;
245         }
246
247         if (state == TOUCHSCREEN_ON)
248                 LOG_DUMP(fp, "Touchscreen is enabled\n");
249         else
250                 LOG_DUMP(fp, "Touchscreen is disabled\n");
251
252         return 0;
253 }
254
255 static GVariant *dbus_touchscreen_enable(GDBusConnection *conn,
256         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
257         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
258 {
259         int ret;
260         ret = touchscreen_start(NORMAL_MODE);
261
262         return g_variant_new("(i)", ret);
263 }
264
265 static GVariant *dbus_touchscreen_disable(GDBusConnection *conn,
266         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
267         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
268 {
269         int ret;
270         ret = touchscreen_stop(TOUCH_SCREEN_OFF_MODE);
271
272         return g_variant_new("(i)", ret);
273 }
274
275 static const dbus_method_s dbus_methods[] = {
276         { "Enable",     NULL,    "i",  dbus_touchscreen_enable },
277         { "Disable",    NULL,    "i",  dbus_touchscreen_disable },
278         /* Add methods here */
279 };
280
281 static const dbus_interface_u dbus_interface = {
282         .oh = NULL,
283         .name = DEVICED_INTERFACE_TOUCH,
284         .methods = dbus_methods,
285         .nr_methods = ARRAY_SIZE(dbus_methods),
286 };
287
288 static int delayed_init_done(void *data)
289 {
290         static int done = false;
291
292         if (!data)
293                 return done;
294
295         done = *(int *)data;
296
297         return done;
298 }
299
300 static void touchscreen_init(void *data)
301 {
302         int ret, val;
303
304         if (battery_plgn->handle) {
305                 fp_get_var_battery_status = dlsym(battery_plgn->handle, "get_var_battery_status");
306                 if (fp_get_var_battery_status) {
307                         battery = fp_get_var_battery_status();
308                         if (!battery)
309                                 _E("Failed to get battery status variable");
310                 } else
311                         _E("Failed to obtain address of get_var_battery_status, %s.", dlerror());
312         } else
313                 _I("There is no battery module.");
314
315         ret = hal_device_touchscreen_set_powersaving(0);
316         if (touchscreen_dev_available && (ret != -ENODEV)) {
317                 if (ret < 0)
318                         powersaving_support = false;
319                 else
320                         powersaving_support = true;
321         } else
322                 powersaving_support = false;
323
324         vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_WAKEUP_ENABLE,
325                         touchscreen_wakeup_status, NULL);
326         ret = vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_WAKEUP_ENABLE, &val);
327         if (g_display_plugin.config && ret == 0)
328                 g_display_plugin.config->touch_wakeup = val;
329
330
331         ret = gdbus_add_object(NULL, DEVICED_PATH_TOUCH, &dbus_interface);
332
333         if (ret < 0)
334                 _E("Failed to init dbus method. (%d)", ret);
335
336         syscommon_notifier_subscribe_notify(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
337 }
338
339 static const struct device_ops touchscreen_device_ops = {
340         DECLARE_NAME_LEN("touchscreen"),
341         .probe    = touchscreen_probe,
342         .init     = touchscreen_init,
343         .exit     = touchscreen_exit,
344         .start    = touchscreen_start,
345         .stop     = touchscreen_stop,
346         .dump     = touchscreen_dump,
347         .execute  = touchscreen_execute,
348 };
349
350 DEVICE_OPS_REGISTER(&touchscreen_device_ops)
351
352 static void __CONSTRUCTOR__ initialize(void)
353 {
354         battery_plgn = get_var_battery_plugin();
355         if (!battery_plgn)
356                 _E("Failed to get battery plugin variable.");
357 }