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;
+}