Fix device API handling poweroff
[platform/core/telephony/tel-plugin-manager.git] / src / manager_modem.c
index bc63972..97f8b44 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <string.h>
 #include <glib.h>
+#include <stdlib.h>
 #include <tcore.h>
 #include <server.h>
 #include <manager.h>
@@ -39,6 +40,8 @@
 #include "tfeature.h"
 
 #include <vconf.h>
+#include <system_info.h>
+#include <device/power-internal.h>
 
 /*
  * Timeout of 1 second for normal cases, we may have to consider 4 sec for Verizon.
 #define MANAGER_FLIGHT_MODE_REQUEST_TIMEOUT     (1000)  /* 1 seconds */
 #define MANAGER_MODEM_POWER_OFF_REQUEST_TIMEOUT (1000)  /* 1 seconds */
 
+/*
+ * Timeout for 5 seconds for poweroff wait timer set
+ */
+#define MANAGER_DEFAULT_TIMEOUT        (5 * 1000)
+#define MANAGER_RETRY_TIMEOUT  (1 * 1000)
+
 static enum tcore_hook_return on_noti_hook_manager_call_status_idle(Server *server,
                                                                       CoreObject *source, enum tcore_notification_command command,
                                                                       unsigned int data_len, void *data, void *user_data)
@@ -104,7 +113,7 @@ static enum tcore_manager_return __handle_flight_mode_end(Server *server, UserRe
                        co_call = co_call_other;
                        plugin_subs = plugin_subs_other;
                }
-       } else{
+       } else {
                priv_data->is_end_all_initiated = FALSE;
        }
 
