Merge commit '2268d748b893f82330f1be50b09d699cb8e7f9d3' into HEAD

Change-Id: I00331c122f55594e36d3766504a2da5ca4aa4fed
diff --git a/qcwcn/wifi_hal/gscan.cpp b/qcwcn/wifi_hal/gscan.cpp
index e6d71a0..b55e629 100644
--- a/qcwcn/wifi_hal/gscan.cpp
+++ b/qcwcn/wifi_hal/gscan.cpp
@@ -461,6 +461,7 @@
             __FUNCTION__);
         return WIFI_ERROR_NOT_SUPPORTED;
     }
+    return (wifi_error)ret;
 
     /* Route GSCAN request through LOWI if supported */
     lowiWifiHalApi = getLowiCallbackTable(GSCAN_SUPPORTED);
diff --git a/qcwcn/wifi_hal/tdlsCommand.h b/qcwcn/wifi_hal/tdlsCommand.h
old mode 100755
new mode 100644
diff --git a/qcwcn/wifi_hal/wifihal_internal.h b/qcwcn/wifi_hal/wifihal_internal.h
old mode 100755
new mode 100644
diff --git a/qcwcn/wpa_supplicant_8_lib/Android.mk b/qcwcn/wpa_supplicant_8_lib/Android.mk
index a573141..9c98321 100644
--- a/qcwcn/wpa_supplicant_8_lib/Android.mk
+++ b/qcwcn/wpa_supplicant_8_lib/Android.mk
@@ -36,7 +36,8 @@
 
 ifdef CONFIG_DRIVER_NL80211
 WPA_SUPPL_DIR_INCLUDE += external/libnl/include
-WPA_SRC_FILE += driver_cmd_nl80211.c
+WPA_SRC_FILE += driver_cmd_nl80211_extn.c \
+		driver_cmd_nl80211.c
 endif
 
 ifeq ($(TARGET_ARCH),arm)
diff --git a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
index c5d1c93..cfc56f3 100644
--- a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
+++ b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
@@ -23,6 +23,7 @@
 #ifdef ANDROID
 #include "android_drv.h"
 #endif
+#include "driver_cmd_nl80211_extn.h"
 
 #define WPA_PS_ENABLED		0
 #define WPA_PS_DISABLED		1
