Get battery status from battery plugin.
[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 <hw/touchscreen.h>
22 #include <libsyscommon/dbus-system.h>
23 #include <vconf.h>
24 #include <dlfcn.h>
25 #include "core/devices.h"
26 #include "core/common.h"
27 #include "core/log.h"
28 #include "core/device-notifier.h"
29 #include "battery/power-supply.h"
30 #include "display/core.h"
31 #include "display/display-ops.h"
32 #include "power/boot.h"
33 #include "shared/plugin.h"
34
35 enum ps_mode {
36         POWERSAVING_OFF,
37         POWERSAVING_ON,
38 };
39
40 static struct display_plugin *disp_plgn;
41 static struct battery_plugin *battery_plgn;
42 static struct touchscreen_device *touchscreen_dev;
43 static int touchscreen_enable = DEVICE_OPS_STATUS_START;
44 static int powersaving_support = true;
45
46 static int touchscreen_start(enum device_flags flags);
47 static int touchscreen_stop(enum device_flags flags);
48
49 static int booting_done(void *data);
50
51 static struct display_config *_display_conf;
52 static struct _backlight_ops *_backlight_ops;
53 static struct battery_status *battery = NULL;
54
55 static struct _backlight_ops* (*_get_var_backlight_ops)(void);
56 static struct display_config* (*_get_var_display_config)(void);
57 static struct battery_status* (*_get_var_battery_status)(void);
58
59 static void touchscreen_wakeup_status(keynode_t *key, void *data)
60 {
61         if (!key)
62                 return;
63
64         if (!_display_conf || !_backlight_ops)
65                 return;
66
67         _display_conf->touch_wakeup = vconf_keynode_get_bool(key);
68
69         if (_backlight_ops->get_lcd_power() != DPMS_ON) {
70                 if (_display_conf->touch_wakeup)
71                         touchscreen_start(NORMAL_MODE);
72                 else
73                         touchscreen_stop(TOUCH_SCREEN_OFF_MODE);
74         }
75 }
76
77 static int touchscreen_powersaving(enum ps_mode mode)
78 {
79         bool state;
80         int ret;
81
82         if (!powersaving_support)
83                 return -ENOTSUP;
84
85         if (touchscreen_enable != DEVICE_OPS_STATUS_START)
86                 return 0;
87
88         if (mode == POWERSAVING_ON)
89                 state = true;
90         else if (mode == POWERSAVING_OFF)
91                 state = false;
92         else
93                 return -EINVAL;
94
95         if (touchscreen_dev && touchscreen_dev->set_powersaving) {
96                 ret = touchscreen_dev->set_powersaving(state);
97                 if (ret < 0) {
98                         _E("Failed to set touch powersaving node.");
99                         return -EIO;
100                 }
101         }
102
103         _I("Set touch powersaving %s.", state ? "ON" : "OFF");
104
105         return 0;
106 }
107 static int touchscreen_probe(void *data)
108 {
109         int ret;
110         struct hw_info *info;
111
112         if (touchscreen_dev)
113                 return 0;
114
115         ret = hw_get_info(TOUCHSCREEN_HARDWARE_DEVICE_ID,
116                         (const struct hw_info **)&info);
117         if (ret < 0) {
118                 _E("Failed to load touchscreen shared library: %d", ret);
119                 return -ENODEV;
120         }
121
122         if (!info->open) {
123                 _E("Failed to open touchscreen device: open(NULL)");
124                 return -EPERM;
125         }
126
127         ret = info->open(info, NULL, (struct hw_common **)&touchscreen_dev);
128         if (ret < 0) {
129                 _E("Failed to get touchscreen device structure: %d", ret);
130                 return -EPERM;
131         }
132
133         _I("Touchscreen device structure load success.");
134         return 0;
135 }
136
137 static void touchscreen_exit(void *data)
138 {
139         struct hw_info *info;
140
141         if (!touchscreen_dev)
142                 return;
143
144         info = touchscreen_dev->common.info;
145         assert(info);
146
147         info->close((struct hw_common *)touchscreen_dev);
148         touchscreen_dev = NULL;
149 }
150
151 static int touchscreen_set_state(enum touchscreen_state state)
152 {
153         int ret;
154         char *act;
155
156         if (!touchscreen_dev) {
157                 _E("Touchscreen device structure is not loaded.");
158                 return -ENOENT;
159         }
160
161         if (state != TOUCHSCREEN_ON && state != TOUCHSCREEN_OFF) {
162                 _E("Invalid parameter.");
163                 return -EINVAL;
164         }
165
166         if (!touchscreen_dev->set_state) {
167                 _E("Touchscreen state change is not supported.");
168                 return -ENOTSUP;
169         }
170
171         act = (state == TOUCHSCREEN_ON) ? "enable" : "disable";
172
173         ret = touchscreen_dev->set_state(state);
174         if (ret == 0)
175                 _I("Success to %s touchscreen.", act);
176         else
177                 _E("Failed to %s touchscreen: %d", act, ret);
178
179         return ret;
180 }
181
182 static int touchscreen_execute(void *data)
183 {
184         touchscreen_enable = (int)((intptr_t)data);
185         return 0;
186 }
187
188 static int touchscreen_start(enum device_flags flags)
189 {
190         int state, ret;
191
192         if (touchscreen_enable != DEVICE_OPS_STATUS_START)
193                 return 0;
194
195         if (!_backlight_ops || !_backlight_ops->get_lcd_power)
196                 return -ENOTSUP;
197
198         /* Do not enable touchscreen during silent boot mode */
199         if (silent_boot && !booting_done(NULL))
200                 return -ENOTSUP;
201
202         /*
203          * It is safe to turn touchscreen on before powersaving on/off.
204          */
205         ret = touchscreen_set_state(TOUCHSCREEN_ON);
206
207         state = _backlight_ops->get_lcd_power();
208
209         if (state == DPMS_OFF)
210                 touchscreen_powersaving(POWERSAVING_ON);
211         else
212                 touchscreen_powersaving(POWERSAVING_OFF);
213
214         return ret;
215 }
216
217 static int touchscreen_stop(enum device_flags flags)
218 {
219         if (!_display_conf || !_backlight_ops) {
220                 _I("Touchscreen is not initialized.");
221                 goto exit;
222         }
223
224         /*
225          * Touchscreen control priority
226          *  1. Touchscreen module control by execute(touchscreen_enable)
227          *  2. Device charger status by charging dock
228          *  3. Touch wakeup setting(touch_wakeup_enable) value
229          *  4. Normal mode(Basic request)
230          */
231         if (touchscreen_enable != DEVICE_OPS_STATUS_START)
232                 return 0;
233
234         if (flags & TOUCH_SCREEN_OFF_MODE) {
235                 touchscreen_powersaving(POWERSAVING_OFF);
236                 return touchscreen_set_state(TOUCHSCREEN_OFF);
237         }
238
239         if (battery && battery->online_type >= CHARGER_TYPE_WIRE) {
240                 _I("Battery charging one %d %d.", battery->online, battery->online_type);
241                 return touchscreen_powersaving(POWERSAVING_ON);
242         }
243
244         if (_display_conf->touch_wakeup) {
245                 _I("Touch wakeup enabled.");
246                 return touchscreen_powersaving(POWERSAVING_ON);
247         }
248
249 exit:
250         touchscreen_powersaving(POWERSAVING_OFF);
251         return touchscreen_set_state(TOUCHSCREEN_OFF);
252 }
253
254 static int touchscreen_dump(FILE *fp, int mode, void *dump_data)
255 {
256         int ret;
257         enum touchscreen_state state;
258
259         if (!touchscreen_dev || !touchscreen_dev->get_state)
260                 return 0;
261
262         ret = touchscreen_dev->get_state(&state);
263         if (ret < 0)
264                 _E("Failed to get touchscreen state: %d", ret);
265
266         if (state == TOUCHSCREEN_ON)
267                 LOG_DUMP(fp, "Touchscreen is enabled\n");
268         else
269                 LOG_DUMP(fp, "Touchscreen is disabled\n");
270
271         return 0;
272 }
273
274 static GVariant *dbus_touchscreen_enable(GDBusConnection *conn,
275         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
276         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
277 {
278         int ret;
279         ret = touchscreen_start(NORMAL_MODE);
280
281         return g_variant_new("(i)", ret);
282 }
283
284 static GVariant *dbus_touchscreen_disable(GDBusConnection *conn,
285         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
286         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
287 {
288         int ret;
289         ret = touchscreen_stop(TOUCH_SCREEN_OFF_MODE);
290
291         return g_variant_new("(i)", ret);
292 }
293
294 static const dbus_method_s dbus_methods[] = {
295         { "Enable",     NULL,    "i",  dbus_touchscreen_enable },
296         { "Disable",    NULL,    "i",  dbus_touchscreen_disable },
297         /* Add methods here */
298 };
299
300 static const dbus_interface_u dbus_interface = {
301         .oh = NULL,
302         .name = DEVICED_INTERFACE_TOUCH,
303         .methods = dbus_methods,
304         .nr_methods = ARRAY_SIZE(dbus_methods),
305 };
306
307 static int booting_done(void *data)
308 {
309         static int done = false;
310
311         if (!data)
312                 return done;
313
314         done = *(int *)data;
315
316         return done;
317 }
318
319 static void touchscreen_init(void *data)
320 {
321         int ret, val;
322
323         _get_var_display_config = dlsym(disp_plgn->handle, "get_display_config");
324         if (_get_var_display_config) {
325                 _display_conf = _get_var_display_config();
326                 if (!_display_conf)
327                         _E("Failed to get display config.");
328         } else
329                 _E("Failed to obtain address of get_display_config, %s.", dlerror());
330
331         /* 'backlight_ops' is declared static and used a lot of places with same name.
332          * So it fails that fetching symbol directly with name 'backlight_ops'.
333          * To avoid this, fetches getter function 'get_backlight_ops' instead, and
334          * retrieve the 'backlight_ops' by using it */
335         _get_var_backlight_ops = dlsym(disp_plgn->handle, "get_backlight_ops");
336         if (_get_var_backlight_ops) {
337                 _backlight_ops = _get_var_backlight_ops();
338                 if (!_backlight_ops)
339                         _E("Failed to get backlight operator.");
340         } else
341                 _E("Failed to obtain address of get_backlight_ops, %s.", dlerror());
342
343         if (battery_plgn->handle) {
344                 _get_var_battery_status = dlsym(battery_plgn->handle, "get_var_battery_status");
345                 if (_get_var_battery_status) {
346                         battery = _get_var_battery_status();
347                         if (!battery)
348                                 _E("Failed to get battery status.");
349                 } else
350                         _E("Failed to obtain address of get_var_battery_status, %s.", dlerror());
351         } else
352                 _I("There is no battery module.");
353
354         if (touchscreen_dev && touchscreen_dev->set_powersaving) {
355                 ret = touchscreen_dev->set_powersaving(0);
356                 if (ret < 0)
357                         powersaving_support = false;
358                 else
359                         powersaving_support = true;
360         } else {
361                 powersaving_support = false;
362         }
363
364         vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_WAKEUP_ENABLE,
365                         touchscreen_wakeup_status, NULL);
366         ret = vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_WAKEUP_ENABLE, &val);
367         if (_display_conf && ret == 0)
368                 _display_conf->touch_wakeup = val;
369
370
371         ret = dbus_handle_add_dbus_object(NULL, DEVICED_PATH_TOUCH, &dbus_interface);
372
373         if (ret < 0)
374                 _E("Failed to init dbus method. (%d)", ret);
375
376         register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
377 }
378
379 static const struct device_ops touchscreen_device_ops = {
380         DECLARE_NAME_LEN("touchscreen"),
381         .probe    = touchscreen_probe,
382         .init     = touchscreen_init,
383         .exit     = touchscreen_exit,
384         .start    = touchscreen_start,
385         .stop     = touchscreen_stop,
386         .dump     = touchscreen_dump,
387         .execute  = touchscreen_execute,
388 };
389
390 DEVICE_OPS_REGISTER(&touchscreen_device_ops)
391
392 static void __CONSTRUCTOR__ initialize(void)
393 {
394         disp_plgn = get_display_plugin();
395         if (!disp_plgn) {
396                 _E("Failed to get display plugin.");
397         }
398
399         battery_plgn = get_battery_plugin();
400         if (!battery_plgn) {
401                 _E("Failed to get battery plugin.");
402         }
403 }