Merge commit '2be1e7cd941e52646455bc2155fee3d7447e7136' into wlan-aosp.lnx.2.9-rel
* commit '2be1e7cd941e52646455bc2155fee3d7447e7136':
WiFiHAL: Sync with wpa_supplicant src/common/qca-vendor.h
WiFiHAL: Remove unused param warnings in WifiEvent class
WifiHAL: Free the stats received so far if requestResponse() fails
Wifi-HAL: Move llstats freeing to a common API
WiFi-Hal: Support new header of size 16-bytes for fate stats
WiFi-Hal: Parse new event for packet fate stats
cld80211-lib: Create cld80211 lib for communication with driver
WiFi-HAL: changes to support cld80211 family
Move libwifi-hal and dependencies to /vendor
Change-Id: Ifa2930471c6501c01c4a30b4356b64fe74a07f48
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;
+}