@@ -120,7 +129,7 @@ static enum tcore_manager_return __handle_flight_mode_end(Server *server, UserRe
                tcore_user_request_set_command(new_ur, TREQ_CALL_END);
                tcore_user_request_set_data(new_ur, sizeof(struct treq_call_end), &req);
                if (TCORE_RETURN_SUCCESS != tcore_server_dispatch_request(server, new_ur)) {
-                       err("END_ALL request failed!!r");
+                       err("END_ALL request failed!!");
                        tcore_user_request_free(new_ur);
                } else {
                        info("queueing flight mode request");
@@ -130,8 +139,8 @@ static enum tcore_manager_return __handle_flight_mode_end(Server *server, UserRe
        }
 
        return TCORE_MANAGER_RETURN_CONTINUE;
-
 }
+
 enum tcore_manager_return manager_modem_process_request(Server *server,
                                                        UserRequest *ur)
 {
@@ -201,10 +210,103 @@ static void __update_private_info(Manager *manager, CoreObject *co_modem, enum m
 
 }
 
+static void __on_resp_modem_poweroff(UserRequest *ur, enum tcore_response_command command,
+                                    unsigned int data_len, const void *data, void *user_data)
+{
+       struct tresp_modem_power_off *poweroff_status = (struct tresp_modem_power_off *)data;
+       TcorePlugin *modem_plugin = (TcorePlugin *)user_data;
+
+       dbg("enter");
+
+       if (!poweroff_status || !modem_plugin) {
+               err("NULL data : poweroff_status[%p], modem_plugin[%p]", poweroff_status, modem_plugin);
+               return;
+       }
+
+}
+
+static void __request_modem_poweroff(TcorePlugin *modem_plugin)
+{
+       struct treq_modem_power_off poweroff_cmd = {};
+       gboolean ret = FALSE;
+
+       dbg("enter");
+
+       if (G_UNLIKELY(!modem_plugin))
+               return;
+
+       ret = manager_util_send_request(modem_plugin, TREQ_MODEM_POWER_OFF,
+                                       sizeof(poweroff_cmd), &poweroff_cmd, __on_resp_modem_poweroff, modem_plugin);
+
+       if (!ret) {
+               err("Fail to request modem power off!!");
+       }
+
+       dbg("done");
+}
+
+static void manager_modem_poweroff_handler(device_power_state_e prev_state, device_power_state_e next_state,
+                                                            uint64_t wait_callback_id, device_power_transition_reason_e reason, void *user_data)
+{
+       ModemPrivateInfo *modem_info = user_data;
+       TcorePlugin *modem_plugin = NULL;
+       dbg("enter");
+
+       if (G_UNLIKELY(!modem_info))
+               return;
+
+       modem_info->poweroff_id = wait_callback_id;
+
+       modem_plugin = tcore_object_ref_plugin(modem_info->co_modem);
+       dbg("poweroff state changed is happened");
+       __request_modem_poweroff(modem_plugin);
+
+       dbg("done");
+}
+
+static void mamager_modem_register_poweroff_handler(ModemPrivateInfo *modem_info)
+{
+       int ret;
+       char *profile = NULL;
+
+       dbg("enter");
+
+       if (G_UNLIKELY(!modem_info)) {
+               err("Invalid data");
+               return;
+       }
+
+       /*      Poweroff signal support should be executed only mobile and wearable profile.
+               In case of TV or IoT profile etc... (dongle modem support case),
+               dongle modem can be power off with udev_remove event.  */
+       ret = system_info_get_platform_string("tizen.org/feature/profile", &profile);
+       if (ret != SYSTEM_INFO_ERROR_NONE) {
+               err("system_info_get_platform_string() failed!!! (%d,%s)", ret, get_error_message(ret));
+               return;
+       }
+
+       dbg("profile: %s", profile);
+       if (g_strcmp0(profile, "mobile") && g_strcmp0(profile, "wearable")) {
+               dbg("No need to subscribe poweroff signal handling to deviced");
+               free(profile);
+               return;
+       }
+       if (profile)
+               free(profile);
+
+       device_power_add_state_wait_callback(DEVICE_POWER_STATE_POWEROFF | DEVICE_POWER_STATE_REBOOT, manager_modem_poweroff_handler, modem_info);
+
+       dbg("done");
+}
+
 gboolean manager_modem_initialize_private_info(ModemBoard *mb)
 {
-       if (G_UNLIKELY(!mb))
+       dbg("enter");
+
+       if (G_UNLIKELY(!mb)) {
+               err("Invalid data");
                return FALSE;
+       }
 
        if (mb->modem_info)
                mb->modem_info->modem_status = MODEM_STATE_UNKNOWN;
@@ -213,9 +315,39 @@ gboolean manager_modem_initialize_private_info(ModemBoard *mb)
        mb->modem_info->co_modem = tcore_plugin_ref_core_object(mb->modem_plugin, CORE_OBJECT_TYPE_MODEM);
        mb->modem_info->modem_status = MODEM_STATE_UNKNOWN;
 
+       /* For executing CP detach process when Device Power off */
+       /* It should be subscribed power off waiting timer to deviced */
+       /* Poweroff timer should be added only one time, in case of modem index (0) */
+       if (mb->index == MANAGER_MODEM_BOARD_INDEX_0) {
+               dbg("manager_modem_register_poweroff_handler() for modem index (%d)", mb->index);
+               mamager_modem_register_poweroff_handler(mb->modem_info);
+       }
+
        dbg("Initialized modem private info");
        return TRUE;
 }
+
+void manager_modem_clear_private_info(ModemBoard *mb)
+{
+
+       dbg("enter");
+
+       if (G_UNLIKELY(!mb || !mb->modem_info)) {
+               err("Invalid data");
+               return;
+       }
+
+       if (mb->index == MANAGER_MODEM_BOARD_INDEX_0) {
+               dbg("device_power_remove_state_wait_callback() for modem index (%d)", mb->index);
+               device_power_remove_state_wait_callback(DEVICE_POWER_STATE_POWEROFF | DEVICE_POWER_STATE_REBOOT);
+       }
+
+       g_free(mb->modem_info);
+       mb->modem_info = NULL;
+
+       dbg("done");
+}
+
 enum tcore_manager_return manager_modem_process_notification(Manager *manager,
                                                             CoreObject *source, enum tcore_notification_command command,
                                                             unsigned int data_len, void *data)
@@ -224,7 +356,9 @@ enum tcore_manager_return manager_modem_process_notification(Manager *manager,
        TcorePlugin *manager_plugin = tcore_manager_get_plugin(manager);
        PrivateData *priv_data = tcore_plugin_ref_user_data(manager_plugin);
 
-       if (!data || !priv_data) {
+       ModemBoard *mb = manager_core_get_modem_board(manager, tcore_object_ref_plugin(source));
+
+       if (!data || !priv_data || !mb || !mb->modem_info) {
                err("Invalid data");
                return ret;
        }
@@ -234,11 +368,15 @@ enum tcore_manager_return manager_modem_process_notification(Manager *manager,
                const struct tnoti_modem_power *modem_power = data;
 
                switch (modem_power->state) {
-               case MODEM_STATE_ERROR:
+               case MODEM_STATE_ERROR: {
                        dbg("Modem RESET happened");
+
                        manager_network_process_modem_error(source);
                        manager_call_process_modem_error(source);
+                       manager_sim_process_modem_error(source);
+
                        priv_data->fm_processing_state = MANAGER_FLIGHT_PROCESSING_NONE;
+               }
                        break;
 
                case MODEM_STATE_ONLINE: {
@@ -246,8 +384,26 @@ enum tcore_manager_return manager_modem_process_notification(Manager *manager,
                        dbg("Write MODEM_STATE to /sys/class/sec/bsp/boot_stat");
                        manager_util_write_to_proc_file(msg, strlen(msg));
                        g_free(msg);
+
                }
-               break;
+                       break;
+
+               case MODEM_STATE_OFFLINE: {
+                       dbg("MODEM_STATE has been changed to OFFLINE");
+
+                       /* Once MODEM has been power off successufully, */
+                       /* It should be removed  power off waiting timer from deviced */
+                       /* Poweroff timer should be removed only one time, in case of modem index (0) */
+                       if (mb->index == MANAGER_MODEM_BOARD_INDEX_0) {
+                               dbg("Should removed poweroff timer in case of modem index (0)");
+
+                               if (mb->modem_info->poweroff_id > 0) {
+                                       device_power_confirm_wait_callback(mb->modem_info->poweroff_id);
+                                       mb->modem_info->poweroff_id = 0;
+                               }
+                       }
+               }
+                       break;
 
                default:
                        break;
@@ -257,7 +413,7 @@ enum tcore_manager_return manager_modem_process_notification(Manager *manager,
                set_nw_dds_ds_on_boot(manager);
 #endif
        }
-       break;
+               break;
 
        default:
                break;