Add wcnss-service for Android One Seed (msm8916/8909)

- Imported clean from lmp-mr1-dev (hardware/qcom/seed/wlan).
- Guard in Android.mk to only be included in msm8916 and msm8909
  based products.

Bug: 21866114

Change-Id: Ifbfe49e6f874272bcaa972050e4bdafecbacd057
diff --git a/qcwcn/wcnss-service/Android.mk b/qcwcn/wcnss-service/Android.mk
new file mode 100644
index 0000000..39cdc57
--- /dev/null
+++ b/qcwcn/wcnss-service/Android.mk
@@ -0,0 +1,27 @@
+ifneq ($(filter msm8916 msm8909,$(TARGET_BOARD_PLATFORM)),)
+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
+include $(BUILD_EXECUTABLE)
+endif
+endif # ifneq ($(filter msm8916 msm8909,$(TARGET_BOARD_PLATFORM)),)
diff --git a/qcwcn/wcnss-service/wcnss_qmi_client.c b/qcwcn/wcnss-service/wcnss_qmi_client.c
new file mode 100644
index 0000000..28acce1
--- /dev/null
+++ b/qcwcn/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>
+
+#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/qcwcn/wcnss-service/wcnss_qmi_client.h b/qcwcn/wcnss-service/wcnss_qmi_client.h
new file mode 100644
index 0000000..51fefac
--- /dev/null
+++ b/qcwcn/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/qcwcn/wcnss-service/wcnss_service.c b/qcwcn/wcnss-service/wcnss_service.c
new file mode 100644
index 0000000..9244ea0
--- /dev/null
+++ b/qcwcn/wcnss-service/wcnss_service.c
@@ -0,0 +1,582 @@
+/*--------------------------------------------------------------------------
+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 <stdio.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 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
+
+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 = 0;
+	unsigned long int hex_num = 0;
+	for(idx; 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;
+}
+
+
+void setup_wcnss_parameters(int *cal, int nv_mac_addr)
+{
+	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
+
+int main(int argc, char *argv[])
+{
+	int rc;
+	int fd_dev, ret_cal;
+	int nv_mac_addr = FAILED;
+#ifdef WCNSS_QMI
+	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
+	setup_wcnss_parameters(&ret_cal, nv_mac_addr);
+
+	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;
+}