tizen 2.3 release
[framework/system/deviced.git] / src / telephony / telephony.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
20 #include <ITapiModem.h>
21 #include <TelPower.h>
22 #include <tapi_event.h>
23 #include <tapi_common.h>
24
25 #include <unistd.h>
26 #include <assert.h>
27 #include <vconf.h>
28
29 #include <device-node.h>
30 #include "dd-deviced.h"
31 #include "core/log.h"
32 #include "core/common.h"
33 #include "core/devices.h"
34 #include "core/edbus-handler.h"
35 #include "display/core.h"
36 #include "power/power-handler.h"
37
38 #define PREDEF_FLIGHT_MODE      "flightmode"
39 #define PREDEF_ENTERSLEEP       "entersleep"
40 #define PREDEF_LEAVESLEEP       "leavesleep"
41
42 #define POWER_RESTART           5
43
44 static TapiHandle *tapi_handle = NULL;
45 static Ecore_Timer *poweroff_timer_id = NULL;
46 static int reboot_opt;
47
48 static Eina_Bool telephony_powerdown_ap_internal(void *data)
49 {
50         powerdown_ap(data);
51         return EINA_FALSE;
52 }
53 static void telephony_powerdown_ap(TapiHandle *handle, const char *noti_id, void *data, void *user_data)
54 {
55         telephony_powerdown_ap_internal(data);
56 }
57
58 static void telephony_restart_ap(TapiHandle *handle, const char *noti_id, void *data, void *user_data)
59 {
60         restart_ap((void *)reboot_opt);
61 }
62
63 static Eina_Bool telephony_restart_ap_by_force(void *data)
64 {
65         if (poweroff_timer_id) {
66                 ecore_timer_del(poweroff_timer_id);
67                 poweroff_timer_id = NULL;
68         }
69         restart_ap(data);
70         return EINA_TRUE;
71 }
72
73 static void powerdown_res_cb(TapiHandle *handle, int result, void *data, void *user_data)
74 {
75         _D("poweroff command request : %d",result);
76 }
77
78 static Eina_Bool telephony_powerdown_ap_by_force(void *data)
79 {
80         if (poweroff_timer_id) {
81                 ecore_timer_del(poweroff_timer_id);
82                 poweroff_timer_id = NULL;
83         }
84         powerdown_ap(data);
85         return EINA_TRUE;
86 }
87
88 static int telephony_start(enum device_flags flags)
89 {
90         int ready = 0;
91
92         if (tapi_handle) {
93                 _I("already initialized");
94                 return 0;
95         }
96         if (vconf_get_bool(VCONFKEY_TELEPHONY_READY,&ready) != 0 || ready != 1) {
97                 _E("fail to get %s(%d)", VCONFKEY_TELEPHONY_READY, ready);
98                 return -EINVAL;
99         }
100         tapi_handle = tel_init(NULL);
101         if (tapi_handle == NULL) {
102                 _E("tapi init error");
103                 return -EINVAL;
104         }
105         return 0;
106 }
107
108 static int telephony_stop(enum device_flags flags)
109 {
110         int ret;
111
112         ret = tel_deregister_noti_event(tapi_handle, TAPI_NOTI_MODEM_POWER);
113         if (ret != TAPI_API_SUCCESS)
114                 _E("tel_deregister_noti_event is not subscribed. error %d", ret);
115
116         ret = tel_deinit(tapi_handle);
117         if (ret != 0) {
118                 _E("fail to deinit");
119                 return -EINVAL;
120         }
121         tapi_handle = NULL;
122         return 0;
123 }
124
125 static void telephony_exit(void *data)
126 {
127         int ret;
128
129         if (!data) {
130                 _E("Option Failed");
131                 return;
132         }
133
134         if (!strncmp(data, POWER_POWEROFF, POWER_POWEROFF_LEN)) {
135                 _I("Terminate");
136                 ret = tel_register_noti_event(tapi_handle, TAPI_NOTI_MODEM_POWER,
137                                 telephony_powerdown_ap, NULL);
138                 if (ret != TAPI_API_SUCCESS) {
139                         _E("tel_register_event is not subscribed. error %d", ret);
140                         telephony_powerdown_ap_by_force(NULL);
141                         return;
142                 }
143                 ret = tel_process_power_command(tapi_handle, TAPI_PHONE_POWER_OFF,
144                                 powerdown_res_cb, NULL);
145                 if (ret != TAPI_API_SUCCESS) {
146                         _E("tel_process_power_command() error %d\n", ret);
147                         telephony_powerdown_ap_by_force(NULL);
148                         return;
149                 }
150                 poweroff_timer_id = ecore_timer_add(15,
151                     telephony_powerdown_ap_internal, NULL);
152                 return;
153         }
154
155         if (strncmp(data, POWER_REBOOT, POWER_REBOOT_LEN) &&
156             strncmp(data, POWER_RECOVERY, POWER_RECOVERY_LEN) &&
157             strncmp(data, POWER_FOTA, POWER_FOTA_LEN)) {
158                 _E("Fail %s", data);
159                 return;
160         }
161
162         _I("Option: %s", data);
163          if (!strncmp(data, POWER_RECOVERY, POWER_RECOVERY_LEN))
164                 reboot_opt = SYSTEMD_STOP_POWER_RESTART_RECOVERY;
165         else if (!strncmp(data, POWER_REBOOT, POWER_REBOOT_LEN))
166                 reboot_opt = SYSTEMD_STOP_POWER_RESTART;
167         else if (!strncmp(data, POWER_FOTA, POWER_FOTA_LEN))
168                 reboot_opt = SYSTEMD_STOP_POWER_RESTART_FOTA;
169
170         ret = tel_register_noti_event(tapi_handle, TAPI_NOTI_MODEM_POWER,
171                         telephony_restart_ap, NULL);
172         if (ret != TAPI_API_SUCCESS) {
173                 _E("tel_register_event is not subscribed. error %d", ret);
174                 telephony_restart_ap_by_force((void *)POWER_RESTART);
175                 return;
176         }
177         ret = tel_process_power_command(tapi_handle, TAPI_PHONE_POWER_OFF,
178                         powerdown_res_cb, NULL);
179         if (ret != TAPI_API_SUCCESS) {
180                 _E("tel_process_power_command() error %d", ret);
181                 telephony_restart_ap_by_force((void *)reboot_opt);
182                 return;
183         }
184         poweroff_timer_id = ecore_timer_add(15,telephony_restart_ap_by_force,
185                                                         (void *)reboot_opt);
186 }
187
188 static void telephony_flight_mode_on(TapiHandle *handle, int result, void *data, void *user_data)
189 {
190         int ret;
191         int bCurFlightMode = 0;
192
193         if (result != TAPI_POWER_FLIGHT_MODE_ENTER) {
194                 _E("flight mode enter failed %d", result);
195                 return;
196         }
197         _D("enter flight mode result : %d", result);
198         ret = vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &bCurFlightMode);
199         if (ret == 0)
200                 _D("Flight Mode is %d", bCurFlightMode);
201         else
202                 _E("failed to get vconf key");
203 }
204
205 static void telephony_flight_mode_off(TapiHandle *handle, int result, void *data, void *user_data)
206 {
207         int ret;
208         int bCurFlightMode = 0;
209
210         if (result != TAPI_POWER_FLIGHT_MODE_LEAVE) {
211                 _E("flight mode leave failed %d", result);
212                 return;
213         }
214         _D("leave flight mode result : %d", result);
215         ret = vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &bCurFlightMode);
216         if (ret == 0)
217                 _D("Flight Mode is %d", bCurFlightMode);
218         else
219                 _E("failed to get vconf key");
220 }
221
222 static int telephony_execute(void *data)
223 {
224         int ret;
225         int mode = *(int *)(data);
226         int err = TAPI_API_SUCCESS;
227
228         if (tapi_handle == NULL) {
229                 ret = telephony_start(NORMAL_MODE);
230                 if (ret != 0) {
231                         _E("fail to get tapi handle");
232                         return -1;
233                 }
234         }
235
236         if (mode == 1) {
237                 err = tel_set_flight_mode(tapi_handle, TAPI_POWER_FLIGHT_MODE_LEAVE,
238                                 telephony_flight_mode_off, NULL);
239         } else if (mode == 0) {
240                 err = tel_set_flight_mode(tapi_handle, TAPI_POWER_FLIGHT_MODE_ENTER,
241                                 telephony_flight_mode_on, NULL);
242         }
243         if (err != TAPI_API_SUCCESS)
244                 _E("FlightMode tel api action failed %d",err);
245
246         return 0;
247 }
248
249 static int telephony_flight_mode(int argc, char **argv)
250 {
251         int mode;
252
253         if (argc != 1 || argv[0] == NULL) {
254                 _E("FlightMode Set predefine action failed");
255                 return -1;
256         }
257         mode = atoi(argv[0]);
258         telephony_execute(&mode);
259         return 0;
260 }
261
262 static int telephony_enter_sleep(int argc, char **argv)
263 {
264         int ret;
265
266         pm_change_internal(getpid(), LCD_NORMAL);
267         sync();
268
269         /* flight mode
270          * TODO - add check, cb, etc...
271          * should be checked wirh telephony part */
272         ret = tel_set_flight_mode(tapi_handle, TAPI_POWER_FLIGHT_MODE_ENTER,
273                         telephony_flight_mode_on, NULL);
274         _I("request for changing into flight mode : %d", ret);
275
276         launch_evenif_exist("/etc/rc.d/rc.entersleep", "");
277         pm_change_internal(getpid(), POWER_OFF);
278
279         return 0;
280 }
281
282 static int telephony_leave_sleep(int argc, char **argv)
283 {
284         int ret;
285
286         pm_change_internal(getpid(), LCD_NORMAL);
287         sync();
288
289         /* flight mode
290          * TODO - add check, cb, etc...
291          * should be checked wirh telephony part */
292         ret = tel_set_flight_mode(tapi_handle, TAPI_POWER_FLIGHT_MODE_LEAVE,
293                         telephony_flight_mode_off, NULL);
294         _I("request for changing into flight mode : %d", ret);
295
296         return 0;
297 }
298
299 static DBusMessage *flight_mode_handler(E_DBus_Object *obj, DBusMessage *msg)
300 {
301         DBusError err;
302         DBusMessageIter iter;
303         DBusMessage *reply;
304         pid_t pid;
305         int ret;
306         int argc;
307         char *type_str;
308         char *argv;
309
310         dbus_error_init(&err);
311
312         if (!dbus_message_get_args(msg, &err,
313                     DBUS_TYPE_STRING, &type_str,
314                     DBUS_TYPE_INT32, &argc,
315                     DBUS_TYPE_STRING, &argv, DBUS_TYPE_INVALID)) {
316                 _E("there is no message");
317                 ret = -EINVAL;
318                 goto out;
319         }
320
321         if (argc < 0) {
322                 _E("message is invalid!");
323                 ret = -EINVAL;
324                 goto out;
325         }
326
327         pid = get_edbus_sender_pid(msg);
328         if (kill(pid, 0) == -1) {
329                 _E("%d process does not exist, dbus ignored!", pid);
330                 ret = -ESRCH;
331                 goto out;
332         }
333
334         telephony_flight_mode(argc, (char **)&argv);
335
336 out:
337         reply = dbus_message_new_method_return(msg);
338         dbus_message_iter_init_append(reply, &iter);
339         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
340
341         return reply;
342 }
343
344 static DBusMessage *telephony_handler(E_DBus_Object *obj, DBusMessage *msg)
345 {
346         DBusError err;
347         DBusMessageIter iter;
348         DBusMessage *reply;
349         pid_t pid;
350         int ret;
351         int argc;
352         char *type_str;
353
354         dbus_error_init(&err);
355
356         if (!dbus_message_get_args(msg, &err,
357                     DBUS_TYPE_STRING, &type_str,
358                     DBUS_TYPE_INT32, &argc, DBUS_TYPE_INVALID)) {
359                 _E("there is no message");
360                 ret = -EINVAL;
361                 goto out;
362         }
363
364         if (argc < 0) {
365                 _E("message is invalid!");
366                 ret = -EINVAL;
367                 goto out;
368         }
369
370         pid = get_edbus_sender_pid(msg);
371         if (kill(pid, 0) == -1) {
372                 _E("%d process does not exist, dbus ignored!", pid);
373                 ret = -ESRCH;
374                 goto out;
375         }
376
377         if (tapi_handle == NULL) {
378                 if (telephony_start(NORMAL_MODE) != 0)
379                         _E("fail to get tapi handle");
380         }
381
382         if (!strncmp(type_str, PREDEF_ENTERSLEEP, strlen(PREDEF_ENTERSLEEP)))
383                 ret = telephony_enter_sleep(0, NULL);
384         else if (!strncmp(type_str, PREDEF_LEAVESLEEP, strlen(PREDEF_LEAVESLEEP)))
385                 ret = telephony_leave_sleep(0, NULL);
386
387 out:
388         reply = dbus_message_new_method_return(msg);
389         dbus_message_iter_init_append(reply, &iter);
390         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
391
392         return reply;
393 }
394
395 static const struct edbus_method edbus_methods[] = {
396         { PREDEF_FLIGHT_MODE, "sis", "i", flight_mode_handler },
397         { PREDEF_ENTERSLEEP, "si", "i", telephony_handler },
398         { PREDEF_LEAVESLEEP, "si", "i", telephony_handler },
399         /* Add methods here */
400 };
401
402 static void telephony_init(void *data)
403 {
404         int ret;
405
406         /* init dbus interface */
407         ret = register_edbus_method(DEVICED_PATH_POWER, edbus_methods,
408                         ARRAY_SIZE(edbus_methods));
409         if (ret < 0)
410                 _E("fail to init edbus method(%d)", ret);
411 }
412
413 static const struct device_ops tel_device_ops = {
414         .priority = DEVICE_PRIORITY_NORMAL,
415         .name     = "telephony",
416         .init     = telephony_init,
417         .start    = telephony_start,
418         .stop     = telephony_stop,
419         .exit     = telephony_exit,
420         .execute = telephony_execute,
421 };
422
423 DEVICE_OPS_REGISTER(&tel_device_ops)