4 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Suresh Kumar N <suresh.n@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
27 #include <core_object.h>
28 #include <user_request.h>
31 #include "manager_core.h"
32 #include "manager_util.h"
33 #include "manager_queue.h"
34 #include "manager_network.h"
35 #include "manager_modem.h"
36 #include "manager_call.h"
37 #include "manager_sim.h"
38 #include "internal/manager_internal.h"
42 #include <system_info.h>
45 * Timeout of 1 second for normal cases, we may have to consider 4 sec for Verizon.
47 #define MANAGER_FLIGHT_MODE_REQUEST_TIMEOUT (1000) /* 1 seconds */
48 #define MANAGER_MODEM_POWER_OFF_REQUEST_TIMEOUT (1000) /* 1 seconds */
51 * Timeout for 5 seconds for poweroff wait timer set
53 #define MANAGER_DEFAULT_TIMEOUT (5 * 1000)
54 #define MANAGER_RETRY_TIMEOUT (1 * 1000)
58 * Dbus interface info for power off wait timer handling
60 #define DEVICED_BUS_NAME "org.tizen.system.deviced"
61 #define DEVICED_OBJECT_PATH "/Org/Tizen/System/DeviceD"
62 #define DEVICED_INTERFACE_NAME DEVICED_BUS_NAME
64 #define DEVICED_PATH_REBOOT DEVICED_OBJECT_PATH"/Reboot"
65 #define DEVICED_PATH_POWEROFF DEVICED_OBJECT_PATH"/PowerOff"
67 #define DEVICED_INTERFACE_REBOOT DEVICED_INTERFACE_NAME".reboot"
68 #define DEVICED_INTERFACE_POWEROFF DEVICED_INTERFACE_NAME".PowerOff"
70 #define DBUS_METHOD_ADD_POWEROFF_WAIT "AddPoweroffWait"
71 #define DBUS_METHOD_REMOVE_POWEROFF_WAIT "RemovePoweroffWait"
72 #define DBUS_SIGNAL_POWEROFF_STATE "ChangeState"
74 static void __manager_modem_add_poweroff_wait(ModemPrivateInfo *modem_info);
76 static enum tcore_hook_return on_noti_hook_manager_call_status_idle(Server *server,
77 CoreObject *source, enum tcore_notification_command command,
78 unsigned int data_len, void *data, void *user_data)
80 TcorePlugin *modem_plugin = tcore_object_ref_plugin(source);
81 UserRequest *ur = user_data;
83 if (manager_call_is_during_call(modem_plugin)) {
84 dbg("Call is still in progress");
85 return TCORE_HOOK_RETURN_CONTINUE;
88 info("Call was disconnected. Dispatch pending ur(%p)", ur);
90 if (tcore_server_dispatch_request_ex(server, ur, TCORE_OPS_TYPE_CP) != TCORE_RETURN_SUCCESS) {
91 err("Failed to dispatch request");
94 tcore_server_remove_notification_hook(server, on_noti_hook_manager_call_status_idle);
96 return TCORE_HOOK_RETURN_CONTINUE;
99 static void manager_modem_resp_hook_flight_mode(UserRequest *ur,
100 enum tcore_response_command command,
101 unsigned int data_len, const void *data, void *user_data)
103 TcorePlugin *manager_plugin = (TcorePlugin *)user_data;
104 PrivateData *priv_data = tcore_plugin_ref_user_data(manager_plugin);
106 priv_data->fm_processing_state = MANAGER_FLIGHT_PROCESSING_NONE;
107 info("flight mode request completed");
110 static enum tcore_manager_return __handle_flight_mode_end(Server *server, UserRequest *ur)
112 TcorePlugin *plugin_subs_other, *plugin_subs;
113 CoreObject *co_call, *co_call_other;
114 gboolean end_all_calls = FALSE;
115 Manager *manager = tcore_server_ref_manager(server);
116 TcorePlugin *manager_plugin = tcore_manager_get_plugin(manager);
117 PrivateData *priv_data = tcore_plugin_ref_user_data(manager_plugin);
119 /* In case of active calls, release all calls before sending flight mode request */
120 co_call = manager_util_get_core_object(server, ur, CORE_OBJECT_TYPE_CALL);
121 plugin_subs = tcore_object_ref_plugin(co_call);
122 plugin_subs_other = manager_util_get_other_subs_plugin(plugin_subs);
123 co_call_other = tcore_plugin_ref_core_object(plugin_subs_other, CORE_OBJECT_TYPE_CALL);
125 info("handle flight mode reqeust ");
126 if (priv_data->is_end_all_initiated == FALSE) {
127 if (tcore_call_object_total_length(co_call) > 0) {
128 end_all_calls = TRUE;
129 } else if (tcore_call_object_total_length(co_call_other) > 0) {
130 end_all_calls = TRUE;
131 co_call = co_call_other;
132 plugin_subs = plugin_subs_other;
135 priv_data->is_end_all_initiated = FALSE;
138 if (end_all_calls == TRUE) {
140 UserRequest *new_ur = tcore_user_request_new(NULL, tcore_server_get_cp_name_by_plugin(plugin_subs));
141 struct treq_call_end req = { 0, };
143 info("Releasing all calls in case of flight mode request");
145 req.type = CALL_END_TYPE_ALL;
147 tcore_user_request_set_command(new_ur, TREQ_CALL_END);
148 tcore_user_request_set_data(new_ur, sizeof(struct treq_call_end), &req);
149 if (TCORE_RETURN_SUCCESS != tcore_server_dispatch_request(server, new_ur)) {
150 err("END_ALL request failed!!r");
151 tcore_user_request_free(new_ur);
153 info("queueing flight mode request");
154 manager_queue_enqueue(manager, ur);
155 return TCORE_MANAGER_RETURN_STOP;
159 return TCORE_MANAGER_RETURN_CONTINUE;
162 enum tcore_manager_return manager_modem_process_request(Server *server,
165 enum tcore_request_command command = tcore_user_request_get_command(ur);
166 enum tcore_manager_return manager_ret = TCORE_MANAGER_RETURN_CONTINUE;
169 case TREQ_MODEM_SET_FLIGHTMODE: {
170 struct treq_modem_set_flightmode *flight_mode = (struct treq_modem_set_flightmode *)tcore_user_request_ref_data(ur, 0);
171 Manager *manager = tcore_server_ref_manager(server);
172 TcorePlugin *manager_plugin = tcore_manager_get_plugin(manager);
173 PrivateData *priv_data = tcore_plugin_ref_user_data(manager_plugin);
175 info("flight mode request is in progress");
176 /* Add response hook */
177 tcore_user_request_set_response_hook(ur,
178 manager_modem_resp_hook_flight_mode, manager_plugin);
180 if (flight_mode->enable == 0) {
181 dbg("Flight mode disable, not required to deregister IMS");
182 priv_data->fm_processing_state = MANAGER_FLIGHT_PROCESSSING_DISABLE;
187 priv_data->fm_processing_state = MANAGER_FLIGHT_PROCESSSING_ENABLE;
188 /* In case calls are present, end all calls before processing flight mode request */
189 if (__handle_flight_mode_end(server, ur) == TCORE_MANAGER_RETURN_STOP) {
190 return TCORE_MANAGER_RETURN_STOP;
192 manager_ret = manager_util_process_ims(server, ur);
196 case TREQ_MODEM_POWER_LOW:
197 case TREQ_MODEM_POWER_OFF: {
198 if (tfeature_is_supported(TFEATURE_DEVICE_WEARABLE)) {
199 TcorePlugin *modem_plugin = manager_util_get_modem_plugin(server, ur);
200 if (manager_call_is_during_call(modem_plugin)) {
201 info("Call is in progress. Hold ur(%p)", ur);
202 tcore_server_add_notification_hook(server, TNOTI_CALL_STATUS_IDLE,
203 on_noti_hook_manager_call_status_idle, ur);
204 return TCORE_MANAGER_RETURN_STOP;
208 manager_ret = manager_util_process_ims(server, ur);
213 * All other requests, would be routed to CP.
222 static void __update_private_info(Manager *manager, CoreObject *co_modem, enum modem_state modem_status)
224 ModemBoard *mb = manager_core_get_modem_board(manager, tcore_object_ref_plugin(co_modem));
226 mb->modem_info->co_modem = co_modem;
227 mb->modem_info->modem_status = modem_status;
231 static void __on_resp_modem_poweroff(UserRequest *ur, enum tcore_response_command command,
232 unsigned int data_len, const void *data, void *user_data)
234 struct tresp_modem_power_off *poweroff_status = (struct tresp_modem_power_off *)data;
235 TcorePlugin *modem_plugin = (TcorePlugin *)user_data;
239 if (!poweroff_status || !modem_plugin) {
240 err("NULL data : poweroff_status[%p], modem_plugin[%p]", poweroff_status, modem_plugin);
246 static void __request_modem_poweroff(TcorePlugin *modem_plugin)
248 struct treq_modem_power_off poweroff_cmd = {};
249 gboolean ret = FALSE;
253 if (G_UNLIKELY(!modem_plugin))
256 ret = manager_util_send_request(modem_plugin, TREQ_MODEM_POWER_OFF,
257 sizeof(poweroff_cmd), &poweroff_cmd, __on_resp_modem_poweroff, modem_plugin);
260 err("Fail to request modem power off!!");
266 static void __manager_modem_poweroff_signal_handler(GDBusConnection *connection,
267 const gchar *sender_name, const gchar *object_path,
268 const gchar *interface_name, const gchar *signal_name,
269 GVariant *parameters, gpointer user_data)
272 ModemPrivateInfo *modem_info = user_data;
273 TcorePlugin *modem_plugin = NULL;
276 if (G_UNLIKELY(!modem_info))
279 if (g_strcmp0(signal_name, DBUS_SIGNAL_POWEROFF_STATE) == 0) {
280 modem_plugin = tcore_object_ref_plugin(modem_info->co_modem);
281 dbg("poweroff state changed is happened");
282 __request_modem_poweroff(modem_plugin);
288 static void __manager_modem_poweroff_subscribe_signal(ModemPrivateInfo *modem_info)
291 char *profile = NULL;
295 if (G_UNLIKELY(!modem_info)) {
300 /* Poweroff signal support should be executed only mobile and wearable profile.
301 In case of TV or IoT profile etc... (dongle modem support case),
302 dongle modem can be power off with udev_remove event. */
303 ret = system_info_get_platform_string("tizen.org/feature/profile", &profile);
304 if (ret != SYSTEM_INFO_ERROR_NONE) {
305 err("system_info_get_platform_string() failed!!! (%d,%s)", ret, get_error_message(ret));
309 dbg("profile: %s", profile);
310 if (g_strcmp0(profile, "mobile") && g_strcmp0(profile, "wearable")) {
311 dbg("No need to subscribe poweroff signal handling to deviced");
315 if (!modem_info->sys_power.conn) {
316 GError *error = NULL;
318 modem_info->sys_power.conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
319 if (modem_info->sys_power.conn == NULL) {
320 err("GDBusconnection is NULL: [%s]", error->message);
324 modem_info->sys_power.set_poweroff_wait = FALSE;
327 if (!modem_info->sys_power.ca) {
328 modem_info->sys_power.ca = g_cancellable_new();
331 if (modem_info->sys_power.subs_id_power_off) {
332 dbg("g_dbus_connection_signal_subscribe() for poweroff_state has been already done.");
336 modem_info->sys_power.subs_id_power_off = g_dbus_connection_signal_subscribe(modem_info->sys_power.conn,
338 DEVICED_INTERFACE_POWEROFF,
339 DBUS_SIGNAL_POWEROFF_STATE,
340 DEVICED_PATH_POWEROFF, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
341 __manager_modem_poweroff_signal_handler, modem_info, NULL);
344 if (modem_info->sys_power.subs_id_power_off == 0) {
345 err("g_dbus_connection_signal_subscribe() is failed.");
346 g_object_unref(modem_info->sys_power.conn);
353 static void __manager_modem_poweroff_unsubscribe_signal(ModemPrivateInfo *modem_info)
357 if (G_UNLIKELY(!modem_info)) {
362 if (modem_info->sys_power.subs_id_power_off > 0) {
363 g_dbus_connection_signal_unsubscribe(modem_info->sys_power.conn, modem_info->sys_power.subs_id_power_off);
364 modem_info->sys_power.subs_id_power_off = 0;
367 if (modem_info->sys_power.ca) {
368 g_cancellable_cancel(modem_info->sys_power.ca);
369 g_object_unref(modem_info->sys_power.ca);
372 if (modem_info->sys_power.conn) {
373 g_object_unref(modem_info->sys_power.conn);
374 modem_info->sys_power.conn = NULL;
377 modem_info->sys_power.set_poweroff_wait = FALSE;
383 static void __manager_modem_add_poweroff_wait_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
385 GError *error = NULL;
386 GDBusConnection *conn = NULL;
388 GVariant *dbus_result = NULL;
389 ModemPrivateInfo *modem_info = user_data;
393 conn = G_DBUS_CONNECTION(source_object);
394 dbus_result = g_dbus_connection_call_finish(conn, res, &error);
396 err("Failed: %s", error->message);
399 dbg("PoweroffWait Added Successufully");
400 modem_info->sys_power.set_poweroff_wait = TRUE;
404 g_variant_get(dbus_result, "(i)", &result);
405 g_variant_unref(dbus_result);
408 dbg("result : %d", result);
412 static void __manager_modem_add_poweroff_wait(ModemPrivateInfo *modem_info)
416 if (G_UNLIKELY(!modem_info)) {
421 if (modem_info->sys_power.set_poweroff_wait == TRUE) {
425 if (modem_info->sys_power.conn) {
426 g_dbus_connection_call(modem_info->sys_power.conn, DEVICED_BUS_NAME,
427 DEVICED_PATH_REBOOT, DEVICED_INTERFACE_REBOOT, DBUS_METHOD_ADD_POWEROFF_WAIT,
428 NULL, NULL, G_DBUS_CALL_FLAGS_NONE,
429 MANAGER_DEFAULT_TIMEOUT, modem_info->sys_power.ca,
430 __manager_modem_add_poweroff_wait_cb, modem_info);
438 static void __manager_modem_remove_poweroff_wait_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
440 GError *error = NULL;
441 GDBusConnection *conn = NULL;
443 GVariant *dbus_result = NULL;
444 ModemPrivateInfo *modem_info = user_data;
448 conn = G_DBUS_CONNECTION(source_object);
449 dbus_result = g_dbus_connection_call_finish(conn, res, &error);
451 err("Failed: %s", error->message);
454 dbg("PoweroffWait Removed Successufully");
455 modem_info->sys_power.set_poweroff_wait = FALSE;
459 g_variant_get(dbus_result, "(i)", &result);
460 g_variant_unref(dbus_result);
463 dbg("result : %d", result);
466 static void __manager_modem_remove_poweroff_wait(ModemPrivateInfo *modem_info)
470 if (G_UNLIKELY(!modem_info)) {
475 if (modem_info->sys_power.conn) {
476 g_dbus_connection_call(modem_info->sys_power.conn, DEVICED_BUS_NAME,
477 DEVICED_PATH_REBOOT, DEVICED_INTERFACE_REBOOT, DBUS_METHOD_REMOVE_POWEROFF_WAIT,
478 NULL, NULL, G_DBUS_CALL_FLAGS_NONE,
479 MANAGER_DEFAULT_TIMEOUT, modem_info->sys_power.ca,
480 __manager_modem_remove_poweroff_wait_cb, NULL);
482 modem_info->sys_power.set_poweroff_wait = FALSE;
488 gboolean manager_modem_initialize_private_info(ModemBoard *mb)
492 if (G_UNLIKELY(!mb)) {
498 mb->modem_info->modem_status = MODEM_STATE_UNKNOWN;
500 mb->modem_info = g_malloc0(sizeof(struct manager_modem_private_info));
501 mb->modem_info->co_modem = tcore_plugin_ref_core_object(mb->modem_plugin, CORE_OBJECT_TYPE_MODEM);
502 mb->modem_info->modem_status = MODEM_STATE_UNKNOWN;
504 if (mb->index == MANAGER_MODEM_BOARD_INDEX_0) {
505 dbg("__manager_power_subscribe_signal() for modem index (%d)", mb->index);
506 __manager_modem_poweroff_subscribe_signal(mb->modem_info);
509 dbg("Initialized modem private info");
513 gboolean manager_modem_clear_private_info(ModemBoard *mb)
518 if (G_UNLIKELY(!mb || !mb->modem_info)) {
523 if (mb->index == MANAGER_MODEM_BOARD_INDEX_0) {
524 dbg("__manager_power_unsubscribe_signal() for modem index (%d)", mb->index);
525 __manager_modem_poweroff_unsubscribe_signal(mb->modem_info);
528 g_free(mb->modem_info);
529 mb->modem_info = NULL;
536 enum tcore_manager_return manager_modem_process_notification(Manager *manager,
537 CoreObject *source, enum tcore_notification_command command,
538 unsigned int data_len, void *data)
540 enum tcore_manager_return ret = TCORE_MANAGER_RETURN_CONTINUE;
541 TcorePlugin *manager_plugin = tcore_manager_get_plugin(manager);
542 PrivateData *priv_data = tcore_plugin_ref_user_data(manager_plugin);
544 ModemBoard *mb = manager_core_get_modem_board(manager, tcore_object_ref_plugin(source));
546 if (!data || !priv_data || !mb || !mb->modem_info) {
552 case TNOTI_MODEM_POWER: {
553 const struct tnoti_modem_power *modem_power = data;
555 switch (modem_power->state) {
556 case MODEM_STATE_ERROR:
557 dbg("Modem RESET happened");
558 manager_network_process_modem_error(source);
559 manager_call_process_modem_error(source);
560 priv_data->fm_processing_state = MANAGER_FLIGHT_PROCESSING_NONE;
563 case MODEM_STATE_ONLINE: {
564 char *msg = g_strdup("setRadioPower on");
565 dbg("Write MODEM_STATE to /sys/class/sec/bsp/boot_stat");
566 manager_util_write_to_proc_file(msg, strlen(msg));
569 /* For executing CP detach process when Device Power off */
570 /* It should be subscribed power off waiting timer to deviced */
571 /* Poweroff timer should be added only one time, in case of modem index (0) */
572 if (mb->index == MANAGER_MODEM_BOARD_INDEX_0) {
573 dbg("Should add poweroff timer in case of modem index(0)");
574 if (!mb->modem_info->sys_power.set_poweroff_wait) {
575 //__manager_power_subscribe_signal(mb->modem_info);
576 __manager_modem_add_poweroff_wait(mb->modem_info);
582 case MODEM_STATE_OFFLINE: {
583 dbg("MODEM_STATE has been changed to OFFLINE");
585 /* Once MODEM has been power off successufully, */
586 /* It should be removed power off waiting timer from deviced */
587 /* Poweroff timer should be removed only one time, in case of modem index (0) */
588 if (mb->index == MANAGER_MODEM_BOARD_INDEX_0) {
589 dbg("Should removed poweroff timer in case of modem index (0)");
591 if (mb->modem_info->sys_power.set_poweroff_wait == TRUE) {
592 __manager_modem_remove_poweroff_wait(mb->modem_info);
601 __update_private_info(manager, source, modem_power->state);
602 #ifdef TIZEN_SUPPORT_SIM_PREFERRED_SUBSCRIPTION
603 set_nw_dds_ds_on_boot(manager);