Modem : NVM initial commit 43/8443/1
authorParesh Agarwal <paresh.agwl@samsung.com>
Tue, 7 May 2013 13:41:48 +0000 (19:11 +0530)
committerwootak.jung <wootak.jung@samsung.com>
Tue, 20 Aug 2013 00:28:17 +0000 (09:28 +0900)
Change-Id: Idd562c0c35b9c0c395570a7efca1107f3fdb33f3

CMakeLists.txt [changed mode: 0644->0755]
include/nvm/nvm.h [new file with mode: 0755]
include/s_modem.h [changed mode: 0644->0755]
src/desc.c [changed mode: 0644->0755]
src/nvm/nvm.c [new file with mode: 0755]
src/s_modem.c [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index 3ab8348..260778e
@@ -42,6 +42,7 @@ SET(SRCS
                src/s_phonebook.c
                src/s_sap.c
                src/s_gps.c
+               src/nvm/nvm.c
 )
 
 
diff --git a/include/nvm/nvm.h b/include/nvm/nvm.h
new file mode 100755 (executable)
index 0000000..a654bf2
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * tel-plugin-imc
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Paresh Agarwal<paresh.agwl@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NVM_H__
+#define __NVM_H__
+
+/* Priority level for suspension of all updates */
+#define UTA_FLASH_PLUGIN_PRIO_SUSPEND_ALL              4294967295 /* 0xFFFFFFFF */
+
+/* Priority level for suspension of High priority updates */
+#define UTA_FLASH_PLUGIN_PRIO_SUSPEND_HIGH             3221225472 /* 0xFFFFFFFF */
+
+/* Priority level for suspension of all updates of dynamic data */
+#define UTA_FLASH_PLUGIN_PRIO_SUSPEND_ALL_DYN  1610612735 /* 0x5FFFFFFF */
+
+/* Priority level for suspension of Medium all updates */
+#define UTA_FLASH_PLUGIN_PRIO_SUSPEND_MEDIUM   2147483648 /* 0x5FFFFFFF */
+
+/* Priority level for suspension of Low updates of Medium */
+#define UTA_FLASH_PLUGIN_PRIO_SUSPEND_LOW              1073741824 /* 0x5FFFFFFF */
+
+/* Priority level for unsuspension of all updates */
+#define UTA_FLASH_PLUGIN_PRIO_UNSUSPEND_ALL            0 /* 0x0 */
+
+#define NVM_FUNCTION_ID_OFFSET         20
+#define XDRV_INDICATION                                0x04
+
+#define XDRV_DISABLE                                   "0"
+#define XDRV_ENABLE                                            "1"
+#define XDRV_UNSUSPEND                                 "0"
+
+/* Identifies our group with the xdrv AT command set */
+#define IUFP_GROUP                                             "43"
+#define IUFP_GROUP_ID                                  43
+
+#define IUFP_REGISTER                                  0
+#define IUFP_REGISTER_STR                              "0"
+
+#define IUFP_SUSPEND                                   1
+#define IUFP_SUSPEND_STR                               "1"
+
+#define IUFP_FLUSH                                             2
+#define IUFP_FLUSH_STR                                 "2"
+
+#define IUFP_UPDATE_REQ                                3
+#define IUFP_UPDATE_REQ_STR                    "3"
+
+#define IUFP_UPDATE_REQ_ACK                    3
+#define IUFP_UPDATE_REQ_ACK_STR                "3"
+
+#define IUFP_UPDATE                                            4
+#define IUFP_UPDATE_STR                                "4"
+
+#define IUFP_UPDATE_ACK                                4
+#define IUFP_UPDATE_ACK_STR                    "4"
+
+#define IUFP_NO_PENDING_UPDATE         5
+#define IUFP_NO_PENDING_UPDATE_STR     "5"
+
+/*  XDRV command was executed without any error */
+#define XDRV_RESULT_OK                                 0
+
+typedef enum uta_common_return_codes {
+       UTA_SUCCESS = 0,
+       UTA_FAILURE = -1,
+       UTA_ERROR_OUT_OF_MEMORY = -2,
+       UTA_ERROR_INVALID_HANDLE = -3,
+       UTA_ERROR_OUT_OF_RANGE_PARAM = -4,
+       UTA_ERROR_INVALID_PARAM = -5,
+       UTA_ERROR_TOO_SMALL_BUF_PARAM = -6,
+       UTA_ERROR_NOT_SUPPORTED = -7,
+       UTA_ERROR_TIMEOUT = -8,
+       UTA_ERROR_WRONG_STATE = -9,
+       UTA_ERROR_BAD_FORMAT = -10,
+       UTA_ERROR_INSUFFICIENT_PERMISSIONS = -11,
+       UTA_ERROR_IO_ERROR = -12,
+       UTA_ERROR_OUT_OF_HANDLES = -13,
+       UTA_ERROR_OPERATION_PENDING = -14,
+       UTA_ERROR_SPECIFIC = -100
+} nvm_return_codes;
+
+typedef enum nvm_error_numbers {
+       NVM_NO_ERR = 0,
+       NVM_CMD_ERR,
+       NVM_DATA_ERR,
+       NVM_MEM_FULL_ERR,
+       NVM_RES_ERR,
+       NVM_WRITE_ERR,
+       NVM_READ_ERR,
+       NVM_RES_LEN_ERR,
+       NVM_PCKT_ERR,
+       NVM_REG_FAIL_ERR,
+       NVM_DATA_LEN_ERR,
+       NVM_FILE_ERR,
+       NVM_AT_PORT_ERR,
+       NVM_READ_AT_ERR,
+       NVM_DATA_PORT_ERR,
+       NVM_NO_PENDING_UPDATE,
+       NVM_UPDATE,
+       NVM_REGISTER_ERR,
+       NVM_UNKNOWN_ERR
+} nvm_error;
+
+int nvm_sum_4_bytes(const char *pos);
+gboolean nvm_create_nvm_data();
+nvm_error nvm_process_nv_update(const char *data);
+
+#endif /* __NVM_H__ */
old mode 100644 (file)
new mode 100755 (executable)
index d0fd6a8..3e22c74
@@ -24,6 +24,8 @@
 gboolean s_modem_init(TcorePlugin *cp, CoreObject *co_modem);
 void s_modem_exit(TcorePlugin *cp, CoreObject *co_modem);
 
-gboolean modem_power_on(TcorePlugin *p);
+gboolean modem_power_on(TcorePlugin *plugin);
+void modem_register_nvm(CoreObject *co_modem);
+void modem_deregister_nvm(CoreObject *co_modem);
 
 #endif
old mode 100644 (file)
new mode 100755 (executable)
index 62b4065..f3e98f6
@@ -69,6 +69,7 @@ static void on_response_last_bootup_subscription(TcorePending *p,
                                                        int data_len, const void *data, void *user_data)
 {
        const TcoreATResponse *resp = data;
+       TcorePlugin *plugin = tcore_pending_ref_plugin(p);
        gboolean ret;
        dbg("Last Subscription - COMPLETED");
 
@@ -80,8 +81,14 @@ static void on_response_last_bootup_subscription(TcorePending *p,
 
        dbg("Boot-up configration completed for IMC modem. %s",
                                "Bring CP to ONLINE state based on Flightmode status");
-       ret = modem_power_on(tcore_pending_ref_plugin(p));
+
+       /* Modem Power */
+       ret = modem_power_on(plugin);
        dbg("Modem Power ON: [%s]", (ret == TRUE ? "SUCCESS" : "FAIL"));
+
+       /* NVM Registration */
+       dbg("Registering modem for NVM manager");
+       modem_register_nvm(tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM));
 }
 
 static void _modem_subscribe_events(TcorePlugin *plugin)
diff --git a/src/nvm/nvm.c b/src/nvm/nvm.c
new file mode 100755 (executable)
index 0000000..582220e
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * tel-plugin-imc
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Paresh Agarwal <paresh.agwl@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include <sys/stat.h>
+#include <tcore.h>
+#include "nvm/nvm.h"
+
+/* NVM file type */
+#define NVM_TYPE_CALIB                         0
+#define NVM_TYPE_STATIC                        1
+#define NVM_TYPE_DYNAMIC                       2
+#define NVM_FILE_TYPE_POS                      36
+
+/* NVM Payload information */
+#define NVM_PAYLOAD_OFFSET_0           48
+#define NVM_PAYLOAD_LENGTH_0           52
+#define NVM_PAYLOAD_OFFSET_1           64
+#define NVM_PAYLOAD_LENGTH_1           68
+#define NVM_DATA_LEN_POS                       80
+
+/* Image Path information */
+#define MODEM_IMAGE_PATH                               "/boot/modem.bin"
+#define NVM_DIR_PATH                                   "/csa/nv"
+#define NV_FILE_PATH NVM_DIR_PATH              "/nvdata.bin"
+
+/* NV offsets and size */
+#define MODEM_NV_OFFSET                                0xA00000
+#define MAX_NVDATA_SIZE                                0x200000
+#define NVM_CALIB_OFFSET                               0x80000
+#define NVM_STATIC_OFFSET                              0x100000
+
+struct nvm_payload_info {
+       unsigned long m_offset_0;
+       unsigned long m_length_0;
+       unsigned long m_offset_1;
+       unsigned long m_length_1;
+};
+
+static nvm_error __nvm_file_write(int nvm_type, const char *update_buf, int update_len, int offset)
+{
+       int nv_fd;
+       nvm_error ret_val = NVM_NO_ERR;
+       int ret;
+
+       char err_str[256] = {0, };
+       errno = 0;
+       dbg("Entered");
+
+       if (NULL == update_buf) {
+               err("Buffer is invalid!!!");
+               return NVM_WRITE_ERR;
+       }
+
+       switch (nvm_type) {
+       case NVM_TYPE_CALIB:
+               msg("           [NVM File] calib.nvm");
+               offset = offset + NVM_CALIB_OFFSET;
+               break;
+
+       case NVM_TYPE_STATIC:
+               msg("           [NVM File] static.nvm");
+               offset = offset + NVM_STATIC_OFFSET;
+               break;
+
+       case NVM_TYPE_DYNAMIC:
+               msg("           [NVM File] dynamic.nvm");
+               break;
+
+       default:
+               err("[NVM File] Wrong NVM file type: [%d]", nvm_type);
+               return NVM_FILE_ERR;
+       }
+
+       /* Open NVM file for Write operation */
+       nv_fd = open(NV_FILE_PATH, O_RDWR);
+       if (nv_fd < 0) {
+               strerror_r(errno, err_str, 255);
+               err("[OPEN] Failed: [%s]", err_str);
+               return NVM_READ_ERR;
+       }
+
+       /* Seek the offset */
+       ret = lseek(nv_fd, (long)offset, SEEK_SET);
+       if (ret < 0) {
+               strerror_r(errno, err_str, 255);
+               err("[SEEK] Failed: [%s]", err_str);
+               ret_val = NVM_RES_LEN_ERR;
+       } else {
+               dbg("Buffer: [0x%x] length: [%d]", update_buf, update_len);
+
+               /* Write the buffer to file */
+               ret = write(nv_fd, update_buf, update_len);
+               if (ret > 0) {
+                       dbg("[WRITE] Successfully updated NVM data");
+               } else if (ret == 0) {
+                       strerror_r(errno, err_str, 255);
+                       dbg("[WRITE] Nothing is written: [%s]", err_str);
+               } else {
+                       strerror_r(errno, err_str, 255);
+                       err("[WRITE] Failed: [%s]", err_str);
+                       ret_val = NVM_MEM_FULL_ERR;
+               }
+       }
+
+       /* Close 'fd' */
+       close(nv_fd);
+
+       return ret_val;
+}
+
+static nvm_error __nvm_write_payload_1(int nvm_type,
+                                               const char *p_bin_buff, struct nvm_payload_info *nvm1)
+{
+       const char *p_buf_ptr = p_bin_buff;
+
+       /* Write to file */
+       return __nvm_file_write(nvm_type,
+                                       (p_buf_ptr + NVM_DATA_LEN_POS + nvm1->m_length_0),
+                                       nvm1->m_length_1,
+                                       nvm1->m_offset_1);
+}
+
+static nvm_error __nvm_write_payload_0(int nvm_type,
+                                               const char *p_bin_buff, struct nvm_payload_info *nvm)
+{
+       nvm_error ret_val;
+
+       /* Write to file */
+       ret_val = __nvm_file_write(nvm_type,
+                                       (p_bin_buff + NVM_DATA_LEN_POS),
+                                       nvm->m_length_0,
+                                       nvm->m_offset_0);
+       if (NVM_NO_ERR == ret_val) {
+               /* The payload_0 has been done, so calls this method to write payload_1 to file */
+               ret_val = __nvm_write_payload_1(nvm_type, p_bin_buff, nvm);
+       } else {
+               err("Failed to write to NV data file!!!");
+       }
+
+       return ret_val;
+}
+
+int nvm_sum_4_bytes(const char *pos)
+{
+       int sum = 0;
+       sum = sum | (*(pos+3)) << 24;
+       sum = sum | (*(pos+2)) << 16;
+       sum = sum | (*(pos+1)) << 8;
+       sum = sum | *pos;
+       return sum;
+}
+
+nvm_error nvm_process_nv_update(const char *data)
+{
+       struct nvm_payload_info nvm_info;
+       int nvm_type;
+       nvm_error ret_val;
+       dbg("Entered");
+
+       memset(&nvm_info, 0x0, sizeof(struct nvm_payload_info));
+
+       /* Determine lengths from the little-endian 4 bytes */
+       nvm_info.m_length_0 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_LENGTH_0]);
+       nvm_info.m_offset_0 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_OFFSET_0]);
+       nvm_info.m_length_1 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_LENGTH_1]);
+       nvm_info.m_offset_1 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_OFFSET_1]);
+       dbg("Offsets - 0th: [%d] 1st: [%d]", nvm_info.m_offset_0, nvm_info.m_offset_1);
+
+       nvm_type = *(data + NVM_FILE_TYPE_POS);
+       if ((NVM_TYPE_CALIB <= nvm_type)
+                       && (NVM_TYPE_DYNAMIC >= nvm_type)) {
+               dbg("NVM type: [%d]", nvm_type);
+
+               /* Write NVM data to file */
+               ret_val = __nvm_write_payload_0(nvm_type, data, &nvm_info);
+       } else {
+               err("Wrong NVM file type: [%d]", nvm_type);
+               ret_val = NVM_RES_ERR;
+       }
+
+       return ret_val;
+}
+
+gboolean nvm_create_nvm_data()
+{
+       int modem_fd;
+       int nv_fd;
+       char *buffer = NULL;
+       char err_str[256] = {0, };
+
+       gboolean ret_val = FALSE;
+       dbg("Entered");
+
+       /* Open modem binary */
+       modem_fd = open(MODEM_IMAGE_PATH, O_RDONLY | O_NDELAY);
+       if (modem_fd < 0) {
+               strerror_r(errno, err_str, 255);
+               err("[OPEN] Failed for (%s): [%s]", MODEM_IMAGE_PATH, err_str);
+               return ret_val;
+       }
+
+       /* Create NV data folder if it doesn't exist */
+       if (mkdir(NVM_DIR_PATH, 0755) < 0) {
+               if (errno != EEXIST) {
+                       strerror_r(errno, err_str, 255);
+                       err("mkdir() failed: [%s]", err_str);
+
+                       /* Close 'modem_fd' */
+                       close(modem_fd);
+                       return ret_val;
+               } else if (open(NV_FILE_PATH, O_EXCL) > 0) {
+                       /* NV data file already exists */
+                       dbg("File exists: [%s]", NV_FILE_PATH);
+
+                       /* Close 'modem_fd' */
+                       close(modem_fd);
+                       return TRUE;
+               } else {
+                       dbg("File does't exsits... need to create!!!");
+               }
+       }
+
+       /* Change directory permissions */
+       if (chmod(NVM_DIR_PATH, 0755) < 0) {
+               strerror_r(errno, err_str, 255);
+               err("chmod() failed: [%s]", err_str);
+
+               /* Close 'modem_fd' */
+               close(modem_fd);
+               return ret_val;
+       }
+
+       /* Open NV data file for different file operations */
+       nv_fd = open(NV_FILE_PATH, O_RDWR | O_CREAT | O_SYNC, S_IRWXU);
+       if (nv_fd < 0) {
+               strerror_r(errno, err_str, 255);
+               err("[OPEN] Failed for (%s): %s", NV_FILE_PATH, err_str);
+
+               /* Close 'modem_fd' */
+               close(modem_fd);
+               return ret_val;
+       }
+
+       dbg("Setting the file descriptor offset to NV data in modem.bin");
+       do {
+               /* Seek pre-defined offset in modem binary */
+               if (lseek(modem_fd, MODEM_NV_OFFSET, SEEK_SET) < 0) {
+                       strerror_r(errno, err_str, 255);
+                       err("[SEEK] Failed: [%s]", err_str);
+                       break;
+               }
+
+               /* Allocate memory */
+               buffer = g_try_malloc0(MAX_NVDATA_SIZE);
+               if (NULL == buffer) {
+                       err("Failed to allocate memory");
+                       break;
+               }
+
+               /* Read NV data from modem binary */
+               if (read(modem_fd, buffer, MAX_NVDATA_SIZE) < 0) {
+                       strerror_r(errno, err_str, 255);
+                       err("[READ] Failed: [%s]", err_str);
+                       break;
+               }
+
+               /* Write the data read from modem binary to nvdata */
+               if (write(nv_fd, buffer, MAX_NVDATA_SIZE) < 0) {
+                       strerror_r(errno, err_str, 255);
+                       err("[WRITE} Failed: [%s]", err_str);
+                       break;
+               }
+
+               ret_val = TRUE;
+       } while (0);
+
+       if (ret_val == FALSE) {
+               err("nvdata (%s) creation Failed!!!", NV_FILE_PATH);
+       } else {
+               dbg("nvdata (%s) created Success", NV_FILE_PATH);
+       }
+
+       /* Close 'fds' */
+       close(modem_fd);
+       close(nv_fd);
+
+       /* Free 'buffer' */
+       g_free(buffer);
+
+       return ret_val;
+}
old mode 100644 (file)
new mode 100755 (executable)
index b167868..9c99048
@@ -39,6 +39,7 @@
 
 #include "s_common.h"
 #include "s_modem.h"