@@ -109,7 +110,8 @@
 			ret = 0;
 			if ((os_strcasecmp(cmd, "LINKSPEED") == 0) ||
 			    (os_strcasecmp(cmd, "RSSI") == 0) ||
-			    (os_strcasecmp(cmd, "GETBAND") == 0) )
+			    (os_strcasecmp(cmd, "GETBAND") == 0) ||
+			    (os_strcasecmp(cmd, "GETANTENNAMODE") == 0))
 				ret = strlen(buf);
 			else if (os_strcasecmp(cmd, "P2P_DEV_ADDR") == 0)
 				wpa_printf(MSG_DEBUG, "%s: P2P: Device address ("MACSTR")",
diff --git a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_extn.c b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_extn.c
new file mode 100644
index 0000000..b6136ce
--- /dev/null
+++ b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_extn.c
@@ -0,0 +1,76 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <netlink/object-api.h>
+#include <linux/pkt_sched.h>
+#include <dlfcn.h>
+#include "driver_cmd_nl80211_extn.h"
+#include "common.h"
+
+
+int wpa_driver_oem_initialize(wpa_driver_oem_cb_table_t *oem_cb_table)
+{
+	wpa_driver_oem_get_cb_table_t *get_oem_table;
+	wpa_driver_oem_cb_table_t *oem_cb_table_local = NULL;
+
+	/* Return the callback table if it is already initialized*/
+	if (oem_cb_table->wpa_driver_driver_cmd_oem_cb)
+		return WPA_DRIVER_OEM_STATUS_SUCCESS;
+
+#if __WORDSIZE == 64
+	void* oem_handle = dlopen("/vendor/lib64/libwpa_drv_oem.so", RTLD_NOW);
+#else
+	void* oem_handle = dlopen("/vendor/lib/libwpa_drv_oem.so", RTLD_NOW);
+#endif
+	if (!oem_handle) {
+		return WPA_DRIVER_OEM_STATUS_FAILURE;
+	}
+
+	get_oem_table = (wpa_driver_oem_get_cb_table_t *)dlsym(oem_handle,
+						 "oem_generic_cb_table");
+	if (!get_oem_table) {
+		wpa_printf(MSG_ERROR, "%s: NULL oem callback table",
+			   __FUNCTION__);
+		return WPA_DRIVER_OEM_STATUS_FAILURE;
+	}
+
+	oem_cb_table_local = get_oem_table();
+
+	if (!oem_cb_table_local ||
+		!oem_cb_table_local->wpa_driver_driver_cmd_oem_cb) {
+		wpa_printf(MSG_ERROR, "%s: oem module returned NULL table",
+			   __FUNCTION__);
+		return WPA_DRIVER_OEM_STATUS_FAILURE;
+	}
+	oem_cb_table->wpa_driver_driver_cmd_oem_cb =
+                            oem_cb_table_local->wpa_driver_driver_cmd_oem_cb;
+	wpa_printf(MSG_INFO, "%s: OEM lib initialized\n", __func__);
+
+	return WPA_DRIVER_OEM_STATUS_SUCCESS;
+}
diff --git a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_extn.h b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_extn.h
new file mode 100644
index 0000000..dd2f7c1
--- /dev/null
+++ b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_extn.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef __DRIVER_CMD_NL80211_EXTN__
+#define __DRIVER_CMD_NL80211_EXTN__
+
+#include "qca-vendor.h"
+
+#define IFNAMSIZ 16
+#define WPA_DRIVER_OEM_STATUS_SUCCESS 0
+#define WPA_DRIVER_OEM_STATUS_FAILURE 255
+
+/*
+ * This structure is a table of function pointers to the functions
+ * used by the wpa_supplicant_lib to interface with oem specific APIs
+ */
+typedef struct
+{
+    int (*wpa_driver_driver_cmd_oem_cb)(void *priv,
+			char *cmd, char *buf, size_t buf_len, int *status);
+} wpa_driver_oem_cb_table_t;
+
+typedef wpa_driver_oem_cb_table_t* (wpa_driver_oem_get_cb_table_t)();
+
+int wpa_driver_oem_initialize(wpa_driver_oem_cb_table_t *oem_lib_params);
+#endif
diff --git a/wcnss-service/Android.mk b/wcnss-service/Android.mk
new file mode 100644
index 0000000..16cc10e
--- /dev/null
+++ b/wcnss-service/Android.mk
@@ -0,0 +1,25 @@
+ifneq (,$(filter arm aarch64 arm64, $(TARGET_ARCH)))
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := wcnss_service
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/common/inc/
+LOCAL_SRC_FILES := wcnss_service.c
+ifeq ($(strip $(TARGET_USES_QCOM_WCNSS_QMI)),true)
+LOCAL_CFLAGS += -DWCNSS_QMI
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qmi/inc
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qmi/services
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qmi/platform
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qmi/src
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qmi/core/lib/inc
+LOCAL_SRC_FILES += wcnss_qmi_client.c
+endif #TARGET_USES_QCOM_WCNSS_QMI
+LOCAL_SHARED_LIBRARIES := libc libcutils libutils liblog
+ifeq ($(strip $(TARGET_USES_QCOM_WCNSS_QMI)),true)
+LOCAL_SHARED_LIBRARIES += libqmiservices libqmi libqcci_legacy libqmi_client_qmux
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/libmdmdetect/inc
+LOCAL_SHARED_LIBRARIES += libmdmdetect
+endif #TARGET_USES_QCOM_WCNSS_QMI
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS += -Wall -Werror
+include $(BUILD_EXECUTABLE)
+endif
diff --git a/wcnss-service/wcnss_qmi_client.c b/wcnss-service/wcnss_qmi_client.c
new file mode 100644
index 0000000..b9f94f7
--- /dev/null
+++ b/wcnss-service/wcnss_qmi_client.c
@@ -0,0 +1,246 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of The Linux Foundation nor
+      the names of its contributors may be used to endorse or promote
+      products derived from this software without specific prior written
+      permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+
+#ifdef WCNSS_QMI
+#define LOG_TAG "wcnss_qmi"
+#include <cutils/log.h>
+#include "wcnss_qmi_client.h"
+#include "qmi.h"
+#include "qmi_client.h"
+#include "device_management_service_v01.h"
+#include <cutils/properties.h>
+#include <string.h>
+
+#define SUCCESS 0
+#define FAILED -1
+
+#define WLAN_ADDR_SIZE   6
+#define DMS_QMI_TIMEOUT (2000)
+
+static qmi_client_type dms_qmi_client;
+static int qmi_handle;
+static int dms_init_done = FAILED;
+
+/* Android system property for fetching the modem type */
+#define QMI_UIM_PROPERTY_BASEBAND               "ro.baseband"
+
+/* Android system property values for various modem types */
+#define QMI_UIM_PROP_BASEBAND_VALUE_SVLTE_1     "svlte1"
+#define QMI_UIM_PROP_BASEBAND_VALUE_SVLTE_2A    "svlte2a"
+#define QMI_UIM_PROP_BASEBAND_VALUE_CSFB        "csfb"
+#define QMI_UIM_PROP_BASEBAND_VALUE_SGLTE       "sglte"
+#define QMI_UIM_PROP_BASEBAND_VALUE_SGLTE2      "sglte2"
+#define QMI_UIM_PROP_BASEBAND_VALUE_MSM         "msm"
+#define QMI_UIM_PROP_BASEBAND_VALUE_APQ         "apq"
+#define QMI_UIM_PROP_BASEBAND_VALUE_MDMUSB      "mdm"
+#define QMI_UIM_PROP_BASEBAND_VALUE_DSDA        "dsda"
+#define QMI_UIM_PROP_BASEBAND_VALUE_DSDA_2      "dsda2"
+
+static char *dms_find_modem_port( char *prop_value_ptr)
+{
+	char *qmi_modem_port_ptr = QMI_PORT_RMNET_0;
+
+	/* Sanity check */
+	if (prop_value_ptr == NULL) {
+		ALOGE("%s: NULL prop_value_ptr, using default port", __func__);
+		return qmi_modem_port_ptr;
+	}
+
+	ALOGE("%s: Baseband property value read: %s", __func__,
+			prop_value_ptr);
+
+	/* Map the port based on the read property */
+	if ((strcmp(prop_value_ptr,
+		QMI_UIM_PROP_BASEBAND_VALUE_SVLTE_1)  == 0) ||
+		(strcmp(prop_value_ptr,
+		QMI_UIM_PROP_BASEBAND_VALUE_SVLTE_2A) == 0) ||
+		(strcmp(prop_value_ptr,
+		QMI_UIM_PROP_BASEBAND_VALUE_CSFB) == 0)) {
+		qmi_modem_port_ptr = QMI_PORT_RMNET_SDIO_0;
+	} else if ((strcmp(prop_value_ptr,
+		QMI_UIM_PROP_BASEBAND_VALUE_MDMUSB) == 0) ||
+		(strcmp(prop_value_ptr,
+		QMI_UIM_PROP_BASEBAND_VALUE_SGLTE2) == 0)) {
+		qmi_modem_port_ptr = QMI_PORT_RMNET_USB_0;
+	} else if ((strcmp(prop_value_ptr,
+		QMI_UIM_PROP_BASEBAND_VALUE_MSM) == 0) ||
+		(strcmp(prop_value_ptr,
+		QMI_UIM_PROP_BASEBAND_VALUE_APQ) == 0) ||
+		(strcmp(prop_value_ptr,
+		QMI_UIM_PROP_BASEBAND_VALUE_SGLTE) == 0)) {
+		qmi_modem_port_ptr = QMI_PORT_RMNET_0;
+	} else if (strcmp(prop_value_ptr,
+		QMI_UIM_PROP_BASEBAND_VALUE_DSDA) == 0) {
+		/* If it is a DSDA configuration, use the existing API */
+		qmi_modem_port_ptr = (char *)QMI_PLATFORM_INTERNAL_USE_PORT_ID;
+	} else if (strcmp(prop_value_ptr,
+		QMI_UIM_PROP_BASEBAND_VALUE_DSDA_2) == 0) {
+		/* If it is a DSDA2 configuration, use the existing API */
+		qmi_modem_port_ptr = (char *)QMI_PLATFORM_INTERNAL_USE_PORT_ID;
+	} else {
+		ALOGE("%s: Property value does not match,using default port:%s",
+			__func__, qmi_modem_port_ptr);
+	}
+
+	ALOGE("%s: QMI port found for modem: %s", __func__, qmi_modem_port_ptr);
+
+	return qmi_modem_port_ptr;
+}
+
+int wcnss_init_qmi()
+{
+	qmi_client_error_type qmi_client_err;
+	qmi_idl_service_object_type dms_service;
+	char prop_value[PROPERTY_VALUE_MAX];
+	char *qmi_modem_port = NULL;
+
+	ALOGE("%s: Initialize wcnss QMI Interface", __func__);
+
+	qmi_handle = qmi_init(NULL, NULL);
+	if (qmi_handle < 0) {
+		ALOGE("%s: Error while initializing qmi", __func__);
+		return FAILED;
+	}
+
+	dms_service = dms_get_service_object_v01();
+	if (dms_service == NULL) {
+		ALOGE("%s: Not able to get the service handle", __func__);
+		goto exit;
+	}
+
+	/* Find out the modem type */
+	memset(prop_value, 0x00, sizeof(prop_value));
+	property_get(QMI_UIM_PROPERTY_BASEBAND, prop_value, "");
+
+	/* Map to a respective QMI port */
+	qmi_modem_port = dms_find_modem_port(prop_value);
+	if (qmi_modem_port == NULL) {
+		ALOGE("%s: qmi_modem_port is NULL", __func__);
+		goto exit;
+	}
+
+	qmi_client_err = qmi_client_init((const char *)qmi_modem_port,
+			dms_service, NULL, dms_service, &dms_qmi_client);
+
+	if ((qmi_client_err == QMI_PORT_NOT_OPEN_ERR) &&
+			(strcmp(qmi_modem_port, QMI_PORT_RMNET_0) == 0)){
+		ALOGE("%s: Retrying with port RMNET_1: %d",
+				__func__, qmi_client_err);
+		qmi_modem_port = QMI_PORT_RMNET_1;
+		qmi_client_err = qmi_client_init((const char *)qmi_modem_port,
+			       dms_service, NULL, dms_service, &dms_qmi_client);
+	}
+
+	if (qmi_client_err != QMI_NO_ERR){
+		ALOGE("%s: Error while Initializing QMI Client: %d",
+			__func__, qmi_client_err);
+		goto exit;
+	}
+
+	dms_init_done = SUCCESS;
+	return SUCCESS;
+
+exit:
+	qmi_handle = qmi_release(qmi_handle);
+	if ( qmi_handle < 0 )    {
+		ALOGE("%s: Error while releasing qmi %d",
+			 __func__, qmi_handle);
+	}
+	return FAILED;
+}
+
+int wcnss_qmi_get_wlan_address(unsigned char *pBdAddr)
+{
+	qmi_client_error_type qmi_client_err;
+	dms_get_mac_address_req_msg_v01 addr_req;
+	dms_get_mac_address_resp_msg_v01 addr_resp;
+
+	if ((dms_init_done == FAILED) || (pBdAddr == NULL)) {
+		ALOGE("%s: DMS init fail or pBdAddr is NULL", __func__);
+		return FAILED;
+	}
+
+	/* clear the request content */
+	memset(&addr_req, 0, sizeof(addr_req));
+
+	/*Request to get the WLAN MAC address */
+	addr_req.device = DMS_DEVICE_MAC_WLAN_V01;
+
+	qmi_client_err = qmi_client_send_msg_sync(dms_qmi_client,
+		QMI_DMS_GET_MAC_ADDRESS_REQ_V01, &addr_req, sizeof(addr_req),
+		&addr_resp, sizeof(addr_resp), DMS_QMI_TIMEOUT);
+
+	if (qmi_client_err != QMI_NO_ERR){
+		ALOGE("%s: Failed to get Rsp from Modem Error:%d",
+				__func__, qmi_client_err);
+		return FAILED;
+	}
+
+	ALOGE("%s: Mac Address_valid: %d Mac Address Len: %d",
+				__func__, addr_resp.mac_address_valid,
+				addr_resp.mac_address_len);
+
+	if (addr_resp.mac_address_valid &&
+		(addr_resp.mac_address_len == WLAN_ADDR_SIZE)) {
+		memcpy(pBdAddr, addr_resp.mac_address,
+			addr_resp.mac_address_len);
+		ALOGE("%s: Succesfully Read WLAN MAC Address", __func__);
+		return SUCCESS;
+	} else {
+		ALOGE("%s: Failed to Read WLAN MAC Address", __func__);
+		return FAILED;
+	}
+}
+
+void wcnss_qmi_deinit()
+{
+	qmi_client_error_type qmi_client_err;
+
+	ALOGE("%s: Deinitialize wcnss QMI Interface", __func__);
+
+	if (dms_init_done == FAILED) {
+		ALOGE("%s: DMS Service was not Initialized", __func__);
+		return;
+	}
+
+	qmi_client_err = qmi_client_release(dms_qmi_client);
+
+	if (qmi_client_err != QMI_NO_ERR){
+		ALOGE("%s: Error while releasing qmi_client: %d",
+			__func__, qmi_client_err);
+	}
+
+	qmi_handle = qmi_release(qmi_handle);
+	if (qmi_handle < 0)    {
+		ALOGE("%s: Error while releasing qmi %d",
+			__func__, qmi_handle);
+	}
+
+	dms_init_done = FAILED;
+}
+#endif
diff --git a/wcnss-service/wcnss_qmi_client.h b/wcnss-service/wcnss_qmi_client.h
new file mode 100644
index 0000000..51fefac
--- /dev/null
+++ b/wcnss-service/wcnss_qmi_client.h
@@ -0,0 +1,49 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of The Linux Foundation nor
+      the names of its contributors may be used to endorse or promote
+      products derived from this software without specific prior written
+      permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#if defined(__BIONIC_FORTIFY)
+#include <sys/system_properties.h>
+#endif
+
+#define MODEM_BASEBAND_PROPERTY   "ro.baseband"
+#if defined(__BIONIC_FORTIFY)
+#define MODEM_BASEBAND_PROPERTY_SIZE  PROP_VALUE_MAX
+#else
+#define MODEM_BASEBAND_PROPERTY_SIZE  10
+#endif
+#define MODEM_BASEBAND_VALUE_APQ  "apq"
+
+#ifdef WCNSS_QMI
+#ifndef WCNSS_QMI_CLIENT_H
+#define WCNSS_QMI_CLIENT_H
+
+int wcnss_init_qmi(void);
+int wcnss_qmi_get_wlan_address(unsigned char *pBdAddr);
+void wcnss_qmi_deinit(void);
+
+#endif
+#endif
diff --git a/wcnss-service/wcnss_service.c b/wcnss-service/wcnss_service.c
new file mode 100644
index 0000000..94c474d
--- /dev/null
+++ b/wcnss-service/wcnss_service.c
@@ -0,0 +1,815 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of The Linux Foundation nor
+      the names of its contributors may be used to endorse or promote
+      products derived from this software without specific prior written
+      permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <grp.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/sendfile.h>
+#define LOG_TAG "wcnss_service"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#ifdef WCNSS_QMI
+#include "wcnss_qmi_client.h"
+#include "mdm_detect.h"
+#endif
+
+#define SUCCESS 0
+#define FAILED -1
+#define BYTE_0  0
+#define BYTE_1  8
+#define BYTE_2  16
+#define BYTE_3  24
+#define UNUSED(x)	(void)(x)
+
+#define MAX_FILE_LENGTH    (1024)
+#define WCNSS_MAX_CMD_LEN  (128)
+
+/* control messages to wcnss driver */
+#define WCNSS_USR_CTRL_MSG_START    0x00000000
+#define WCNSS_USR_SERIAL_NUM        (WCNSS_USR_CTRL_MSG_START + 1)
+#define WCNSS_USR_HAS_CAL_DATA      (WCNSS_USR_CTRL_MSG_START + 2)
+#define WCNSS_USR_WLAN_MAC_ADDR     (WCNSS_USR_CTRL_MSG_START + 3)
+
+
+#define WCNSS_CAL_CHUNK (3*1024)
+#define WCNSS_CAL_FILE  "/data/misc/wifi/WCNSS_qcom_wlan_cal.bin"
+#define WCNSS_FACT_FILE "/data/misc/wifi/WCN_FACTORY"
+#define WCNSS_DEVICE    "/dev/wcnss_wlan"
+#define WCNSS_CTRL      "/dev/wcnss_ctrl"
+#define WLAN_INI_FILE_DEST   "/data/misc/wifi/WCNSS_qcom_cfg.ini"
+#define WLAN_INI_FILE_SOURCE "/system/etc/wifi/WCNSS_qcom_cfg.ini"
+#define WCNSS_HAS_CAL_DATA\
+		"/sys/module/wcnsscore/parameters/has_calibrated_data"
+#define WLAN_DRIVER_ATH_DEFAULT_VAL "0"
+
+#define ASCII_A		65
+#define ASCII_a		97
+#define ASCII_0		48
+#define HEXA_A		10
+#define HEX_BASE		16
+
+#ifdef WCNSS_QMI
+#define WLAN_ADDR_SIZE   6
+unsigned char wlan_nv_mac_addr[WLAN_ADDR_SIZE];
+#define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+/* As we Want to write in 00:0a:f5:11:22:33 format in sysfs file
+   so taking mac length as 12 char + 5 for ":" + NULL
+ */
+#define WLAN_MAC_ADDR_STRING 18
+#endif
+
+#define MAX_SOC_INFO_NAME_LEN (15)
+#define MAX_DATA_NVBIN_PATH_LEN (64)
+#define QRD_DYNAMIC_NV_PROP  "persist.sys.dynamic.nv"
+#define QRD_HW_PLATFORM  "QRD"
+#define QRD_PLATFORM_SUBTYPE_ID  0
+#define PERSIST_NVFILE    "/persist/WCNSS_qcom_wlan_nv.bin"
+#define DATA_NVFILE_DIR   "/data/misc/wifi/nvbin/"
+#define SYSFS_SOCID_PATH1   "/sys/devices/soc0/soc_id"
+#define SYSFS_SOCID_PATH2   "/sys/devices/system/soc/soc0/id"
+#define SYSFS_HW_PLATFORM_PATH1  "/sys/devices/soc0/hw_platform"
+#define SYSFS_HW_PLATFORM_PATH2   "/sys/devices/system/soc/soc0/hw_platform"
+#define SYSFS_PLATFORM_SUBTYPE_PATH1   "/sys/devices/soc0/platform_subtype_id"
+#define SYSFS_PLATFORM_SUBTYPE_PATH2    "/sys/devices/system/soc/soc0/platform_subtype_id"
+#define SYSFS_PLATFORM_VERSION_PATH1  "/sys/devices/soc0/platform_version"
+#define SYSFS_PLATFORM_VERSION_PATH2   "/sys/devices/system/soc/soc0/platform_version"
+#define SOCINFO_HWVER_MAJOR(ver) (((ver) & 0x00ff0000) >> 16)
+#define SOCINFO_HWVER_MINOR(ver) ((ver) & 0x000000ff)
+#define GET_SOC_INFO(buf, soc_node_path1, soc_node_path2, info_got) \
+		{  if (get_soc_info(buf, soc_node_path1, soc_node_path2) < 0) \
+		    { \
+		        ALOGE("get_soc_info failed!\n"); \
+		        return FAILED; \
+		    } \
+		    info_got = atoi(buf); \
+		}
+
+int wcnss_write_cal_data(int fd_dev)
+{
+	int rcount = 0;
+	int size = 0;
+	int rc = 0;
+	int wcount = 0;
+	int fd_file;
+	struct stat st;
+
+	char buf[WCNSS_CAL_CHUNK];
+
+	ALOGI("wcnss_write_cal_data trying to write cal");
+
+	rc = stat(WCNSS_CAL_FILE, &st);
+	if (rc < 0) {
+		ALOGE("Failed to stat cal file : %s",
+				strerror(errno));
+		goto exit;
+	}
+
+	size = st.st_size;
+
+	fd_file = open(WCNSS_CAL_FILE, O_RDONLY);
+	if (fd_file < 0) {
+		ALOGE("cal file doesn't exist: %s",
+				strerror(errno));
+		rc = fd_file;
+		goto exit;
+	}
+
+	/* write the file size first, so that platform driver knows
+	 * when it recieves the full data */
+	wcount = write(fd_dev, (void *)&size, 4);
+	if (wcount != 4) {
+		ALOGE("Failed to write to wcnss device : %s",
+				strerror(errno));
+		rc = wcount;
+		goto exit_close;
+	}
+
+	do {
+		rcount = read(fd_file, (void *)buf, sizeof(buf));
+		if (rcount < 0) {
+			ALOGE("Failed to read from cal file ; %s",
+					strerror(errno));
+			rc = rcount;
+			goto exit_remove;
+		}
+
+		if (!rcount)
+			break;
+
+		wcount = write(fd_dev, buf, rcount);
+		if (wcount < 0) {
+			ALOGE("Failed to write to wcnss device : %s",
+				strerror(errno));
+			rc = wcount;
+			goto exit_close;
+		}
+
+	} while (rcount);
+	close(fd_file);
+
+	return SUCCESS;
+
+exit_remove:
+	close(fd_file);
+	remove("WCNSS_CAL_FILE");
+	return rc;
+
+exit_close:
+	close(fd_file);
+
+exit:
+	return rc;
+}
+
+
+int wcnss_read_and_store_cal_data(int fd_dev)
+{
+	int rcount = 0;
+	int wcount = 0;
+	int fd_file = -1;
+	int rc = 0;
+
+	char buf[WCNSS_CAL_CHUNK];
+
+	ALOGI("wcnss_read_and_store_cal_data trying to read cal");
+
+	do {
+		/* wait on this read until data comes from fw */
+		rcount = read(fd_dev, (void *)buf, sizeof(buf));
+		if (rcount < 0) {
+			ALOGE("Failed to read from wcnss device : %s",
+					strerror(errno));
+			rc = rcount;
+			goto exit;
+		}
+
+		/* truncate the file only if there is fw data, this read
+		 * may never return if the fw decides that no more cal is
+		 * required; and the data we have now is good enough.
+		 */
+		if (fd_file < 0) {
+			fd_file = open(WCNSS_CAL_FILE, O_WRONLY
+					| O_CREAT | O_TRUNC, 0664);
+			if (fd_file < 0) {
+				ALOGE("Failed to open cal file : %s",
+						strerror(errno));
+				rc = fd_file;
+				goto exit;
+			}
+		}
+
+		if (!rcount)
+			break;
+
+		wcount = write(fd_file, buf, rcount);
+		if (wcount < 0) {
+			ALOGE("Failed to write to cal file : %s",
+				strerror(errno));
+			rc = wcount;
+			goto exit_remove;
+		}
+
+	} while (rcount);
+
+	close(fd_file);
+
+	return SUCCESS;
+
+exit_remove:
+	close(fd_file);
+	remove(WCNSS_CAL_FILE);
+
+exit:
+	return rc;
+}
+
+
+void find_full_path(char *cur_dir, char *file_to_find, char *full_path)
+{
+	DIR *dir;
+	struct stat st;
+	struct dirent *dr;
+	char cwd[1024];
+	int rc;
+
+	chdir(cur_dir);
+
+	dir = opendir(".");
+
+	if (dir != NULL) {
+		while ((dr = readdir(dir))) {
+
+			rc = lstat(dr->d_name, &st);
+			if (rc < 0) {
+				ALOGE("lstat failed %s", strerror(errno));
+				return;
+			}
+			if (S_ISDIR(st.st_mode)) {
+				if ((strcmp(dr->d_name, ".")) &&
+					(strcmp(dr->d_name, ".."))) {
+				find_full_path(dr->d_name,
+						file_to_find, full_path);
+				}
+			} else if (!strcmp(file_to_find, dr->d_name)) {
+				getcwd(cwd, sizeof(cwd));
+				snprintf(full_path, MAX_FILE_LENGTH, "%s/%s",
+					cwd, file_to_find);
+			}
+		}
+		closedir(dir);
+	}
+
+	chdir("..");
+}
+
+void setup_wlan_config_file()
+{
+	int rfd;
+	int wfd;
+	struct stat st_dest, st_src;
+	int rc_dest;
+	int rc;
+	struct group *grp;
+	struct utimbuf new_time;
+
+	rc = stat(WLAN_INI_FILE_SOURCE, &st_src);
+	if (rc != 0) {
+		ALOGE("source file do not exist %s", WLAN_INI_FILE_SOURCE);
+		return;
+	}
+
+	rc_dest = stat(WLAN_INI_FILE_DEST, &st_dest);
+	if (rc_dest == 0 && st_dest.st_size &&
+			(st_dest.st_mtime > st_src.st_mtime)) {
+		ALOGE("wlan ini file exists %s and is newer than %s",
+				WLAN_INI_FILE_DEST, WLAN_INI_FILE_SOURCE);
+		goto out_nocopy;
+	}
+
+	rfd = open(WLAN_INI_FILE_SOURCE, O_RDONLY);
+	if (rfd < 0) {
+		ALOGE("Failed to open ini source file: %s", strerror(errno));
+		return;
+	}
+
+	wfd = open(WLAN_INI_FILE_DEST, O_WRONLY | O_CREAT | O_TRUNC, 0660);
+	if (wfd < 0) {
+		ALOGE("Failed to open ini dest file: %s", strerror(errno));
+		close(rfd);
+		return;
+	}
+
+	rc = sendfile(wfd, rfd, 0, st_src.st_size);
+	if (rc != st_src.st_size) {
+		ALOGE("Failed to copy ini file: %s", strerror(errno));
+		goto out;
+	}
+
+	new_time.actime = st_src.st_atime;
+	new_time.modtime = st_src.st_mtime;
+
+	rc = utime(WLAN_INI_FILE_DEST, &new_time);
+	if (rc != 0)
+		ALOGE("could not preserve the timestamp %s", strerror(errno));
+
+	grp = getgrnam("wifi");
+	if (grp != NULL) {
+		rc = chown(WLAN_INI_FILE_DEST, -1, grp->gr_gid);
+		if (rc != 0)
+			ALOGE("Failed change group of ini file %s", strerror(errno));
+	} else {
+			ALOGE("Failed to get group wifi %s", strerror(errno));
+	}
+
+	property_set("wlan.driver.config", WLAN_INI_FILE_DEST);
+
+out:
+	close(rfd);
+	close(wfd);
+	return;
+
+out_nocopy:
+	property_set("wlan.driver.config", WLAN_INI_FILE_DEST);
+	return;
+}
+unsigned int convert_string_to_hex(char* string)
+{
+	int idx;
+	unsigned long int hex_num = 0;
+	for(idx = 0; string[idx] != '\0'; idx++){
+		if(isalpha(string[idx])) {
+			if(string[idx] >='a' && string[idx] <='f') {
+				hex_num = hex_num * HEX_BASE + ((int)string[idx]
+					       - ASCII_a + HEXA_A);
+			} else if ( string[idx] >='A' && string[idx] <='F') {
+				hex_num = hex_num * HEX_BASE + ((int)string[idx]
+						- ASCII_A + HEXA_A);
+			} else
+				hex_num = hex_num * HEX_BASE + (int)string[idx];
+		} else {
+			hex_num = hex_num * HEX_BASE + (string[idx]- ASCII_0);
+		}
+	}
+	hex_num = hex_num & 0xFFFFFFFF;
+	return hex_num;
+}
+
+
+#ifdef WCNSS_QMI
+void setup_wcnss_parameters(int *cal, int nv_mac_addr)
+#else
+void setup_wcnss_parameters(int *cal)
+#endif
+{
+	char msg[WCNSS_MAX_CMD_LEN];
+	char serial[PROPERTY_VALUE_MAX];
+	int fd, rc, pos = 0;
+	struct stat st;
+	unsigned int serial_num = 0;
+
+	fd = open(WCNSS_CTRL, O_WRONLY);
+	if (fd < 0) {
+		ALOGE("Failed to open %s : %s", WCNSS_CTRL, strerror(errno));
+		return;
+	}
+
+	rc = property_get("ro.serialno", serial, "");
+	if (rc) {
+		serial_num = convert_string_to_hex(serial);
+		ALOGE("Serial Number is  %x", serial_num);
+
+		msg[pos++] = WCNSS_USR_SERIAL_NUM >> BYTE_1;
+		msg[pos++] = WCNSS_USR_SERIAL_NUM >> BYTE_0;
+		msg[pos++] = serial_num >> BYTE_3;
+		msg[pos++] = serial_num >> BYTE_2;
+		msg[pos++] = serial_num >> BYTE_1;
+		msg[pos++] = serial_num >> BYTE_0;
+
+		if (write(fd, msg, pos) < 0) {
+			ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
+					strerror(errno));
+			goto fail;
+		}
+	}
+
+#ifdef WCNSS_QMI
+	if (SUCCESS == nv_mac_addr)
+	{
+		pos = 0;
+		msg[pos++] = WCNSS_USR_WLAN_MAC_ADDR >> BYTE_1;
+		msg[pos++] = WCNSS_USR_WLAN_MAC_ADDR >> BYTE_0;
+		msg[pos++] = wlan_nv_mac_addr[0];
+		msg[pos++] = wlan_nv_mac_addr[1];
+		msg[pos++] = wlan_nv_mac_addr[2];
+		msg[pos++] = wlan_nv_mac_addr[3];
+		msg[pos++] = wlan_nv_mac_addr[4];
+		msg[pos++] = wlan_nv_mac_addr[5];
+
+		ALOGI("WLAN MAC Addr:" MAC_ADDRESS_STR,
+			MAC_ADDR_ARRAY(wlan_nv_mac_addr));
+
+		if (write(fd, msg, pos) < 0) {
+			ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
+						strerror(errno));
+			goto fail;
+		}
+	}
+#endif
+
+	pos = 0;
+	msg[pos++] = WCNSS_USR_HAS_CAL_DATA >> BYTE_1;
+	msg[pos++] = WCNSS_USR_HAS_CAL_DATA >> BYTE_0;
+
+	rc = stat(WCNSS_FACT_FILE, &st);
+	if (rc == 0) {
+		ALOGE("Factory file found, deleting cal file");
+		unlink(WCNSS_CAL_FILE);
+		goto fail_resp;
+	}
+
+	rc = stat(WCNSS_CAL_FILE, &st);
+	if (rc != 0) {
+		ALOGE("CAL file not found");
+		goto fail_resp;
+	}
+
+	/* has cal data */
+	msg[pos++] = 1;
+
+	if (write(fd, msg, pos) < 0) {
+		ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
+				strerror(errno));
+		goto fail;
+	}
+
+	ALOGI("Correctly triggered cal file");
+	*cal = SUCCESS;
+	close(fd);
+	return;
+
+fail_resp:
+	msg[pos++] = 0;
+	if (write(fd, msg, pos) < 0)
+		ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
+				strerror(errno));
+
+fail:
+	*cal = FAILED;
+	close(fd);
+	return;
+}
+
+void setup_wlan_driver_ath_prop()
+{
+	property_set("wlan.driver.ath", WLAN_DRIVER_ATH_DEFAULT_VAL);
+}
+
+#ifdef WCNSS_QMI
+int check_modem_compatability(struct dev_info *mdm_detect_info)
+{
+	char args[MODEM_BASEBAND_PROPERTY_SIZE] = {0};
+	int ret = 0;
+	/* Get the hardware property */
+	ret = property_get(MODEM_BASEBAND_PROPERTY, args, "");
+	if (ret > MODEM_BASEBAND_PROPERTY_SIZE) {
+		ALOGE("property [%s] has size [%d] that exceeds max [%d]",
+				MODEM_BASEBAND_PROPERTY, ret, MODEM_BASEBAND_PROPERTY_SIZE);
+		return 0;
+	}
+	/* This will check for the type of hardware, and if the
+	   hardware type needs external modem, it will check if the
+	   modem type is external*/
+	if(!strncmp(MODEM_BASEBAND_VALUE_APQ, args, 3)) {
+
+		for (ret = 0; ret < mdm_detect_info->num_modems; ret++) {
+			if (mdm_detect_info->mdm_list[ret].type == MDM_TYPE_EXTERNAL) {
+				ALOGE("Hardware supports external modem");
+				return 1;
+			}
+		}
+		ALOGE("Hardware does not support external modem");
+		return 0;
+	}
+	return 1;
+}
+#endif
+
+static int read_line_from_file(const char *path, char *buf, size_t count)
+{
+	char * fgets_ret;
+	FILE * fd;
+	int rv;
+
+	fd = fopen(path, "r");
+	if (fd == NULL)
+	return -1;
+
+	fgets_ret = fgets(buf, (int)count, fd);
+	if (NULL != fgets_ret) {
+	    rv = (int)strlen(buf);
+	} else {
+	    rv = ferror(fd);
+	}
+
+	fclose(fd);
+
+	return rv;
+}
+
+static int get_soc_info(char *buf, char *soc_node_path1,
+			char *soc_node_path2)
+{
+	int ret = 0;
+
+	ret = read_line_from_file(soc_node_path1, buf,
+					MAX_SOC_INFO_NAME_LEN);
+	if (ret < 0) {
+		ret = read_line_from_file(soc_node_path2, buf,
+					MAX_SOC_INFO_NAME_LEN);
+		if (ret < 0) {
+		    ALOGE("getting socinfo(%s, %d) failed.\n",
+					soc_node_path1, ret);
+		    return ret;
+		}
+	}
+	if (ret && buf[ret - 1] == '\n')
+		buf[ret - 1] = '\0';
+
+	return ret;
+}
+
+static int get_data_nvfile_path(char *data_nvfile_path,
+	struct stat *pdata_nvfile_stat)
+{
+	char target_board_platform[PROP_VALUE_MAX] = {'\0'};
+	char buf[MAX_SOC_INFO_NAME_LEN] = {'\0'};
+	int  soc_id, platform_subtype_id, platform_version;
+	int  major_hwver, minor_hwver;
+	int  rc;
+
+	rc = property_get("ro.board.platform", target_board_platform, "");
+	if (!rc)
+	{
+		ALOGE("get ro.board.platform fail, rc=%d(%s)\n",
+				rc, strerror(errno));
+		return FAILED;
+	}
+
+	GET_SOC_INFO(buf, SYSFS_SOCID_PATH1, SYSFS_SOCID_PATH2, soc_id);
+	GET_SOC_INFO(buf, SYSFS_PLATFORM_SUBTYPE_PATH1,
+			SYSFS_PLATFORM_SUBTYPE_PATH2, platform_subtype_id);
+	GET_SOC_INFO(buf, SYSFS_PLATFORM_VERSION_PATH1,
+			SYSFS_PLATFORM_VERSION_PATH2, platform_version);
+
+	major_hwver = SOCINFO_HWVER_MAJOR(platform_version);
+	minor_hwver = SOCINFO_HWVER_MINOR(platform_version);
+
+	snprintf(data_nvfile_path, MAX_DATA_NVBIN_PATH_LEN,
+		"%s%s_%d_0x%02x_0x%02x_0x%02x_nv.bin", DATA_NVFILE_DIR,
+		target_board_platform, soc_id, platform_subtype_id&0xff,
+		major_hwver&0xff, minor_hwver&0xff);
+	ALOGI("data_nvfile_path %s\n",
+			data_nvfile_path);
+
+	if (stat(data_nvfile_path, pdata_nvfile_stat) != 0)
+	{
+		ALOGE("source file do not exist %s\n",
+				data_nvfile_path);
+		return FAILED;
+	}
+
+	return SUCCESS;
+}
+
+static int nvbin_sendfile(const char *dst, const char *src,
+	struct stat *src_stat)
+{
+	struct utimbuf new_time;
+	int fp_src, fp_dst;
+	int rc;
+	if ((fp_src = open(src, O_RDONLY)) < 0)
+	{
+		ALOGE("open %s failed(%s).\n",
+				src, strerror(errno));
+		return FAILED;
+	}
+
+	if ((fp_dst = open(dst, O_WRONLY |O_TRUNC)) < 0)
+	{
+		close(fp_src);
+		ALOGE("open %s failed(%s).\n",
+				dst, strerror(errno));
+		return FAILED;
+	}
+
+	if (sendfile(fp_dst, fp_src, 0, src_stat->st_size) == -1)
+	{
+		ALOGE("dynamic nv sendfile failed: (%s).\n",
+				strerror(errno));
+		rc = FAILED;
+		goto exit;
+	}
+
+	new_time.actime  = src_stat->st_atime;
+	new_time.modtime = src_stat->st_mtime;
+	if (utime(dst, &new_time) != 0)
+	{
+		ALOGE("could not preserve the timestamp %s",
+				strerror(errno));
+		rc = FAILED;
+		goto exit;
+	}
+
+	rc = SUCCESS;
+exit:
+	close(fp_dst);
+	close(fp_src);
+	return rc;
+}
+void dynamic_nv_replace()
+{
+	char data_nvfile_path[MAX_DATA_NVBIN_PATH_LEN] = {'\0'};
+	char property_nv_replaced_status [PROPERTY_VALUE_MAX] = { '\0' };
+	char buf[MAX_SOC_INFO_NAME_LEN] = {'\0'};
+	struct stat  data_nvfile_stat;
+	int rc;
+
+	if (property_get(QRD_DYNAMIC_NV_PROP, property_nv_replaced_status, NULL)
+		&& strcmp(property_nv_replaced_status, "done") == 0) {
+		ALOGI("dynamic nv have been replaced. leave\n");
+		return;
+	}
+
+	rc = get_soc_info(buf, SYSFS_HW_PLATFORM_PATH1, SYSFS_HW_PLATFORM_PATH2);
+	if (rc < 0)
+	{
+		ALOGE("get_soc_info(HW_PLATFORM) fail!\n");
+		return;
+	} else {
+		if( 0 != strncmp(buf, QRD_HW_PLATFORM, MAX_SOC_INFO_NAME_LEN))
+		{
+			ALOGI("dynamic nv only for QRD platform, current platform:%s.\n",
+					buf);
+			return;
+		}
+	}
+
+	rc = get_data_nvfile_path(data_nvfile_path, &data_nvfile_stat);
+	if (rc != SUCCESS)
+	{
+		ALOGE("Get source file path fail !\n");
+		return;
+	}
+
+	if (property_set(QRD_DYNAMIC_NV_PROP, "replacing") < 0)
+	{
+		ALOGE("set %s to replacing failed (%s).\n",
+				QRD_DYNAMIC_NV_PROP, strerror(errno));
+		return;
+	}
+
+	rc = nvbin_sendfile(PERSIST_NVFILE, data_nvfile_path, &data_nvfile_stat);
+	if ( rc != SUCCESS)
+	{
+		ALOGE("nvbin_sendfile failed.\n");
+		return;
+	}
+
+	if (property_set(QRD_DYNAMIC_NV_PROP, "done") < 0)
+	{
+		ALOGE("set %s to done failed(%s).\n",
+				QRD_DYNAMIC_NV_PROP, strerror(errno));
+		return;
+	}
+
+	ALOGI("dynamic nv replace sucessfully!\n");
+
+}
+
+int main(int argc, char *argv[])
+{
+	UNUSED(argc), UNUSED(argv);
+	int rc;
+	int fd_dev, ret_cal;
+#ifdef WCNSS_QMI
+	int nv_mac_addr = FAILED;
+	struct dev_info mdm_detect_info;
+	int nom = 0;
+#endif
+
+	setup_wlan_config_file();
+
+#ifdef WCNSS_QMI
+	/* Call ESOC API to get the number of modems.
+	   If the number of modems is not zero, only then proceed
+	   with the eap_proxy intialization.*/
+
+	nom = get_system_info(&mdm_detect_info);
+
+	if (nom > 0)
+		ALOGE("Failed to get system info, ret %d", nom);
+
+	if (mdm_detect_info.num_modems == 0) {
+		ALOGE("wcnss_service: No Modem support for this target"
+				" number of modems is %d", mdm_detect_info.num_modems);
+		goto nomodem;
+	}
+
+	ALOGE("wcnss_service: num_modems = %d", mdm_detect_info.num_modems);
+
+	if(!check_modem_compatability(&mdm_detect_info)) {
+		ALOGE("wcnss_service: Target does not have external modem");
+		goto nomodem;
+	}
+
+	/* initialize the DMS client and request the wlan mac address */
+
+	if (SUCCESS == wcnss_init_qmi()) {
+
+		rc = wcnss_qmi_get_wlan_address(wlan_nv_mac_addr);
+
+		if (rc == SUCCESS) {
+			nv_mac_addr = SUCCESS;
+			ALOGE("WLAN MAC Addr:" MAC_ADDRESS_STR,
+					MAC_ADDR_ARRAY(wlan_nv_mac_addr));
+		} else
+			ALOGE("Failed to Get MAC addr from modem");
+
+		wcnss_qmi_deinit();
+	}
+	else
+		ALOGE("Failed to Initialize wcnss QMI Interface");
+
+nomodem:
+#endif
+
+	dynamic_nv_replace();
+
+#ifdef WCNSS_QMI
+	setup_wcnss_parameters(&ret_cal, nv_mac_addr);
+#else
+	setup_wcnss_parameters(&ret_cal);
+#endif
+
+	fd_dev = open(WCNSS_DEVICE, O_RDWR);
+	if (fd_dev < 0) {
+		ALOGE("Failed to open wcnss device : %s",
+				strerror(errno));
+		return fd_dev;
+	}
+
+	if (ret_cal != FAILED) {
+		rc = wcnss_write_cal_data(fd_dev);
+		if (rc != SUCCESS)
+			ALOGE("No cal data is written to WCNSS %d", rc);
+		else
+			ALOGE("Cal data is successfully written to WCNSS");
+	}
+
+	setup_wlan_driver_ath_prop();
+
+	rc = wcnss_read_and_store_cal_data(fd_dev);
+	if (rc != SUCCESS)
+		ALOGE("Failed to read and save cal data %d", rc);
+	else
+		ALOGI("Calibration data was successfull written to %s",
+			WCNSS_CAL_FILE);
+
+	close(fd_dev);
+
+	return rc;
+}