diff --git a/BoardConfig.mk b/BoardConfig.mk
index b3f2be2..c6abae2 100644
--- a/BoardConfig.mk
+++ b/BoardConfig.mk
@@ -21,6 +21,8 @@ endif
 
 WITH_DEXPREOPT := $(CONFIG_DEX_PREOPT)
 
+BOARD_SEPOLICY_DIRS += device/linaro/generic/sepolicy
+
 # generic wifi
 WPA_SUPPLICANT_VERSION := VER_0_8_X
 BOARD_WPA_SUPPLICANT_DRIVER := NL80211
diff --git a/Kconfig b/Kconfig
index 6fb1083..fafe435 100644
--- a/Kconfig
+++ b/Kconfig
@@ -74,8 +74,12 @@ menuconfig WIFI
 
 if WIFI
 
+config QCOM_WIFI
+	bool "Qualcomm WCNSS wifi support"
+
 endif
 
+
 config ETHERNET
 	bool "Ethernet support"
 
diff --git a/sepolicy/conn_init.te b/sepolicy/conn_init.te
new file mode 100644
index 0000000..becb3b5
--- /dev/null
+++ b/sepolicy/conn_init.te
@@ -0,0 +1,10 @@
+# wifi connection service
+type conn_init, domain, domain_deprecated;
+type conn_init_exec, exec_type, file_type;
+
+init_daemon_domain(conn_init)
+
+# Runs start_qcom_wifi.sh
+allow conn_init shell_exec:file rx_file_perms;
+allow conn_init conn_init_exec:file rx_file_perms;
+
diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts
new file mode 100644
index 0000000..1c5409c
--- /dev/null
+++ b/sepolicy/file_contexts
@@ -0,0 +1,2 @@
+/system/bin/conn_init              u:object_r:conn_init_exec:s0
+/system/bin/start_qcom_wifi\.sh    u:object_r:conn_init_exec:s0
diff --git a/wifi/Android.mk b/wifi/Android.mk
index d31a80c..5125461 100644
--- a/wifi/Android.mk
+++ b/wifi/Android.mk
@@ -7,3 +7,5 @@ LOCAL_MODULE:= wifi.rc
 LOCAL_INIT_RC := $(LOCAL_MODULE)
 
 include $(BUILD_PHONY_PACKAGE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/wifi/device.mk b/wifi/device.mk
index 6cfae76..ecd0f1c 100644
--- a/wifi/device.mk
+++ b/wifi/device.mk
@@ -12,3 +12,9 @@ PRODUCT_COPY_FILES += \
 PRODUCT_PROPERTY_OVERRIDES += \
 		wifi.interface=wlan0 \
 		wifi.supplicant_scan_interval=15
+
+
+subdirs-true :=
+subdirs-$(CONFIG_QCOM_WIFI) += qcom
+include $(foreach dir,$(subdirs-true), $(LOCAL_PATH)/wifi/$(dir)/device.mk)
+PRODUCT_COPY_FILES += $(PRODUCT_COPY_FILES-true)
diff --git a/wifi/qcom/Android.mk b/wifi/qcom/Android.mk
new file mode 100644
index 0000000..f758de7
--- /dev/null
+++ b/wifi/qcom/Android.mk
@@ -0,0 +1,58 @@
+#
+# Copyright 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libwfcu
+LOCAL_SRC_FILES := wfc_util_fctrl.c \
+                   wfc_util_common.c
+LOCAL_CFLAGS := -Wall \
+                -Werror
+LOCAL_CFLAGS += -DCONFIG_LGE_WLAN_WIFI_PATCH
+LOCAL_SRC_FILES += wfc_util_qcom.c
+LOCAL_CFLAGS += -DCONFIG_LGE_WLAN_QCOM_PATCH
+LOCAL_CFLAGS += -DWLAN_CHIP_VERSION_WCNSS
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_OWNER := qcom
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := conn_init.c
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_SHARED_LIBRARIES += libwfcu
+LOCAL_CFLAGS += -Wall -Werror
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT)/bin
+LOCAL_MODULE := conn_init
+LOCAL_MODULE_OWNER := qcom
+
+# Make sure the symlinks get created as well.
+LOCAL_POST_INSTALL_CMD := \
+  mkdir -p $(TARGET_OUT_VENDOR)/firmware/wlan/prima/; \
+  ln -sf /data/misc/wifi/WCNSS_qcom_cfg.ini \
+    $(TARGET_OUT_VENDOR)/firmware/wlan/prima/WCNSS_qcom_cfg.ini; \
+  ln -sf /data/misc/wifi/WCNSS_qcom_wlan_nv.bin \
+    $(TARGET_OUT_VENDOR)/firmware/wlan/prima/WCNSS_qcom_wlan_nv.bin
+
+include $(BUILD_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= qcom-wifi.rc
+LOCAL_INIT_RC := $(LOCAL_MODULE)
+include $(BUILD_PHONY_PACKAGE)
diff --git a/wifi/qcom/NOTICE b/wifi/qcom/NOTICE
new file mode 100644
index 0000000..33ff961
--- /dev/null
+++ b/wifi/qcom/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2012, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/wifi/qcom/WCNSS_cfg.dat b/wifi/qcom/WCNSS_cfg.dat
new file mode 100644
index 0000000000000000000000000000000000000000..16ba06f087a4ce2d0a0ee50f54e3f3db56d3fc13
GIT binary patch
diff --git a/wifi/qcom/WCNSS_qcom_cfg.ini b/wifi/qcom/WCNSS_qcom_cfg.ini
new file mode 100644
index 0000000..aa7e616
--- /dev/null
+++ b/wifi/qcom/WCNSS_qcom_cfg.ini
@@ -0,0 +1,254 @@
+# This file allows user to override the factory
+# defaults for the WLAN Driver
+
+# Enable IMPS or not
+gEnableImps=1
+
+# Enable/Disable Idle Scan
+gEnableIdleScan=0
+
+# Increase sleep duration (seconds) during IMPS
+# 0 implies no periodic wake up from IMPS. Periodic wakeup is
+# unnecessary if Idle Scan is disabled.
+gImpsModSleepTime=0
+
+# Enable BMPS or not
+gEnableBmps=1
+
+# Enable Close Loop or not
+gEnableCloseLoop=1
+
+# Enable suspend or not
+# 1: Enable standby, 2: Enable Deep sleep, 3: Enable Mcast/Bcast Filter
+gEnableSuspend=3
+
+# Phy Mode (auto, b, g, n, etc)
+gDot11Mode=0
+
+# Handoff Enable(1) Disable(0)
+gEnableHandoff=0
+
+# CSR Roaming Enable(1) Disable(0)
+gRoamingTime=0
+
+# Assigned MAC Addresses - This will be used until NV items are in place
+# Each byte of MAC address is represented in Hex format as XX
+Intf0MacAddress=000AF58989FF
+Intf1MacAddress=000AF58989FE
+Intf2MacAddress=000AF58989FD
+Intf3MacAddress=000AF58989FC
+
+# UAPSD service interval for VO,VI, BE, BK traffic
+InfraUapsdVoSrvIntv=0
+InfraUapsdViSrvIntv=0
+InfraUapsdBeSrvIntv=0
+InfraUapsdBkSrvIntv=0
+
+# Enable Firmware RSSI monitoring for roaming
+gEnableFWRssiMonitoring=1
+
+# Make 1x1 the default antenna configuration
+gNumRxAnt=1
+
+# Beacon filtering frequency (unit in beacon intervals)
+gNthBeaconFilter=50
+
+# Enable WAPI or not
+# WAPIIsEnabled=0
+
+# Flags to filter Mcast and Bcast RX packets.
+# Value 0: No filtering, 1: Filter all Multicast.
+# 2: Filter all Broadcast. 3: Filter all Mcast and Bcast
+McastBcastFilter=3
+
+# Flag to enable Active mode offload
+gEnableActiveModeOffload=1
+
+# Flag to enable HostARPOffload feature or not
+hostArpOffload=1
+
+# Flag to enable Host IPv6 NS Offload feature or not
+hostNSOffload=1
+
+#SoftAP Related Parameters
+# AP MAc addr (obsolete)
+gAPMacAddr=000AF58989EF
+
+# Enable Random BSSID
+gEnableApRandomBssid=1
+
+# 802.11n Protection flag
+gEnableApProt=1
+
+# Enable OBSS protection
+gEnableApOBSSProt=0
+
+# Enable/Disable UAPSD for SoftAP
+gEnableApUapsd=1
+
+# Fixed Rate
+gFixedRate=0
+
+# Maximum Tx power
+# gTxPowerCap=30
+
+# Fragmentation Threshold
+# gFragmentationThreshold=2346
+
+# RTS threshold
+RTSThreshold=2347
+
+# Intra-BSS forward
+gDisableIntraBssFwd=0
+
+# WMM Enable/Disable
+WmmIsEnabled=0
+
+# 802.11d support
+g11dSupportEnabled=1
+
+# CCX Support and fast transition
+CcxEnabled=0
+FastTransitionEnabled=1
+ImplicitQosIsEnabled=1
+gNeighborScanTimerPeriod=200
+
+gNeighborLookupThreshold=76
+gNeighborReassocThreshold=81
+
+gNeighborScanChannelMinTime=20
+gNeighborScanChannelMaxTime=30
+gMaxNeighborReqTries=3
+
+# Legacy (non-CCX, non-802.11r) Fast Roaming Support
+# To enable, set FastRoamEnabled=1, gEnableFWRssiMonitoring=1, FastTransitionEnabled=1
+# To disable, set FastRoamEnabled=0, gEnableFWRssiMonitoring=0, FastTransitionEnabled=0
+FastRoamEnabled=1
+
+#Check if the AP to which we are roaming is better than current AP in terms of RSSI.
+#Checking is disabled if set to Zero.Otherwise it will use this value as to how better
+#the RSSI of the new/roamable AP should be for roaming
+RoamRssiDiff=3
+
+#Configure the RSSI gap that will be used to partition/categorize width of
+#each  individual category (aka bucket).
+gRssiCatGap=5
+
+# SAP Country code
+# Default Country Code is 2 bytes, 3rd byte is optional indoor or out door.
+# Example
+#   US Indoor, USI
+#   Korea Outdoor, KRO
+#   Japan without optional byte, JP
+#   France without optional byte, FR
+#gAPCntryCode=USI
+
+#Short Guard Interval Enable/disable
+gShortGI20Mhz=1
+gShortGI40Mhz=1
+
+#Auto Shutdown  Value in seconds. A value of 0 means Auto shutoff is disabled
+gAPAutoShutOff=0
+
+# SAP auto channel selection configuration
+# 0 = disable auto channel selection
+# 1 = enable auto channel selection, channel provided by supplicant will be ignored
+gApAutoChannelSelection=0
+
+# Listen Energy Detect Mode Configuration
+# Valid values 0-128
+# 128 means disable Energy Detect feature
+# 0-9 are threshold code and 7 is recommended value from system if feature is to be enabled.
+# 10-128 are reserved.
+# The EDET threshold mapping is as follows in 3dB step:
+# 0 = -60 dBm
+# 1 = -63 dBm
+# 2 = -66 dBm
+# ...
+# 7 = -81 dBm
+# 8 = -84 dBm
+# 9 = -87 dBm
+# Note: Any of these settings are valid. Setting 0 would yield the highest power saving (in a noisy environment) at the cost of more range. The range impact is approximately #calculated as:
+#
+#  Range Loss  (dB)  =  EDET threshold level (dBm) + 97 dBm.
+#
+gEnablePhyAgcListenMode=128
+
+#Preferred band (both or 2.4 only or 5 only)
+BandCapability=0
+
+#Forced Device Listen Interval in multiples of DTIM Period aligned to DTIM
+gEnableModulatedDTIM=3
+
+#Beacon Early Termination (1 = enable the BET feature, 0 = disable)
+enableBeaconEarlyTermination=1
+beaconEarlyTerminationWakeInterval=11
+
+#Bluetooth Alternate Mac Phy (1 = enable the BT AMP feature, 0 = disable)
+gEnableBtAmp=0
+
+#Preferred channel to start BT AMP AP mode (0 means, any channel)
+BtAmpPreferredChannel=0
+
+#SOFTAP Channel Range selection
+gAPChannelSelectStartChannel=1
+gAPChannelSelectEndChannel=11
+
+#SOFTAP Channel Range selection Operating band
+# 0:2.4GHZ 1: LOW-5GHZ 2:MID-5GHZ 3:HIGH-5GHZ 4: 4.9HZ BAND
+gAPChannelSelectOperatingBand=0
+
+#Enable Keep alive with non-zero period value
+gStaKeepAlivePeriod = 25
+
+#If set will start with active scan after driver load, otherwise will start with
+#passive scan to find out the domain
+gEnableBypass11d=1
+
+#If set to 0, will not scan DFS channels
+gEnableDFSChnlScan=1
+
+# Enable logp/SSR
+gEnableLogp=1
+
+# Enable HT40
+gChannelBondingMode5GHz=1
+
+# Enable Automatic Tx Power control
+gEnableAutomaticTxPowerControl=1
+
+# Derive P2P MAC address from primary MAC address
+isP2pDeviceAddrAdministrated=1
+
+# Disable channel 165 for Indonesia
+gIgnore_Chan165=1
+
+btcStaticLenLeBt=120000
+btcStaticLenLeWlan=30000
+
+#Data Inactivity Timeout when in powersave (in ms)
+gDataInactivityTimeout=200
+
+gCountryCodePriority=1
+
+gNumChanCombinedConc=255
+
+# TDLS configuration
+gEnableTDLSSupport=1
+gEnableTDLSImplicitTrigger=1
+gTDLSExternalControl=1
+gTDLSTxStatsPeriod=500
+gTDLSTxPacketThreshold=10
+gTDLSDiscoveryPeriod=20000
+gTDLSMaxDiscoveryAttempt=5
+gTDLSIdleTimeout=40000
+gTDLSRssiHysteresis=100
+gTDLSRSSITriggerThreshold=-60
+gTDLSIdlePacketThreshold=5
+gTDLSRSSITeardownThreshold=-70
+
+# Enable IPv6 RA filtering
+gMCAddrListEnable=1
+
+END
+# Note: Configuration parser would not read anything past the END marker
diff --git a/wifi/qcom/WCNSS_qcom_wlan_nv_deb.bin b/wifi/qcom/WCNSS_qcom_wlan_nv_deb.bin
new file mode 100644
index 0000000000000000000000000000000000000000..505319b640ff906a1dc68a3cbc74a762a5588e68
GIT binary patch
diff --git a/wifi/qcom/WCNSS_qcom_wlan_nv_flo.bin b/wifi/qcom/WCNSS_qcom_wlan_nv_flo.bin
new file mode 100644
index 0000000000000000000000000000000000000000..8f98da69c7480e4da626c3f82b9a1f1910f73b50
GIT binary patch
diff --git a/wifi/qcom/conn_init.c b/wifi/qcom/conn_init.c
new file mode 100644
index 0000000..2cb5591
--- /dev/null
+++ b/wifi/qcom/conn_init.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+extern int wfc_util_qcom_check_config(unsigned char *nv_mac_addr);
+extern void wfc_util_atoh(char *pAsciiString, int szAsciiString, unsigned char *pHexaBuff, int szHexaBuff);
+
+static int wifi_check_qcom_cfg_files()
+{
+    char macAddress[13];
+    char hex[7];
+    memset(macAddress, 0, 13);
+    memset(hex, 0, 7);
+
+    // Read MAC String
+    FILE *fp = NULL;
+    int n = 0;
+    fp = fopen("/persist/wifi/.macaddr", "r");
+    if ( fp == NULL )
+    {
+        wfc_util_qcom_check_config((unsigned char *)macAddress);
+        return 0;
+    }
+    else
+    {
+        n = fread(macAddress, 12, 1, fp);
+        fclose(fp);
+
+        // Write MAC String
+        wfc_util_atoh( macAddress, 12, (unsigned char *)hex, 6);
+        wfc_util_qcom_check_config((unsigned char *)hex);
+    }
+    return 1;
+}
+
+int main(void)
+{
+    wifi_check_qcom_cfg_files();
+
+    return 0;
+}
diff --git a/wifi/qcom/device.mk b/wifi/qcom/device.mk
new file mode 100644
index 0000000..3d7effd
--- /dev/null
+++ b/wifi/qcom/device.mk
@@ -0,0 +1,14 @@
+#these are all qcom specific (need to split them out somewhere)
+PRODUCT_PACKAGES += \
+		libwfcu \
+		conn_init \
+		qcom-wifi.rc \
+
+PRODUCT_COPY_FILES += \
+	device/linaro/generic/wifi/qcom/start_qcom_wifi.sh:system/bin/start_qcom_wifi.sh \
+	device/linaro/generic/wifi/qcom/WCNSS_cfg.dat:system/vendor/firmware/wlan/prima/WCNSS_cfg.dat \
+	device/linaro/generic/wifi/qcom/WCNSS_qcom_cfg.ini:system/etc/wifi/WCNSS_qcom_cfg.ini \
+	device/linaro/generic/wifi/qcom/WCNSS_qcom_wlan_nv_flo.bin:system/etc/wifi/WCNSS_qcom_wlan_nv_flo.bin \
+	device/linaro/generic/wifi/qcom/WCNSS_qcom_wlan_nv_deb.bin:system/etc/wifi/WCNSS_qcom_wlan_nv_deb.bin
+
+
diff --git a/wifi/qcom/qcom-wifi.rc b/wifi/qcom/qcom-wifi.rc
new file mode 100644
index 0000000..61335c4
--- /dev/null
+++ b/wifi/qcom/qcom-wifi.rc
@@ -0,0 +1,8 @@
+on property:sys.boot_completed=1
+	start wcnss_init
+
+service wcnss_init /system/bin/start_qcom_wifi.sh
+	user root
+	group root root
+	oneshot
+
diff --git a/wifi/qcom/start_qcom_wifi.sh b/wifi/qcom/start_qcom_wifi.sh
new file mode 100755
index 0000000..14a5394
--- /dev/null
+++ b/wifi/qcom/start_qcom_wifi.sh
@@ -0,0 +1,10 @@
+#!/system/bin/sh
+
+# Workaround for conn_init not copying the updated firmware
+rm /data/misc/wifi/WCNSS_qcom_cfg.ini
+rm /data/misc/wifi/WCNSS_qcom_wlan_nv.bin
+
+/system/bin/conn_init
+
+echo 1 > /dev/wcnss_wlan
+echo start > /sys/kernel/debug/remoteproc/remoteproc0/state
diff --git a/wifi/qcom/wfc_util_common.c b/wifi/qcom/wfc_util_common.c
new file mode 100644
index 0000000..b149920
--- /dev/null
+++ b/wifi/qcom/wfc_util_common.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "wfc_util_log.h"
+
+#define WFC_UTIL_RANDOM_MAC_HEADER "001122"
+
+void wfc_util_htoa(unsigned char *pHexaBuff, int szHexaBuff, char *pAsciiStringBuff, int szAsciiStringBuff)
+{
+	int i, j;
+	char hex_table[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+	                                 'A', 'B', 'C', 'D', 'E', 'F'};
+
+	if ((szHexaBuff*2) > szAsciiStringBuff) {
+		wfc_util_log_error("wfc_util_htoa : not enough buffer size(%d)", szAsciiStringBuff);
+		return;
+	}
+
+	memset(pAsciiStringBuff, 0, szAsciiStringBuff);
+
+	/* for (i = szHexaBuff-1, j = 0; i >= 0; i--, j += 2) { */
+	for (i = 0, j = 0; i < szHexaBuff; i++, j += 2) {
+		/*pAsciiStringBuff[j]     = hex_table[(pHexaBuff[i] >> 4) & 0x0F];
+		*/
+		pAsciiStringBuff[j]     = hex_table[pHexaBuff[i] >> 4];
+		pAsciiStringBuff[j + 1] = hex_table[pHexaBuff[i] & 0x0F];
+	}
+
+	return;
+}
+
+void wfc_util_atoh(char *pAsciiString, int szAsciiString, unsigned char *pHexaBuff, int szHexaBuff)
+{
+	int i, pos;
+	char temp;
+
+	if ( 0!=(szAsciiString%2) || (szHexaBuff*2) < szAsciiString) {
+		wfc_util_log_error("wfc_util_atoh : not enough buffer size(%d)", szHexaBuff);
+		return;
+	}
+
+	memset(pHexaBuff, 0, szHexaBuff);
+
+	for (i=0 ; i<szAsciiString ; i++) {
+
+		/* pos = (szAsciiString - i - 1) / 2; */
+		pos = i / 2;
+		temp = pAsciiString[i];
+
+		if (temp >= '0' && temp <= '9') {
+			temp = temp - '0';
+		} else if ( temp >= 'a' && temp <= 'f' ) {
+			temp = temp - 'a' + 10;
+		} else if ( temp >= 'A' && temp <= 'F' ) {
+			temp = temp - 'A' + 10;
+		} else {
+			temp = 0;
+		}
+
+		if (0==i%2) {
+			pHexaBuff[pos] = temp<<4;
+		} else {
+			pHexaBuff[pos] |= temp;
+		}
+	}
+
+	return;
+}
+
+/*
+ * wfc_util_is_random_mac
+ *
+ * return : it will return 1 if [mac_add] is same with WFC_UTIL_RANDOM_MAC_HEADER
+ *          or will return 0 if not.
+ */
+int wfc_util_is_random_mac(char *mac_add)
+{
+	if(0 == strncmp(mac_add, WFC_UTIL_RANDOM_MAC_HEADER, 6)) {
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * wfc_util_random_mac
+ *
+ * Create random MAC address
+ *
+ * return : void
+ */
+void wfc_util_random_mac(unsigned char* mac_addr)
+{
+	unsigned long int rand_mac;
+
+	if(NULL == mac_addr) {
+		wfc_util_log_error("wfc_util_random_mac : buffer is NULL");
+		return;
+	}
+
+	/* Create random MAC address: offset 3, 4 and 5 */
+	srandom(time(NULL));
+	rand_mac=random();
+
+	#ifndef WFC_UTIL_RANDOM_MAC_HEADER
+	mac_addr[0] = (unsigned char)0x00;
+	mac_addr[1] = (unsigned char)0x11;
+	mac_addr[2] = (unsigned char)0x22;
+	#else  /* WFC_UTIL_RANDOM_MAC_HEADER */
+	wfc_util_atoh(WFC_UTIL_RANDOM_MAC_HEADER, 6, mac_addr, 3);
+	#endif /* WFC_UTIL_RANDOM_MAC_HEADER */
+	mac_addr[3] = (unsigned char)rand_mac;
+	mac_addr[4] = (unsigned char)(rand_mac >> 8);
+	mac_addr[5] = (unsigned char)(rand_mac >> 16);
+
+	return;
+}
diff --git a/wifi/qcom/wfc_util_common.h b/wifi/qcom/wfc_util_common.h
new file mode 100644
index 0000000..c91f899
--- /dev/null
+++ b/wifi/qcom/wfc_util_common.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WFC_UTIL_COMMON_H__
+#define __WFC_UTIL_COMMON_H__
+
+/*
+ * wfc_util_htoa
+ *
+ * return : void
+ */
+extern void wfc_util_htoa(unsigned char *pHexaBuff, int szHexaBuff, char *pAsciiStringBuff, int szAsciiStringBuff);
+
+/*
+ * wfc_util_atoh
+ *
+ * return : void
+ */
+extern void wfc_util_atoh(char *pAsciiString, int szAsciiString, unsigned char *pHexaBuff, int szHexaBuff);
+
+/*
+ * wfc_util_is_random_mac
+ *
+ * return : it will return 1 if [mac_add] is same with WFC_UTIL_RANDOM_MAC_HEADER
+ *          or will return 0 if not.
+ */
+extern int wfc_util_is_random_mac(char *mac_add);
+
+/*
+ * wfc_util_random_mac
+ *
+ * Create random MAC address
+ *
+ * return : void
+ */
+void wfc_util_random_mac(unsigned char* mac_addr);
+
+#endif
diff --git a/wifi/qcom/wfc_util_fctrl.c b/wifi/qcom/wfc_util_fctrl.c
new file mode 100644
index 0000000..cd532a9
--- /dev/null
+++ b/wifi/qcom/wfc_util_fctrl.c
@@ -0,0 +1,662 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "wfc_util_log.h"
+
+/*
+static void wfc_util_printf(char *pSPointer, int length)
+{
+	char *pPrintBuff = NULL;
+
+	if( NULL == pSPointer || 0 >= length ) {
+		wfc_util_log_error("wfc_util_printf : unvalid parameters");
+		return;
+	}
+
+	wfc_util_log_error("wfc_util_printf : lenght is (%d)", length);
+	pPrintBuff = malloc(length+1);
+
+	if( NULL != pPrintBuff ) {
+		memset( pPrintBuff, 0, (length+1) );
+		memcpy(pPrintBuff, pSPointer, length);
+
+		wfc_util_log_error("wfc_util_printf : %s", pPrintBuff);
+
+		free(pPrintBuff);
+	} else {
+		wfc_util_log_error("wfc_util_printf : can not malloc(%d)", (length+1));
+	}
+	return;
+}
+*/
+
+static void wfc_util_finsert_new_string(int fd, char **ppReadedBuff, char *pNewStringValue, char *pEndOfCfg)
+{
+	off_t sz_file;
+	int   sz_backupBuff = 0;
+	char *pReadBuff = NULL, *pBackupBuff = NULL;
+	char *pSPointer = NULL, *pETagPointer = NULL;
+
+	if( 0 == fd || NULL == pNewStringValue || 0 == strlen(pNewStringValue) ) {
+		wfc_util_log_error("wfc_util_finsert_new_string : unvalid parameters");
+		return;
+	}
+
+	if( NULL == ppReadedBuff) {
+		// TODO:
+		return;
+	} else {
+		pReadBuff = *ppReadedBuff;
+	}
+
+	/*
+	 * find END TAG string
+	 */
+	pETagPointer = strstr(pReadBuff, pEndOfCfg);
+	pSPointer = pETagPointer - 1;
+
+	/*
+	 * calcurate file size and size of the tail of file
+	 */
+	sz_file = lseek( fd,  0, SEEK_END );
+	sz_backupBuff = (int)sz_file - (pETagPointer - pReadBuff);
+
+	/*
+	 * prefare the buffer to store the tail of file
+	 */
+	pBackupBuff = malloc(sz_backupBuff);
+
+	if( NULL != pBackupBuff ) {
+		/*
+		 * copy the tail of file.
+		 */
+		memset( pBackupBuff, 0, sz_backupBuff );
+		memcpy( pBackupBuff, pETagPointer, sz_backupBuff );
+
+		/*
+		 * write new string.
+		 */
+		lseek( fd, (int)(pSPointer-pReadBuff), SEEK_SET );
+		write( fd, pNewStringValue, strlen(pNewStringValue));
+
+		/*
+		 * update pETagPointer.
+		 */
+		pETagPointer = pSPointer + strlen(pNewStringValue);
+
+		/*
+		 * write the tail of file.
+		 */
+		lseek( fd, (int)(pETagPointer-pReadBuff), SEEK_SET );
+		write( fd, pBackupBuff, sz_backupBuff );
+
+		ftruncate(fd, sz_file + strlen(pNewStringValue) - 1); /* we use "-1" becasue of "pSPointer = pETagPointer - 1"*/
+
+		free(pBackupBuff);
+
+		/*
+		 * make new *ppReadedBuff
+		 */
+		if( NULL != ppReadedBuff) {
+			// TODO:
+		}
+	} else {
+		wfc_util_log_error("wfc_util_finsert_new_string : can not malloc(%d)", sz_backupBuff);
+	}
+
+	return;
+}
+
+static void wfc_util_fupdate_string(int fd, char **ppReadedBuff,
+                                    char *pETagPointer, char *pSValuePointer, char *pNewValueString)
+{
+	off_t sz_file;
+	int   sz_newReadBuff = 0;
+	char *pReadBuff = NULL, *pNewReadBuff = NULL, *pCurReadBuff = NULL;
+
+	if( 0 == fd ) {
+		wfc_util_log_error("wfc_util_fupdate_string : unvalid parameters");
+		return;
+	}
+
+	if( NULL == ppReadedBuff) {
+		// TODO:
+		return;
+	} else {
+		pReadBuff = *ppReadedBuff;
+	}
+
+	/*
+	 * calcurate file size and new file size
+	 */
+	sz_file  = lseek( fd,  0, SEEK_END );
+	sz_newReadBuff = (int)sz_file - (int)(pETagPointer - pSValuePointer) + strlen(pNewValueString);
+
+	/*
+	 * prefare the buffer to read file
+	 */
+	pNewReadBuff = malloc(sz_newReadBuff);
+
+	if( NULL != pNewReadBuff ) {
+		/*
+		 * copy buffer
+		 */
+		memset( pNewReadBuff, 0, sz_file );
+		pCurReadBuff = pNewReadBuff;
+		memcpy( pNewReadBuff, pReadBuff, (int)(pSValuePointer-pReadBuff) );
+		pCurReadBuff += (int)(pSValuePointer-pReadBuff);
+
+		/*
+		 * copy new value string
+		 */
+		memcpy( pCurReadBuff, pNewValueString, strlen(pNewValueString));
+		pCurReadBuff += strlen(pNewValueString);
+
+		/*
+		 * copy the remained buffer
+		 */
+		memcpy( pCurReadBuff, pETagPointer, ((int)(sz_file) - (int)(pETagPointer - pReadBuff) + 1));
+
+		/*
+		 * write file and update the file size
+		 */
+		lseek( fd,  0, SEEK_SET );
+		write( fd, pNewReadBuff, sz_newReadBuff);
+		ftruncate(fd, sz_newReadBuff);
+
+		free(pNewReadBuff);
+	} else {
+		wfc_util_log_error("wfc_util_fupdate_string : can not malloc(%d)", (int)sz_newReadBuff);
+	}
+
+	return;
+}
+
+/*
+ * wfc_util_fset_buffer
+ *
+ * return : void
+ */
+void wfc_util_fset_buffer(char *pFileName, int positionStart, unsigned char *pNewValue, int newValueLength)
+{
+	int fd;
+	off_t sz_file;
+	char *pReadBuff = NULL;
+
+	fd = open( pFileName, O_RDWR );
+
+	if( fd >= 0 ) {
+		/*
+		 * calcurate file size
+		 */
+		sz_file  = lseek( fd,  0, SEEK_END );
+
+		/*
+		 * prefare the buffer to read file
+		 */
+		pReadBuff = malloc(sz_file + 1);  // null terminated
+
+		if( NULL != pReadBuff ) {
+			/*
+			 * read file
+			 */
+			memset( pReadBuff, 0, sz_file + 1);
+			lseek( fd,  0, SEEK_SET );
+			read( fd, pReadBuff, sz_file );
+
+			if(sz_file >= (positionStart+newValueLength)) {
+				lseek( fd, positionStart, SEEK_SET );
+				write( fd, pNewValue, newValueLength );
+			} else {
+				/*
+				 * insert with new length value buffer
+				 */
+				wfc_util_log_error("wfc_util_fset_buffer : file size(%d) is less than to write position(%d)", (int)sz_file, (positionStart+newValueLength));
+				// TODO:
+			}
+
+			free(pReadBuff);
+		} else {
+			wfc_util_log_error("wfc_util_fset_buffer : can not malloc(%d)", (int)sz_file);
+		}
+
+		if ( -1 == fsync( fd ) ) {
+			wfc_util_log_error("wfc_util_fset_buffer : fail to fsync()");
+		}
+
+		close( fd );
+	} else {
+		wfc_util_log_error("wfc_util_fset_buffer : can not open file");
+	}
+
+	return;
+}
+
+/*
+ * wfc_util_fget_buffer
+ *
+ * return : it will return the length of the stored buffer value if procedure is success
+ *          or will return 0 if not.
+ */
+int wfc_util_fget_buffer(char *pFileName, int positionStart, int lengthToRead, unsigned char *pValueBuff, int buffLength)
+{
+	int result = 0;
+	int fd;
+	off_t sz_file;
+	char *pReadBuff = NULL;
+	char *pSValuePointer = NULL, *pETagPointer = NULL;
+
+	fd = open( pFileName, O_RDONLY );
+
+	if( fd >= 0 ) {
+		/*
+		 * calcurate file size
+		 */
+		sz_file  = lseek( fd,  0, SEEK_END );
+
+		if(sz_file >= (positionStart+lengthToRead)) {
+			/*
+			 * prefare the buffer to read file
+			 */
+			pReadBuff = malloc(sz_file + 1); // null terminated
+
+			if( NULL != pReadBuff ) {
+				/*
+				 * read file
+				 */
+				memset( pReadBuff, 0, sz_file + 1 );
+				lseek( fd,  0, SEEK_SET );
+				read( fd, pReadBuff, sz_file );
+
+				/*
+				 * calculate the start buffer pointer
+				 */
+				pSValuePointer = pReadBuff + positionStart;
+
+				/*
+				 * calculate the end buffer pointer
+				 */
+				pETagPointer = pSValuePointer + lengthToRead;
+
+				/*
+				 * read the string value
+				 */
+				if( buffLength >= (int)(pETagPointer-pSValuePointer) ) {
+					memset( pValueBuff, 0, buffLength );
+					memcpy( pValueBuff, pSValuePointer, (int)(pETagPointer-pSValuePointer) );
+					result = (int)(pETagPointer-pSValuePointer);
+				} else {
+					wfc_util_log_error("wfc_util_fget_buffer : not enough string value buffer(%d)", (int)(pETagPointer-pSValuePointer));
+				}
+
+				free(pReadBuff);
+			} else {
+				wfc_util_log_error("wfc_util_fget_buffer : can not malloc(%d)", (int)sz_file);
+			}
+		} else {
+			wfc_util_log_error("wfc_util_fget_buffer : file size(%d) is less than to read position(%d)", (int)sz_file, (positionStart+lengthToRead));
+		}
+		close( fd );
+	} else {
+		wfc_util_log_error("wfc_util_fget_buffer : can not open file");
+	}
+
+	return result;
+}
+
+/*
+ * wfc_util_fset_string
+ *
+ * The following format string will be added or updated to the file pFileName.
+ * [pSTagString][pNewValueString][pETagString]
+ *
+ * pFileName       : file name and path
+ * pEndOfCfg       : tag string to notify the end of configuration file
+ * pSTagString     : tag string to notify purpose of the value
+ * pETagString     : tag string to notify the end of the value
+ * pNewValueString : string to set for pSTagString
+ *
+ * return : void
+ */
+void wfc_util_fset_string(char *pFileName, char *pEndOfCfg, char *pSTagString, char *pETagString, char *pNewValueString)
+{
+	int fd;
+	off_t sz_file;
+	int   sz_NewValueBuff = 0;
+	char *pReadBuff = NULL, *pNewValueBuff = NULL;
+	char *pSPointer = NULL, *pETagPointer = NULL, *pSValuePointer = NULL;
+
+	fd = open( pFileName, O_RDWR );
+
+	if( fd >= 0 ) {
+		/*
+		 * calcurate file size
+		 */
+		sz_file  = lseek( fd,  0, SEEK_END );
+
+		/*
+		 * prefare the buffer to read file
+		 */
+		if (sz_file > 0)
+			pReadBuff = malloc(sz_file + 1); // null terminated
+
+		if( NULL != pReadBuff ) {
+			/*
+			 * read file
+			 */
+			memset( pReadBuff, 0x00, sz_file + 1);
+			if(lseek(fd, 0, SEEK_SET) != 0) {
+				wfc_util_log_error("lseek failure");
+			}
+			read( fd, pReadBuff, sz_file );
+
+			/* WBT fix, make sure it is terminated with \0 */
+			pReadBuff[sz_file] = '\0';
+
+			/*
+			 * find TAG string
+			 */
+			pSPointer = strstr(pReadBuff, pSTagString);
+
+			if(NULL != pSPointer) {
+				/*
+				 * find END OF LINE string
+				 */
+				pETagPointer = strstr(pSPointer, pETagString);
+
+				if(NULL != pETagPointer) {
+					/*
+					 * write the new string value
+					 */
+					pSValuePointer = pSPointer+strlen(pSTagString);
+					if(strlen(pNewValueString) == (unsigned int)(pETagPointer-pSValuePointer)) {
+						lseek( fd, (int)(pSValuePointer-pReadBuff), SEEK_SET );
+						write( fd, pNewValueString, strlen(pNewValueString));
+					} else {
+						/*
+						 * insert with new length value string
+						 */
+						wfc_util_fupdate_string(fd, &pReadBuff, pETagPointer, pSValuePointer, pNewValueString);
+					}
+				} else {
+					wfc_util_log_error("wfc_util_fset_string : can not find End TAG");
+				}
+			} else {
+				/*
+				 * "\n""[Start TAG][String Value][End TAG]""\n"
+				 */
+				sz_NewValueBuff = strlen(pSTagString) +
+				                  strlen(pNewValueString) +
+				                  strlen(pETagString) +
+				                  2 + 1;
+				pNewValueBuff = malloc( sz_NewValueBuff);
+
+				if( NULL != pNewValueBuff ) {
+					/*
+					 * prefare the new string to insert
+					 */
+					memset( pNewValueBuff, 0, sz_NewValueBuff );
+					sprintf( pNewValueBuff, "%c%s%s%s%c", '\n', pSTagString, pNewValueString, pETagString,'\n' );
+
+					/*
+					 * insert new string to the file
+					 */
+					wfc_util_finsert_new_string(fd, &pReadBuff, pNewValueBuff, pEndOfCfg);
+
+					free( pNewValueBuff );
+				} else {
+					wfc_util_log_error("wfc_util_fset_string : can not malloc(%d)", (int)sz_file);
+				}
+			}
+
+			free(pReadBuff);
+		} else {
+			wfc_util_log_error("wfc_util_fset_string : can not malloc(%d)", (int)sz_file);
+		}
+
+		if ( -1 == fsync( fd ) ) {
+			wfc_util_log_error("wfc_util_fset_string : fail to fsync()");
+		}
+
+		close( fd );
+	} else {
+		wfc_util_log_error("wfc_util_fset_string : can not open file");
+	}
+
+	return;
+}
+
+/*
+ * wfc_util_fget_string
+ *
+ * Read value from the following format string in the file pFileName.
+ * [pSTagString][string value to read][pETagString]
+ *
+ * pFileName        : file name and path
+ * pEndOfCfg        : tag string to notify the end of configuration file
+ * pSTagString      : tag string to notify purpose of the value
+ * pETagString      : tag string to notify the end of the value
+ * pValueStringBuff : string buffer to get string value
+ * stringBuffLength : the length of pValueStringBuff
+ *
+ * return : it will return the length of the stored string value if procedure is success
+ *          or will return 0 if not.
+ */
+int wfc_util_fget_string(char *pFileName, char *pEndOfCfg __attribute__((unused)), char *pSTagString,
+			 char *pETagString, char *pValueStringBuff, int stringBuffLength)
+{
+	int result = 0;
+	int fd;
+	off_t sz_file;
+	char *pReadBuff = NULL;
+	char *pSPointer = NULL, *pETagPointer = NULL, *pSValuePointer = NULL;
+
+	fd = open( pFileName, O_RDONLY );
+
+	if( fd >= 0 ) {
+		/*
+		 * calcurate file size
+		 */
+		sz_file  = lseek( fd,  0, SEEK_END );
+
+		/*
+		 * prefare the buffer to read file
+		 */
+		if (sz_file > 0)		// skip when value is 0
+			pReadBuff = malloc(sz_file + 1);
+
+		if( NULL != pReadBuff ) {
+			/*
+			 * read file
+			 */
+			memset( pReadBuff, 0, sz_file + 1);
+			if(lseek(fd, 0, SEEK_SET) != 0) {
+				wfc_util_log_error("lseek failure");
+			}
+			read( fd, pReadBuff, sz_file );
+
+			/* WBT fix, make sure it is terminated with \0 */
+			pReadBuff[sz_file] = '\0';
+
+			/*
+			 * find TAG string
+			 */
+			pSPointer = strstr( pReadBuff, pSTagString );
+
+			if( NULL != pSPointer ) {
+				/*
+				 * find END OF LINE string
+				 */
+				pETagPointer = strstr(pSPointer, pETagString);
+
+				if( NULL != pETagPointer ) {
+					/*
+					 * read the string value
+					 */
+					pSValuePointer = pSPointer+strlen(pSTagString);
+					if( stringBuffLength >= (int)(pETagPointer-pSValuePointer) ) {
+						memset( pValueStringBuff, 0, stringBuffLength );
+						memcpy( pValueStringBuff, pSValuePointer, (int)(pETagPointer-pSValuePointer) );
+						result = (int)(pETagPointer-pSValuePointer);
+					} else {
+						wfc_util_log_error("wfc_util_fget_string : not enough string value buffer(%d)", (int)(pETagPointer-pSValuePointer));
+					}
+				} else {
+					wfc_util_log_error("wfc_util_fget_string : can not find End TAG");
+				}
+			} else {
+				wfc_util_log_error("wfc_util_fget_string : can not find Start TAG");
+			}
+			free(pReadBuff);
+		} else {
+			wfc_util_log_error("wfc_util_fget_string : can not malloc(%d)", (int)sz_file);
+		}
+		close( fd );
+	} else {
+		wfc_util_log_error("wfc_util_fget_string : can not open file");
+	}
+
+	return result;
+}
+
+/*
+ * wfc_util_ffile_check
+ *
+ * check whether pDestFName file exist or not
+ *
+ * pFileName   : file name and path
+ * access_mode : R_OK | W_OK | X_OK | F_OK
+ *
+ * return : it will return 0 if the file exist
+ *          or will return -1 if not.
+ */
+int wfc_util_ffile_check(char *pDestFName, int access_mode)
+{
+	struct stat st;
+
+	if (access(pDestFName, access_mode) == 0) {
+		if( stat( pDestFName, &st ) < 0 ) {
+			wfc_util_log_error("Cannot stat the file \"%s\": %s", pDestFName, strerror(errno));
+			return -1;
+		}
+		//check if config file has some data or is it empty due to previous errors
+		if( st.st_size ) {
+			return 0;
+		}
+	} else {
+		wfc_util_log_error("Cannot access \"%s\": %s", pDestFName, strerror(errno));
+	}
+
+	return -1;
+}
+
+/*
+ * wfc_util_ffile_check_copy
+ *
+ * check whether pDestFName file exist if not it will copy from pSourceFName file
+ *
+ * return : it will return 0 if procedure is success
+ *          or will return -1 if not.
+ */
+int wfc_util_ffile_check_copy(char *pDestFName, char *pSourceFName, mode_t mode, uid_t uID, gid_t gID)
+{
+#define WFC_BUFFER_SIZE 2048
+	char buf[WFC_BUFFER_SIZE] = {0}; // Null terminated
+	int srcfd, destfd;
+	int nread;
+	struct stat st;
+
+	if (access(pDestFName, R_OK|W_OK) == 0) {
+		if( stat( pDestFName, &st ) < 0 ) {
+			wfc_util_log_error("Cannot stat the file \"%s\": %s", pDestFName, strerror(errno));
+			return -1;
+		}
+		//check if config file has some data or is it empty due to previous errors
+		if( st.st_size ) {
+			return 0;
+		}
+	//else continue to write the config from default template.
+	} else if (errno != ENOENT) {
+		wfc_util_log_error("Cannot access \"%s\": %s", pDestFName, strerror(errno));
+		return -1;
+	}
+
+	srcfd = open(pSourceFName, O_RDONLY);
+	if (srcfd < 0) {
+		wfc_util_log_error("Cannot open \"%s\": %s", pSourceFName, strerror(errno));
+		return -1;
+	}
+
+	destfd = open(pDestFName, O_CREAT|O_WRONLY, mode);
+	if (destfd < 0) {
+		close(srcfd);
+		wfc_util_log_error("Cannot create \"%s\": %s", pDestFName, strerror(errno));
+		return -1;
+	}
+
+	while ((nread = read(srcfd, buf, WFC_BUFFER_SIZE-1)) != 0) {
+		if (nread < 0) {
+			wfc_util_log_error("Error reading \"%s\": %s", pSourceFName, strerror(errno));
+			close(srcfd);
+			close(destfd);
+			unlink(pDestFName);
+			return -1;
+		}
+		// WBT fix, according to manual, the number of bytes read can't be bigger than read_size. I don't know why WBT complains for this.
+		if (nread < WFC_BUFFER_SIZE)
+			buf[nread] = '\0';
+		else {
+			buf[WFC_BUFFER_SIZE-1] = '\0';
+			nread = WFC_BUFFER_SIZE-1;
+		}
+		write(destfd, buf, nread);
+	}
+
+	close(destfd);
+	close(srcfd);
+
+	/* remove this code because of permission problem when it is accessed from "atd" having system permission. */
+	{
+	#ifndef CONFIG_LGE_WLAN_WIFI_PATCH
+	uid_t uid = getuid();
+	gid_t gid = getgid();
+	wfc_util_log_error("Error changing group ownership (%d) of %s to %d: %s", gid, pDestFName, gID, strerror(errno));
+	if (0 == uid) {
+	#endif /* CONFIG_LGE_WLAN_WIFI_PATCH */
+		if (chown(pDestFName, uID, gID) < 0) {
+			wfc_util_log_error("Error changing group ownership of %s to %d: %s", pDestFName, gID, strerror(errno));
+			unlink(pDestFName);
+			return -1;
+		}
+	#ifndef CONFIG_LGE_WLAN_WIFI_PATCH
+	} else {
+		wfc_util_log_error("wfc_util_ffile_check_copy : we can not excute chown[uid = %d, gid = %d]", uid, getgid());
+	}
+	#endif /* CONFIG_LGE_WLAN_WIFI_PATCH */
+	}
+
+	return 0;
+}
+
diff --git a/wifi/qcom/wfc_util_fctrl.h b/wifi/qcom/wfc_util_fctrl.h
new file mode 100644
index 0000000..5c49899
--- /dev/null
+++ b/wifi/qcom/wfc_util_fctrl.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WFC_UTIL_FCTRL_H__
+#define __WFC_UTIL_FCTRL_H__
+
+/*
+ * wfc_util_fset_buffer
+ *
+ * return : void
+ */
+void wfc_util_fset_buffer(char *pFileName, int positionStart, unsigned char *pNewValue, int newValueLength);
+
+/*
+ * wfc_util_fget_buffer
+ *
+ * return : it will return the length of the stored buffer value if procedure is success
+ *          or will return 0 if not.
+ */
+extern int wfc_util_fget_buffer(char *pFileName, int positionStart, int lengthToRead, unsigned char *pValueBuff, int buffLength);
+
+/*
+ * wfc_util_fset_string
+ *
+ * The following format string will be added or updated to the file pFileName.
+ * [pSTagString][pNewValueString][pETagString]
+ *
+ * pFileName       : file name and path
+ * pEndOfCfg       : tag string to notify the end of configuration file
+ * pSTagString     : tag string to notify purpose of the value
+ * pETagString     : tag string to notify the end of the value
+ * pNewValueString : string to set for pSTagString
+ *
+ * return : void
+ */
+extern void wfc_util_fset_string(char *pFileName, char *pEndOfCfg, char *pSTagString, char *pETagString, char *pNewValueString);
+
+/*
+ * wfc_util_fget_string
+ *
+ * Read value from the following format string in the file pFileName.
+ * [pSTagString][string value to read][pETagString]
+ *
+ * pFileName        : file name and path
+ * pEndOfCfg        : tag string to notify the end of configuration file
+ * pSTagString      : tag string to notify purpose of the value
+ * pETagString      : tag string to notify the end of the value
+ * pValueStringBuff : string buffer to get string value
+ * stringBuffLength : the length of pValueStringBuff
+ *
+ * return : it will return the length of the stored string value if procedure is success
+ *          or will return 0 if not.
+ */
+extern int wfc_util_fget_string(char *pFileName, char *pEndOfCfg, char *pSTagString, char *pETagString, char *pValueStringBuff, int stringBuffLength);
+
+/*
+ * wfc_util_ffile_check
+ *
+ * check whether pDestFName file exist or not
+ *
+ * pFileName   : file name and path
+ * access_mode : R_OK | W_OK | X_OK | F_OK
+ *
+ * return : it will return 0 if the file exist
+ *          or will return -1 if not.
+ */
+extern int wfc_util_ffile_check(char *pDestFName, int access_mode);
+
+/*
+ * wfc_util_ffile_check_copy
+ *
+ * check whether pDestFName file exist if not it will copy from pSourceFName file
+ *
+ * return : it will return 0 if procedure is success
+ *          or will return -1 if not.
+ */
+extern int wfc_util_ffile_check_copy(char *pDestFName, char *pSourceFName, mode_t mode,  uid_t uID, gid_t gID);
+
+#endif
diff --git a/wifi/qcom/wfc_util_log.h b/wifi/qcom/wfc_util_log.h
new file mode 100644
index 0000000..fcc4239
--- /dev/null
+++ b/wifi/qcom/wfc_util_log.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WFC_UTIL_LOG_H__
+#define __WFC_UTIL_LOG_H__
+
+#ifdef ANDROID
+#define LOG_TAG "WifiUtil"
+#include <cutils/log.h>
+
+#define wfc_util_log_info(...)  ALOGI(__VA_ARGS__)
+#define wfc_util_log_error(...) ALOGE(__VA_ARGS__)
+#else  /* ANDROID */
+#define wfc_util_log_info(...)  printf(__VA_ARGS__);printf("\n")
+#define wfc_util_log_error(...) printf(__VA_ARGS__);printf("\n")
+#endif /* ANDROID */
+
+#endif
+
diff --git a/wifi/qcom/wfc_util_main.c b/wifi/qcom/wfc_util_main.c
new file mode 100644
index 0000000..01e1c86
--- /dev/null
+++ b/wifi/qcom/wfc_util_main.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include "wfc_util_fctrl.h"
+#include "wfc_util_common.h"
+
+#ifdef WLAN_CHIP_VERSION_WCNSS
+#ifndef WFC_UTIL_CFG_FILE_NAME
+#define WFC_UTIL_CFG_FILE_NAME          "./WCNSS_qcom_cfg.ini"
+#endif
+#ifndef WFC_UTIL_NV_BIN_FILE_NAME
+#define WFC_UTIL_NV_BIN_FILE_NAME       "./WCNSS_qcom_wlan_nv.bin"
+#endif
+#else  /* WLAN_CHIP_VERSION_WCN1314 */
+#ifndef WFC_UTIL_CFG_FILE_NAME
+#define WFC_UTIL_CFG_FILE_NAME          "./WCN1314_qcom_cfg.ini"
+#endif
+#ifndef WFC_UTIL_NV_BIN_FILE_NAME
+#define WFC_UTIL_NV_BIN_FILE_NAME       "./WCN1314_qcom_wlan_nv.bin"
+#endif
+#endif /* WLAN_CHIP_VERSION_XXXX */
+#define WFC_UTIL_CFG_TAG_END_OF_CFG     "END"
+#define WFC_UTIL_CFG_TAG_MAC_ADDRESS    "NetworkAddress="
+#define WFC_UTIL_CFG_TAG_AP_MAC_ADDRESS "gAPMacAddr="
+#define WFC_UTIL_CFG_TAG_END_OF_LINE    "\n"
+#define WFC_UTIL_CFG_LENGHT_MAC         (6)
+#define WFC_UTIL_CFG_LENGHT_MAC_STRING  (WFC_UTIL_CFG_LENGHT_MAC*2)
+
+/*
+ * persist/WCNSS_qcom_wlan_nv.bin
+ *
+ * typedef PACKED_PRE struct PACKED_POST
+ * {
+ *     //always ensure fields are aligned to 32-bit boundaries
+ *     tANI_U16  productId;
+ *     tANI_U8   productBands;
+ *     tANI_U8   wlanNvRevId;
+ *
+ *     tANI_U8   numOfTxChains;
+ *     tANI_U8   numOfRxChains;
+ *     tANI_U8   macAddr[NV_FIELD_MAC_ADDR_SIZE];
+ *     tANI_U8   mfgSN[NV_FIELD_MFG_SN_SIZE];
+ * } sNvFields;
+ */
+#define WFC_UTIL_NV_BIN_HEADER_LENGTH    (4)
+#define WFC_UTIL_NV_BIN_POS_PRODUCT_ID   (WFC_UTIL_NV_BIN_HEADER_LENGTH + 0)
+#define WFC_UTIL_NV_BIN_POS_PRODUCT_BAND (WFC_UTIL_NV_BIN_HEADER_LENGTH + 2)
+#define WFC_UTIL_NV_BIN_POS_MAC_ADDR     (WFC_UTIL_NV_BIN_HEADER_LENGTH + 6)
+
+int main(int argc, char **argv)
+{
+	int ret = 0;
+	char mac_add_buff[WFC_UTIL_CFG_LENGHT_MAC_STRING+1];
+	unsigned char mac_add_buff_2[WFC_UTIL_CFG_LENGHT_MAC] = {0x88, 0xcd, 0xba, 0x0c, 0x90, 0x00};
+	unsigned char mac_add_buff_3[WFC_UTIL_CFG_LENGHT_MAC] = {0x00, 0x90, 0x0c, 0xba, 0xcd, 0x88};
+
+	printf("wfc_util_main is started\n");
+
+	if(0 < wfc_util_fget_string(WFC_UTIL_CFG_FILE_NAME,
+	                            WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                            WFC_UTIL_CFG_TAG_MAC_ADDRESS,
+	                            WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                            mac_add_buff,
+	                            WFC_UTIL_CFG_LENGHT_MAC_STRING+1)) {
+		printf("wfc_util_main : %s%s\n", WFC_UTIL_CFG_TAG_MAC_ADDRESS, mac_add_buff);
+	} else {
+		printf("wfc_util_main : %s is not found\n", WFC_UTIL_CFG_TAG_MAC_ADDRESS);
+	}
+
+	wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+	                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                     WFC_UTIL_CFG_TAG_AP_MAC_ADDRESS,
+	                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                     "00900cbacd88");
+
+	wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+	                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                     WFC_UTIL_CFG_TAG_MAC_ADDRESS,
+	                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                     "00900cbacd88");
+
+	if(0 < wfc_util_fget_string(WFC_UTIL_CFG_FILE_NAME,
+	                            WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                            WFC_UTIL_CFG_TAG_MAC_ADDRESS,
+	                            WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                            mac_add_buff,
+	                            WFC_UTIL_CFG_LENGHT_MAC_STRING+1)) {
+		printf("wfc_util_main : %s%s\n", WFC_UTIL_CFG_TAG_MAC_ADDRESS, mac_add_buff);
+
+		wfc_util_atoh(mac_add_buff, strlen(mac_add_buff), mac_add_buff_2, WFC_UTIL_CFG_LENGHT_MAC);
+		printf("wfc_util_main : %s%02x:%02x:%02x:%02x:%02x:%02x\n",
+		                        WFC_UTIL_CFG_TAG_MAC_ADDRESS,
+		                        mac_add_buff_2[0], mac_add_buff_2[1], mac_add_buff_2[2],
+		                        mac_add_buff_2[3], mac_add_buff_2[4], mac_add_buff_2[5]);
+
+		wfc_util_htoa(mac_add_buff_2, WFC_UTIL_CFG_LENGHT_MAC, mac_add_buff, WFC_UTIL_CFG_LENGHT_MAC_STRING);
+		printf("wfc_util_main : %s%s\n", WFC_UTIL_CFG_TAG_MAC_ADDRESS, mac_add_buff);
+
+	} else {
+		printf("wfc_util_main : %s is not found\n", WFC_UTIL_CFG_TAG_MAC_ADDRESS);
+	}
+
+	wfc_util_fset_buffer(WFC_UTIL_NV_BIN_FILE_NAME,
+	                     WFC_UTIL_NV_BIN_POS_MAC_ADDR,
+	                     mac_add_buff_3,
+	                     WFC_UTIL_CFG_LENGHT_MAC);
+
+	if(0 < wfc_util_fget_buffer(WFC_UTIL_NV_BIN_FILE_NAME,
+	                            WFC_UTIL_NV_BIN_POS_MAC_ADDR,
+	                            6,
+	                            mac_add_buff_2,
+	                            WFC_UTIL_CFG_LENGHT_MAC)) {
+		printf("wfc_util_main : wfc_util_fget_buffer[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+		                        mac_add_buff_2[0], mac_add_buff_2[1], mac_add_buff_2[2],
+		                        mac_add_buff_2[3], mac_add_buff_2[4], mac_add_buff_2[5]);
+	} else {
+		printf("wfc_util_main : %s is not found\n", WFC_UTIL_CFG_TAG_MAC_ADDRESS);
+	}
+
+	return ret;
+}
+
diff --git a/wifi/qcom/wfc_util_qcom.c b/wifi/qcom/wfc_util_qcom.c
new file mode 100644
index 0000000..8508893
--- /dev/null
+++ b/wifi/qcom/wfc_util_qcom.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef CONFIG_LGE_WLAN_QCOM_PATCH
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "wfc_util_log.h"
+#include "wfc_util_fctrl.h"
+#include "wfc_util_common.h"
+
+#include "cutils/properties.h"
+
+#include "private/android_filesystem_config.h"
+
+#define WFC_UTIL_FEAUTRE_COPY_NV_BIN
+
+#ifdef WLAN_CHIP_VERSION_WCNSS
+#ifndef WFC_UTIL_CFG_FILE_NAME
+#define WFC_UTIL_CFG_FILE_NAME          "/data/misc/wifi/WCNSS_qcom_cfg.ini"
+#endif
+#ifndef WFC_UTIL_CFG_TEMPFILE_NAME
+#define WFC_UTIL_CFG_TEMPFILE_NAME      "/system/etc/wifi/WCNSS_qcom_cfg.ini"
+#endif
+#else  /* WLAN_CHIP_VERSION_WCN1314 */
+#ifndef WFC_UTIL_CFG_FILE_NAME
+#define WFC_UTIL_CFG_FILE_NAME          "/data/misc/wifi/WCN1314_qcom_cfg.ini"
+#endif
+#ifndef WFC_UTIL_CFG_TEMPFILE_NAME
+#define WFC_UTIL_CFG_TEMPFILE_NAME      "/system/etc/wifi/WCN1314_qcom_cfg.ini"
+#endif
+#endif /* WLAN_CHIP_VERSION_XXXX */
+
+#ifdef WFC_UTIL_FEAUTRE_COPY_NV_BIN
+#ifdef WLAN_CHIP_VERSION_WCNSS
+#ifndef WFC_UTIL_NV_BIN_TEMPFILE_NAME
+#define WFC_UTIL_NV_BIN_TEMPFILE_NAME   "/system/etc/wifi/WCNSS_qcom_wlan_nv.bin"
+#endif
+#ifndef WFC_UTIL_NV_BIN_FILE_NAME
+#define WFC_UTIL_NV_BIN_FILE_NAME       "/data/misc/wifi/WCNSS_qcom_wlan_nv.bin"
+#endif
+#else  /* WLAN_CHIP_VERSION_WCN1314 */
+#ifndef WFC_UTIL_NV_BIN_TEMPFILE_NAME
+#define WFC_UTIL_NV_BIN_TEMPFILE_NAME   "/persist/WCN1314_qcom_wlan_nv.bin"
+#endif
+#ifndef WFC_UTIL_NV_BIN_FILE_NAME
+#define WFC_UTIL_NV_BIN_FILE_NAME       "/data/misc/wifi/WCN1314_qcom_wlan_nv.bin"
+#endif
+#endif /* WLAN_CHIP_VERSION_XXXX */
+#else  /* WFC_UTIL_FEAUTRE_COPY_NV_BIN */
+#ifndef WFC_UTIL_NV_BIN_FILE_NAME
+#ifdef WLAN_CHIP_VERSION_WCNSS
+#define WFC_UTIL_NV_BIN_FILE_NAME       "/persist/WCNSS_qcom_wlan_nv.bin"
+#else  /* WLAN_CHIP_VERSION_WCN1314 */
+#define WFC_UTIL_NV_BIN_FILE_NAME       "/persist/WCN1314_qcom_wlan_nv.bin"
+#endif /* WLAN_CHIP_VERSION_XXXX */
+#endif
+#endif /* WFC_UTIL_FEAUTRE_COPY_NV_BIN */
+
+#define WFC_UTIL_CFG_TAG_END_OF_CFG     "END"
+/*
+ * Station Mode MAC Address
+ */
+#ifdef WLAN_CHIP_VERSION_WCNSS
+#define WFC_UTIL_CFG_TAG_MAC_ADDRESS    "Intf0MacAddress="
+#else  /* WLAN_CHIP_VERSION_WCN1314 */
+#define WFC_UTIL_CFG_TAG_MAC_ADDRESS    "NetworkAddress="
+#endif /* WLAN_CHIP_VERSION_XXXX */
+/*
+ * AP Mode MAC Address
+ */
+#define WFC_UTIL_CFG_TAG_AP_MAC_ADDRESS "gAPMacAddr="
+
+/*
+ * Idle Mode Power Save enable/disable for OTA test
+ */
+#define WFC_UTIL_CFG_TAG_IDLE_MODE_POWER_SAVE "gEnableImps="
+
+/*
+ * Beacon Mode Power Save enable/disable for OTA test
+ */
+#define WFC_UTIL_CFG_TAG_POWER_SAVE "gEnableBmps="
+
+/*
+ * L2 roaming on/off for OTA test
+ */
+#define WFC_UTIL_CFG_TAG_L2Roaming "gEnableHandoff="
+
+/*
+ * Heartbeat24 changing for OtA test
+ */
+#define WFC_UTIL_CFG_TAG_HEARTBEAT24 "gHeartbeat24="
+
+/*
+ * TAG for end of line
+ */
+#define WFC_UTIL_CFG_TAG_END_OF_LINE    "\n"
+
+#define WFC_UTIL_CFG_LENGHT_MAC         (6)
+#define WFC_UTIL_CFG_LENGHT_MAC_STRING  (WFC_UTIL_CFG_LENGHT_MAC*2)
+
+/*
+ * persist/WCNSS_qcom_wlan_nv.bin
+ *
+ * NV validity bitmap (4 bytes)
+ * {
+ *     Bit 0 - Regulatory domain tables
+ *     Bit 1 - Fields(including product ID, product bands, number of Tx/Rx chains, MAC address, manufacturing board number)
+ *     Bit 2 - Optimal power per rate table
+ *     Bit 3 - Default regulatory domain and country code
+ *     Bit 4:31 - Reserved; always 0
+ * }
+ *
+ * typedef PACKED_PRE struct PACKED_POST
+ * {
+ *     //always ensure fields are aligned to 32-bit boundaries
+ *     tANI_U16  productId;
+ *     tANI_U8   productBands;        //0: 0.4 GHz, 1: 2.4+5.0 GHz, 2: 5.0 GHz
+ *     tANI_U8   wlanNvRevId;         //0: WCN1312, 1: WCN1314, 2: PRIMA
+ *
+ *     tANI_U8   numOfTxChains;
+ *     tANI_U8   numOfRxChains;
+ *     tANI_U8   macAddr[NV_FIELD_MAC_ADDR_SIZE];
+ *     tANI_U8   mfgSN[NV_FIELD_MFG_SN_SIZE];
+ * } sNvFields;
+ */
+#define WFC_UTIL_NV_BIN_HEADER_LENGTH   (4)
+#define WFC_UTIL_NV_BIN_POS_PRODUCT_ID  (WFC_UTIL_NV_BIN_HEADER_LENGTH + 0)
+#define WFC_UTIL_NV_BIN_POS_MAC_ADDR    (WFC_UTIL_NV_BIN_HEADER_LENGTH + 6)
+
+#ifdef WLAN_CHIP_VERSION_WCNSS
+/* refer to prima/CORE/WDA/src/wlan_nv.c */
+static unsigned char nvFilelds_default[6] = {0, 0, /* productId */
+                                             1,    /* productBands */
+                                             2,    /* wlanNvRevId */
+                                             1,    /* numOfTxChains */
+                                             2};   /* numOfRxChains */
+#else  /* WLAN_CHIP_VERSION_WCN1314 */
+static unsigned char nvFilelds_default[6] = {1, 0, /* productId */
+                                             1,    /* productBands */
+                                             1,    /* wlanNvRevId */
+                                             1,    /* numOfTxChains */
+                                             1};   /* numOfRxChains */
+#endif /* WLAN_CHIP_VERSION_XXXX */
+
+/*
+ * wfc_util_qcom_is_default_mac
+ *
+ *
+ *
+ * return : it will return 1 if mac_add is default mac address,
+ *          2 if mac_add is RFT mac address
+ *          or 0 if not.
+ */
+static int wfc_util_qcom_is_default_mac(char *mac_add)
+{
+#define WFC_UTIL_CFG_DEFAULT_MAC_RFT     "00900CBACD88"
+#define WFC_UTIL_CFG_DEFAULT_MAC_00      "000000000000"
+#define WFC_UTIL_CFG_DEFAULT_MAC_FF      "FFFFFFFFFFFF"
+#define WFC_UTIL_CFG_DEFAULT_MAC_QCOM_I0 "000AF58989FF"
+#define WFC_UTIL_CFG_DEFAULT_MAC_QCOM_I1 "000AF58989FE"
+#define WFC_UTIL_CFG_DEFAULT_MAC_QCOM_I2 "000AF58989FD"
+#define WFC_UTIL_CFG_DEFAULT_MAC_QCOM_I3 "000AF58989FC"
+#define WFC_UTIL_CFG_DEFAULT_MAC_QCOM_AP "000AF58989EF"
+
+	int i, sZarray=0;
+	/*
+	 * default mac address array
+	 */
+	char mac_add_buff[][WFC_UTIL_CFG_LENGHT_MAC_STRING+1] = {
+			{WFC_UTIL_CFG_DEFAULT_MAC_00},
+			{WFC_UTIL_CFG_DEFAULT_MAC_FF},
+			{WFC_UTIL_CFG_DEFAULT_MAC_QCOM_I0}
+	};
+
+	sZarray = sizeof(mac_add_buff) / sizeof(mac_add_buff[0]);
+
+	for(i=0; i<sZarray ;i++) {
+		if(0 == strncmp(mac_add, mac_add_buff[i], WFC_UTIL_CFG_LENGHT_MAC_STRING)) {
+			wfc_util_log_error("This is default MAC address [%s]", mac_add_buff[i]);
+			return 1;
+		}
+	}
+
+	/*
+	if(1 == wfc_util_is_random_mac(mac_add)) {
+		wfc_util_log_error("This is Random MAC address");
+		return 1;
+	}
+	*/
+
+	if(0 == strncmp(mac_add, WFC_UTIL_CFG_DEFAULT_MAC_RFT, WFC_UTIL_CFG_LENGHT_MAC_STRING)) {
+		wfc_util_log_error("This is RFT MAC address [%s]", WFC_UTIL_CFG_DEFAULT_MAC_RFT);
+		return 2;
+	}
+
+	return 0;
+}
+
+static void wfc_util_qcom_write_mac(char *mac_add)
+{
+	/*
+	 * Station Mode MAC Address
+	 */
+	wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+	                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                     WFC_UTIL_CFG_TAG_MAC_ADDRESS,
+	                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                     mac_add);
+
+	/*
+	 * AP Mode MAC Address
+	 */
+	wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+	                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                     WFC_UTIL_CFG_TAG_AP_MAC_ADDRESS,
+	                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                     mac_add);
+
+	return;
+}
+
+/*
+ *  When OTA is enabled, power save mode and L2 roaming trigger should be off
+ */
+static void wfc_util_qcom_write_ota_enable(void)
+{
+/*
+ * write Beacon Mode Power Save off and L2 Roaming off
+ */
+	char *PowerSaveOff = "0";
+	//char *L2RoamingOff = "0";
+	char *Heartbeat24 = "120";
+
+	char string_buff[5];
+
+	wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+	                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                     WFC_UTIL_CFG_TAG_IDLE_MODE_POWER_SAVE,
+	                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                     PowerSaveOff);
+
+	wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+	                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                     WFC_UTIL_CFG_TAG_POWER_SAVE,
+	                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                     PowerSaveOff);
+
+/* We don't need to change this becasue the default value of WFC_UTIL_CFG_TAG_L2Roaming is 0.
+	wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+	                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                     WFC_UTIL_CFG_TAG_L2Roaming,
+	                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                     L2RoamingOff);
+*/
+
+	if(0 < wfc_util_fget_string(WFC_UTIL_CFG_FILE_NAME,
+	                            WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                            WFC_UTIL_CFG_TAG_HEARTBEAT24,
+	                            WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                            string_buff,
+	                            5)) {
+		wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+		                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+		                     WFC_UTIL_CFG_TAG_HEARTBEAT24,
+		                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+		                     Heartbeat24);
+	} else {
+		wfc_util_log_error("%s is not exist", WFC_UTIL_CFG_TAG_HEARTBEAT24);
+	}
+
+	return;
+}
+
+/*
+ *  When OTA is enabled, power save mode and L2 roaming trigger should be off
+ */
+static void wfc_util_qcom_write_ota_disable(void)
+{
+/*
+ * write Beacon Mode Power Save on and L2 Roaming on
+ */
+	char *PowerSaveOff = "1";
+	//char *L2RoamingOff = "1";
+	char *Heartbeat24 = "40";
+
+	char string_buff[5];
+
+	wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+	                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                     WFC_UTIL_CFG_TAG_IDLE_MODE_POWER_SAVE,
+	                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                     PowerSaveOff);
+
+	wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+	                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                     WFC_UTIL_CFG_TAG_POWER_SAVE,
+	                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                     PowerSaveOff);
+
+/* We don't need to change this becasue the default value of WFC_UTIL_CFG_TAG_L2Roaming is 0.
+	wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+	                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                     WFC_UTIL_CFG_TAG_L2Roaming,
+	                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                     L2RoamingOff);
+*/
+
+	if(0 < wfc_util_fget_string(WFC_UTIL_CFG_FILE_NAME,
+	                            WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                            WFC_UTIL_CFG_TAG_HEARTBEAT24,
+	                            WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                            string_buff,
+	                            5)) {
+		wfc_util_fset_string(WFC_UTIL_CFG_FILE_NAME,
+		                     WFC_UTIL_CFG_TAG_END_OF_CFG,
+		                     WFC_UTIL_CFG_TAG_HEARTBEAT24,
+		                     WFC_UTIL_CFG_TAG_END_OF_LINE,
+		                     Heartbeat24);
+	} else {
+		wfc_util_log_error("%s is not exist", WFC_UTIL_CFG_TAG_HEARTBEAT24);
+	}
+
+	return;
+}
+
+static void wfc_util_qcom_write_mac_to_bin(unsigned char *mac_add)
+{
+	unsigned char nvValidityBitmap[WFC_UTIL_NV_BIN_HEADER_LENGTH];
+
+	if(0 != wfc_util_ffile_check(WFC_UTIL_NV_BIN_FILE_NAME,
+	                             F_OK|R_OK|W_OK)) {
+		wfc_util_log_error("We don't access file [%s]", WFC_UTIL_NV_BIN_FILE_NAME);
+		return;
+	}
+
+	memset(nvValidityBitmap, 0, WFC_UTIL_NV_BIN_HEADER_LENGTH);
+
+	/*
+	 * Write RFT MAC Address
+	 */
+	wfc_util_fset_buffer(WFC_UTIL_NV_BIN_FILE_NAME,
+	                     WFC_UTIL_NV_BIN_POS_MAC_ADDR,
+	                     mac_add,
+	                     WFC_UTIL_CFG_LENGHT_MAC);
+
+	/*
+	 * Read NV validity bitmap
+	 */
+	if (0 < wfc_util_fget_buffer(WFC_UTIL_NV_BIN_FILE_NAME,
+	                             0,
+	                             WFC_UTIL_NV_BIN_HEADER_LENGTH,
+	                             nvValidityBitmap,
+	                             WFC_UTIL_NV_BIN_HEADER_LENGTH)){
+	        /*
+	         * Check whether Fields bit(Bit 1) is set
+	         */
+		if (0x02 & nvValidityBitmap[0]) {
+			wfc_util_log_info("We don't need to write the default value for NvFilelds");
+		} else {
+		        /*
+		         * Update the Fields bit(Bit 1)
+		         */
+			nvValidityBitmap[0] |= 0x02;
+			wfc_util_fset_buffer(WFC_UTIL_NV_BIN_FILE_NAME,
+			                     0,
+			                     nvValidityBitmap,
+			                     WFC_UTIL_NV_BIN_HEADER_LENGTH);
+
+		        /*
+		         * Write the default value for NvFilelds
+		         */
+			wfc_util_fset_buffer(WFC_UTIL_NV_BIN_FILE_NAME,
+			                     WFC_UTIL_NV_BIN_POS_PRODUCT_ID,
+			                     nvFilelds_default,
+			                     6);
+		}
+	} else {
+		wfc_util_log_error("Read Fail nvValidityBitmap");
+	}
+
+	return;
+}
+
+/*
+ * wfc_util_qcom_reset_mac_to_bin
+ *
+ * reset the mac address of nv bin file
+ *
+ * return : void
+ */
+static void wfc_util_qcom_reset_mac_to_bin(void)
+{
+	unsigned char mac_addr[WFC_UTIL_CFG_LENGHT_MAC];
+
+	if(0 != wfc_util_ffile_check(WFC_UTIL_NV_BIN_FILE_NAME,
+	                             F_OK|R_OK|W_OK)) {
+		wfc_util_log_error("We don't access file [%s]", WFC_UTIL_NV_BIN_FILE_NAME);
+		return;
+	}
+
+	if(0 < wfc_util_fget_buffer(WFC_UTIL_NV_BIN_FILE_NAME,
+	                            WFC_UTIL_NV_BIN_POS_MAC_ADDR,
+	                            WFC_UTIL_CFG_LENGHT_MAC,
+	                            mac_addr,
+	                            WFC_UTIL_CFG_LENGHT_MAC)) {
+		if(0x00 == mac_addr[0] && 0x00 == mac_addr[1] && 0x00 == mac_addr[2] &&
+		   0x00 == mac_addr[3] && 0x00 == mac_addr[4] && 0x00 == mac_addr[5])
+		{
+			return;
+		}
+	}
+
+	memset(mac_addr, 0, WFC_UTIL_CFG_LENGHT_MAC);
+
+	wfc_util_fset_buffer(WFC_UTIL_NV_BIN_FILE_NAME,
+	                     WFC_UTIL_NV_BIN_POS_MAC_ADDR,
+	                     mac_addr,
+	                     WFC_UTIL_CFG_LENGHT_MAC);
+
+	return;
+}
+
+static int wfc_util_qcom_write_mac_process(unsigned char *nv_mac_addr, char *mac_add_buff)
+{
+	char nv_mac_add_buff[WFC_UTIL_CFG_LENGHT_MAC_STRING+1];
+	int  is_default_nv_mac = 0;
+	int  is_same_mac = -1;
+
+	if (NULL == nv_mac_addr) {
+		return 0;
+	}
+
+	wfc_util_htoa(nv_mac_addr, WFC_UTIL_CFG_LENGHT_MAC,
+	              nv_mac_add_buff, WFC_UTIL_CFG_LENGHT_MAC_STRING+1);
+
+	is_default_nv_mac = wfc_util_qcom_is_default_mac(nv_mac_add_buff);
+
+	is_same_mac = strncmp(mac_add_buff, nv_mac_add_buff, WFC_UTIL_CFG_LENGHT_MAC_STRING);
+
+	/*
+	 * 1. nv mac address is not a default mac address
+	 * 2. same with mac address of config file
+	 */
+	if (((!is_default_nv_mac) && (0==is_same_mac)) ||
+	/*
+	 * 1. nv mac address is RFT mac address
+	 * 2. same with mac address of config file
+	 */
+	    ((2==is_default_nv_mac) && (0==is_same_mac))
+	   ) {
+		return 1;
+	}
+	/*
+	 * 1. nv mac address not a default mac address excepting RFT mac address
+	 * 2. does not same with mac address of config file
+	 */
+	else if ((1!=is_default_nv_mac) && (0!=is_same_mac)) {
+		wfc_util_log_error("Change %s%s", WFC_UTIL_CFG_TAG_MAC_ADDRESS, nv_mac_add_buff);
+		/*
+		 * Update MAC address
+		 */
+		wfc_util_qcom_write_mac(nv_mac_add_buff);
+
+#ifdef WFC_UTIL_FEATURE_DO_NOT_WRITE_MAC_TO_BIN
+		/*
+		 * Write RFT MAC address to nv.bin
+		 */
+		if (2==is_default_nv_mac) {
+			wfc_util_qcom_write_mac_to_bin(nv_mac_addr);
+		/*
+		 * reset mac address of nv.bin if nv_mac_addr is not RFT mac address
+		 */
+		} else {
+			wfc_util_qcom_reset_mac_to_bin();
+		}
+#else  /* WFC_UTIL_FEATURE_DO_NOT_WRITE_MAC_TO_BIN */
+		/*
+		 * Write MAC address to nv.bin
+		 */
+		wfc_util_qcom_write_mac_to_bin(nv_mac_addr);
+#endif /* WFC_UTIL_FEATURE_DO_NOT_WRITE_MAC_TO_BIN */
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static void wfc_util_qcom_create_random_mac(void)
+{
+	unsigned char random_mac_addr[WFC_UTIL_CFG_LENGHT_MAC];
+	char mac_add_buff[WFC_UTIL_CFG_LENGHT_MAC_STRING+1];
+
+	wfc_util_log_info("wfc_util_qcom_create_random_mac");
+
+	wfc_util_random_mac(random_mac_addr);
+
+	wfc_util_htoa(random_mac_addr, WFC_UTIL_CFG_LENGHT_MAC, mac_add_buff, WFC_UTIL_CFG_LENGHT_MAC_STRING+1);
+
+	wfc_util_qcom_write_mac(mac_add_buff);
+
+#ifdef WFC_UTIL_FEATURE_DO_NOT_WRITE_MAC_TO_BIN
+	wfc_util_qcom_reset_mac_to_bin();
+#else  /* WFC_UTIL_FEATURE_DO_NOT_WRITE_MAC_TO_BIN */
+	wfc_util_qcom_write_mac_to_bin(random_mac_addr);
+#endif /* WFC_UTIL_FEATURE_DO_NOT_WRITE_MAC_TO_BIN */
+
+	return;
+}
+
+/*
+ * wfc_util_qcom_check_config
+ *
+ * check the qcom wlan driver config file
+ *
+ * return : it will return 0 if procedure is success
+ *          or will return -1 if not.
+ */
+int wfc_util_qcom_check_config(unsigned char *nv_mac_addr)
+{
+	char mac_add_buff[WFC_UTIL_CFG_LENGHT_MAC_STRING+1];
+
+	/* make sure driver config file exists */
+	if(0 > wfc_util_ffile_check_copy(WFC_UTIL_CFG_FILE_NAME,
+	                             WFC_UTIL_CFG_TEMPFILE_NAME,
+	                             0660,
+	                             AID_SYSTEM,
+	                             /* we use "radio" for gid to access from "rild" for AT cmd. */
+	                             AID_WIFI/*AID_WIFI*/)) {
+		wfc_util_log_error("Fail to Access [%s]", WFC_UTIL_CFG_FILE_NAME);
+		return -1;
+	}
+
+#ifdef WFC_UTIL_FEAUTRE_COPY_NV_BIN
+	char nv_bin_tempfile_name[50];
+	char baseband[PROPERTY_VALUE_MAX];
+
+	// Default use WCNSS_qcom_wlan_nv_flo.bin
+	property_get("ro.boot.baseband", baseband, "apq");
+	if(!strncmp(baseband, "apq", 3)) {
+		sprintf(nv_bin_tempfile_name, "/system/etc/wifi/WCNSS_qcom_wlan_nv_flo.bin");
+	} else if( !strncmp(baseband, "mdm", 3)){
+		sprintf(nv_bin_tempfile_name, "/system/etc/wifi/WCNSS_qcom_wlan_nv_deb.bin");
+	}
+	wfc_util_log_error("nv bin : %s", nv_bin_tempfile_name);
+
+	if(0 > wfc_util_ffile_check_copy(WFC_UTIL_NV_BIN_FILE_NAME,
+	                             nv_bin_tempfile_name,
+	                             0660,
+	                             AID_SYSTEM,
+	                             /* we use "radio" for gid to access from "rild" for AT cmd. */
+	                             AID_WIFI/*AID_WIFI*/)) {
+		wfc_util_log_error("Fail to Access [%s]", WFC_UTIL_NV_BIN_FILE_NAME);
+		return -1;
+	}
+#endif /* WFC_UTIL_FEAUTRE_COPY_NV_BIN */
+
+	/*
+	 * Read MAC address from config file
+	 */
+	if(0 < wfc_util_fget_string(WFC_UTIL_CFG_FILE_NAME,
+	                        WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                        WFC_UTIL_CFG_TAG_MAC_ADDRESS,
+	                        WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                        mac_add_buff,
+	                        WFC_UTIL_CFG_LENGHT_MAC_STRING+1)) {
+		wfc_util_log_info("%s%s", WFC_UTIL_CFG_TAG_MAC_ADDRESS, mac_add_buff);
+
+		/*
+		 * Write nv mac address
+		 */
+		if (1 != wfc_util_qcom_write_mac_process(nv_mac_addr, mac_add_buff)) {
+			/*
+			 * Check whether this is default mac address or not
+			 */
+			if (wfc_util_qcom_is_default_mac(mac_add_buff)) {
+				/*
+				 * Create random MAC address
+				 */
+				wfc_util_qcom_create_random_mac();
+			}
+		}
+	} else {
+		wfc_util_log_error("%s does not have mac address", WFC_UTIL_CFG_FILE_NAME);
+
+		memset( mac_add_buff, 0, WFC_UTIL_CFG_LENGHT_MAC_STRING+1 );
+
+		/*
+		 * Write nv mac address
+		 */
+		if (1 != wfc_util_qcom_write_mac_process(nv_mac_addr, mac_add_buff)) {
+			/*
+			 * Create random MAC address
+			 */
+			wfc_util_qcom_create_random_mac();
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * wfc_util_qcom_reset_mac
+ *
+ * reset the mac address of config file
+ *
+ * return : void
+ */
+void wfc_util_qcom_reset_mac(void)
+{
+	wfc_util_qcom_write_mac("000000000000");
+
+	wfc_util_qcom_reset_mac_to_bin();
+
+	return;
+}
+
+/*
+ * wfc_util_qcom_ota_enable
+ *
+ * enable ota mode by reconfiguring BMPS and L2Roaming
+ *
+ * return : int (boolean)
+ */
+int wfc_util_qcom_ota_enable(void)
+{
+	wfc_util_qcom_write_ota_enable();
+	return 1;
+}
+
+/*
+ * wfc_util_qcom_ota_disable
+ *
+ * disable ota mode by reconfiguring BMPS and L2Roaming
+ *
+ * return : int (boolean)
+ */
+int wfc_util_qcom_ota_disable(void)
+{
+	wfc_util_qcom_write_ota_disable();
+	return 1;
+}
+
+/*
+ * wfc_util_qcom_checkt_roaming_off
+ *
+ * Check L2Roaming configuration
+ *
+ * return : int (boolean)
+ */
+int wfc_util_qcom_checkt_roaming_off(void)
+{
+	char string_buff[5];
+	/*
+	 * check whether OTA test is enabled or not.
+	 */
+	if(0 < wfc_util_fget_string(WFC_UTIL_CFG_FILE_NAME,
+	                            WFC_UTIL_CFG_TAG_END_OF_CFG,
+	                            //WFC_UTIL_CFG_TAG_L2Roaming,
+	                            WFC_UTIL_CFG_TAG_POWER_SAVE,
+	                            WFC_UTIL_CFG_TAG_END_OF_LINE,
+	                            string_buff,
+	                            5)) {
+		//wfc_util_log_info("%s%s", WFC_UTIL_CFG_TAG_L2Roaming, string_buff);
+		wfc_util_log_info("%s%s", WFC_UTIL_CFG_TAG_POWER_SAVE, string_buff);
+		if(0 == strncmp(string_buff, "0", 1)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+#endif /* CONFIG_LGE_WLAN_QCOM_PATCH */
+
diff --git a/wifi/qcom/wfc_util_qcom.h b/wifi/qcom/wfc_util_qcom.h
new file mode 100644
index 0000000..1bd4cc1
--- /dev/null
+++ b/wifi/qcom/wfc_util_qcom.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WFC_UTIL_QCOM_H__
+#define __WFC_UTIL_QCOM_H__
+
+#ifdef CONFIG_LGE_WLAN_QCOM_PATCH
+/*
+ * wfc_util_qcom_check_config
+ *
+ * check the qcom wlan driver config file
+ *
+ * return : it will return 0 if procedure is success
+ *          or will return -1 if not.
+ */
+extern int wfc_util_qcom_check_config(unsigned char *nv_mac_addr);
+
+/*
+ * wfc_util_qcom_reset_mac
+ *
+ * reset the mac address of config file
+ *
+ * return : void
+ */
+extern void wfc_util_qcom_reset_mac(void);
+
+/*
+ * wfc_util_qcom_ota_enable/disable
+ *
+ * enable OTA mode for Wi-Fi related certificiation
+ *
+ * return : int (boolean)
+ */
+extern int wfc_util_qcom_ota_enable(void);
+extern int wfc_util_qcom_ota_disable(void);
+extern int wfc_util_qcom_checkt_roaming_off(void);
+#endif /* CONFIG_LGE_WLAN_QCOM_PATCH */
+#endif
+