+#include "nvm/nvm.h"
 
 
 #define ID_RESERVED_AT 0x0229
@@ -103,6 +104,15 @@ static void on_confirmation_modem_message_send(TcorePending *p, gboolean result,
 static void on_response_network_registration(TcorePending *p, int data_len, const void *data, void *user_data);
 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data);
 
+/* NVM */
+static gboolean on_event_nvm_update(CoreObject *o, const void *event_info, void *user_data);
+static void modem_send_nvm_update_ack(CoreObject *o);
+static void modem_send_nvm_update_request_ack(CoreObject *o);
+static void modem_unsuspend_nvm_updates(CoreObject *o);
+static void modem_send_nvm_update_ack(CoreObject *o);
+static void modem_send_nvm_update_request_ack(CoreObject *o);
+static void modem_send_flush_nvm_update(CoreObject *o);
+
 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data)
 {
        dbg("on_confirmation_modem_message_send - msg out from queue.\n");
@@ -448,14 +458,14 @@ static enum tcore_hook_return on_hook_sim_status(Server *s,
        return TCORE_HOOK_RETURN_CONTINUE;
 }
 
-gboolean modem_power_on(TcorePlugin *p)
+gboolean modem_power_on(TcorePlugin *plugin)
 {
        CoreObject *co_modem = NULL;
        struct treq_modem_set_flightmode flight_mode_set = {0};
        struct tnoti_modem_power modem_power = {0};
        Storage *strg = NULL;
 
-       co_modem = tcore_plugin_ref_core_object(p, CORE_OBJECT_TYPE_MODEM);
+       co_modem = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
        if (co_modem == NULL) {
                err("Modem Core object is NULL");
                return FALSE;
@@ -465,7 +475,7 @@ gboolean modem_power_on(TcorePlugin *p)
        tcore_modem_set_powered(co_modem, TRUE);
 
        /* Get Flight mode from VCONFKEY */
-       strg = tcore_server_find_storage(tcore_plugin_ref_server(p), "vconf");
+       strg = tcore_server_find_storage(tcore_plugin_ref_server(plugin), "vconf");
        flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE_BOOL);
 
        /* Set Flight mode as per AP settings */
@@ -495,7 +505,7 @@ gboolean modem_power_on(TcorePlugin *p)
        modem_power.state = MODEM_STATE_ONLINE;
 
        dbg("Sending notification - Modem Power state: [ONLINE]");
-       tcore_server_send_notification(tcore_plugin_ref_server(p),
+       tcore_server_send_notification(tcore_plugin_ref_server(plugin),
                co_modem, TNOTI_MODEM_POWER, sizeof(modem_power), &modem_power);
 
        return TRUE;
@@ -650,6 +660,8 @@ gboolean s_modem_init(TcorePlugin *cp, CoreObject *co_modem)
 
        tcore_server_add_notification_hook(tcore_plugin_ref_server(cp),
                                                        TNOTI_SIM_STATUS, on_hook_sim_status, NULL);
+       dbg("Registering for +XDRVI event");
+       tcore_object_add_callback(co_modem, "+XDRVI", on_event_nvm_update, NULL);
 
        dbg("Exit");
        return TRUE;
@@ -673,3 +685,439 @@ void s_modem_exit(TcorePlugin *cp, CoreObject *co_modem)
 
        dbg("Exit");
 }
+
+/*
+ * NV Manager - Support for Remote File System
+ */
+/* NVM Hook */
+static gboolean modem_rfs_hook(const char *data)
+{
+       if (data != NULL)
+               if (data[NVM_FUNCTION_ID_OFFSET] == XDRV_INDICATION)
+                       return TRUE;
+
+       return FALSE;
+}
+
+/* NVM event Notification */
+static gboolean on_event_nvm_update(CoreObject *o, const void *event_info, void *user_data)
+{
+       GSList *tokens = NULL;
+       GSList *lines;
+       const char *line;
+       int function_id;
+
+       gboolean ret = TRUE;
+       dbg("Entered");
+
+       lines = (GSList *)event_info;
+       line = lines->data;
+       dbg("Line: [%s]", line);
+
+       function_id = nvm_sum_4_bytes(&line[NVM_FUNCTION_ID_OFFSET]);
+       dbg("Function ID: [%d]", function_id);
+       if (IUFP_UPDATE == function_id) {
+               dbg("Calling process nvm_update");
+
+               /*
+                * Process NV Update indication
+                *
+                * +XDRVI: IUFP_GROUP, IUFP_UPDATE, <xdrv_result>, <data>
+                */
+               if (NVM_NO_ERR == nvm_process_nv_update(line)) {
+                       dbg("NV data processed successfully");
+
+                       /* Acknowledge NV Update */
+                       modem_send_nvm_update_ack(o);
+
+                       return ret;
+               } else {
+                       err("NV data processing failed");
+                       ret = FALSE;
+               }
+       } else {
+               tokens = tcore_at_tok_new(line);
+               if (g_slist_length(tokens) < 3) {
+                       err("XDRVI event with less number of tokens, Ignore!!!");
+                       ret = FALSE;
+               }
+               else if (IUFP_GROUP_ID != atoi(g_slist_nth_data(tokens, 0))) {
+                       err("Group ID mismatch, Ignore!!!");
+                       ret = FALSE;
+               }
+               else {
+                       switch (atoi(g_slist_nth_data(tokens, 1))) {
+                               case IUFP_UPDATE_REQ:
+                                       dbg("NV Update Request");
+
+                                       /* Acknowledge the Update Request */
+                                       modem_send_nvm_update_request_ack(o);
+                               break;
+
+                               case IUFP_NO_PENDING_UPDATE:
+                                       dbg("NO pending NV Update(s)!!!");
+                                       /* Can send FLUSH request to get fresh updates */
+                               break;
+
+                               default:
+                                       err("Unspported Function ID [%d], Ignore", atoi(g_slist_nth_data(tokens, 1)));
+                                       ret = FALSE;
+                       }
+               }
+
+               tcore_at_tok_free(tokens);
+       }
+
+       dbg("Exit");
+       return ret;
+}
+
+/* NVM Responses */
+static gboolean __modem_check_nvm_response(const void *data, int command)
+{
+       const TcoreATResponse *resp = data;
+       const char *line;
+       char *resp_str;
+       GSList *tokens = NULL;
+       gboolean ret = FALSE;
+       dbg("Entered");
+
+       /* +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>] */
+       if (NULL == resp) {
+               err("Input data is NULL");
+               return FALSE;
+       }
+
+       if (resp->success > 0) {
+               dbg("RESPONSE OK");
+               line = (const char *) (((GSList *) resp->lines)->data);
+               tokens = tcore_at_tok_new(line);
+
+               /* Group ID */
+               resp_str = g_slist_nth_data(tokens, 0);
+               if (NULL == resp_str) {
+                       err("Group ID is missing ");
+                       goto OUT;
+               }
+               else if (IUFP_GROUP_ID != atoi(resp_str)) {
+                       err("Group ID mismatch");
+                       goto OUT;
+               }
+
+               /* Function ID */
+               resp_str =  g_slist_nth_data(tokens, 1);
+               if (NULL == resp_str) {
+                       err("Function ID is missing ");
+                       goto OUT;
+               }
+               else if (command != atoi(resp_str)) {
+                       err("Function ID mismatch");
+                       goto OUT;
+               }
+
+               /* XDRV Result */
+               resp_str =  g_slist_nth_data(tokens, 2);
+               if (NULL == resp_str) {
+                       err("XDRV result is missing ");
+                       goto OUT;
+               }
+               else if (XDRV_RESULT_OK != atoi(resp_str)) {
+                       err("XDRV result[%d] ", atoi(resp_str));
+                       goto OUT;
+               }
+
+               /* Result code */
+               resp_str =  g_slist_nth_data(tokens, 3);
+               if (NULL == resp_str) {
+                       err("UTA result is missing ");
+                       goto OUT;
+               }
+               else if (UTA_SUCCESS != atoi(resp_str)) {
+                       err("uta result[%d] ", atoi(resp_str));
+                       goto OUT;
+               }
+
+               ret = TRUE;
+       } else {
+               dbg("Response NOK");
+       }
+
+OUT:
+       tcore_at_tok_free(tokens);
+
+       dbg("Exit");
+       return ret;
+}
+
+static void _on_response_modem_unsuspend_nvm_updates(TcorePending *p,
+                                                       int data_len, const void *data, void *user_data)
+{
+       /* Check NVM response */
+       if (TRUE == __modem_check_nvm_response(data, IUFP_SUSPEND)) {
+               dbg("Priority level is set to get all updates since Boot-up");
+
+               /* Create NV data file */
+               if (nvm_create_nvm_data() == FALSE) {
+                       err("Failed to Create NV data file");
+               }
+
+               return;
+       }
+
+       err("Response NOT OK");
+}
+
+static void _on_response_modem_send_nvm_update_ack(TcorePending *p,
+                                                       int data_len, const void *data, void *user_data)
+{
+       /* Check NVM response */
+       if (TRUE ==  __modem_check_nvm_response(data, IUFP_UPDATE_ACK)) {
+               dbg("[UPDATE ACK] OK");
+               return;
+       }
+
+       err("[UPDATE ACK] NOT OK");
+}
+
+static void _on_response_modem_send_nvm_update_request_ack(TcorePending *p,
+                                                       int data_len, const void *data, void *user_data)
+{
+       /* Check NVM response */
+       if (TRUE == __modem_check_nvm_response(data, IUFP_UPDATE_REQ_ACK)) {
+               dbg("[REQUEST ACK] OK");
+               return;
+       }
+
+       err("[REQUEST ACK] NOT OK");
+}
+
+static void _on_response_modem_send_flush_nvm_update(TcorePending *p,
+                                                       int data_len, const void *data, void *user_data)
+{
+       /* Check NVM response */
+       if (TRUE == __modem_check_nvm_response(data, IUFP_FLUSH)) {
+               dbg("Flushing of FLUSH data successful");
+               return;
+       }
+
+       err("Response NOT OK");
+}
+
+static void _on_response_modem_register_nvm(TcorePending *p,
+                                               int data_len, const void *data, void *user_data)
+{
+       /* Check NVM response */
+       if (TRUE == __modem_check_nvm_response(data, IUFP_REGISTER)) {
+               dbg("Registering successful");
+
+               /* Send SUSPEND_UPDATE for all UPDATES */
+               modem_unsuspend_nvm_updates(tcore_pending_ref_core_object(p));
+
+               dbg("Exit");
+               return;
+       }
+
+       err("Response NOT OK");
+}
+
+static void _on_response_modem_deregister_nvm(TcorePending *p,
+                                                       int data_len, const void *data, void *user_data)
+{
+       /* Check NVM response */
+       if (TRUE == __modem_check_nvm_response(data, IUFP_REGISTER)) {
+               dbg("Deregistering successful");
+               return;
+       }
+
+       err("Response NOT OK");
+}
+
+/* NVM Requests */
+static void modem_unsuspend_nvm_updates(CoreObject *o)
+{
+       TcorePending *pending = NULL;
+       char *cmd_str;
+       dbg("Entered");
+
+       /* Prepare AT-Command */
+       cmd_str = g_strdup_printf("AT+XDRV=%d, %d, %d, %d",
+                                       IUFP_GROUP_ID, IUFP_SUSPEND,
+                                       0, UTA_FLASH_PLUGIN_PRIO_UNSUSPEND_ALL);
+
+       /* Prepare pending request */
+       pending = tcore_at_pending_new(o,
+                                                               cmd_str,
+                                                               "+XDRV:",
+                                                               TCORE_AT_SINGLELINE,
+                                                               _on_response_modem_unsuspend_nvm_updates,
+                                                               NULL);
+       if (pending == NULL) {
+               err("Failed to form pending request");
+       }
+       else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
+                       != TCORE_RETURN_SUCCESS) {
+               err("IUFP_SUSPEND - Unable to send AT-Command");
+       }
+       else {
+               dbg("IUFP_SUSPEND - Successfully sent AT-Command");
+       }
+
+       g_free(cmd_str);
+}
+
+static void modem_send_nvm_update_ack(CoreObject *o)
+{
+       TcorePending *pending = NULL;
+       char *cmd_str;
+       dbg("Entered");
+
+       /* Prepare AT-Command */
+       cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_ACK_STR);
+
+       /* Prepare pending request */
+       pending = tcore_at_pending_new(o,
+                                                               cmd_str,
+                                                               "+XDRV:",
+                                                               TCORE_AT_SINGLELINE,
+                                                               _on_response_modem_send_nvm_update_ack,
+                                                               NULL);
+       if (pending == NULL) {
+               err("Failed to form pending request");
+       }
+       else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
+                                                                               != TCORE_RETURN_SUCCESS) {
+               err("IUFP_UPDATE_ACK - Unable to send AT-Command");
+       }
+       else {
+               dbg("IUFP_UPDATE_ACK - Successfully sent AT-Command");
+       }
+
+       g_free(cmd_str);
+}
+
+static void modem_send_nvm_update_request_ack(CoreObject *o)
+{
+       TcorePending *pending = NULL;
+       char *cmd_str;
+       dbg("Entered");
+
+       /* Prepare AT-Command */
+       cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_REQ_ACK_STR);
+
+       /* Prepare pending request */
+       pending = tcore_at_pending_new(o,
+                                                               cmd_str,
+                                                               "+XDRV:",
+                                                               TCORE_AT_SINGLELINE,
+                                                               _on_response_modem_send_nvm_update_request_ack,
+                                                               NULL);
+
+
+       if (pending == NULL) {
+               err("Failed to form pending request");
+       }
+       else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
+                                                                       != TCORE_RETURN_SUCCESS) {
+               err("IUFP_UPDATE_REQ_ACK - Unable to send AT-Ccommand");
+       }
+       else {
+               dbg("IUFP_UPDATE_REQ_ACK - Successfully sent AT-Command");
+       }
+
+       g_free(cmd_str);
+}
+
+static void modem_send_flush_nvm_update(CoreObject *o)
+{
+       TcorePending *pending = NULL;
+       char *cmd_str;
+       dbg("Entered");
+
+       /* Prepare AT-Command */
+       cmd_str = g_strdup_printf("AT+XDRV=%d, %d, %d", IUFP_GROUP_ID, IUFP_FLUSH, 0);
+
+       /* Prepare pending request */
+       pending = tcore_at_pending_new(o,
+                                                               cmd_str,
+                                                               "+XDRV:",
+                                                               TCORE_AT_SINGLELINE,
+                                                               _on_response_modem_send_flush_nvm_update,
+                                                               NULL);
+       if (pending == NULL) {
+               err("Failed to form pending request");
+       }
+       else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
+                                                                       != TCORE_RETURN_SUCCESS) {
+               err("IUFP_FLUSH - Unable to send AT-Command");
+       }
+       else {
+               dbg("IUFP_FLUSH - Successfully sent AT-Command");
+       }
+
+       g_free(cmd_str);
+}
+
+void modem_register_nvm(CoreObject *co_modem)
+{
+       TcorePending *pending = NULL;
+       char *cmd_str;
+       dbg("Entered");
+
+       /* Prepare AT-Command */
+       cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s",
+                                       IUFP_GROUP, IUFP_REGISTER_STR, XDRV_ENABLE);
+
+       /* Prepare pending request */
+       pending = tcore_at_pending_new(co_modem,
+                                                               cmd_str,
+                                                               "+XDRV:",
+                                                               TCORE_AT_SINGLELINE,
+                                                               _on_response_modem_register_nvm,
+                                                               NULL);
+       if (pending == NULL) {
+               err("Failed to form pending request");
+       }
+       else if (tcore_hal_send_request(tcore_object_get_hal(co_modem), pending)
+                                                                       != TCORE_RETURN_SUCCESS) {
+               err("IUFP_REGISTER (Enable) -Unable to send AT-Command");
+       }
+       else {
+               dbg("IUFP_REGISTER (Enable) -Successfully sent AT-Command");
+
+               /* Add RFS hook */
+               tcore_at_add_hook(tcore_object_get_hal(co_modem), modem_rfs_hook);
+       }
+
+       g_free(cmd_str);
+}
+
+void modem_deregister_nvm(CoreObject *co_modem)
+{
+       TcorePending *pending = NULL;
+       char *cmd_str;
+       dbg("Entered");
+
+       /* Prepare AT-Command */
+       cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s",
+                               IUFP_GROUP, IUFP_REGISTER_STR, XDRV_DISABLE);
+
+       /* Prepare pending request */
+       pending = tcore_at_pending_new(co_modem,
+                                                               cmd_str,
+                                                               "+XDRV:",
+                                                               TCORE_AT_SINGLELINE,
+                                                               _on_response_modem_deregister_nvm,
+                                                               NULL);
+       if (pending == NULL) {
+               err("Failed to form pending request");
+       }
+       else if (tcore_hal_send_request(tcore_object_get_hal(co_modem), pending)
+                                                                               != TCORE_RETURN_SUCCESS) {
+               err("IUFP_REGISTER (Disable) -Unable to send AT-Command");
+       }
+       else {
+               dbg("IUFP_REGISTER (Disable) -Successfully sent AT-Command");
+       }
+
+       g_free(cmd_str);
+}