[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/connectivity/combo_tool/6631_combo_tool/Android.mk b/src/connectivity/combo_tool/6631_combo_tool/Android.mk
new file mode 100644
index 0000000..a4b9e6d
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/Android.mk
@@ -0,0 +1,56 @@
+# Copyright Statement:
+#
+# This software/firmware and related documentation ("MediaTek Software") are
+# protected under relevant copyright laws. The information contained herein
+# is confidential and proprietary to MediaTek Inc. and/or its licensors.
+# Without the prior written permission of MediaTek inc. and/or its licensors,
+# any reproduction, modification, use or disclosure of MediaTek Software,
+# and information contained herein, in whole or in part, shall be strictly prohibited.
+#
+# MediaTek Inc. (C) 2010. All rights reserved.
+#
+# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+#
+# The following software/firmware and/or related documentation ("MediaTek Software")
+# have been modified by MediaTek Inc. All revisions are subject to any receiver's
+# applicable license agreements with MediaTek Inc.
+
+
+# Copyright (C) 2008 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.
+
+ifeq ($(MTK_COMBO_SUPPORT), yes)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
+endif
diff --git a/src/connectivity/combo_tool/6631_combo_tool/LICENSE b/src/connectivity/combo_tool/6631_combo_tool/LICENSE
new file mode 100644
index 0000000..77f59ed
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:
+
+This software/firmware and related documentation ("MediaTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+the prior written permission of MediaTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MediaTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MediaTek Inc. (C) 2015. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
diff --git a/src/connectivity/combo_tool/6631_combo_tool/Makefile.am b/src/connectivity/combo_tool/6631_combo_tool/Makefile.am
new file mode 100644
index 0000000..16d341a
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/Makefile.am
@@ -0,0 +1,16 @@
+bin_PROGRAMS = wmt_loader wmt_launcher wmt_loopback wmt_concurrency stp_dump3
+wmt_loader_SOURCES = combo_loader/yocto_loader.c
+wmt_loopback_SOURCES = src/wmt_loopback.c
+wmt_launcher_SOURCES = src/yocto_stp_uart_launcher.c
+wmt_launcher_LDADD = -lpthread
+
+power_on_wifi_SOURCES = src/power_on_wifi.c
+
+wmt_concurrency_SOURCES = src/yocto_wmt_concurrency.c
+
+stp_dump3_SOURCES = src/stp_dump/os_linux.c \
+                   src/stp_dump/eloop.c \
+                   src/stp_dump/stp_dump.c \
+                   src/stp_dump/bt_fw_logger.c \
+                   src/stp_dump/wifi_fw_logger.c
+stp_dump3_LDADD = -lpthread
\ No newline at end of file
diff --git a/src/connectivity/combo_tool/6631_combo_tool/README b/src/connectivity/combo_tool/6631_combo_tool/README
new file mode 100644
index 0000000..d4b3313
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/README
@@ -0,0 +1,22 @@
+This module serves the common part driver of connectivity
+
+WHAT IT DOES?
+=============
+This module creates some executable binary files for loading/configuring/testing 
+the common part driver, in addition, it installs the Firmware patch and common part 
+cfg files into device.
+
+HOW IT WAS BUILT?
+==================
+It needs the following library from AOSP:
+
+libcutils, libc
+
+HOW TO USE IT?
+==============
+The firmware patch and common part cfg file was installed into device directly when build.
+And the executable binary files will be started in init.rc when boot. they will work together
+to load/configure the common part driver of connectivity
+
+The majority of source code was written by MediaTek. Some code from open source codes are used.
+more detail info, pls ref the NOTICE under the specific sub folder.
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT.cfg
new file mode 100644
index 0000000..71c7ba1
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT.cfg
@@ -0,0 +1,4 @@
+mt6620.defAnt=mt6620_ant_m3.cfg
+mt6628.defAnt=mt6628_ant_m1.cfg
+mt6630.defAnt=mt6630_ant_m1.cfg
+mt6632.defAnt=mt6632_ant_m1.cfg
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_SOC.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_SOC.cfg
new file mode 100644
index 0000000..79cd55f
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_SOC.cfg
@@ -0,0 +1,7 @@
+coex_wmt_ant_mode=1
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+co_clock_flag=0
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_CONNAC.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_CONNAC.cfg
new file mode 100644
index 0000000..f9f6aa6
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_CONNAC.cfg
@@ -0,0 +1,340 @@
+// Action                                      | symbol | Param1                | Param2                  | Param3        | Param4                | Param5
+// Read EMI                                    | _EMI   | R(0)                  | Begin offset            | End offset
+// Read EMI to temp register                   | _EMI   | R(0)                  | offset                  | Temp Reg ID($)
+// Read EMI to temp register                   | _EMI   | R(0)                  | offset                  | mask          | Temp Reg ID ($)
+// Read CR                                     | _REG   | R(0)                  | Pre-define base-addr ID | offset        | times                 | delay time(ms)
+// Read CR                                     | _REG   | R(0)                  | AP Physical address     | offset        | times                 | delay time(ms)
+// Read CR to temp register                    | _REG   | R(0)                  | Pre-define base-addr ID | offset        | Temp Reg ID($)
+// Read CR to temp register                    | _REG   | R(0)                  | AP Physical address     | offset        | Temp Reg ID($)
+// Read CR to temp register                    | _REG   | R(0)                  | Pre-define base-addr ID | offset        | mask                  | Temp Reg ID($)
+// Read CR to temp register                    | _REG   | R(0)                  | AP Physical address     | offset        | mask                  | Temp Reg ID($)
+// Write CR                                    | _REG   | W(1)                  | Pre-define base-addr ID | offset        | value
+// Write CR                                    | _REG   | W(1)                  | AP Physical address     | offset        | value
+// Write CR some bit                           | _REG   | W(1)                  | Pre-define base-addr ID | offset        | value                 | mask
+// Write CR some bit                           | _REG   | W(1)                  | AP Physical address     | offset        | value                 | mask
+// Read GPIO                                   | GPIO   | R(0)                  | Pin number
+// Disable reset                               | DRST
+// Chip reset                                  | _RST
+// Keep Wakeup Connsys                         | WAK+
+// Cancel keep Wakeup                          | WAK-
+// Show message                                | SHOW   | String(No space)
+// Sleep                                       | _SLP   | time(ms)
+// Check condition to result temp register     | COND   | Result Temp Reg ID($) | Left Temp Reg ID($)     | Operator      | Right Temp Reg ID($)
+// Check condition to result temp register     | COND   | Result Temp Reg ID($) | Left Temp Reg ID($)     | Operator      | Value(Dec or Hex)
+// Save value to temp register                 | _VAL   | Temp Reg ID($)        | Value
+//
+// Condition Action                            | symbol | Param1                   | Param2 | Param3                  | Param4         | Param5          | Param6
+// Read EMI with Condition                     | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | End offset
+// Read EMI to temp register with Condition    | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | Temp Reg ID($)
+// Read EMI to temp register with Condition    | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | mask           | Temp Reg ID($)
+// Read CR with Condition                      | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | times           | delay time(ms)
+// Read CR with Condition                      | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | times           | delay time(ms)
+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | Temp Reg ID($)
+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | Temp Reg ID($)
+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | mask            | Temp Reg ID($)
+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | mask            | Temp Reg ID($)
+// Write CR with Condition                     | CREG   | Condition Temp Reg ID($) | W(1)   | Pre-define base-addr ID | offset         | value
+// Write CR with Condition                     | CREG   | Condition Temp Reg ID($) | W(1)   | AP Physical address     | offset         | value
+// Write CR some bit with Condition            | CREG   | Condition Temp Reg ID($) | W(1)   | Pre-define base-addr ID | offset         | value           | mask
+// Write CR some bit with Condition            | CREG   | Condition Temp Reg ID($) | W(1)   | AP Physical address     | offset         | value           | mask
+//
+// Periodic dump: Add PD in trigger point
+// [TP x] Trigger point
+// [PD+] ms
+//  [AT] xxxx
+//  [AT] xxxx
+// [PD-]
+//
+// Temp Reg ID: ($0 ~ $9)
+//
+// Operator: ==, !=, >, >=, <, <=, &&, ||
+//
+// Pre-define base-addr ID: (You can find address and size in DTS file)
+// #1 => CONN_MCU_CONFIG_BASE
+// #2 => AP_RGU_BASE
+// #3 => TOPCKGEN_BASE
+// #4 => SPM_BASE
+// #5 => CONN_HIF_ON_BASE
+// #6 => CONN_TOP_MISC_OFF_BASE
+// #7 => CONN_MCU_CFG_ON_BASE
+// #8 => CONN_MCU_CIRQ_BASE
+
+[TP 1] When Command timeout
+    // Host_CSR
+    [AT] _REG 0 #5 0x100 1 0
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 0 #5 0x108 1 0
+    [AT] _REG 0 #5 0x10c 1 0
+    [AT] _REG 0 #5 0x110 1 0
+    [AT] _REG 0 #5 0x114 1 0
+    [AT] _REG 0 #5 0x118 1 0
+    [AT] _REG 0 #5 0x11c 1 0
+    [AT] _REG 0 #5 0x120 1 0
+    [AT] _REG 0 #5 0x124 1 0
+    [AT] _REG 0 #5 0x128 1 0
+    [AT] _REG 0 #5 0x12c 1 0
+    [AT] _REG 0 #5 0x130 1 0
+
+    // PC log from Host_CSR
+    [AT] _REG 1 #5 0x14 0xff000380
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000382
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000384
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000386
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000388
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00038a
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00038c
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00038e
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000390
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000392
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000394
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000396
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000398
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00039a
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00039c
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00039e
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003a0
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003a2
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003a4
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003a6
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003a8
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003aa
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003ac
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003ae
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003b0
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003b2
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003b4
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003b6
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003b8
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003ba
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003bc
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003be
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003c0
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003c2
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003c4
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003c6
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003c8
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003ca
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003cc
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003ce
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003d0
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003fe
+
+    // Bus timeout debug
+    [AT] _REG 0 0x10000000 0x0000 1 0
+    [AT] _REG 0 0x10000000 0x0200 1 0
+    [AT] _REG 0 0x10000000 0x6408 1 0
+    [AT] _REG 0 0x10000000 0x640c 1 0
+    [AT] _REG 0 0x10000000 0x644c 1 0
+    [AT] _REG 0 0x1020e000 0x02c 1 0
+    [AT] _REG 0 0x1020e000 0x180 1 0
+    [AT] _REG 0 0x1020e000 0x184 1 0
+    [AT] _REG 0 0x1020e000 0x188 1 0
+    [AT] _REG 0 0x1020e000 0x18c 1 0
+    [AT] _REG 0 #3 0x220 1 0
+    [AT] _REG 0 #3 0x224 1 0
+    [AT] _REG 0 #3 0x228 1 0
+    [AT] _REG 0 #3 0x250 1 0
+    [AT] _REG 0 #3 0x254 1 0
+    [AT] _REG 0 #3 0x258 1 0
+
+[TP 2] When Firmware trigger assert
+
+[TP 3] Before Chip reset
+    // Host_CSR
+    [AT] _REG 0 #5 0x100 1 0
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 0 #5 0x108 1 0
+    [AT] _REG 0 #5 0x10c 1 0
+    [AT] _REG 0 #5 0x110 1 0
+    [AT] _REG 0 #5 0x114 1 0
+    [AT] _REG 0 #5 0x118 1 0
+    [AT] _REG 0 #5 0x11c 1 0
+    [AT] _REG 0 #5 0x120 1 0
+    [AT] _REG 0 #5 0x124 1 0
+    [AT] _REG 0 #5 0x128 1 0
+    [AT] _REG 0 #5 0x12c 1 0
+    [AT] _REG 0 #5 0x130 1 0
+
+    // PC log from Host_CSR
+    [AT] _REG 1 #5 0x14 0xff000380
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000382
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000384
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000386
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000388
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00038a
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00038c
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00038e
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000390
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000392
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000394
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000396
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff000398
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00039a
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00039c
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff00039e
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003a0
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003a2
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003a4
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003a6
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003a8
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003aa
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003ac
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003ae
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003b0
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003b2
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003b4
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003b6
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003b8
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003ba
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003bc
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003be
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003c0
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003c2
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003c4
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003c6
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003c8
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003ca
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003cc
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003ce
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003d0
+    [AT] _REG 0 #5 0x104 1 0
+    [AT] _REG 1 #5 0x14 0xff0003fe
+
+    // Bus timeout debug
+    [AT] _REG 0 0x10000000 0x0000 1 0
+    [AT] _REG 0 0x10000000 0x0200 1 0
+    [AT] _REG 0 0x10000000 0x6408 1 0
+    [AT] _REG 0 0x10000000 0x640c 1 0
+    [AT] _REG 0 0x10000000 0x644c 1 0
+    [AT] _REG 0 0x1020e000 0x02c 1 0
+    [AT] _REG 0 0x1020e000 0x180 1 0
+    [AT] _REG 0 0x1020e000 0x184 1 0
+    [AT] _REG 0 0x1020e000 0x188 1 0
+    [AT] _REG 0 0x1020e000 0x18c 1 0
+    [AT] _REG 0 #3 0x220 1 0
+    [AT] _REG 0 #3 0x224 1 0
+    [AT] _REG 0 #3 0x228 1 0
+    [AT] _REG 0 #3 0x250 1 0
+    [AT] _REG 0 #3 0x254 1 0
+    [AT] _REG 0 #3 0x258 1 0
+
+[TP 4] After Chip reset
+
+[TP 5] Before Wifi function on
+
+[TP 6] Before Wifi function off
+
+[TP 7] Before BT function on
+
+[TP 8] Before BT function off
+
+[TP 9] Before FM function on
+
+[TP 10] Before FM function off
+
+[TP 11] Before GPS function on
+
+[TP 12] Before GPS function off
+
+[TP 13] Before read consys thermal
+
+[TP 14] Power on sequence(0): Start power on
+
+[TP 15] Power on sequence(1): Before can get connsys id
+
+[TP 16] Power on sequence(2): Before send download patch
+
+[TP 17] Power on sequence(3): Before connsys reset (donwload patch)
+
+[TP 18] Power on sequence(4): Before set wifi and lte coex
+
+[TP 19] Power on sequence(5): Before set BT and Wifi calibration
+
+[TP 20] Power on sequence(6): End power on
+
+[TP 21] Before WMT power off
+
+[TP 22] When AP suspend
+
+[TP 23] When AP resume
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_GEN2.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_GEN2.cfg
new file mode 100644
index 0000000..bd9b47f
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_GEN2.cfg
@@ -0,0 +1,102 @@
+// Action                                      | symbol | Param1                | Param2                  | Param3        | Param4                | Param5

+// Read EMI                                    | _EMI   | R(0)                  | Begin offset            | End offset

+// Read EMI to temp register                   | _EMI   | R(0)                  | offset                  | Temp Reg ID($)

+// Read EMI to temp register                   | _EMI   | R(0)                  | offset                  | mask          | Temp Reg ID ($)

+// Read CR                                     | _REG   | R(0)                  | Pre-define base-addr ID | offset        | times                 | delay time(ms)

+// Read CR                                     | _REG   | R(0)                  | AP Physical address     | offset        | times                 | delay time(ms)

+// Read CR to temp register                    | _REG   | R(0)                  | Pre-define base-addr ID | offset        | Temp Reg ID($)

+// Read CR to temp register                    | _REG   | R(0)                  | AP Physical address     | offset        | Temp Reg ID($)

+// Read CR to temp register                    | _REG   | R(0)                  | Pre-define base-addr ID | offset        | mask                  | Temp Reg ID($)

+// Read CR to temp register                    | _REG   | R(0)                  | AP Physical address     | offset        | mask                  | Temp Reg ID($)

+// Write CR                                    | _REG   | W(1)                  | Pre-define base-addr ID | offset        | value

+// Write CR                                    | _REG   | W(1)                  | AP Physical address     | offset        | value

+// Write CR some bit                           | _REG   | W(1)                  | Pre-define base-addr ID | offset        | value                 | mask

+// Write CR some bit                           | _REG   | W(1)                  | AP Physical address     | offset        | value                 | mask

+// Read GPIO                                   | GPIO   | R(0)                  | Pin number

+// Disable reset                               | DRST

+// Chip reset                                  | _RST

+// Keep Wakeup Connsys                         | WAK+

+// Cancel keep Wakeup                          | WAK-

+// Show message                                | SHOW   | String(No space)

+// Sleep                                       | _SLP   | time(ms)

+// Check condition to result temp register     | COND   | Result Temp Reg ID($) | Left Temp Reg ID($)     | Operator      | Right Temp Reg ID($)

+// Check condition to result temp register     | COND   | Result Temp Reg ID($) | Left Temp Reg ID($)     | Operator      | Value(Dec or Hex)

+// Save value to temp register                 | _VAL   | Temp Reg ID($)        | Value

+//

+// Condition Action                            | symbol | Param1                   | Param2 | Param3                  | Param4         | Param5          | Param6

+// Read EMI with Condition                     | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | End offset

+// Read EMI to temp register with Condition    | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | Temp Reg ID($)

+// Read EMI to temp register with Condition    | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | mask           | Temp Reg ID($)

+// Read CR with Condition                      | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | times           | delay time(ms)

+// Read CR with Condition                      | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | times           | delay time(ms)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | Temp Reg ID($)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | Temp Reg ID($)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | mask            | Temp Reg ID($)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | mask            | Temp Reg ID($)

+// Write CR with Condition                     | CREG   | Condition Temp Reg ID($) | W(1)   | Pre-define base-addr ID | offset         | value

+// Write CR with Condition                     | CREG   | Condition Temp Reg ID($) | W(1)   | AP Physical address     | offset         | value

+// Write CR some bit with Condition            | CREG   | Condition Temp Reg ID($) | W(1)   | Pre-define base-addr ID | offset         | value           | mask

+// Write CR some bit with Condition            | CREG   | Condition Temp Reg ID($) | W(1)   | AP Physical address     | offset         | value           | mask

+//

+// Periodic dump: Add PD in trigger point

+// [TP x] Trigger point

+// [PD+] ms

+//  [AT] xxxx

+//  [AT] xxxx

+// [PD-]

+//

+// Temp Reg ID: ($0 ~ $9)

+//

+// Operator: ==, !=, >, >=, <, <=, &&, ||

+//

+// Pre-define base-addr ID: (You can find address and size in DTS file)

+// #1 => CONN_MCU_CONFIG_BASE

+// #2 => AP_RGU_BASE

+// #3 => TOPCKGEN_BASE

+// #4 => SPM_BASE

+

+[TP 1] When Command timeout

+

+[TP 2] When Firmware trigger assert

+

+[TP 3] Before Chip reset

+

+[TP 4] After Chip reset

+

+[TP 5] Before Wifi function on

+

+[TP 6] Before Wifi function off

+

+[TP 7] Before BT function on

+

+[TP 8] Before BT function off

+

+[TP 9] Before FM function on

+

+[TP 10] Before FM function off

+

+[TP 11] Before GPS function on

+

+[TP 12] Before GPS function off

+

+[TP 13] Before read consys thermal

+

+[TP 14] Power on sequence(0): Start power on

+

+[TP 15] Power on sequence(1): Before can get connsys id

+

+[TP 16] Power on sequence(2): Before send download patch

+

+[TP 17] Power on sequence(3): Before connsys reset (donwload patch)

+

+[TP 18] Power on sequence(4): Before set wifi and lte coex

+

+[TP 19] Power on sequence(5): Before set BT and Wifi calibration

+

+[TP 20] Power on sequence(6): End power on

+

+[TP 21] Before WMT power off

+

+[TP 22] When AP suspend

+

+[TP 23] When AP resume

diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_GEN3.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_GEN3.cfg
new file mode 100644
index 0000000..bd9b47f
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_GEN3.cfg
@@ -0,0 +1,102 @@
+// Action                                      | symbol | Param1                | Param2                  | Param3        | Param4                | Param5

+// Read EMI                                    | _EMI   | R(0)                  | Begin offset            | End offset

+// Read EMI to temp register                   | _EMI   | R(0)                  | offset                  | Temp Reg ID($)

+// Read EMI to temp register                   | _EMI   | R(0)                  | offset                  | mask          | Temp Reg ID ($)

+// Read CR                                     | _REG   | R(0)                  | Pre-define base-addr ID | offset        | times                 | delay time(ms)

+// Read CR                                     | _REG   | R(0)                  | AP Physical address     | offset        | times                 | delay time(ms)

+// Read CR to temp register                    | _REG   | R(0)                  | Pre-define base-addr ID | offset        | Temp Reg ID($)

+// Read CR to temp register                    | _REG   | R(0)                  | AP Physical address     | offset        | Temp Reg ID($)

+// Read CR to temp register                    | _REG   | R(0)                  | Pre-define base-addr ID | offset        | mask                  | Temp Reg ID($)

+// Read CR to temp register                    | _REG   | R(0)                  | AP Physical address     | offset        | mask                  | Temp Reg ID($)

+// Write CR                                    | _REG   | W(1)                  | Pre-define base-addr ID | offset        | value

+// Write CR                                    | _REG   | W(1)                  | AP Physical address     | offset        | value

+// Write CR some bit                           | _REG   | W(1)                  | Pre-define base-addr ID | offset        | value                 | mask

+// Write CR some bit                           | _REG   | W(1)                  | AP Physical address     | offset        | value                 | mask

+// Read GPIO                                   | GPIO   | R(0)                  | Pin number

+// Disable reset                               | DRST

+// Chip reset                                  | _RST

+// Keep Wakeup Connsys                         | WAK+

+// Cancel keep Wakeup                          | WAK-

+// Show message                                | SHOW   | String(No space)

+// Sleep                                       | _SLP   | time(ms)

+// Check condition to result temp register     | COND   | Result Temp Reg ID($) | Left Temp Reg ID($)     | Operator      | Right Temp Reg ID($)

+// Check condition to result temp register     | COND   | Result Temp Reg ID($) | Left Temp Reg ID($)     | Operator      | Value(Dec or Hex)

+// Save value to temp register                 | _VAL   | Temp Reg ID($)        | Value

+//

+// Condition Action                            | symbol | Param1                   | Param2 | Param3                  | Param4         | Param5          | Param6

+// Read EMI with Condition                     | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | End offset

+// Read EMI to temp register with Condition    | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | Temp Reg ID($)

+// Read EMI to temp register with Condition    | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | mask           | Temp Reg ID($)

+// Read CR with Condition                      | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | times           | delay time(ms)

+// Read CR with Condition                      | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | times           | delay time(ms)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | Temp Reg ID($)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | Temp Reg ID($)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | mask            | Temp Reg ID($)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | mask            | Temp Reg ID($)

+// Write CR with Condition                     | CREG   | Condition Temp Reg ID($) | W(1)   | Pre-define base-addr ID | offset         | value

+// Write CR with Condition                     | CREG   | Condition Temp Reg ID($) | W(1)   | AP Physical address     | offset         | value

+// Write CR some bit with Condition            | CREG   | Condition Temp Reg ID($) | W(1)   | Pre-define base-addr ID | offset         | value           | mask

+// Write CR some bit with Condition            | CREG   | Condition Temp Reg ID($) | W(1)   | AP Physical address     | offset         | value           | mask

+//

+// Periodic dump: Add PD in trigger point

+// [TP x] Trigger point

+// [PD+] ms

+//  [AT] xxxx

+//  [AT] xxxx

+// [PD-]

+//

+// Temp Reg ID: ($0 ~ $9)

+//

+// Operator: ==, !=, >, >=, <, <=, &&, ||

+//

+// Pre-define base-addr ID: (You can find address and size in DTS file)

+// #1 => CONN_MCU_CONFIG_BASE

+// #2 => AP_RGU_BASE

+// #3 => TOPCKGEN_BASE

+// #4 => SPM_BASE

+

+[TP 1] When Command timeout

+

+[TP 2] When Firmware trigger assert

+

+[TP 3] Before Chip reset

+

+[TP 4] After Chip reset

+

+[TP 5] Before Wifi function on

+

+[TP 6] Before Wifi function off

+

+[TP 7] Before BT function on

+

+[TP 8] Before BT function off

+

+[TP 9] Before FM function on

+

+[TP 10] Before FM function off

+

+[TP 11] Before GPS function on

+

+[TP 12] Before GPS function off

+

+[TP 13] Before read consys thermal

+

+[TP 14] Power on sequence(0): Start power on

+

+[TP 15] Power on sequence(1): Before can get connsys id

+

+[TP 16] Power on sequence(2): Before send download patch

+

+[TP 17] Power on sequence(3): Before connsys reset (donwload patch)

+

+[TP 18] Power on sequence(4): Before set wifi and lte coex

+

+[TP 19] Power on sequence(5): Before set BT and Wifi calibration

+

+[TP 20] Power on sequence(6): End power on

+

+[TP 21] Before WMT power off

+

+[TP 22] When AP suspend

+

+[TP 23] When AP resume

diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_GEN3_5.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_GEN3_5.cfg
new file mode 100644
index 0000000..bd9b47f
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/WMT_STEP_GEN3_5.cfg
@@ -0,0 +1,102 @@
+// Action                                      | symbol | Param1                | Param2                  | Param3        | Param4                | Param5

+// Read EMI                                    | _EMI   | R(0)                  | Begin offset            | End offset

+// Read EMI to temp register                   | _EMI   | R(0)                  | offset                  | Temp Reg ID($)

+// Read EMI to temp register                   | _EMI   | R(0)                  | offset                  | mask          | Temp Reg ID ($)

+// Read CR                                     | _REG   | R(0)                  | Pre-define base-addr ID | offset        | times                 | delay time(ms)

+// Read CR                                     | _REG   | R(0)                  | AP Physical address     | offset        | times                 | delay time(ms)

+// Read CR to temp register                    | _REG   | R(0)                  | Pre-define base-addr ID | offset        | Temp Reg ID($)

+// Read CR to temp register                    | _REG   | R(0)                  | AP Physical address     | offset        | Temp Reg ID($)

+// Read CR to temp register                    | _REG   | R(0)                  | Pre-define base-addr ID | offset        | mask                  | Temp Reg ID($)

+// Read CR to temp register                    | _REG   | R(0)                  | AP Physical address     | offset        | mask                  | Temp Reg ID($)

+// Write CR                                    | _REG   | W(1)                  | Pre-define base-addr ID | offset        | value

+// Write CR                                    | _REG   | W(1)                  | AP Physical address     | offset        | value

+// Write CR some bit                           | _REG   | W(1)                  | Pre-define base-addr ID | offset        | value                 | mask

+// Write CR some bit                           | _REG   | W(1)                  | AP Physical address     | offset        | value                 | mask

+// Read GPIO                                   | GPIO   | R(0)                  | Pin number

+// Disable reset                               | DRST

+// Chip reset                                  | _RST

+// Keep Wakeup Connsys                         | WAK+

+// Cancel keep Wakeup                          | WAK-

+// Show message                                | SHOW   | String(No space)

+// Sleep                                       | _SLP   | time(ms)

+// Check condition to result temp register     | COND   | Result Temp Reg ID($) | Left Temp Reg ID($)     | Operator      | Right Temp Reg ID($)

+// Check condition to result temp register     | COND   | Result Temp Reg ID($) | Left Temp Reg ID($)     | Operator      | Value(Dec or Hex)

+// Save value to temp register                 | _VAL   | Temp Reg ID($)        | Value

+//

+// Condition Action                            | symbol | Param1                   | Param2 | Param3                  | Param4         | Param5          | Param6

+// Read EMI with Condition                     | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | End offset

+// Read EMI to temp register with Condition    | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | Temp Reg ID($)

+// Read EMI to temp register with Condition    | CEMI   | Condition Temp Reg ID($) | R(0)   | Begin offset            | mask           | Temp Reg ID($)

+// Read CR with Condition                      | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | times           | delay time(ms)

+// Read CR with Condition                      | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | times           | delay time(ms)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | Temp Reg ID($)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | Temp Reg ID($)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | Pre-define base-addr ID | offset         | mask            | Temp Reg ID($)

+// Read CR to temp register with Condition     | CREG   | Condition Temp Reg ID($) | R(0)   | AP Physical address     | offset         | mask            | Temp Reg ID($)

+// Write CR with Condition                     | CREG   | Condition Temp Reg ID($) | W(1)   | Pre-define base-addr ID | offset         | value

+// Write CR with Condition                     | CREG   | Condition Temp Reg ID($) | W(1)   | AP Physical address     | offset         | value

+// Write CR some bit with Condition            | CREG   | Condition Temp Reg ID($) | W(1)   | Pre-define base-addr ID | offset         | value           | mask

+// Write CR some bit with Condition            | CREG   | Condition Temp Reg ID($) | W(1)   | AP Physical address     | offset         | value           | mask

+//

+// Periodic dump: Add PD in trigger point

+// [TP x] Trigger point

+// [PD+] ms

+//  [AT] xxxx

+//  [AT] xxxx

+// [PD-]

+//

+// Temp Reg ID: ($0 ~ $9)

+//

+// Operator: ==, !=, >, >=, <, <=, &&, ||

+//

+// Pre-define base-addr ID: (You can find address and size in DTS file)

+// #1 => CONN_MCU_CONFIG_BASE

+// #2 => AP_RGU_BASE

+// #3 => TOPCKGEN_BASE

+// #4 => SPM_BASE

+

+[TP 1] When Command timeout

+

+[TP 2] When Firmware trigger assert

+

+[TP 3] Before Chip reset

+

+[TP 4] After Chip reset

+

+[TP 5] Before Wifi function on

+

+[TP 6] Before Wifi function off

+

+[TP 7] Before BT function on

+

+[TP 8] Before BT function off

+

+[TP 9] Before FM function on

+

+[TP 10] Before FM function off

+

+[TP 11] Before GPS function on

+

+[TP 12] Before GPS function off

+

+[TP 13] Before read consys thermal

+

+[TP 14] Power on sequence(0): Start power on

+

+[TP 15] Power on sequence(1): Before can get connsys id

+

+[TP 16] Power on sequence(2): Before send download patch

+

+[TP 17] Power on sequence(3): Before connsys reset (donwload patch)

+

+[TP 18] Power on sequence(4): Before set wifi and lte coex

+

+[TP 19] Power on sequence(5): Before set BT and Wifi calibration

+

+[TP 20] Power on sequence(6): End power on

+

+[TP 21] Before WMT power off

+

+[TP 22] When AP suspend

+

+[TP 23] When AP resume

diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m1.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m1.cfg
new file mode 100644
index 0000000..2557394
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m1.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=1
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xCE
+coex_wifi_rssi_mid_limit=0xBB
+coex_wifi_rssi_lower_limit=0xBB
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m2.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m2.cfg
new file mode 100644
index 0000000..1801583
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m2.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=2
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xCE
+coex_wifi_rssi_mid_limit=0xBB
+coex_wifi_rssi_lower_limit=0xBB
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m3.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m3.cfg
new file mode 100644
index 0000000..c019bae
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m3.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=3
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xD2
+coex_wifi_rssi_mid_limit=0xC8
+coex_wifi_rssi_lower_limit=0xBF
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m4.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m4.cfg
new file mode 100644
index 0000000..8788db8
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m4.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=4
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xD2
+coex_wifi_rssi_mid_limit=0xC8
+coex_wifi_rssi_lower_limit=0xBF
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m5.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m5.cfg
new file mode 100644
index 0000000..44eb8c8
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m5.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=5
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xD2
+coex_wifi_rssi_mid_limit=0xC8
+coex_wifi_rssi_lower_limit=0xBF
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m6.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m6.cfg
new file mode 100644
index 0000000..0f9372c
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m6.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=6
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xD2
+coex_wifi_rssi_mid_limit=0xC8
+coex_wifi_rssi_lower_limit=0xBF
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m7.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m7.cfg
new file mode 100644
index 0000000..8b7d601
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6620_ant_m7.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=7
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xD2
+coex_wifi_rssi_mid_limit=0xC8
+coex_wifi_rssi_lower_limit=0xBF
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m1.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m1.cfg
new file mode 100644
index 0000000..346233d
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m1.cfg
@@ -0,0 +1,8 @@
+coex_wmt_ant_mode=1
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m2.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m2.cfg
new file mode 100644
index 0000000..dba5e25
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m2.cfg
@@ -0,0 +1,6 @@
+coex_wmt_ant_mode=2
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m3.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m3.cfg
new file mode 100644
index 0000000..1459ed0
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m3.cfg
@@ -0,0 +1,6 @@
+coex_wmt_ant_mode=3
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m4.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m4.cfg
new file mode 100644
index 0000000..b3011f3
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6628_ant_m4.cfg
@@ -0,0 +1,7 @@
+coex_wmt_ant_mode=4
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m1.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m1.cfg
new file mode 100644
index 0000000..b86c1aa
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m1.cfg
@@ -0,0 +1,9 @@
+coex_wmt_ant_mode=1
+coex_wmt_ext_component=0
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m2.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m2.cfg
new file mode 100644
index 0000000..dba5e25
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m2.cfg
@@ -0,0 +1,6 @@
+coex_wmt_ant_mode=2
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m3.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m3.cfg
new file mode 100644
index 0000000..1459ed0
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m3.cfg
@@ -0,0 +1,6 @@
+coex_wmt_ant_mode=3
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m4.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m4.cfg
new file mode 100644
index 0000000..b3011f3
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6630_ant_m4.cfg
@@ -0,0 +1,7 @@
+coex_wmt_ant_mode=4
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m1.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m1.cfg
new file mode 100644
index 0000000..802bf75
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m1.cfg
@@ -0,0 +1,10 @@
+coex_wmt_ant_mode=44
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+coex_wmt_wifi_path=0x0006
+
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m2.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m2.cfg
new file mode 100644
index 0000000..0f020ef
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m2.cfg
@@ -0,0 +1,10 @@
+coex_wmt_ant_mode=40
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+coex_wmt_wifi_path=0x000f
+
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m3.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m3.cfg
new file mode 100644
index 0000000..c61eea0
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m3.cfg
@@ -0,0 +1,10 @@
+coex_wmt_ant_mode=45
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+coex_wmt_wifi_path=0x000E
+
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m4.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m4.cfg
new file mode 100644
index 0000000..8740e80
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/mt6632_ant_m4.cfg
@@ -0,0 +1,10 @@
+coex_wmt_ant_mode=46
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+coex_wmt_wifi_path=0x0007
+
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/txpowerctrl.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/txpowerctrl.cfg
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/txpowerctrl.cfg
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/wifi.cfg b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/wifi.cfg
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/cfg_folder/wifi.cfg
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/src/connectivity/combo_tool/6631_combo_tool/combo_loader/Android.mk b/src/connectivity/combo_tool/6631_combo_tool/combo_loader/Android.mk
new file mode 100644
index 0000000..8a6fe9c
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/combo_loader/Android.mk
@@ -0,0 +1,102 @@
+# Copyright Statement:
+#
+# This software/firmware and related documentation ("MediaTek Software") are
+# protected under relevant copyright laws. The information contained herein
+# is confidential and proprietary to MediaTek Inc. and/or its licensors.
+# Without the prior written permission of MediaTek inc. and/or its licensors,
+# any reproduction, modification, use or disclosure of MediaTek Software,
+# and information contained herein, in whole or in part, shall be strictly prohibited.
+#
+# MediaTek Inc. (C) 2010. All rights reserved.
+#
+# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+#
+# The following software/firmware and/or related documentation ("MediaTek Software")
+# have been modified by MediaTek Inc. All revisions are subject to any receiver's
+# applicable license agreements with MediaTek Inc.
+
+
+# Copyright (C) 2008 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.
+
+# Configuration
+BUILD_LOADER  := false
+BUILD_MT6582_CONSYS := false
+LOCAL_PATH := $(call my-dir)
+
+ifneq ($(MTK_COMBO_CHIP), )
+ifneq ($(MTK_COMBO_CHIP),MT7668)
+BUILD_LOADER  := true
+endif
+endif
+
+ifneq ($(filter CONSYS_6572,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6582,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6592,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6735,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6755,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6797,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifeq ($(BUILD_LOADER), true)
+$(warning build loader)
+include $(CLEAR_VARS)
+
+ifeq ($(BUILD_MT6582_CONSYS), true)
+LOCAL_CFLAGS := -DMTK_SOC_CONSYS_SUPPORT
+endif
+
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_HEADER_LIBRARIES := libcutils_headers
+LOCAL_SRC_FILES  := loader.c
+LOCAL_MODULE := wmt_loader
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+LOCAL_MODULE_TAGS := optional
+LOCAL_INIT_RC := ../init_connectivity.rc
+include $(MTK_EXECUTABLE)
+endif
diff --git a/src/connectivity/combo_tool/6631_combo_tool/combo_loader/README b/src/connectivity/combo_tool/6631_combo_tool/combo_loader/README
new file mode 100644
index 0000000..053fc8b
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/combo_loader/README
@@ -0,0 +1,19 @@
+This module serves the common part driver of connectivity
+
+WHAT IT DOES?
+=============
+This module creates one executable binary files for loading/initializing the common part driver including 
+wifi, fm, gps and BT if needed.
+
+HOW IT WAS BUILT?
+==================
+It needs the following library from AOSP:
+
+libcutils
+
+HOW TO USE IT?
+==============
+the executable binary files, wmt_loader, will be started in init.rc when boot. it will load/initialize
+to load the common part drivers(common part/wifi/fm/gps/BT) of connectivity
+
+The source code was written by MediaTek.
diff --git a/src/connectivity/combo_tool/6631_combo_tool/combo_loader/loader.c b/src/connectivity/combo_tool/6631_combo_tool/combo_loader/loader.c
new file mode 100644
index 0000000..2f90f81
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/combo_loader/loader.c
@@ -0,0 +1,305 @@
+
+#include "loader.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "wmt_loader"
+
+#define WCN_COMBO_LOADER_CHIP_ID_PROP    "persist.vendor.connsys.chipid"
+#define WCN_DRIVER_READY_PROP            "vendor.connsys.driver.ready"
+#define WCN_COMBO_LOADER_DEV             "/dev/wmtdetect"
+#define WMT_MODULES_PRE                  "/system/lib/modules/"
+#define WMT_MODULES_SUFF                 ".ko"
+#define WMT_DETECT_IOC_MAGIC                    'w'
+
+#define COMBO_IOCTL_GET_CHIP_ID          _IOR(WMT_DETECT_IOC_MAGIC, 0, int)
+#define COMBO_IOCTL_SET_CHIP_ID          _IOW(WMT_DETECT_IOC_MAGIC, 1, int)
+#define COMBO_IOCTL_EXT_CHIP_DETECT      _IOR(WMT_DETECT_IOC_MAGIC, 2, int)
+#define COMBO_IOCTL_GET_SOC_CHIP_ID      _IOR(WMT_DETECT_IOC_MAGIC, 3, int)
+#define COMBO_IOCTL_DO_MODULE_INIT       _IOR(WMT_DETECT_IOC_MAGIC, 4, int)
+#define COMBO_IOCTL_MODULE_CLEANUP       _IOR(WMT_DETECT_IOC_MAGIC, 5, int)
+#define COMBO_IOCTL_EXT_CHIP_PWR_ON      _IOR(WMT_DETECT_IOC_MAGIC, 6, int)
+#define COMBO_IOCTL_EXT_CHIP_PWR_OFF     _IOR(WMT_DETECT_IOC_MAGIC, 7, int)
+#define COMBO_IOCTL_DO_SDIO_AUDOK        _IOR(WMT_DETECT_IOC_MAGIC, 8, int)
+
+
+
+#define STP_WMT_MODULE_PRE_FIX           "mtk_stp_wmt"
+#define STP_BT_MODULE_PRE_FIX            "mtk_stp_bt"
+#define STP_GPS_MODULE_PRE_FIX           "mtk_stp_gps"
+#define HIF_SDIO_MODULE_PRE_FIX          "mtk_hif_sdio"
+#define STP_SDIO_MODULE_PRE_FIX          "mtk_stp_sdio"
+#define STP_UART_MODULE_PRE_FIX          "mtk_stp_uart"
+
+#define WMT_PROC_DBG_PATH                "/proc/driver/wmt_dbg"
+#define WMT_PROC_AEE_PATH                "/proc/driver/wmt_aee"
+
+static int g_loader_fd = -1;
+
+static int g_chipid_array[] = {
+    0x6620, 0x6628, 0x6630, 0x6632, 0x6572, 0x6582, 0x6592, 0x8127,
+    0x6571, 0x6752, 0x6735, 0x0321, 0x0335, 0x0337, 0x8163, 0x6580,
+    0x6755, 0x0326, 0x6797, 0x0279, 0x6757, 0x0551, 0x8167, 0x6759,
+    0x0507, 0x6763, 0x0690, 0x6570, 0x0713, 0x6775, 0x0788, 0x6771,
+    0x6765, 0x3967, 0x6761, 0x8168,
+};
+
+static int loader_do_chipid_vaild_check(int chip_id)
+{
+    int ret = -1;
+    unsigned char i;
+
+    for (i = 0; i < sizeof(g_chipid_array)/sizeof(0x6630); i++) {
+        if (chip_id == g_chipid_array[i]) {
+            ALOGI("chipid vaild check: %d :0x%x!\n", i, chip_id);
+            ret = 0;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static int loader_do_kernel_module_init(int loader_fd, int chip_id) {
+    int ret = 0;
+
+    if (loader_fd < 0) {
+        ALOGE("invalid loaderfd: %d\n", loader_fd);
+        return -1;
+    }
+
+    ret = ioctl(loader_fd, COMBO_IOCTL_MODULE_CLEANUP, chip_id);
+    if (ret) {
+        ALOGE("do WMT-DETECT module cleanup failed: %d\n", ret);
+        return -2;
+    }
+
+    ret = ioctl(loader_fd, COMBO_IOCTL_DO_MODULE_INIT, chip_id);
+    if (ret) {
+        ALOGE("do kernel module init failed: %d\n", ret);
+        return -3;
+    }
+
+    ALOGI("do kernel module init succeed: %d\n", ret);
+
+    return 0;
+}
+
+static void loader_do_combo_sdio_autok(int loader_fd, int chip_id) {
+    int retry_counter = 10;
+    int ret = -1;
+    int no_ext_chip = -1;
+    int chipid_detect = -1;
+    int autok_ret = 0;
+
+    ALOGV("chip id :%x\n", chip_id);
+
+    /*trigger autok process, incase last autok process is interrupted by abnormal power off or battery down*/
+    do {
+        /*power on combo chip*/
+        ret = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_PWR_ON);
+        if (0 != ret) {
+            ALOGE("external combo chip power on failed\n");
+            no_ext_chip = 1;
+        } else {
+            /*detect is there is an external combo chip, this step should not be must*/
+            no_ext_chip = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_DETECT, NULL);
+        }
+
+        ALOGI("external combo chip detected\n");
+        chipid_detect = ioctl(loader_fd, COMBO_IOCTL_GET_CHIP_ID, NULL);
+        ALOGI("chipid (0x%x) detected\n", chipid_detect);
+
+        if (0 == no_ext_chip) {
+            autok_ret = ioctl(loader_fd, COMBO_IOCTL_DO_SDIO_AUDOK, chipid_detect);
+            ALOGE("do SDIO3.0 autok %s\n", autok_ret ? "fail" : "succeed");
+        }
+
+        ret = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_PWR_OFF);
+        ALOGI("external combo chip power off %s\n", ret ? "fail" : "succeed");
+
+        if ((0 == no_ext_chip) && (-1 == chipid_detect)) {
+            /*extenral chip detected, but no valid chipId detected, retry*/
+            retry_counter--;
+            ALOGE("chipId detect failed, retrying, left retryCounter:%d\n", retry_counter);
+            usleep(500000);
+        } else
+            break;
+
+    } while (0 < retry_counter);
+
+}
+
+static void loader_do_first_chip_detect(int loader_fd, int *chip) {
+    int retry_counter = 20;
+    int ret = -1;
+    int no_ext_chip = -1;
+    int chip_id = -1;
+    int autok_ret = 0;
+    char chipid_str[PROPERTY_VALUE_MAX] = {0};
+
+    do {
+        /*power on combo chip*/
+        ret = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_PWR_ON);
+        if (-1 == ret) {
+            ALOGI("SOC chip no need do combo chip power on.\n");
+            no_ext_chip = 1;
+            chip_id = ioctl(loader_fd, COMBO_IOCTL_GET_SOC_CHIP_ID, NULL);
+        } else if (0 == ret) {
+            /*detect is there is an external combo chip*/
+            no_ext_chip = 0;
+            ret = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_DETECT, NULL);
+            if (0 != ret)
+                ALOGE("external combo chip detect failed (%d)\n", ret);
+            else
+                chip_id = ioctl(loader_fd, COMBO_IOCTL_GET_CHIP_ID, NULL);
+        } else
+            ALOGE("external combo power on failed (%d)\n", ret);
+
+        ALOGI("chipid (0x%x) detected\n", chip_id);
+
+        if (chip_id != -1) {
+            sprintf(chipid_str, "0x%04x", chip_id);
+            ret = property_set(WCN_COMBO_LOADER_CHIP_ID_PROP, chipid_str);
+            if (0 != ret) {
+                ALOGE("set property(%s) to %s failed,ret:%d, errno:%d\n",
+                    WCN_COMBO_LOADER_CHIP_ID_PROP, chipid_str, ret, errno);
+            } else
+                ALOGI("set property(%s) to %s succeed.\n", WCN_COMBO_LOADER_CHIP_ID_PROP, chipid_str);
+        }
+
+        if (0 == no_ext_chip) {
+            autok_ret = ioctl(loader_fd, COMBO_IOCTL_DO_SDIO_AUDOK, chip_id);
+            ALOGI("do SDIO3.0 autok %s\n", autok_ret ? "fail" : "succeed");
+            ret = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_PWR_OFF);
+            ALOGI("external combo chip power off %s\n", ret ? "fail" : "succeed");
+        }
+
+        if ((0 == no_ext_chip) && (-1 == chip_id)) {
+            /*extenral chip detected, but no valid chipId detected, retry*/
+            retry_counter--;
+#ifdef HAVE_AEE_FEATURE
+            if (0 == retry_counter) {
+                AEE_SYSTEM_EXCEPTION("Connsys Combo chip detect failed");
+            }
+#endif
+            usleep(500000);
+            ALOGE("chipId detect failed, retrying, left retryCounter:%d\n", retry_counter);
+        } else
+            break;
+    } while (0 < retry_counter);
+
+    *chip = chip_id;
+}
+
+static int loader_do_driver_ready_set(void) {
+    int ret = -1;
+    char ready_str[PROPERTY_VALUE_MAX] = {0};
+    ret = property_get(WCN_DRIVER_READY_PROP, ready_str, NULL);
+    if ((0 >= ret) || (0 == strcmp(ready_str, "yes"))) {
+        ALOGE("get property(%s) failed iRet:%d or property is %s\n",
+               WCN_DRIVER_READY_PROP, ret, ready_str);
+    }
+    /*set it to yes anyway*/
+    sprintf(ready_str, "%s", "yes");
+    ret = property_set(WCN_DRIVER_READY_PROP, ready_str);
+    if (0 != ret) {
+        ALOGE("set property(%s) to %s failed ret:%d\n",
+              WCN_DRIVER_READY_PROP, ready_str, ret);
+    } else
+        ALOGI("set property(%s) to %s succeed\n", WCN_DRIVER_READY_PROP, ready_str);
+
+    return ret;
+}
+
+int main(int argc, char *argv[]) {
+    int ret = -1;
+    int chip_id = -1;
+    int count = 0;
+    char chipid_str[PROPERTY_VALUE_MAX] = {0};
+    char ready_str[PROPERTY_VALUE_MAX] = {0};
+
+    ALOGV("argc:%d,argv:%s\n", argc, argv[0]);
+
+    ret = property_get(WCN_DRIVER_READY_PROP, ready_str, NULL);
+    if (0 == strcmp(ready_str, "yes")) {
+        ALOGE("WMT driver has been ready.\n");
+        return ret;
+    }
+
+    do {
+        g_loader_fd = open(WCN_COMBO_LOADER_DEV, O_RDWR | O_NOCTTY);
+        if (g_loader_fd < 0) {
+            count++;
+            ALOGI("Can't open device node(%s) count(%d)\n", WCN_COMBO_LOADER_DEV, count);
+            usleep(300000);
+        }
+        else
+            break;
+    }while(1);
+
+    /*read from system property*/
+    ret = property_get(WCN_COMBO_LOADER_CHIP_ID_PROP, chipid_str, NULL);
+    chip_id = strtoul(chipid_str, NULL, 16);
+    ALOGI("chip id from property:%d\n", chip_id);
+    if ((0 != ret) && (-1 != loader_do_chipid_vaild_check(chip_id))) {
+        /*valid chip_id detected*/
+        ALOGI("key:(%s)-value:(%s),chipId:0x%04x,ret(%d)\n",
+              WCN_COMBO_LOADER_CHIP_ID_PROP, chipid_str, chip_id, ret);
+        if (0x6630 == chip_id || 0x6632 == chip_id)
+            loader_do_combo_sdio_autok(g_loader_fd, chip_id);
+    } else {
+        /*trigger external combo chip detect and chip identification process*/
+        loader_do_first_chip_detect(g_loader_fd, &chip_id);
+    }
+
+    /*set chipid to kernel*/
+    ioctl(g_loader_fd, COMBO_IOCTL_SET_CHIP_ID, chip_id);
+
+    if ((0x0321 == chip_id) || (0x0335 == chip_id) || (0x0337 == chip_id))
+        chip_id = 0x6735;
+
+    if (0x0326 == chip_id)
+        chip_id = 0x6755;
+
+    if (0x0551 == chip_id)
+        chip_id = 0x6757;
+
+    if (0x0690 == chip_id)
+        chip_id = 0x6763;
+
+    if (0x0279 == chip_id)
+        chip_id = 0x6797;
+
+    if (0x0507 == chip_id)
+        chip_id = 0x6759;
+
+    if (0x0713 == chip_id)
+        chip_id = 0x6775;
+
+    if (0x0788 == chip_id)
+        chip_id = 0x6771;
+
+    /*how to handling if not all module init fail?*/
+    if (chip_id == -1) {
+        ALOGE("chip id error !!(0x%x)\n", chip_id);
+        return -1;
+    }
+    loader_do_kernel_module_init(g_loader_fd, chip_id);
+    if (g_loader_fd >= 0) {
+        close(g_loader_fd);
+        g_loader_fd = -1;
+    }
+
+    if ((chown(WMT_PROC_DBG_PATH, AID_SHELL, AID_SYSTEM) == -1) ||
+       (chown(WMT_PROC_AEE_PATH, AID_SHELL, AID_SYSTEM) == -1))
+        ALOGE("chown wmt_dbg or wmt_aee fail:%s\n", strerror(errno));
+
+    ret = loader_do_driver_ready_set();
+
+    return ret;
+}
+
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/combo_loader/loader.h b/src/connectivity/combo_tool/6631_combo_tool/combo_loader/loader.h
new file mode 100644
index 0000000..6c77b03
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/combo_loader/loader.h
@@ -0,0 +1,28 @@
+#ifndef __WMT_LOADER_H_
+#define __WMT_LOADER_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+//#include <cutils/properties.h>
+//#include <cutils/misc.h>
+#include <sys/ioctl.h>
+//#include <cutils/android_filesystem_config.h>
+//#include <log/log.h>
+
+#ifdef HAVE_AEE_FEATURE
+#include <aee.h>
+#define AEE_SYSTEM_EXCEPTION(String) \
+    do { \
+        aee_system_exception( \
+            "wmt_loader", \
+            NULL, \
+            DB_OPT_DEFAULT, \
+            String); \
+    } while(0)
+#endif
+#endif
diff --git a/src/connectivity/combo_tool/6631_combo_tool/combo_loader/yocto_loader.c b/src/connectivity/combo_tool/6631_combo_tool/combo_loader/yocto_loader.c
new file mode 100644
index 0000000..75c51a9
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/combo_loader/yocto_loader.c
@@ -0,0 +1,428 @@
+
+#include "loader.h"
+#include <sys/utsname.h>
+#include <sys/syscall.h>
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "wmt_loader"
+#ifndef ALOGI
+#define ALOGI printf
+#endif
+#ifndef ALOGE
+#define ALOGE printf
+#endif
+#ifndef ALOGV
+#define ALOGV printf
+#endif
+#ifndef PROPERTY_VALUE_MAX
+#define PROPERTY_VALUE_MAX (128)
+#endif
+
+
+#define WCN_COMBO_LOADER_CHIP_ID_PROP    "persist.vendor.connsys.chipid"
+#define WCN_DRIVER_READY_PROP            "vendor.connsys.driver.ready"
+#define WCN_COMBO_LOADER_DEV             "/dev/wmtdetect"
+#define WMT_MODULES_PRE                  "/system/lib/modules/"
+#define WMT_MODULES_SUFF                 ".ko"
+#define WMT_DETECT_IOC_MAGIC                    'w'
+
+/* connectivity modules are built out of kernel tree */
+#define WMT_OUT_KO_PATH_PREFIX          "/lib/modules/mt66xx/"
+#define WMT_OUT_WMT_WIFI_MODULE_PATH    "wmt_chrdev_wifi.ko"
+#define WMT_OUT_WLAN_MODULE_PATH        "wlan_drv_gen4m.ko"
+#define WMT_OUT_WLAN_GEN3_MODULE_PATH        "wlan_gen3.ko"
+#define WMT_OUT_BT_MODULE_PATH        "wmt_cdev_bt.ko"
+#define WMT_OUT_BT_DRV_MODULE_PATH        "bt_drv.ko"
+
+
+
+#define COMBO_IOCTL_GET_CHIP_ID          _IOR(WMT_DETECT_IOC_MAGIC, 0, int)
+#define COMBO_IOCTL_SET_CHIP_ID          _IOW(WMT_DETECT_IOC_MAGIC, 1, int)
+#define COMBO_IOCTL_EXT_CHIP_DETECT      _IOR(WMT_DETECT_IOC_MAGIC, 2, int)
+#define COMBO_IOCTL_GET_SOC_CHIP_ID      _IOR(WMT_DETECT_IOC_MAGIC, 3, int)
+#define COMBO_IOCTL_DO_MODULE_INIT       _IOR(WMT_DETECT_IOC_MAGIC, 4, int)
+#define COMBO_IOCTL_MODULE_CLEANUP       _IOR(WMT_DETECT_IOC_MAGIC, 5, int)
+#define COMBO_IOCTL_EXT_CHIP_PWR_ON      _IOR(WMT_DETECT_IOC_MAGIC, 6, int)
+#define COMBO_IOCTL_EXT_CHIP_PWR_OFF     _IOR(WMT_DETECT_IOC_MAGIC, 7, int)
+#define COMBO_IOCTL_DO_SDIO_AUDOK        _IOR(WMT_DETECT_IOC_MAGIC, 8, int)
+
+
+
+#define STP_WMT_MODULE_PRE_FIX           "mtk_stp_wmt"
+#define STP_BT_MODULE_PRE_FIX            "mtk_stp_bt"
+#define STP_GPS_MODULE_PRE_FIX           "mtk_stp_gps"
+#define HIF_SDIO_MODULE_PRE_FIX          "mtk_hif_sdio"
+#define STP_SDIO_MODULE_PRE_FIX          "mtk_stp_sdio"
+#define STP_UART_MODULE_PRE_FIX          "mtk_stp_uart"
+
+#define WMT_PROC_DBG_PATH                "/proc/driver/wmt_dbg"
+#define WMT_PROC_AEE_PATH                "/proc/driver/wmt_aee"
+
+static int g_loader_fd = -1;
+
+static char DRIVER_MODULE_PATH[64]  = {0};
+static char DRIVER_MODULE_ARG[8] = "";
+
+static int g_chipid_array[] = {
+    0x6620, 0x6628, 0x6630, 0x6632, 0x6572, 0x6582, 0x6592, 0x8127,
+    0x6571, 0x6752, 0x6735, 0x0321, 0x0335, 0x0337, 0x8163, 0x6580,
+    0x6755, 0x0326, 0x6797, 0x0279, 0x6757, 0x0551, 0x8167, 0x6759,
+    0x0507, 0x6763, 0x0690, 0x6570, 0x0713, 0x6775, 0x0788, 0x6771,
+    0x6765, 0x3967, 0x6761, 0x8168, 0x8512,
+};
+
+
+/* TBD in platform-specific way */
+static int get_persist_chip_id(char *str, size_t len) { return -1; }
+static int set_persist_chip_id(int id) { return 0; }
+static void set_proc_owner(void) { }
+static void update_driver_ready(void) { }
+
+static int loader_do_chipid_vaild_check(int chip_id)
+{
+    int ret = -1;
+    unsigned char i;
+
+    for (i = 0; i < sizeof(g_chipid_array)/sizeof(0x6630); i++) {
+        if (chip_id == g_chipid_array[i]) {
+            ALOGI("chipid vaild check: %d :0x%x!\n", i, chip_id);
+            ret = 0;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static int loader_do_kernel_module_init(int loader_fd, int chip_id) {
+    int ret = 0;
+
+    if (loader_fd < 0) {
+        ALOGE("invalid loaderfd: %d\n", loader_fd);
+        return -1;
+    }
+
+    ret = ioctl(loader_fd, COMBO_IOCTL_MODULE_CLEANUP, chip_id);
+    if (ret) {
+        ALOGE("do WMT-DETECT module cleanup failed: %d\n", ret);
+        return -2;
+    }
+
+    ret = ioctl(loader_fd, COMBO_IOCTL_DO_MODULE_INIT, chip_id);
+    if (ret) {
+        ALOGE("do kernel module init failed: %d\n", ret);
+        return -3;
+    }
+
+    ALOGI("do kernel module init succeed: %d\n", ret);
+
+    return 0;
+}
+
+static void loader_do_combo_sdio_autok(int loader_fd, int chip_id) {
+    int retry_counter = 10;
+    int ret = -1;
+    int no_ext_chip = -1;
+    int chipid_detect = -1;
+    int autok_ret = 0;
+
+    ALOGV("chip id :%x\n", chip_id);
+
+    /*trigger autok process, incase last autok process is interrupted by abnormal power off or battery down*/
+    do {
+        /*power on combo chip*/
+        ret = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_PWR_ON);
+        if (0 != ret) {
+            ALOGE("external combo chip power on failed\n");
+            no_ext_chip = 1;
+        } else {
+            /*detect is there is an external combo chip, this step should not be must*/
+            no_ext_chip = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_DETECT, NULL);
+        }
+
+        ALOGI("external combo chip detected\n");
+        chipid_detect = ioctl(loader_fd, COMBO_IOCTL_GET_CHIP_ID, NULL);
+        ALOGI("chipid (0x%x) detected\n", chipid_detect);
+
+        if (0 == no_ext_chip) {
+            autok_ret = ioctl(loader_fd, COMBO_IOCTL_DO_SDIO_AUDOK, chipid_detect);
+            ALOGE("do SDIO3.0 autok %s\n", autok_ret ? "fail" : "succeed");
+        }
+
+        ret = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_PWR_OFF);
+        ALOGI("external combo chip power off %s\n", ret ? "fail" : "succeed");
+
+        if ((0 == no_ext_chip) && (-1 == chipid_detect)) {
+            /*extenral chip detected, but no valid chipId detected, retry*/
+            retry_counter--;
+            ALOGE("chipId detect failed, retrying, left retryCounter:%d\n", retry_counter);
+            usleep(500000);
+        } else
+            break;
+
+    } while (0 < retry_counter);
+
+}
+
+static void loader_do_first_chip_detect(int loader_fd, int *chip) {
+    int retry_counter = 20;
+    int ret = -1;
+    int no_ext_chip = -1;
+    int chip_id = -1;
+    int autok_ret = 0;
+    char chipid_str[PROPERTY_VALUE_MAX] = {0};
+
+    do {
+        /*power on combo chip*/
+        ret = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_PWR_ON);
+        if (-1 == ret) {
+            ALOGI("SOC chip no need do combo chip power on.\n");
+            no_ext_chip = 1;
+            chip_id = ioctl(loader_fd, COMBO_IOCTL_GET_SOC_CHIP_ID, NULL);
+        } else if (0 == ret) {
+            /*detect is there is an external combo chip*/
+            no_ext_chip = 0;
+            ret = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_DETECT, NULL);
+            if (0 != ret)
+                ALOGE("external combo chip detect failed (%d)\n", ret);
+            else
+                chip_id = ioctl(loader_fd, COMBO_IOCTL_GET_CHIP_ID, NULL);
+        } else
+            ALOGE("external combo power on failed (%d)\n", ret);
+
+        ALOGI("chipid (0x%x) detected\n", chip_id);
+
+        if (chip_id != -1) {
+            sprintf(chipid_str, "0x%04x", chip_id);
+            ret = set_persist_chip_id(chip_id);
+            if (0 != ret) {
+                ALOGE("set property(%s) to %s failed,ret:%d, errno:%d\n",
+                    WCN_COMBO_LOADER_CHIP_ID_PROP, chipid_str, ret, errno);
+            } else
+                ALOGI("set property(%s) to %s succeed.\n", WCN_COMBO_LOADER_CHIP_ID_PROP, chipid_str);
+        }
+
+        if (0 == no_ext_chip) {
+            autok_ret = ioctl(loader_fd, COMBO_IOCTL_DO_SDIO_AUDOK, chip_id);
+            ALOGI("do SDIO3.0 autok %s\n", autok_ret ? "fail" : "succeed");
+            ret = ioctl(loader_fd, COMBO_IOCTL_EXT_CHIP_PWR_OFF);
+            ALOGI("external combo chip power off %s\n", ret ? "fail" : "succeed");
+        }
+
+        if ((0 == no_ext_chip) && (-1 == chip_id)) {
+            /*extenral chip detected, but no valid chipId detected, retry*/
+            retry_counter--;
+#ifdef HAVE_AEE_FEATURE
+            if (0 == retry_counter) {
+                AEE_SYSTEM_EXCEPTION("Connsys Combo chip detect failed");
+            }
+#endif
+            usleep(500000);
+            ALOGE("chipId detect failed, retrying, left retryCounter:%d\n", retry_counter);
+        } else
+            break;
+    } while (0 < retry_counter);
+
+    *chip = chip_id;
+}
+
+#if 0
+static int loader_do_driver_ready_set(void) {
+    int ret = -1;
+    char ready_str[PROPERTY_VALUE_MAX] = {0};
+    ret = property_get(WCN_DRIVER_READY_PROP, ready_str, NULL);
+    if ((0 >= ret) || (0 == strcmp(ready_str, "yes"))) {
+        ALOGE("get property(%s) failed iRet:%d or property is %s\n",
+               WCN_DRIVER_READY_PROP, ret, ready_str);
+    }
+    /*set it to yes anyway*/
+    sprintf(ready_str, "%s", "yes");
+    ret = property_set(WCN_DRIVER_READY_PROP, ready_str);
+    if (0 != ret) {
+        ALOGE("set property(%s) to %s failed ret:%d\n",
+              WCN_DRIVER_READY_PROP, ready_str, ret);
+    } else
+        ALOGI("set property(%s) to %s succeed\n", WCN_DRIVER_READY_PROP, ready_str);
+
+    return ret;
+}
+#endif
+
+static int insmod(const char *filename, const char *args)
+{
+
+  int ret;
+  int fd;
+  fd = open(filename, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+  if (fd < 0) {
+    ALOGI("insmod: open(\"%s\") failed: %s", filename, strerror(errno));
+    return -1;
+  }
+  ret = syscall(__NR_finit_module, fd, args, 0);
+  if (ret < 0) {
+    ALOGI("finit_module for (\"%s\") failed: %s", filename, strerror(errno));
+  }
+  close(fd);
+  return ret;
+}
+
+
+int load_wifi_bt_module(int chip_id)
+{
+	int ret = -1;
+	struct utsname utsname;
+	char wifi_module_path[100] = "";
+	char wlan_module_path[100] = "";
+	char bt_module_path[100] = "";
+
+	/* Use modules built out of kernel tree */
+	ALOGI("Use modules built out of kernel tree chip id %x \n", chip_id);
+	snprintf(wifi_module_path, sizeof(wifi_module_path), "%s%s", WMT_OUT_KO_PATH_PREFIX, WMT_OUT_WMT_WIFI_MODULE_PATH);
+	if (0x6771 == chip_id) snprintf(wlan_module_path, sizeof(wlan_module_path), "%s%s", WMT_OUT_KO_PATH_PREFIX, WMT_OUT_WLAN_GEN3_MODULE_PATH);
+	else snprintf(wlan_module_path, sizeof(wlan_module_path), "%s%s", WMT_OUT_KO_PATH_PREFIX, WMT_OUT_WLAN_MODULE_PATH);
+	if (0x6771 == chip_id) snprintf(bt_module_path, sizeof(bt_module_path), "%s%s", WMT_OUT_KO_PATH_PREFIX, WMT_OUT_BT_DRV_MODULE_PATH);
+	else snprintf(bt_module_path, sizeof(bt_module_path), "%s%s", WMT_OUT_KO_PATH_PREFIX, WMT_OUT_BT_MODULE_PATH);
+
+	if ((0x8512 == chip_id) || (0x8168 == chip_id) || (0x6771 == chip_id)) {
+		//insert 6631 driver
+		if (0 == insmod(wifi_module_path, DRIVER_MODULE_ARG)) {
+			ret = 0;
+			ALOGI("Success to insmod wmt wifi module\n");
+		} else {
+			ALOGI("Fail to insmod wmt wifi module %s\n", wifi_module_path);
+			return -2;
+		}
+
+		if (0 == insmod(wlan_module_path, DRIVER_MODULE_ARG)) {
+			ret = 0;
+			ALOGI("Success to insmod wlan module\n");
+		} else {
+			ALOGI("Fail to insmod wlan module %s\n", wlan_module_path);
+			return -3;
+		}
+
+		if (0 == insmod(bt_module_path, DRIVER_MODULE_ARG)) {
+			ret = 0;
+			ALOGI("Success to insmod bt module\n");
+		} else {
+			ALOGI("Fail to insmod bt module %s\n", bt_module_path);
+			return -4;
+		}
+    }
+
+
+    
+	return ret;
+}
+
+
+int main(int argc, char *argv[]) {
+    int ret = -1;
+    int chip_id = -1;
+    int count = 0;
+    int loadWlanResult = 0;
+    char chipid_str[PROPERTY_VALUE_MAX] = {0};
+    char ready_str[PROPERTY_VALUE_MAX] = {0};
+
+    ALOGV("argc:%d,argv:%s\n", argc, argv[0]);
+
+#if 0
+    ret = property_get(WCN_DRIVER_READY_PROP, ready_str, NULL);
+    if (0 == strcmp(ready_str, "yes")) {
+        ALOGE("WMT driver has been ready.\n");
+        return ret;
+    }
+#endif
+
+    do {
+        g_loader_fd = open(WCN_COMBO_LOADER_DEV, O_RDWR | O_NOCTTY);
+        if (g_loader_fd < 0) {
+            count++;
+            ALOGI("Can't open device node(%s) count(%d)\n", WCN_COMBO_LOADER_DEV, count);
+            usleep(300000);
+        }
+        else
+            break;
+    }while(1);
+
+    /*read from system property*/
+    //ret = property_get(WCN_COMBO_LOADER_CHIP_ID_PROP, chipid_str, NULL);
+    //chip_id = strtoul(chipid_str, NULL, 16);
+    chip_id = get_persist_chip_id(chipid_str, sizeof(chipid_str));
+    ALOGI("chip id from property:%d\n", chip_id);
+    if (-1 != loader_do_chipid_vaild_check(chip_id)) {
+        /*valid chip_id detected*/
+        ALOGI("key:(%s)-value:(%s),chipId:0x%04x,ret(%d)\n",
+              WCN_COMBO_LOADER_CHIP_ID_PROP, chipid_str, chip_id, ret);
+        if (0x6630 == chip_id || 0x6632 == chip_id)
+            loader_do_combo_sdio_autok(g_loader_fd, chip_id);
+    } else {
+        /*trigger external combo chip detect and chip identification process*/
+        loader_do_first_chip_detect(g_loader_fd, &chip_id);
+    }
+
+    /*set chipid to kernel*/
+    ioctl(g_loader_fd, COMBO_IOCTL_SET_CHIP_ID, chip_id);
+
+    if ((0x0321 == chip_id) || (0x0335 == chip_id) || (0x0337 == chip_id))
+        chip_id = 0x6735;
+
+    if (0x0326 == chip_id)
+        chip_id = 0x6755;
+
+    if (0x0551 == chip_id)
+        chip_id = 0x6757;
+
+    if (0x0690 == chip_id)
+        chip_id = 0x6763;
+
+    if (0x0279 == chip_id)
+        chip_id = 0x6797;
+
+    if (0x0507 == chip_id)
+        chip_id = 0x6759;
+
+    if (0x0713 == chip_id)
+        chip_id = 0x6775;
+
+    if (0x0788 == chip_id)
+        chip_id = 0x6771;
+
+    /*how to handling if not all module init fail?*/
+    if (chip_id == -1) {
+        ALOGE("chip id error !!(0x%x)\n", chip_id);
+        return -1;
+    }
+    loader_do_kernel_module_init(g_loader_fd, chip_id);
+    if (g_loader_fd >= 0) {
+        close(g_loader_fd);
+        g_loader_fd = -1;
+    }
+
+
+#if 0
+    if ((chown(WMT_PROC_DBG_PATH, AID_SHELL, AID_SYSTEM) == -1) ||
+       (chown(WMT_PROC_AEE_PATH, AID_SHELL, AID_SYSTEM) == -1))
+        ALOGE("chown wmt_dbg or wmt_aee fail:%s\n", strerror(errno));
+
+	ret = loader_do_driver_ready_set();
+#endif
+
+	set_proc_owner();
+	/*insmod wmt_chrdev_wifi.ko & wlan_gen4m.ko & wmt_cdev_bt.ko*/
+	loadWlanResult = load_wifi_bt_module(chip_id);
+	if (loadWlanResult) {
+		ALOGI("load WIFI_BT modules fail(%d):(%d)\n", loadWlanResult, __LINE__);
+		return loadWlanResult;
+	}
+
+	update_driver_ready();
+
+    return ret;
+}
+
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/configure.ac b/src/connectivity/combo_tool/6631_combo_tool/configure.ac
new file mode 100644
index 0000000..dfe0c2c
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/configure.ac
@@ -0,0 +1,5 @@
+AC_INIT([wmt_loader], [1.0])
+AM_INIT_AUTOMAKE([foreign])
+AC_PROG_CC
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/src/connectivity/combo_tool/6631_combo_tool/launcher-service b/src/connectivity/combo_tool/6631_combo_tool/launcher-service
new file mode 100644
index 0000000..3476241
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/launcher-service
@@ -0,0 +1,64 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides: launcher
+# Required-Start:	$syslog $local_fs $remote_fs 
+# Required-Stop:	$syslog $local_fs $remote_fs 
+# Default-Start:	2 3 4 5
+# Default-Stop:		0 1 6
+# Short-Description: 66xx launcher Daemon
+### END INIT INFO
+
+. /etc/init.d/init-functions
+prog=launcher
+PIDFILE=/var/run/$prog.pid
+DESC="66xx launcher Daemon"
+start() {
+	log_daemon_msg "Starting $DESC" "$prog"
+	start_daemon_background -p $PIDFILE /usr/bin/wmt_launcher -p /lib/firmware
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+	exit 0
+}
+
+stop() {
+	log_daemon_msg "Stopping $DESC" "$prog"
+	killproc -p $PIDFILE /usr/bin/wmt_launcher
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+}
+
+force_reload() {
+	stop
+	start
+
+}
+
+case "$1" in
+	start)
+		start
+		;;
+	stop)
+		stop
+		;;
+	force-reload)
+		force_reload
+		;;
+	restart)
+		stop
+		start
+		;;
+
+	*)
+		echo "$Usage: $prog {start|stop|force-reload|restart}"
+		exit 2
+esac
diff --git a/src/connectivity/combo_tool/6631_combo_tool/launcher.service b/src/connectivity/combo_tool/6631_combo_tool/launcher.service
new file mode 100644
index 0000000..61d54ec
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/launcher.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=66xx launcher Daemon
+After=wmtd.service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/wmt_launcher -p /lib/firmware > ttyS0
+StandardOutput=tty
+StandardError=tty
+
+[Install]
+Alias=launcherd
+WantedBy=multi-user.target
diff --git a/src/connectivity/combo_tool/6631_combo_tool/launcher_6627.service b/src/connectivity/combo_tool/6631_combo_tool/launcher_6627.service
new file mode 100644
index 0000000..61d54ec
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/launcher_6627.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=66xx launcher Daemon
+After=wmtd.service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/wmt_launcher -p /lib/firmware > ttyS0
+StandardOutput=tty
+StandardError=tty
+
+[Install]
+Alias=launcherd
+WantedBy=multi-user.target
diff --git a/src/connectivity/combo_tool/6631_combo_tool/mt6631_drv_insmod.sh b/src/connectivity/combo_tool/6631_combo_tool/mt6631_drv_insmod.sh
new file mode 100644
index 0000000..2cd2743
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/mt6631_drv_insmod.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+# insmod wmt driver before wmt_loader starts
+echo insmod wmt driver
+insmod /lib/modules/mt66xx/wmt_drv.ko
+#echo insmod wifi cdev driver
+#insmod /lib/modules/mt66xx/wmt_chrdev_wifi.ko
+#echo insmod wifi driver
+#insmod /lib/modules/mt66xx/wlan_drv_gen4m.ko
+#echo insmod bt driver
+#insmod /lib/modules/mt66xx/wmt_cdev_bt.ko
+
+#wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf
diff --git a/src/connectivity/combo_tool/6631_combo_tool/mt66xx_drv_insmod-service b/src/connectivity/combo_tool/6631_combo_tool/mt66xx_drv_insmod-service
new file mode 100644
index 0000000..27cfc28
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/mt66xx_drv_insmod-service
@@ -0,0 +1,64 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides: mt66xx_drv_insmod
+# Required-Start:	$syslog $local_fs 
+# Required-Stop:	$syslog $local_fs 
+# Default-Start:	2 3 4 5
+# Default-Stop:		0 1 6
+# Short-Description: mt66xx_drv_insmod
+### END INIT INFO
+
+. /etc/init.d/init-functions
+prog=mt66xx_drv_insmod
+PIDFILE=/var/run/$prog.pid
+DESC="mt66xx_drv_insmod"
+start() {
+	log_daemon_msg "Starting $DESC" "$prog"
+	start_daemon_background -p $PIDFILE /bin/sh /etc/mt66xx_drv_insmod.sh
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+	exit 0
+}
+
+stop() {
+	log_daemon_msg "Stopping $DESC" "$prog"
+	killproc -p $PIDFILE /bin/sh
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+}
+
+force_reload() {
+	stop
+	start
+
+}
+
+case "$1" in
+	start)
+		start
+		;;
+	stop)
+		stop
+		;;
+	force-reload)
+		force_reload
+		;;
+	restart)
+		stop
+		start
+		;;
+
+	*)
+		echo "$Usage: $prog {start|stop|force-reload|restart}"
+		exit 2
+esac
diff --git a/src/connectivity/combo_tool/6631_combo_tool/mt66xx_drv_insmod.service b/src/connectivity/combo_tool/6631_combo_tool/mt66xx_drv_insmod.service
new file mode 100644
index 0000000..bfcb919
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/mt66xx_drv_insmod.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=mt66xx_drv_insmod
+After=ubi-data-mnt.service
+
+[Service]
+Type=simple
+ExecStart=/bin/sh /etc/mt66xx_drv_insmod.sh
+
+[Install]
+WantedBy=multi-user.target
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/LICENSE b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/LICENSE
new file mode 100644
index 0000000..77f59ed
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:
+
+This software/firmware and related documentation ("MediaTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+the prior written permission of MediaTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MediaTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MediaTek Inc. (C) 2015. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/MNL.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/MNL.bin
new file mode 100644
index 0000000..0b91cf4
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/MNL.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv1_patch_1_0_hdr.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv1_patch_1_0_hdr.bin
new file mode 100644
index 0000000..9fa29dc
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv1_patch_1_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv1_patch_1_1_hdr.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv1_patch_1_1_hdr.bin
new file mode 100644
index 0000000..179a1cd
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv1_patch_1_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_0.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_0.bin
new file mode 100644
index 0000000..39e50ed
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_0.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_0_hdr.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_0_hdr.bin
new file mode 100644
index 0000000..283b355
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_1.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_1.bin
new file mode 100644
index 0000000..95d8ddd
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_1.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_1_hdr.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_1_hdr.bin
new file mode 100644
index 0000000..3e880b8
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_lm_patch_1_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_patch_1_0_hdr.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_patch_1_0_hdr.bin
new file mode 100644
index 0000000..8efc731
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_patch_1_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_patch_1_1_hdr.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_patch_1_1_hdr.bin
new file mode 100644
index 0000000..733a65f
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv2_patch_1_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv3_patch_1_0_hdr.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv3_patch_1_0_hdr.bin
new file mode 100644
index 0000000..e4318e6
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv3_patch_1_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv3_patch_1_1_hdr.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv3_patch_1_1_hdr.bin
new file mode 100644
index 0000000..70b88c8
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/ROMv3_patch_1_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/mt6630_patch_e3_0_hdr.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/mt6630_patch_e3_0_hdr.bin
new file mode 100644
index 0000000..e44a293
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/mt6630_patch_e3_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/patch_folder/mt6630_patch_e3_1_hdr.bin b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/mt6630_patch_e3_1_hdr.bin
new file mode 100644
index 0000000..5021d09
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/patch_folder/mt6630_patch_e3_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/6631_combo_tool/poweronwifi.service b/src/connectivity/combo_tool/6631_combo_tool/poweronwifi.service
new file mode 100644
index 0000000..db06dce
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/poweronwifi.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=power on wifi Daemon
+After=wmtd.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/usr/bin/power_on_wifi
+
+[Install]
+Alias=pwrwifid
+WantedBy=multi-user.target
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/Android.mk b/src/connectivity/combo_tool/6631_combo_tool/src/Android.mk
new file mode 100644
index 0000000..6454cd2
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/Android.mk
@@ -0,0 +1,148 @@
+# Copyright Statement:
+#
+# This software/firmware and related documentation ("MediaTek Software") are
+# protected under relevant copyright laws. The information contained herein
+# is confidential and proprietary to MediaTek Inc. and/or its licensors.
+# Without the prior written permission of MediaTek inc. and/or its licensors,
+# any reproduction, modification, use or disclosure of MediaTek Software,
+# and information contained herein, in whole or in part, shall be strictly prohibited.
+#
+# MediaTek Inc. (C) 2010. All rights reserved.
+#
+# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+#
+# The following software/firmware and/or related documentation ("MediaTek Software")
+# have been modified by MediaTek Inc. All revisions are subject to any receiver's
+# applicable license agreements with MediaTek Inc.
+
+
+# Copyright (C) 2008 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.
+
+# Configuration
+BUILD_LAUNCHER  := false
+BUILD_WMT_LPBK  := false
+BUILD_WMT_CONCURRENCY := false
+BUILD_STP_DUMP := false
+BUILD_FDB := false
+LOCAL_PATH := $(call my-dir)
+NDS32_310_V2J := false
+NDS32_321_V3J := false
+NDS32_410_V3 := false
+
+ifneq ($(filter "CONSYS_6765" "CONSYS_6761",$(MTK_COMBO_CHIP)),)
+    NDS32_410_V3 := true
+endif
+
+ifeq ($(NDS32_310_V2J), true)
+    NDS32_PATH := $(LOCAL_PATH)/fdb/nds32_toolchain/bsp310_v2j
+else ifeq ($(NDS32_321_V3J), true)
+    NDS32_PATH := $(LOCAL_PATH)/fdb/nds32_toolchain/bsp321_v3j
+else ifeq ($(NDS32_410_V3), true)
+    NDS32_PATH := $(LOCAL_PATH)/fdb/nds32_toolchain/bsp410_v3
+else
+    NDS32_PATH := $(LOCAL_PATH)/fdb/nds32_toolchain/bsp410_v3
+endif
+
+#ifneq ($(MTK_COMBO_CHIP), )
+#ifneq ($(MTK_COMBO_CHIP),MT7668)
+BUILD_LAUNCHER  := true
+BUILD_WMT_LPBK  := true
+BUILD_WMT_CONCURRENCY := true
+BUILD_FDB := true
+
+#ifneq ($(filter MT6620E3,$(MTK_COMBO_CHIP)),)
+    BUILD_STP_DUMP := true
+#endif
+#endif
+#endif
+
+ifeq ($(BUILD_LAUNCHER), true)
+include $(CLEAR_VARS)
+
+$(warning after build launcher)
+LOCAL_SRC_FILES  := stp_uart_launcher.c
+LOCAL_MODULE := wmt_launcher
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+LOCAL_MODULE_TAGS := optional
+LOCAL_INIT_RC := ../init_connectivity.rc
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+include $(MTK_EXECUTABLE)
+endif
+
+ifeq ($(BUILD_WMT_LPBK), true)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES  := wmt_loopback.c
+LOCAL_MODULE := wmt_loopback
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+LOCAL_MODULE_TAGS := eng
+include $(MTK_EXECUTABLE)
+endif
+
+
+ifeq ($(BUILD_WMT_CONCURRENCY), true)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES  := wmt_concurrency.c
+LOCAL_MODULE := wmt_concurrency
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+LOCAL_MODULE_TAGS := eng
+include $(MTK_EXECUTABLE)
+endif
+
+ifeq ($(BUILD_STP_DUMP), true)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES :=                                      \
+		  stp_dump/stp_dump.c			\
+		  stp_dump/eloop.c	\
+		  stp_dump/os_linux.c	
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+LOCAL_MODULE := stp_dump3
+LOCAL_MODULE_TAGS := optional
+LOCAL_INIT_RC := ../init_connectivity.rc
+include $(MTK_EXECUTABLE)
+endif
+
+ifeq ($(BUILD_FDB), true)
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -I$(NDS32_PATH)
+LOCAL_SRC_FILES :=		\
+		  fdb/fdb.c	\
+                  fdb/wmt_if.c
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+LOCAL_MODULE := wmt_fdb
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+LOCAL_MODULE_TAGS := optional
+include $(MTK_EXECUTABLE)
+endif
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/NOTICE b/src/connectivity/combo_tool/6631_combo_tool/src/NOTICE
new file mode 100644
index 0000000..1602dea
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/NOTICE
@@ -0,0 +1,30 @@
+This MediaTek software package contains software with the following notices and under the following licenses:
+
+==============================================================================================================
+
+Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+
+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 <ORGANIZATION> 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 AND FITNESS FOR A PARTICULAR PURPOSE 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.
+
+
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/README b/src/connectivity/combo_tool/6631_combo_tool/src/README
new file mode 100644
index 0000000..5c3e03f
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/README
@@ -0,0 +1,20 @@
+This module serves the common part driver of connectivity
+
+WHAT IT DOES?
+=============
+This module creates four executable binary files for configuring/testing 
+the common part driver.
+
+HOW IT WAS BUILT?
+==================
+It needs the following library from AOSP:
+
+libcutils, libc
+
+HOW TO USE IT?
+==============
+The executable binary files will be started in init.rc when boot. they will work together
+with wmt_loader to load/configure the common part driver of connectivity, meanwhile some test
+tool was supplied.
+
+The majority of source code was written by MediaTek. Some code from open source codes are used.
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/power_on_wifi.c b/src/connectivity/combo_tool/6631_combo_tool/src/power_on_wifi.c
new file mode 100644
index 0000000..c913982
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/power_on_wifi.c
@@ -0,0 +1,117 @@
+
+/******************************************************************************
+*                         C O M P I L E R   F L A G S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                    E X T E R N A L   R E F E R E N C E S
+*******************************************************************************
+*/
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+/*#include <syslog.h>*/
+#include <time.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+
+
+/******************************************************************************
+*                              C O N S T A N T S
+*******************************************************************************
+*/
+/* !defined(ANDROID) */
+#ifndef ALOGI
+#define ALOGI printf
+#endif
+#ifndef ALOGE
+#define ALOGE printf
+#endif
+#ifndef ALOGD
+#define ALOGD printf
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "6620_launcher"
+
+#if TARGET_PLATFORM == mt2635
+#define CUST_COMBO_WIFI_DEV "/dev/wmtWifi"
+#define POWER_ON_WIFI "AP"
+#define POWER_ON_WIFI_LEN 2
+#else
+#define CUST_COMBO_WIFI_DEV "/dev/wmtWifi"
+#define POWER_ON_WIFI "1"
+#define POWER_ON_WIFI_LEN 1
+#endif
+
+/******************************************************************************
+*                             D A T A   T Y P E S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                                 M A C R O S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                   F U N C T I O N   D E C L A R A T I O N S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                            P U B L I C   D A T A
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                           P R I V A T E   D A T A
+*******************************************************************************
+*/
+
+static int gWifiFd = -1;
+
+/******************************************************************************
+*                              F U N C T I O N S
+*******************************************************************************
+*/
+int main(int argc, char *argv[]) {
+        int retryCounter = 0;
+        int i_ret = -1;
+
+        gWifiFd = open(CUST_COMBO_WIFI_DEV, O_RDWR | O_NOCTTY);
+        do {
+                if (gWifiFd < 0) {
+                        ALOGI("Can't open device node(%s) error:%d \n", CUST_COMBO_WIFI_DEV, gWifiFd);
+                        usleep(300000);
+                } else {
+                       break;
+                }
+                retryCounter++;
+        } while (retryCounter < 20);
+
+        if (gWifiFd > 0) {
+                do {
+                        i_ret = write(gWifiFd, POWER_ON_WIFI, POWER_ON_WIFI_LEN);
+                        if (i_ret == 1) {
+                                ALOGI("Power on device node(%s) gWifiFd:%d succeed !!\n", CUST_COMBO_WIFI_DEV, gWifiFd);
+                                break;
+                        } else {
+                               ALOGI("Power on device node(%s) gWifiFd:%d Fail (%d) and retry\n", CUST_COMBO_WIFI_DEV, gWifiFd, i_ret);
+                        }
+                        retryCounter++;
+                        usleep(1000000);
+                } while (retryCounter < 20);
+        }
+        close(gWifiFd);
+
+    return 0;
+}
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/serial.h b/src/connectivity/combo_tool/6631_combo_tool/src/serial.h
new file mode 100644
index 0000000..4e6b745
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/serial.h
@@ -0,0 +1,79 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein is
+* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+* the prior written permission of MediaTek inc. and/or its licensors, any
+* reproduction, modification, use or disclosure of MediaTek Software, and
+* information contained herein, in whole or in part, shall be strictly
+* prohibited.
+*
+* MediaTek Inc. (C) 2014. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek
+* Software") have been modified by MediaTek Inc. All revisions are subject to
+* any receiver's applicable license agreements with MediaTek Inc.
+*/
+
+#ifndef _LINUX_SERIAL_H
+#define _LINUX_SERIAL_H
+
+struct serial_struct {
+ int type;
+ int line;
+ unsigned int port;
+ int irq;
+ int flags;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int baud_base;
+ unsigned short close_delay;
+ char io_type;
+ char reserved_char[1];
+ int hub6;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ unsigned char *iomem_base;
+ unsigned short iomem_reg_shift;
+ unsigned int port_high;
+ unsigned long iomap_base;
+};
+
+#define ASYNCB_HUP_NOTIFY  0
+#define ASYNCB_FOURPORT   1
+#define ASYNCB_SAK   2
+#define ASYNCB_SPLIT_TERMIOS  3
+#define ASYNCB_SPD_HI   4
+#define ASYNCB_SPD_VHI   5
+#define ASYNCB_SKIP_TEST  6
+#define ASYNCB_AUTO_IRQ   7
+#define ASYNCB_SESSION_LOCKOUT  8
+#define ASYNCB_PGRP_LOCKOUT  9
+#define ASYNCB_CALLOUT_NOHUP 10
+#define ASYNCB_HARDPPS_CD 11
+#define ASYNCB_SPD_SHI  12
+#define ASYNCB_LOW_LATENCY 13
+#define ASYNCB_BUGGY_UART 14
+#define ASYNCB_AUTOPROBE 15
+
+#endif /* _LINUX_SERIAL_H */
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/bt_fw_logger.c b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/bt_fw_logger.c
new file mode 100644
index 0000000..e8e4384
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/bt_fw_logger.c
@@ -0,0 +1,590 @@
+/**
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2016. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#define BT_FW_LOG_CTRL_FIFO "/tmp/bt_fwlog_ctrl"
+static int fw_log_ctrl_fd = 0;
+#define FIFO_BUF_SIZE   (128)
+
+#define BT_FW_LOG_NODE  "/dev/fw_log_bt"
+#define BT_FW_LOG_DEFAULT_PATH  "/data/misc/stp_dump"
+
+#define LOG_PATH_LENGTH   (128)
+static char fw_log_path[LOG_PATH_LENGTH] = {0};
+#define DUMP_PICUS_NAME_EXT ".picus"
+#define DUMP_PICUS_NAME_PREFIX "dump_"
+#define BT_FW_LOG_DEFAULT_SIZE  (10 * 1024 * 1024)
+static uint32_t log_file_size = BT_FW_LOG_DEFAULT_SIZE;
+#define BT_FW_LOG_BUF_SIZE  (1024*32)   //(1944)    // Cover old BT driver return size
+#define LOG_VERSION 0x100
+
+#define TRUE    (1)
+#define FALSE   (0)
+
+static const unsigned long BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
+static unsigned long timestamp = 0;
+static unsigned int dump_file_seq_num = 0;
+static int file_size_remain_to_switch = 0;
+static uint8_t buffer[BT_FW_LOG_BUF_SIZE] = {0};
+static int log_file_num = 6;
+static int logger_on = 1;
+
+static pthread_t bt_fw_logger_thread = 0;
+static int fw_log_fd = 0;
+
+#define BT_STACK_CONF_FILE "/data/misc/bluedroid/bt_stack.conf"
+enum
+{
+    FW_LOG_LEVEL_OFF,
+    FW_LOG_LEVEL_LOW_POWER,
+    FW_LOG_LEVEL_SQC,
+    FW_LOG_LEVEL_FULL,  //All log
+    FW_LOG_LEVEL_MAX,   //invalid
+};
+
+const char *fw_log_cmd[FW_LOG_LEVEL_MAX] = {
+    "echo raw-hex, 01 5d fc 04 02 00 01 00 > /dev/fw_log_bt",
+    "echo raw-hex, 01 5d fc 04 02 00 01 01 > /dev/fw_log_bt",
+    "echo raw-hex, 01 5d fc 04 02 00 01 02 > /dev/fw_log_bt",
+    "echo raw-hex, 01 5d fc 04 02 00 01 03 > /dev/fw_log_bt"
+};
+
+static char *trim(char *str) {
+  while (isspace(*str))
+    ++str;
+
+  if (!*str)
+    return str;
+
+  char *end_str = str + strlen(str) - 1;
+  while (end_str > str && isspace(*end_str))
+    --end_str;
+
+  end_str[1] = '\0';
+  return str;
+}
+
+static void parse_fwlog_config(void)
+{
+    int line_num = 0;
+    char line[1024];
+
+    printf("[bt_fw_logger]%s\n", __func__);
+
+    FILE *fp = fopen(BT_STACK_CONF_FILE, "rt");
+    if (!fp)
+    {
+        printf("[bt_fw_logger]%s unable to open file '%s': %s\n", __func__, BT_STACK_CONF_FILE, strerror(errno));
+        return;
+    }
+
+    while (fgets(line, sizeof(line), fp))
+    {
+        char *line_ptr = trim(line);
+        ++line_num;
+
+        // Skip blank and comment lines.
+        if (*line_ptr == '\0' || *line_ptr == '#')
+            continue;
+
+        if (line_ptr)
+        {
+            char *split = strchr(line_ptr, '=');
+            if (!split)
+            {
+                printf("[bt_fw_logger]%s no key/value separator found on line %d\n", __func__, line_num);
+                continue;
+            }
+            *split = '\0';
+            if (strcmp(trim(line_ptr), "mt66xx_fwlog_level") == 0)  //log level
+            {
+                char *level_str = trim(split + 1);
+                if (level_str)
+                {
+                    uint32_t level = atoi(&level_str[0]);
+                    if (level < FW_LOG_LEVEL_MAX)
+                    {
+                        printf("[bt_fw_logger]conf file set fwlog level: %d, set fwlog level to driver!!!\n", level);
+                        system(fw_log_cmd[level]);
+                    }
+                    else
+                        printf("[bt_fw_logger]log level in conf file is invalid: %d\n", level);
+                }
+            }
+            else if (strcmp(trim(line_ptr), "mt66xx_fwlog_path") == 0)//log location
+            {
+                char *path_str = trim(split + 1);
+                if (path_str)
+                {
+                    struct stat st_buf;
+                    stat(path_str, &st_buf);
+                    if (S_ISDIR(st_buf.st_mode))
+                    {
+                        snprintf(fw_log_path, LOG_PATH_LENGTH, "%s", path_str);
+                        printf("[bt_fw_logger]conf file set fwlog path: %s\n", fw_log_path);
+                    }
+                    else
+                    {
+                        printf("[bt_fw_logger]invalid file path %s or permission denied, errno:%d\n", path_str, errno);
+                    }
+                }
+            }
+            else if (strcmp(trim(line_ptr), "mt66xx_fwlog_size") == 0)//single log file size
+            {
+                char *size_str = trim(split + 1);
+                if (size_str)
+                {
+                    char *ptr = NULL;
+                    uint32_t size = (uint32_t)strtoul(size_str, &ptr, 10);
+                    if ((size >= 10240) && (size <= (1024*1024*20)))
+                    {
+                        log_file_size = size;
+                        printf("[bt_fw_logger]conf file set fwlog size: %d\n", log_file_size);
+                    }
+                }
+            }
+            else if (strcmp(trim(line_ptr), "mt66xx_fwlog_count") == 0)//log file number
+            {
+                char *count_str = trim(split + 1);
+                if (count_str)
+                {
+                    char *ptr = NULL;
+                    uint32_t num = (uint32_t)strtoul(count_str, &ptr, 10);
+                    if ((num > 0) && (num <= 100))
+                    {
+                        log_file_num = num;
+                        printf("[bt_fw_logger]conf file set fwlog count: %d\n", log_file_num);
+                    }
+                }
+            }
+        }
+    }
+
+    printf("[bt_fw_logger]%s end\n", __func__);
+}
+
+static void mv_last_log_files(void)
+{
+    char cmd[256] = {0};
+    char old_picus_log_folder[LOG_PATH_LENGTH] = {0};
+
+    snprintf(old_picus_log_folder, LOG_PATH_LENGTH, "%s/%s", fw_log_path, "picus_last");
+
+    if (0 != mkdir(old_picus_log_folder, 0777)) {
+        if (errno != EEXIST) {
+            printf("[bt_fw_logger]create old picus log folder fail errno %d\n", errno);
+            return;
+        }
+    }
+    memset(cmd, 0, sizeof(cmd));
+    snprintf(cmd, sizeof(cmd), "rm -rf %s/*.picus", old_picus_log_folder);
+    if (0 != system(cmd)) {
+        printf("[bt_fw_logger]delete old old files fail errno %d\n", errno);
+        return;
+    }
+    printf("[bt_fw_logger]delete picus files in %s\n", old_picus_log_folder);
+
+    memset(cmd, 0, sizeof(cmd));
+    snprintf(cmd, sizeof(cmd), "mv %s/*.picus %s/", fw_log_path, old_picus_log_folder);
+    if (0 != system(cmd)) {
+        printf("[bt_fw_logger]move old files fail errno %d\n", errno);
+        return;
+    }
+    system("sync");
+    printf("[bt_fw_logger]move last picus files to %s\n", old_picus_log_folder);
+}
+
+static void remove_old_log_files(char *log_path, int all, int index)
+{
+    /* check already exist file under log_path */
+    char temp_picus_filename[36] = {0};
+    char picus_fullname[256] = {0};
+
+    DIR *p_dir = opendir(log_path);
+    if (p_dir != NULL)
+    {
+        struct dirent *p_file;
+        while ((p_file = readdir(p_dir)) != NULL)
+        {
+            /* ignore . and .. directory */
+            if (strncmp(p_file->d_name, "..", 2) == 0
+                || strncmp(p_file->d_name, ".", 1) == 0)
+            {
+                continue;
+            }
+            memset(temp_picus_filename, 0, sizeof(temp_picus_filename));
+            memset(picus_fullname, 0, sizeof(picus_fullname));
+            if (strstr(p_file->d_name, DUMP_PICUS_NAME_EXT) != NULL)
+            {
+                if (all)    //remove all old log files
+                {
+                    snprintf(picus_fullname, sizeof(picus_fullname), "%s/%s", log_path, p_file->d_name);
+                    if (remove(picus_fullname)) {
+                        printf("[bt_fw_logger]The old log:%s can't remove, errno: %d\n", p_file->d_name, errno);
+                    }
+                    else {
+                        printf("[bt_fw_logger]The old log: %s is removed\n", p_file->d_name);
+                    }
+                }
+                else    //remove a specific log file
+                {
+                    snprintf(temp_picus_filename, sizeof(temp_picus_filename), "_%d.picus", index);
+                    if (strstr(p_file->d_name, temp_picus_filename) != NULL) {
+                        snprintf(picus_fullname, sizeof(picus_fullname), "%s/%s", log_path, p_file->d_name);
+                        if (remove(picus_fullname)) {
+                        printf("[bt_fw_logger]The old log: %s can't remove, errno: %d\n", p_file->d_name, errno);
+                        } else {
+                            printf("[bt_fw_logger]The old log: %s is removed\n", p_file->d_name);
+                        }
+                    }
+                }
+            }
+        }
+        closedir(p_dir);
+    }
+    else
+    {
+        printf("[bt_fw_logger]readdir fail, errno: %d\n", errno);
+    }
+}
+
+static unsigned long btsnoop_timestamp(void)
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    // Timestamp is in microseconds.
+    timestamp = tv.tv_sec * 1000000ULL;
+    timestamp += tv.tv_usec;
+    timestamp += BTSNOOP_EPOCH_DELTA;
+    return timestamp;
+}
+
+static void fillheader(unsigned char *header, int headerlen,
+        unsigned short int dump_file_seq_num)
+{
+    int copy_header_len = 0;
+    unsigned int logversion = htobe32(LOG_VERSION);
+    memset(header, 0, headerlen);
+    memcpy(header, &logversion, sizeof(logversion));
+    copy_header_len += 4;   /** 4 byte for logversion */
+    copy_header_len += 4;   /** 4 byte for chip id, not implement yet */
+    dump_file_seq_num = htobe16(dump_file_seq_num);
+    memcpy(header + copy_header_len, &dump_file_seq_num, sizeof(dump_file_seq_num));
+    copy_header_len += 2;   /** 2 byte for sequence number */
+    copy_header_len += 6;   /** first hci log length(2), zero(4) */
+    btsnoop_timestamp();
+    timestamp = htobe64(timestamp);
+    memcpy(header + copy_header_len, &timestamp, sizeof(timestamp));
+}
+
+static FILE * create_new_log_file(int index)
+{
+    time_t local_timestamp;
+    char timestamp_buffer[24];
+    char dump_file_name[128] = {0};
+    unsigned char header[24] = {0};
+    unsigned char padding[8] = {0};
+    FILE *fp = NULL;
+
+    /* get current timestamp */
+    time(&local_timestamp);
+    strftime(timestamp_buffer, 24, "%Y%m%d%H%M%S", localtime(&local_timestamp));
+    snprintf(dump_file_name, sizeof(dump_file_name), "%s/" DUMP_PICUS_NAME_PREFIX "%s_%d" DUMP_PICUS_NAME_EXT, fw_log_path, timestamp_buffer, index);
+
+    /* dump file for picus log */
+    if ((fp = fopen(dump_file_name, "wb")) == NULL) {
+        printf("[bt_fw_logger]create log file %s fail [%s] errno %d\n", dump_file_name, strerror(errno), errno);
+        return NULL;
+    } else {
+        printf("[bt_fw_logger]log file %s is created, dumping...\n", dump_file_name);
+    }
+
+    fillheader(header, sizeof(header), index);
+    fwrite(header, 1, sizeof(header), fp);
+    fwrite(padding, 1, sizeof(padding), fp);
+    file_size_remain_to_switch = log_file_size;
+
+    return fp;
+}
+
+static void *bt_fw_logger_main(void *arg)
+{
+    int nRead = 0;
+    int nWritten = 0;
+    fd_set rset;    /** For select */
+    struct timeval tv;
+    FILE *current_fp = NULL;
+    int current_index = 0;
+    int i_ret = 0;
+
+    printf("[bt_fw_logger]%s, thread_id: 0x%x\n", __func__, pthread_self());
+
+    //create log ctrl fifo
+    i_ret = access(BT_FW_LOG_CTRL_FIFO, F_OK);
+    if (i_ret != 0)
+    {
+        i_ret = mkfifo(BT_FW_LOG_CTRL_FIFO, 0777);
+        if (i_ret < 0)
+            printf("mkfifo %s fail, errno: %d\n", BT_FW_LOG_CTRL_FIFO, errno);
+        else
+            printf("mkfifo %s success\n", BT_FW_LOG_CTRL_FIFO);
+    }
+
+    parse_fwlog_config();
+
+    do
+    {
+        int max_fd = fw_log_fd;
+
+        if ((fw_log_ctrl_fd = open(BT_FW_LOG_CTRL_FIFO, O_RDWR|O_NONBLOCK)) < 0)
+        {
+            printf("open fifo %s fail, errno: %d\n", BT_FW_LOG_CTRL_FIFO, errno);
+        }
+        FD_ZERO(&rset);
+        FD_SET(fw_log_fd, &rset);
+        if (fw_log_ctrl_fd > 0)
+        {
+            FD_SET(fw_log_ctrl_fd, &rset);
+            max_fd = (fw_log_ctrl_fd > fw_log_fd) ? fw_log_ctrl_fd : fw_log_fd;
+        }
+        tv.tv_sec = 10; /* timeout is 10s for select method */
+        tv.tv_usec = 0;
+        if (select(max_fd + 1, &rset, NULL, NULL, NULL) == 0) {
+            printf("[bt_fw_logger]Read data timeout(10s) from fw_log_bt\n");
+            if (fw_log_ctrl_fd > 0) close(fw_log_ctrl_fd);
+            continue;
+        }
+
+        if (fw_log_ctrl_fd > 0)
+        {
+            if (FD_ISSET(fw_log_ctrl_fd, &rset)) //parse log ctrl event
+            {
+                int res = 0;
+                char fifo_buf[FIFO_BUF_SIZE] = {0};
+
+                memset(fifo_buf, 0, FIFO_BUF_SIZE);
+                res = read(fw_log_ctrl_fd, fifo_buf, FIFO_BUF_SIZE);
+                printf("read %d byte from fw_log_ctrl_fd, fifo_buf: %s\n", res, fifo_buf);
+                if (NULL != strstr(fifo_buf, "log_path"))   //change log location
+                {
+                    struct stat st_buf;
+                    fifo_buf[res-1] = '\0'; //replace the \n to \0
+                    stat(fifo_buf+9, &st_buf);
+                    if (S_ISDIR(st_buf.st_mode))
+                    {
+                        snprintf(fw_log_path, LOG_PATH_LENGTH, "%s", fifo_buf+9);
+                        printf("[bt_fw_logger]change log path to %s\n", fw_log_path);
+                        //close current log file in the current location, and create log file with index 0 in new location
+                        if (current_fp > 0)
+                        {
+                            fflush(current_fp);
+                            fclose(current_fp);
+                            current_fp = 0;
+                        }
+                    }
+                    else
+                    {
+                        printf("[bt_fw_logger]invalid file path %s or permission denied, errno:%d\n", fifo_buf+9, errno);
+                    }
+                }
+                else if (NULL != strstr(fifo_buf, "log_size"))  //change single log file size
+                {
+                    char *ptr = NULL;
+                    uint32_t size = (uint32_t)strtoul(fifo_buf+9, &ptr, 10);
+                    if ((size >= 10240) && (size <= (1024*1024*20)))
+                    {
+                        if (size > log_file_size)
+                            file_size_remain_to_switch += (size - log_file_size);
+                        else
+                            file_size_remain_to_switch = 0;
+                        log_file_size = size;
+                        printf("[bt_fw_logger]change log_file_size to %d\n", log_file_size);
+                    }
+                }
+                else if (NULL != strstr(fifo_buf, "log_count")) //change log file count
+                {
+                    char *ptr = NULL;
+                    uint32_t num = (uint32_t)strtoul(fifo_buf+10, &ptr, 10);
+                    if ((num > 0) && (num <= 100))
+                    {
+                        log_file_num = num;
+                        printf("[bt_fw_logger]change log_file_num to %d\n", log_file_num);
+                    }
+                }
+            }
+        }
+
+        if (fw_log_ctrl_fd > 0) close(fw_log_ctrl_fd);
+
+        if (!FD_ISSET(fw_log_fd, &rset))
+            continue;
+
+        if (current_fp == 0)
+        {
+            mv_last_log_files(); // move old log to a folder
+            current_fp = create_new_log_file(0);
+            if (NULL == current_fp)
+            {
+                printf("[bt_fw_logger]fatal error: create new log file fail\n");
+                return NULL;
+            }
+        }
+        /* Read all packet from driver fwlog queue */
+        nRead = read(fw_log_fd, buffer, sizeof(buffer));
+        if (nRead > 0)
+        {
+            nWritten = fwrite(buffer, 1, nRead, current_fp);
+            if (nWritten != nRead)
+            {
+                printf("[bt_fw_logger]write may fail, nRead(%d) != nWritten(%d)\n", nRead, nWritten);
+            }
+            file_size_remain_to_switch -= nWritten;
+        }
+        else if (nRead < 0)
+        {
+            printf("[bt_fw_logger]read fail, errno=%d\n", errno);
+            continue;
+        }
+        /* switch file name if file size is over file_size */
+        if (file_size_remain_to_switch <= 0) {
+            file_size_remain_to_switch = log_file_size;
+            fclose(current_fp);
+            if (log_file_num - 1 > current_index) {
+                current_index++;
+            } else {
+                current_index = 0;
+            }
+            if (current_index == 1) {   // if the old picus log is not pulled, it will be lost
+                char old_picus_log_folder[LOG_PATH_LENGTH] = {0};
+                snprintf(old_picus_log_folder, LOG_PATH_LENGTH, "%s/%s", fw_log_path, "picus_last");
+                remove_old_log_files(old_picus_log_folder, TRUE, 0);
+            }
+            /* remove the file before creating */
+            remove_old_log_files(fw_log_path, FALSE, current_index);
+            current_fp = create_new_log_file(current_index);
+            if (NULL == current_fp)
+            {
+                printf("[bt_fw_logger]create new log file fail\n");
+                //TODO
+                return NULL;
+            }
+        }
+        fflush(current_fp);
+        usleep(50000);
+    } while (logger_on);
+
+
+    printf("[bt_fw_logger]%s exit, thread_id: 0x%x\n", __func__, pthread_self());
+
+    return NULL;
+}
+
+
+void bt_fw_logger_start(void)
+{
+    uint16_t index = 0;
+    printf("[bt_fw_logger]%s\n", __func__);
+    if (fw_log_fd > 0)
+    {
+        printf("%s, device is already opened\n", __func__);
+        return;
+    }
+    //1. open device
+    do
+    {
+        fw_log_fd = open(BT_FW_LOG_NODE, O_RDWR | O_NOCTTY | O_NONBLOCK);
+        if (fw_log_fd <= 0) {
+            printf("[bt_fw_logger]Can't open device node %s, errno: %d\n", BT_FW_LOG_NODE, errno);
+            sleep(1);
+        } else {
+            printf("[bt_fw_logger]Open device node successfully fw_log_fd = %d, index=%d\n", fw_log_fd, index);
+            break;
+        }
+        if(index == 200)
+        {
+            printf("[bt_fw_logger]Can't open device node with 200 times retry\n");
+            return;
+        }
+    }while (index++ < 200);
+
+    //set default file path
+    snprintf(fw_log_path, LOG_PATH_LENGTH, "%s", BT_FW_LOG_DEFAULT_PATH);
+
+    //2. create logger thread
+    if (bt_fw_logger_thread == 0)
+    {
+        pthread_attr_t thread_attr;
+
+        pthread_attr_init(&thread_attr);
+        pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+        if (pthread_create(&bt_fw_logger_thread, &thread_attr, bt_fw_logger_main, NULL))
+        {
+            printf("[bt_fw_logger]create logger thread fail\n",__func__);
+            bt_fw_logger_thread = 0;
+            return;
+        }
+        pthread_attr_destroy(&thread_attr);
+    }
+}
+
+void bt_fw_logger_stop(void)
+{
+    //disable fw log first
+    system("echo raw-hex, 01 5d fc 04 02 00 01 00 > /dev/fw_log_bt");
+
+    if (fw_log_fd > 0)
+    {
+        close(fw_log_fd);
+    }
+
+    //thread exit
+    logger_on = 0;
+    bt_fw_logger_thread = 0;
+    printf("[bt_fw_logger]%s\n", __func__);
+
+}
+//---------------------------------------------------------------------------
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/bt_fw_logger.h b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/bt_fw_logger.h
new file mode 100644
index 0000000..8a0e731
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/bt_fw_logger.h
@@ -0,0 +1,40 @@
+/**
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2016. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+void bt_fw_logger_start(void);
+void bt_fw_logger_stop(void);
+
+
+//---------------------------------------------------------------------------
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/eloop.c b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/eloop.c
new file mode 100644
index 0000000..c9be496
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/eloop.c
@@ -0,0 +1,653 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ */
+
+/*
+ * Event loop based on select() loop
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <sys/stat.h>
+#include <grp.h>
+#include <stddef.h>
+//#include <cutils/sockets.h>
+//#include <android/log.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <dirent.h>
+//#include <cutils/properties.h>
+#include <sys/un.h>
+#include <dirent.h>
+#include <linux/limits.h>
+//#include <cutils/sockets.h>
+//#include <cutils/memory.h>
+
+#include "os_linux.h"
+#include "stp_dump.h"
+#include "eloop.h"
+
+struct eloop_sock {
+    int sock;
+    void *eloop_data;
+    void *user_data;
+    eloop_sock_handler handler;
+};
+
+struct eloop_timeout {
+    struct os_time time;
+    void *eloop_data;
+    void *user_data;
+    eloop_timeout_handler handler;
+    struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+    int sig;
+    void *user_data;
+    eloop_signal_handler handler;
+    int signaled;
+};
+
+struct eloop_sock_table {
+    int count;
+    struct eloop_sock *table;
+    int changed;
+};
+
+struct eloop_data {
+    void *user_data;
+
+    int max_sock;
+
+    struct eloop_sock_table readers;
+    struct eloop_sock_table writers;
+    struct eloop_sock_table exceptions;
+
+    struct eloop_timeout *timeout;
+
+    int signal_count;
+    struct eloop_signal *signals;
+    int signaled;
+    int pending_terminate;
+
+    int terminate;
+    int reader_table_changed;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void *user_data)
+{
+    os_memset(&eloop, 0, sizeof(eloop));
+    eloop.user_data = user_data;
+    return 0;
+}
+
+
+static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
+                                     int sock, eloop_sock_handler handler,
+                                     void *eloop_data, void *user_data)
+{
+    struct eloop_sock *tmp;
+
+    if (table == NULL)
+    {
+        stp_printf(MSG_INFO, "table = NULL\n");
+        return -1;
+    }
+    tmp = (struct eloop_sock *)
+        os_realloc(table->table,
+               (table->count + 1) * sizeof(struct eloop_sock));
+    if (tmp == NULL)
+    {
+		stp_printf(MSG_INFO, "memory allocation for eloop_sock failed\n");
+        return -1;
+    }
+    tmp[table->count].sock = sock;
+    tmp[table->count].eloop_data = eloop_data;
+    tmp[table->count].user_data = user_data;
+    tmp[table->count].handler = handler;
+    table->count++;
+    table->table = tmp;
+    if (sock > eloop.max_sock)
+    {
+        eloop.max_sock = sock;
+		stp_printf(MSG_INFO, "set sock number to %d\n", eloop.max_sock);
+    }
+    table->changed = 1;
+
+    return 0;
+}
+
+
+static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
+                                         int sock)
+{
+    int i;
+
+    if (table == NULL || table->table == NULL || table->count == 0)
+        return;
+
+    for (i = 0; i < table->count; i++) {
+        if (table->table[i].sock == sock)
+            break;
+    }
+    if (i == table->count)
+        return;
+    if (i != table->count - 1) {
+        os_memmove(&table->table[i], &table->table[i + 1],
+               (table->count - i - 1) *
+               sizeof(struct eloop_sock));
+    }
+    table->count--;
+    table->changed = 1;
+}
+
+
+static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
+                     fd_set *fds)
+{
+    int i;
+
+    FD_ZERO(fds);
+
+    if (table->table == NULL)
+        return;
+
+    for (i = 0; i < table->count; i++)
+        FD_SET(table->table[i].sock, fds);
+}
+
+
+static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
+                      fd_set *fds)
+{
+    int i;
+
+    if (table == NULL || table->table == NULL)
+    {
+        /*stp_printf(MSG_ERROR, "table == NULL || table->table == NULL\n");*/
+        return;
+    }
+    table->changed = 0;
+    for (i = 0; i < table->count; i++) {
+        if (FD_ISSET(table->table[i].sock, fds)) {
+            table->table[i].handler(table->table[i].sock,
+                        table->table[i].eloop_data,
+                        table->table[i].user_data);
+            if (table->changed)
+                break;
+        }
+    }
+}
+
+
+static void eloop_sock_table_destroy(struct eloop_sock_table *table)
+{
+    if (table) {
+        int i;
+        for (i = 0; i < table->count && table->table; i++) {
+            printf("ELOOP: remaining socket: sock=%d "
+                   "eloop_data=%p user_data=%p handler=%p\n",
+                   table->table[i].sock,
+                   table->table[i].eloop_data,
+                   table->table[i].user_data,
+                   table->table[i].handler);
+        }
+        os_free(table->table);
+    }
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+                 void *eloop_data, void *user_data)
+{
+    return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
+                   eloop_data, user_data);
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+    eloop_unregister_sock(sock, EVENT_TYPE_READ);
+}
+
+
+static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
+{
+    switch (type) {
+    case EVENT_TYPE_READ:
+        return &eloop.readers;
+    case EVENT_TYPE_WRITE:
+        return &eloop.writers;
+    case EVENT_TYPE_EXCEPTION:
+        return &eloop.exceptions;
+    }
+    stp_printf(MSG_ERROR, "tyep (%d) error\n", type);
+    return NULL;
+}
+
+
+int eloop_register_sock(int sock, eloop_event_type type,
+            eloop_sock_handler handler,
+            void *eloop_data, void *user_data)
+{
+    struct eloop_sock_table *table;
+
+    table = eloop_get_sock_table(type);
+    return eloop_sock_table_add_sock(table, sock, handler,
+                     eloop_data, user_data);
+}
+
+
+void eloop_unregister_sock(int sock, eloop_event_type type)
+{
+    struct eloop_sock_table *table;
+
+    table = eloop_get_sock_table(type);
+    eloop_sock_table_remove_sock(table, sock);
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+               eloop_timeout_handler handler,
+               void *eloop_data, void *user_data)
+{
+    struct eloop_timeout *timeout, *tmp, *prev;
+
+    timeout = os_malloc(sizeof(*timeout));
+    if (timeout == NULL)
+        return -1;
+    if (os_get_time(&timeout->time) < 0) {
+        os_free(timeout);
+        return -1;
+    }
+    timeout->time.sec += secs;
+    timeout->time.usec += usecs;
+    while (timeout->time.usec >= 1000000) {
+        timeout->time.sec++;
+        timeout->time.usec -= 1000000;
+    }
+    timeout->eloop_data = eloop_data;
+    timeout->user_data = user_data;
+    timeout->handler = handler;
+    timeout->next = NULL;
+
+    if (eloop.timeout == NULL) {
+        eloop.timeout = timeout;
+        return 0;
+    }
+
+    prev = NULL;
+    tmp = eloop.timeout;
+    while (tmp != NULL) {
+        if (os_time_before(&timeout->time, &tmp->time))
+            break;
+        prev = tmp;
+        tmp = tmp->next;
+    }
+
+    if (prev == NULL) {
+        timeout->next = eloop.timeout;
+        eloop.timeout = timeout;
+    } else {
+        timeout->next = prev->next;
+        prev->next = timeout;
+    }
+
+    return 0;
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+             void *eloop_data, void *user_data)
+{
+    struct eloop_timeout *timeout, *prev, *next;
+    int removed = 0;
+
+    prev = NULL;
+    timeout = eloop.timeout;
+    while (timeout != NULL) {
+        next = timeout->next;
+
+        if (timeout->handler == handler &&
+            (timeout->eloop_data == eloop_data ||
+             eloop_data == ELOOP_ALL_CTX) &&
+            (timeout->user_data == user_data ||
+             user_data == ELOOP_ALL_CTX)) {
+            if (prev == NULL)
+                eloop.timeout = next;
+            else
+                prev->next = next;
+            os_free(timeout);
+            removed++;
+        } else
+            prev = timeout;
+
+        timeout = next;
+    }
+
+    return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+                void *eloop_data, void *user_data)
+{
+    struct eloop_timeout *tmp;
+
+    tmp = eloop.timeout;
+    while (tmp != NULL) {
+        if (tmp->handler == handler &&
+            tmp->eloop_data == eloop_data &&
+            tmp->user_data == user_data)
+            return 1;
+
+        tmp = tmp->next;
+    }
+
+    return 0;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+static void eloop_handle_alarm(__attribute__((unused))int sig)
+{
+    fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
+        "seconds. Looks like there\n"
+        "is a bug that ends up in a busy loop that "
+        "prevents clean shutdown.\n"
+        "Killing program forcefully.\n");
+    exit(1);
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static void eloop_handle_signal(int sig)
+{
+    int i;
+
+#ifndef CONFIG_NATIVE_WINDOWS
+    if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
+        /* Use SIGALRM to break out from potential busy loops that
+         * would not allow the program to be killed. */
+        eloop.pending_terminate = 1;
+        signal(SIGALRM, eloop_handle_alarm);
+        alarm(2);
+    }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+    eloop.signaled++;
+    for (i = 0; i < eloop.signal_count; i++) {
+        if (eloop.signals[i].sig == sig) {
+            eloop.signals[i].signaled++;
+            break;
+        }
+    }
+}
+
+
+static void eloop_process_pending_signals(void)
+{
+    int i;
+
+    if (eloop.signaled == 0)
+        return;
+    eloop.signaled = 0;
+
+    if (eloop.pending_terminate) {
+#ifndef CONFIG_NATIVE_WINDOWS
+        alarm(0);
+#endif /* CONFIG_NATIVE_WINDOWS */
+        eloop.pending_terminate = 0;
+    }
+
+    for (i = 0; i < eloop.signal_count; i++) {
+        if (eloop.signals[i].signaled) {
+            eloop.signals[i].signaled = 0;
+            eloop.signals[i].handler(eloop.signals[i].sig,
+                         eloop.user_data,
+                         eloop.signals[i].user_data);
+        }
+    }
+}
+
+
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+              void *user_data)
+{
+    struct eloop_signal *tmp;
+
+    tmp = (struct eloop_signal *)
+        os_realloc(eloop.signals,
+               (eloop.signal_count + 1) *
+               sizeof(struct eloop_signal));
+    if (tmp == NULL)
+        return -1;
+
+    tmp[eloop.signal_count].sig = sig;
+    tmp[eloop.signal_count].user_data = user_data;
+    tmp[eloop.signal_count].handler = handler;
+    tmp[eloop.signal_count].signaled = 0;
+    eloop.signal_count++;
+    eloop.signals = tmp;
+    signal(sig, eloop_handle_signal);
+
+    return 0;
+}
+
+
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+                    void *user_data)
+{
+    int ret = eloop_register_signal(SIGINT, handler, user_data);
+    if (ret == 0)
+        ret = eloop_register_signal(SIGTERM, handler, user_data);
+    if (ret == 0)
+        ret = eloop_register_signal(SIGSEGV, handler, user_data);
+    return ret;
+}
+
+
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+                   void *user_data)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+    return 0;
+#else /* CONFIG_NATIVE_WINDOWS */
+    return eloop_register_signal(SIGHUP, handler, user_data);
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+void eloop_run(void)
+{
+    fd_set *rfds, *wfds, *efds;
+    int res;
+    struct timeval _tv;
+    struct os_time tv, now;
+
+    rfds = os_malloc(sizeof(*rfds));
+    wfds = os_malloc(sizeof(*wfds));
+    efds = os_malloc(sizeof(*efds));
+    if (rfds == NULL || wfds == NULL || efds == NULL) {
+        stp_printf(MSG_ERROR, "eloop_run - malloc failed\n");
+        goto out;
+    }
+
+    while (!eloop.terminate &&
+           (eloop.timeout || eloop.readers.count > 0 ||
+        eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
+        if (eloop.timeout) {
+            os_get_time(&now);
+            if (os_time_before(&now, &eloop.timeout->time))
+                os_time_sub(&eloop.timeout->time, &now, &tv);
+            else
+                tv.sec = tv.usec = 0;
+#if 1
+            printf("next timeout in %lu.%06lu sec\n",
+                   tv.sec, tv.usec);
+#endif
+            _tv.tv_sec = tv.sec;
+            _tv.tv_usec = tv.usec;
+        }
+
+        eloop_sock_table_set_fds(&eloop.readers, rfds);
+        eloop_sock_table_set_fds(&eloop.writers, wfds);
+        eloop_sock_table_set_fds(&eloop.exceptions, efds);
+        res = select(eloop.max_sock + 1, rfds, wfds, efds,
+                 eloop.timeout ? &_tv : NULL);
+        if (res < 0 && errno != EINTR && errno != 0) {
+            perror("select");
+			stp_printf(MSG_ERROR, "select on socket failed\n");
+            goto out;
+        }
+        eloop_process_pending_signals();
+
+        /* check if some registered timeouts have occurred */
+        if (eloop.timeout) {
+            struct eloop_timeout *tmp;
+
+            os_get_time(&now);
+            if (!os_time_before(&now, &eloop.timeout->time)) {
+                tmp = eloop.timeout;
+                eloop.timeout = eloop.timeout->next;
+                tmp->handler(tmp->eloop_data,
+                         tmp->user_data);
+                os_free(tmp);
+            }
+
+        }
+
+        if (res <= 0)
+            continue;
+
+        eloop_sock_table_dispatch(&eloop.readers, rfds);
+        eloop_sock_table_dispatch(&eloop.writers, wfds);
+        eloop_sock_table_dispatch(&eloop.exceptions, efds);
+    }
+
+out:
+	stp_printf(MSG_INFO, "eloop_run exit\n");
+    os_free(rfds);
+    os_free(wfds);
+    os_free(efds);
+}
+
+
+void eloop_terminate(void)
+{
+    eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+    struct eloop_timeout *timeout, *prev;
+    struct os_time now;
+
+    timeout = eloop.timeout;
+    if (timeout)
+        os_get_time(&now);
+    while (timeout != NULL) {
+        int sec, usec;
+        prev = timeout;
+        timeout = timeout->next;
+        sec = prev->time.sec - now.sec;
+        usec = prev->time.usec - now.usec;
+        if (prev->time.usec < now.usec) {
+            sec--;
+            usec += 1000000;
+        }
+        printf("ELOOP: remaining timeout: %d.%06d eloop_data=%p "
+               "user_data=%p handler=%p\n",
+               sec, usec, prev->eloop_data, prev->user_data,
+               prev->handler);
+        os_free(prev);
+    }
+    eloop_sock_table_destroy(&eloop.readers);
+    eloop_sock_table_destroy(&eloop.writers);
+    eloop_sock_table_destroy(&eloop.exceptions);
+    os_free(eloop.signals);
+}
+
+
+int eloop_terminated(void)
+{
+    return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+    fd_set rfds;
+    int res;
+
+    if (sock < 0)
+        return;
+
+    FD_ZERO(&rfds);
+    FD_SET(sock, &rfds);
+    res = select(sock + 1, &rfds, NULL, NULL, NULL);
+    if (res < 0) {
+        stp_printf(MSG_ERROR, "select on socket failed\n");
+    }
+}
+
+
+void * eloop_get_user_data(void)
+{
+    return eloop.user_data;
+}
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/eloop.h b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/eloop.h
new file mode 100644
index 0000000..333ee08
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/eloop.h
@@ -0,0 +1,375 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ */
+
+/*
+ * Event loop
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file defines an event loop interface that supports processing events
+ * from registered timeouts (i.e., do something after N seconds), sockets
+ * (e.g., a new packet available for reading), and signals. eloop.c is an
+ * implementation of this interface using select() and sockets. This is
+ * suitable for most UNIX/POSIX systems. When porting to other operating
+ * systems, it may be necessary to replace that implementation with OS specific
+ * mechanisms.
+ */
+
+#ifndef ELOOP_H
+#define ELOOP_H
+
+/**
+ * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts
+ */
+#define ELOOP_ALL_CTX (void *) -1
+
+/**
+ * eloop_event_type - eloop socket event type for eloop_register_sock()
+ * @EVENT_TYPE_READ: Socket has data available for reading
+ * @EVENT_TYPE_WRITE: Socket has room for new data to be written
+ * @EVENT_TYPE_EXCEPTION: An exception has been reported
+ */
+typedef enum {
+    EVENT_TYPE_READ = 0,
+    EVENT_TYPE_WRITE,
+    EVENT_TYPE_EXCEPTION
+} eloop_event_type;
+
+
+
+
+
+/**
+ * eloop_sock_handler - eloop socket event callback type
+ * @sock: File descriptor number for the socket
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx);
+
+/**
+ * eloop_event_handler - eloop generic event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_timeout_handler - eloop timeout event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_signal_handler - eloop signal event callback type
+ * @sig: Signal number
+ * @eloop_ctx: Registered callback context data (global user_data from
+ * eloop_init() call)
+ * @signal_ctx: Registered callback context data (user_data from
+ * eloop_register_signal(), eloop_register_signal_terminate(), or
+ * eloop_register_signal_reconfig() call)
+ */
+typedef void (*eloop_signal_handler)(int sig, void *eloop_ctx,
+                     void *signal_ctx);
+
+/**
+ * eloop_init() - Initialize global event loop data
+ * @user_data: Pointer to global data passed as eloop_ctx to signal handlers
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function must be called before any other eloop_* function. user_data
+ * can be used to configure a global (to the process) pointer that will be
+ * passed as eloop_ctx parameter to signal handlers.
+ */
+int eloop_init(void *user_data);
+
+/**
+ * eloop_register_read_sock - Register handler for read events
+ * @sock: File descriptor number for the socket
+ * @handler: Callback function to be called when data is available for reading
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a read socket notifier for the given file descriptor. The handler
+ * function will be called whenever data is available for reading from the
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
+ */
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+                 void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_read_sock - Unregister handler for read events
+ * @sock: File descriptor number for the socket
+ *
+ * Unregister a read socket notifier that was previously registered with
+ * eloop_register_read_sock().
+ */
+void eloop_unregister_read_sock(int sock);
+
+/**
+ * eloop_register_sock - Register handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event to wait for
+ * @handler: Callback function to be called when the event is triggered
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event notifier for the given socket's file descriptor. The
+ * handler function will be called whenever the that event is triggered for the
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
+ */
+int eloop_register_sock(int sock, eloop_event_type type,
+            eloop_sock_handler handler,
+            void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_sock - Unregister handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event for which sock was registered
+ *
+ * Unregister a socket event notifier that was previously registered with
+ * eloop_register_sock().
+ */
+void eloop_unregister_sock(int sock, eloop_event_type type);
+
+/**
+ * eloop_register_event - Register handler for generic events
+ * @event: Event to wait (eloop implementation specific)
+ * @event_size: Size of event data
+ * @handler: Callback function to be called when event is triggered
+ * @eloop_data: Callback context data (eloop_data)
+ * @user_data: Callback context data (user_data)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event handler for the given event. This function is used to
+ * register eloop implementation specific events which are mainly targetted for
+ * operating system specific code (driver interface and l2_packet) since the
+ * portable code will not be able to use such an OS-specific call. The handler
+ * function will be called whenever the event is triggered. The handler
+ * function is responsible for clearing the event after having processed it in
+ * order to avoid eloop from calling the handler again for the same event.
+ *
+ * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE
+ * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable,
+ * and they would call this function with eloop_register_event(h, sizeof(h),
+ * ...).
+ */
+int eloop_register_event(void *event, size_t event_size,
+             eloop_event_handler handler,
+             void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_event - Unregister handler for a generic event
+ * @event: Event to cancel (eloop implementation specific)
+ * @event_size: Size of event data
+ *
+ * Unregister a generic event notifier that was previously registered with
+ * eloop_register_event().
+ */
+void eloop_unregister_event(void *event, size_t event_size);
+
+/**
+ * eloop_register_timeout - Register timeout
+ * @secs: Number of seconds to the timeout
+ * @usecs: Number of microseconds to the timeout
+ * @handler: Callback function to be called when timeout occurs
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a timeout that will cause the handler function to be called after
+ * given time.
+ */
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+               eloop_timeout_handler handler,
+               void *eloop_data, void *user_data);
+
+/**
+ * eloop_cancel_timeout - Cancel timeouts
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all
+ * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all
+ * Returns: Number of cancelled timeouts
+ *
+ * Cancel matching <handler,eloop_data,user_data> timeouts registered with
+ * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for
+ * cancelling all timeouts regardless of eloop_data/user_data.
+ */
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+             void *eloop_data, void *user_data);
+
+/**
+ * eloop_is_timeout_registered - Check if a timeout is already registered
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is registered, 0 if the timeout is not registered
+ *
+ * Determine if a matching <handler,eloop_data,user_data> timeout is registered
+ * with eloop_register_timeout().
+ */
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+                void *eloop_data, void *user_data);
+
+/**
+ * eloop_register_signal - Register handler for signals
+ * @sig: Signal number (e.g., SIGHUP)
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a signal is received.
+ * The callback function is actually called only after the system signal
+ * handler has returned. This means that the normal limits for sighandlers
+ * (i.e., only "safe functions" allowed) do not apply for the registered
+ * callback.
+ *
+ * Signals are 'global' events and there is no local eloop_data pointer like
+ * with other handlers. The global user_data pointer registered with
+ * eloop_init() will be used as eloop_ctx for signal handlers.
+ */
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+              void *user_data);
+
+/**
+ * eloop_register_signal_terminate - Register handler for terminate signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a process termination
+ * signal is received. The callback function is actually called only after the
+ * system signal handler has returned. This means that the normal limits for
+ * sighandlers (i.e., only "safe functions" allowed) do not apply for the
+ * registered callback.
+ *
+ * Signals are 'global' events and there is no local eloop_data pointer like
+ * with other handlers. The global user_data pointer registered with
+ * eloop_init() will be used as eloop_ctx for signal handlers.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers handlers for SIGINT and SIGTERM.
+ */
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+                    void *user_data);
+
+/**
+ * eloop_register_signal_reconfig - Register handler for reconfig signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a reconfiguration /
+ * hangup signal is received. The callback function is actually called only
+ * after the system signal handler has returned. This means that the normal
+ * limits for sighandlers (i.e., only "safe functions" allowed) do not apply
+ * for the registered callback.
+ *
+ * Signals are 'global' events and there is no local eloop_data pointer like
+ * with other handlers. The global user_data pointer registered with
+ * eloop_init() will be used as eloop_ctx for signal handlers.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers a handler for SIGHUP.
+ */
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+                   void *user_data);
+
+/**
+ * eloop_run - Start the event loop
+ *
+ * Start the event loop and continue running as long as there are any
+ * registered event handlers. This function is run after event loop has been
+ * initialized with event_init() and one or more events have been registered.
+ */
+void eloop_run(void);
+
+/**
+ * eloop_terminate - Terminate event loop
+ *
+ * Terminate event loop even if there are registered events. This can be used
+ * to request the program to be terminated cleanly.
+ */
+void eloop_terminate(void);
+
+/**
+ * eloop_destroy - Free any resources allocated for the event loop
+ *
+ * After calling eloop_destroy(), other eloop_* functions must not be called
+ * before re-running eloop_init().
+ */
+void eloop_destroy(void);
+
+/**
+ * eloop_terminated - Check whether event loop has been terminated
+ * Returns: 1 = event loop terminate, 0 = event loop still running
+ *
+ * This function can be used to check whether eloop_terminate() has been called
+ * to request termination of the event loop. This is normally used to abort
+ * operations that may still be queued to be run when eloop_terminate() was
+ * called.
+ */
+int eloop_terminated(void);
+
+/**
+ * eloop_wait_for_read_sock - Wait for a single reader
+ * @sock: File descriptor number for the socket
+ *
+ * Do a blocking wait for a single read socket.
+ */
+void eloop_wait_for_read_sock(int sock);
+
+/**
+ * eloop_get_user_data - Get global user data
+ * Returns: user_data pointer that was registered with eloop_init()
+ */
+void * eloop_get_user_data(void);
+
+#endif /* ELOOP_H */
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/os_linux.c b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/os_linux.c
new file mode 100644
index 0000000..288b7a2
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/os_linux.c
@@ -0,0 +1,492 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ * 
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ * 
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <dirent.h>
+//#include <cutils/properties.h>
+#include <sys/un.h>
+#include <dirent.h>
+#include "os_linux.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+    if (sec)
+        sleep(sec);
+    if (usec)
+        usleep(usec);
+}
+
+int os_get_time(struct os_time *t)
+{
+    int res;
+    struct timeval tv;
+    res = gettimeofday(&tv, NULL);
+    t->sec = tv.tv_sec;
+    t->usec = tv.tv_usec;
+    return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+          os_time_t *t)
+{
+    struct tm tm;
+
+    if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+        hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+        sec > 60)
+        return -1;
+
+    os_memset(&tm, 0, sizeof(tm));
+    tm.tm_year = year - 1900;
+    tm.tm_mon = month - 1;
+    tm.tm_mday = day;
+    tm.tm_hour = hour;
+    tm.tm_min = min;
+    tm.tm_sec = sec;
+
+    *t = (os_time_t) mktime(&tm);
+    return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+    if (daemon(0, 0)) {
+        perror("daemon");
+        return -1;
+    }
+
+    if (pid_file) {
+        FILE *f = fopen(pid_file, "w");
+        if (f) {
+            fprintf(f, "%u\n", getpid());
+            fclose(f);
+        }
+    }
+
+    return -0;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+    if (pid_file)
+        unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+    FILE *f;
+    size_t rc;
+
+    f = fopen("/dev/urandom", "rb");
+    if (f == NULL) {
+        printf("Could not open /dev/urandom.\n");
+        return -1;
+    }
+
+    rc = fread(buf, 1, len, f);
+    fclose(f);
+
+    return rc != len ? -1 : 0;
+}
+
+
+unsigned long os_random(void)
+{
+    return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+    char *buf = NULL, *cwd, *ret;
+    size_t len = 128, cwd_len, rel_len, ret_len;
+
+    if (rel_path[0] == '/')
+        return os_strdup(rel_path);
+
+    for (;;) {
+        buf = os_malloc(len);
+        if (buf == NULL)
+            return NULL;
+        cwd = getcwd(buf, len);
+        if (cwd == NULL) {
+            os_free(buf);
+            if (errno != ERANGE) {
+                return NULL;
+            }
+            len *= 2;
+        } else {
+            break;
+        }
+    }
+
+    cwd_len = strlen(cwd);
+    rel_len = strlen(rel_path);
+    ret_len = cwd_len + 1 + rel_len + 1;
+    ret = os_malloc(ret_len);
+    if (ret) {
+        os_memcpy(ret, cwd, cwd_len);
+        ret[cwd_len] = '/';
+        os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
+        ret[ret_len - 1] = '\0';
+    }
+    os_free(buf);
+    return ret;
+}
+
+
+int os_program_init(void)
+{
+    return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+    return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+    return unsetenv(name);
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+    FILE *f;
+    char *buf;
+
+    f = fopen(name, "rb");
+    if (f == NULL)
+        return NULL;
+
+    fseek(f, 0, SEEK_END);
+    *len = ftell(f);
+    fseek(f, 0, SEEK_SET);
+
+    buf = os_malloc(*len);
+    if (buf == NULL) {
+        fclose(f);
+        return NULL;
+    }
+
+    fread(buf, 1, *len, f);
+    fclose(f);
+
+    return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+    void *n = os_malloc(size);
+    if (n)
+        os_memset(n, 0, size);
+    return n;
+}
+
+
+void * os_malloc(size_t size)
+{
+    return malloc(size);
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+    return realloc(ptr, size);
+}
+
+
+void os_free(void *ptr)
+{
+    free(ptr);
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+    char *d = dest;
+    const char *s = src;
+    while (n--)
+        *d++ = *s++;
+    return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+    if (dest < src)
+        os_memcpy(dest, src, n);
+    else {
+        /* overlapping areas */
+        char *d = (char *) dest + n;
+        const char *s = (const char *) src + n;
+        while (n--)
+            *--d = *--s;
+    }
+    return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+    char *p = s;
+    while (n--)
+        *p++ = c;
+    return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+    const unsigned char *p1 = s1, *p2 = s2;
+
+    if (n == 0)
+        return 0;
+
+    while (*p1 == *p2) {
+        p1++;
+        p2++;
+        n--;
+        if (n == 0)
+            return 0;
+    }
+
+    return *p1 - *p2;
+}
+
+
+char * os_strdup(const char *s)
+{
+    char *res;
+    size_t len;
+    if (s == NULL)
+        return NULL;
+    len = os_strlen(s);
+    res = os_malloc(len + 1);
+    if (res)
+        os_memcpy(res, s, len + 1);
+    return res;
+}
+
+
+size_t os_strlen(const char *s)
+{
+    const char *p = s;
+    while (*p)
+        p++;
+    return p - s;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+    /*
+     * Ignoring case is not required for main functionality, so just use
+     * the case sensitive version of the function.
+     */
+    return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+    /*
+     * Ignoring case is not required for main functionality, so just use
+     * the case sensitive version of the function.
+     */
+    return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+    while (*s) {
+        if (*s == c)
+            return (char *) s;
+        s++;
+        //printf("==>s = %p\n", s);
+    }
+    return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+    const char *p = s;
+    while (*p)
+        p++;
+    p--;
+    while (p >= s) {
+        if (*p == c)
+            return (char *) p;
+        p--;
+    }
+    return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+    while (*s1 == *s2) {
+        if (*s1 == '\0')
+            break;
+        s1++;
+        s2++;
+    }
+
+    return *s1 - *s2;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+    if (n == 0)
+        return 0;
+
+    while (*s1 == *s2) {
+        if (*s1 == '\0')
+            break;
+        s1++;
+        s2++;
+        n--;
+        if (n == 0)
+            return 0;
+    }
+
+    return *s1 - *s2;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+    char *d = dest;
+
+    while (n--) {
+        *d = *src;
+        if (*src == '\0')
+            break;
+        d++;
+        src++;
+    }
+
+    return dest;
+}
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+    const char *s = src;
+    size_t left = siz;
+
+    if (left) {
+        /* Copy string up to the maximum size of the dest buffer */
+        while (--left != 0) {
+            if ((*dest++ = *s++) == '\0')
+                break;
+        }
+    }
+
+    if (left == 0) {
+        /* Not enough room for the string; force NUL-termination */
+        if (siz != 0)
+            *dest = '\0';
+        while (*s++)
+            ; /* determine total src string length */
+    }
+
+    return s - src - 1;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+    size_t len = os_strlen(needle);
+    while (*haystack) {
+        if (os_strncmp(haystack, needle, len) == 0)
+            return (char *) haystack;
+        haystack++;
+    }
+
+    return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+    va_list ap;
+    int ret;
+
+    /* See http://www.ijs.si/software/snprintf/ for portable
+     * implementation of snprintf.
+     */
+
+    va_start(ap, format);
+    ret = vsnprintf(str, size, format, ap);
+    va_end(ap);
+    if (size > 0)
+        str[size - 1] = '\0';
+    return ret;
+}
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/os_linux.h b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/os_linux.h
new file mode 100644
index 0000000..44a10c4
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/os_linux.h
@@ -0,0 +1,117 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ * 
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ * 
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef OS_LINUX_H
+#define OS_LINUX_H
+
+typedef long os_time_t;
+
+void os_sleep(os_time_t sec, os_time_t usec);
+
+struct os_time {
+    os_time_t sec;
+    os_time_t usec;
+};
+
+
+#define os_time_before(a, b) \
+    ((a)->sec < (b)->sec || \
+     ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+
+#define os_time_sub(a, b, res) do { \
+    (res)->sec = (a)->sec - (b)->sec; \
+    (res)->usec = (a)->usec - (b)->usec; \
+    if ((res)->usec < 0) { \
+        (res)->sec--; \
+        (res)->usec += 1000000; \
+    } \
+} while (0)
+
+int os_get_time(struct os_time *t);
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+          os_time_t *t);
+int os_daemonize(const char *pid_file);
+void os_daemonize_terminate(const char *pid_file);
+int os_get_random(unsigned char *buf, size_t len);
+unsigned long os_random(void);
+char * os_rel2abs_path(const char *rel_path);
+int os_program_init(void);
+void os_program_deinit(void);
+int os_setenv(const char *name, const char *value, int overwrite);
+int os_unsetenv(const char *name);
+char * os_readfile(const char *name, size_t *len);
+void * os_zalloc(size_t size);
+void * os_malloc(size_t size);
+void * os_realloc(void *ptr, size_t size);
+void os_free(void *ptr);
+void * os_memcpy(void *dest, const void *src, size_t n);
+void * os_memmove(void *dest, const void *src, size_t n);
+void * os_memset(void *s, int c, size_t n);
+int os_memcmp(const void *s1, const void *s2, size_t n);
+char * os_strdup(const char *s);
+size_t os_strlen(const char *s);
+int os_strcasecmp(const char *s1, const char *s2);
+int os_strncasecmp(const char *s1, const char *s2, size_t n);
+char * os_strchr(const char *s, int c);
+char * os_strrchr(const char *s, int c);
+int os_strcmp(const char *s1, const char *s2);
+int os_strncmp(const char *s1, const char *s2, size_t n);
+char * os_strncpy(char *dest, const char *src, size_t n);
+size_t os_strlcpy(char *dest, const char *src, size_t siz);
+
+char * os_strstr(const char *haystack, const char *needle);
+int os_snprintf(char *str, size_t size, const char *format, ...);
+void os_sleep(os_time_t sec, os_time_t usec);
+int os_get_time(struct os_time *t);
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+          os_time_t *t);
+#define os_daemon daemon
+int os_daemonize(const char *pid_file);
+void os_daemonize_terminate(const char *pid_file);
+int os_get_random(unsigned char *buf, size_t len);
+unsigned long os_random(void);
+char * os_rel2abs_path(const char *rel_path);
+int os_program_init(void);
+void os_program_deinit(void);
+int os_setenv(const char *name, const char *value, int overwrite);
+int os_unsetenv(const char *name);
+char * os_readfile(const char *name, size_t *len);
+void * os_zalloc(size_t size);
+size_t os_strlcpy(char *dest, const char *src, size_t siz);
+
+#endif
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/stp_dump.c b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/stp_dump.c
new file mode 100644
index 0000000..2ae7eee
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/stp_dump.c
@@ -0,0 +1,1452 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <grp.h>
+#include <stddef.h>
+//#include <cutils/sockets.h>
+//#include <android/log.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <dirent.h>
+//#include <cutils/properties.h>
+#include <sys/un.h>
+#include <dirent.h>
+#include <linux/limits.h>
+//#include <cutils/sockets.h>
+//#include <cutils/memory.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+//#include <sys/endian.h>
+#include <linux/serial.h> /* struct serial_struct  */
+#include <unistd.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <termios.h>
+#include <sys/poll.h>
+#include <linux/serial.h> /* struct serial_struct  */
+#include <sched.h>
+#include <netdb.h>
+#include <pthread.h>
+#include "os_linux.h"
+#include "stp_dump.h"
+#include "bt_fw_logger.h"
+#include "wifi_fw_logger.h"
+#include "eloop.h"
+#include <linux/netlink.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/mman.h>
+#include "../wmt_ioctl.h"
+
+#define LOGE printf
+#define LOGD printf
+
+#define GENL_ID_CTRL    NLMSG_MIN_TYPE
+#define GENL_HDRLEN     NLMSG_ALIGN(sizeof(struct genlmsghdr))
+#define COMBO_T32_DIR         "/data/misc/stp_dump/"
+#define COMBO_T32_NAME        "combo_t32"
+#define COMBO_T32_ENAME       ".cmm"
+#define COMBO_T32_NUM_MAX     50
+#define COM_STR_MAX 100
+#define EMI_ENAME             ".emi"
+#define EMI_FILE_NAME         "SYS_WCN_EMI_DUMP"
+#define EMICOREDUMP_CMD       "emicoredump"
+
+enum {
+    CTRL_CMD_UNSPEC,
+    CTRL_CMD_NEWFAMILY,
+    CTRL_CMD_DELFAMILY,
+    CTRL_CMD_GETFAMILY,
+    CTRL_CMD_NEWOPS,
+    CTRL_CMD_DELOPS,
+    CTRL_CMD_GETOPS,
+    CTRL_CMD_NEWMCAST_GRP,
+    CTRL_CMD_DELMCAST_GRP,
+    CTRL_CMD_GETMCAST_GRP, /* unused */
+    __CTRL_CMD_MAX,
+};
+#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1)
+
+enum {
+    CTRL_ATTR_UNSPEC,
+    CTRL_ATTR_FAMILY_ID,
+    CTRL_ATTR_FAMILY_NAME,
+    CTRL_ATTR_VERSION,
+    CTRL_ATTR_HDRSIZE,
+    CTRL_ATTR_MAXATTR,
+    CTRL_ATTR_OPS,
+    CTRL_ATTR_MCAST_GROUPS,
+    __CTRL_ATTR_MAX,
+};
+
+#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
+
+struct genlmsghdr {
+    __u8    cmd;
+    __u8    version;
+    __u16   reserved;
+};
+
+#define GENLMSG_DATA(glh) ((void *)((long)NLMSG_DATA(glh) + GENL_HDRLEN))
+#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
+#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))
+
+typedef struct _tagGenericNetlinkPacket {
+    struct nlmsghdr n;
+    struct genlmsghdr g;
+    char buf[512*16];
+} GENERIC_NETLINK_PACKET, *P_GENERIC_NETLINK_PACKET;
+
+
+
+////typedef int socklen_t;
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+int stp_debug_level = MSG_MSGDUMP;
+
+struct stp_ctrl_dst {
+    struct stp_ctrl_dst *next;
+    struct sockaddr_un addr;
+    socklen_t addrlen;
+    int debug_level;
+    int errors;
+};
+
+struct ctrl_iface_priv {
+    struct stp_dump *stp_d;
+    int sock;
+    struct stp_ctrl_dst *ctrl_dst;
+};
+
+struct trace_iface_priv {
+    struct stp_dump *stp_d;
+    int sock;
+    struct {
+        FILE *fp_pkt;
+        FILE *fp_drv;
+        FILE *fp_fw;
+        FILE *fp_t32;
+    } log_f;
+};
+
+struct stp_dump {
+    const char *ctrl_interface;
+    const char *ifname;
+    char *ctrl_interface_group;
+    int wmt_fd;
+    int chip_type;
+    struct ctrl_iface_priv *ctrl_iface;
+    struct trace_iface_priv *trace_iface;
+};
+struct list_head {
+        char file_name[100];
+        struct list_head *next, *prev;
+};
+
+struct list_head list_head;
+int combo_t32_num = 0;
+char combo_emi[100];
+
+static inline void INIT_LIST_HEAD(struct list_head *list) {
+    list->next = list;
+    list->prev = list;
+}
+
+static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) {
+    next->prev = new;
+    new->next = next;
+    new->prev = prev;
+    prev->next = new;
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head) {
+    __list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head * prev, struct list_head * next) {
+    next->prev = prev;
+    prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry) {
+    __list_del(entry->prev, entry->next);
+    entry->next = NULL;
+    entry->prev = NULL;
+}
+
+void bubble_sort(char *a[], int n)
+{
+    int i, j, len1, len2, len3;
+    char temp[COM_STR_MAX];
+    for (j = 0; j < n - 1; j++)
+        for (i = 0; i < n - 1 - j; i++) {
+            if (atoi(&a[i][10]) > atoi(&a[i+1][10])) {
+                len1 = (strlen(a[i]) <= COM_STR_MAX) ? strlen(a[i]) : COM_STR_MAX;
+                strncpy(temp, a[i], len1);
+                temp[len1-1] = '\0';
+                len2 = (strlen(a[i+1]) <= COM_STR_MAX) ? strlen(a[i+1]) : COM_STR_MAX;
+                strncpy(a[i], a[i+1], len2);
+                a[i][len2-1] = '\0';
+                len3 = (strlen(a[i+1]) <= COM_STR_MAX) ? strlen(a[i+1]) : COM_STR_MAX;
+                strncpy(a[i+1], temp, len3);
+                a[i+1][len3-1] = '\0';
+            }
+        }
+}
+
+/*
+void android_printf(int level, char *format, ...)
+{
+    if (level >= stp_debug_level) {
+        va_list ap;
+        if (level == MSG_ERROR) {
+            level = ANDROID_LOG_ERROR;
+        } else if (level == MSG_WARNING) {
+            level = ANDROID_LOG_WARN;
+        } else if (level == MSG_INFO) {
+            level = ANDROID_LOG_INFO;
+        } else {
+            level = ANDROID_LOG_DEBUG;
+        }
+        va_start(ap, format);
+        __android_log_vprint(level, "stp_dump", format, ap);
+        va_end(ap);
+    }
+}
+*/
+
+int check_log_folder_exit()
+{
+    struct statfs fs_info;
+
+    /* check COMBO_T32_DIR folder */
+    if (statfs(COMBO_T32_DIR,&fs_info) < 0)
+    {
+        if (mkdir(COMBO_T32_DIR, 00777) < 0)
+        {
+            stp_printf(MSG_ERROR, "remake (%s) failed:(%s)\n", COMBO_T32_DIR, strerror(errno));
+            return -1;
+        } else
+            stp_printf(MSG_WARNING, "remake (%s) success\n", COMBO_T32_DIR);
+    }
+    return 0;
+}
+
+/*
+void wait_sdcard_ready()
+{
+    struct statfs fs_status;
+    int count = 0;
+
+    while (1)
+    {
+        if(statfs("/sdcard",&fs_status)==-1)
+        {
+            count++;
+            stp_printf(MSG_WARNING, "fail to get Sdcard stat :%s, count: %d", strerror(errno), count);
+        }
+        else
+        {
+            if(fs_status.f_blocks==0)
+            {
+                stp_printf(MSG_WARNING, "wait sdcard not ready count:%d,:%s", count, strerror(errno));
+            }
+            else if(fs_status.f_blocks>0)
+            {
+                break;
+            }
+        }
+        sleep(2);
+    }
+}
+*/
+
+static void _stp_hexdump(int level, const char *title, const u8 *buf,
+             size_t len, int show)
+{
+    size_t i;
+    if (level < stp_debug_level)
+        return;
+
+    printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+    if (buf == NULL) {
+        printf(" [NULL]");
+    } else if (show) {
+        for (i = 0; i < len; i++)
+            printf(" %02x", buf[i]);
+    } else {
+        printf(" [REMOVED]");
+    }
+    printf("\n");
+}
+
+void stp_hexdump(int level, const char *title, const u8 *buf, size_t len)
+{
+    _stp_hexdump(level, title, buf, len, 1);
+}
+
+static int stp_dump_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+                        struct sockaddr_un *from,
+                        socklen_t fromlen)
+{
+    struct stp_ctrl_dst *dst;
+
+    dst = os_zalloc(sizeof(*dst));
+    if (dst == NULL)
+        return -1;
+    os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+    dst->addrlen = fromlen;
+    dst->debug_level = MSG_INFO;
+    dst->next = priv->ctrl_dst;
+    priv->ctrl_dst = dst;
+    stp_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
+            (u8 *) from->sun_path,
+            fromlen - offsetof(struct sockaddr_un, sun_path));
+    return 0;
+}
+
+static int stp_dump_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+                        struct sockaddr_un *from,
+                        socklen_t fromlen)
+{
+    struct stp_ctrl_dst *dst, *prev = NULL;
+
+    dst = priv->ctrl_dst;
+    while (dst) {
+        if (fromlen == dst->addrlen &&
+            os_memcmp(from->sun_path, dst->addr.sun_path,
+                  fromlen - offsetof(struct sockaddr_un, sun_path))
+            == 0) {
+            if (prev == NULL)
+                priv->ctrl_dst = dst->next;
+            else
+                prev->next = dst->next;
+            os_free(dst);
+            stp_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+                    (u8 *) from->sun_path,
+                    fromlen -
+                    offsetof(struct sockaddr_un, sun_path));
+            return 0;
+        }
+        prev = dst;
+        dst = dst->next;
+    }
+    return -1;
+}
+
+static int stp_dump_ctrl_iface_level(struct ctrl_iface_priv *priv,
+                       struct sockaddr_un *from,
+                       socklen_t fromlen,
+                       char *level)
+{
+    struct stp_ctrl_dst *dst;
+
+    stp_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s\n", level);
+
+    dst = priv->ctrl_dst;
+    while (dst) {
+        if (fromlen == dst->addrlen &&
+            os_memcmp(from->sun_path, dst->addr.sun_path,
+                  fromlen - offsetof(struct sockaddr_un, sun_path))
+            == 0) {
+            stp_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
+                    "level", (u8 *) from->sun_path,
+                    fromlen -
+                    offsetof(struct sockaddr_un, sun_path));
+            dst->debug_level = atoi(level);
+            return 0;
+        }
+        dst = dst->next;
+    }
+
+    return -1;
+}
+
+static void stp_dump_ctrl_iface_receive(int sock, void *eloop_ctx __attribute__((__unused__)),
+                          void *sock_ctx)
+{
+    struct ctrl_iface_priv *priv = sock_ctx;
+    char buf[256];
+    int res;
+    struct sockaddr_un from;
+    socklen_t fromlen = sizeof(from);
+    size_t reply_len = 0;
+    int new_attached = 0;
+
+    res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+               (struct sockaddr *) &from, &fromlen);
+    if (res < 0) {
+        perror("recvfrom(ctrl_iface)");
+        return;
+    }
+    buf[res] = '\0';
+
+    if (os_strcmp(buf, "ATTACH") == 0) {
+        if (stp_dump_ctrl_iface_attach(priv, &from, fromlen))
+            reply_len = 1;
+        else {
+            new_attached = 1;
+            reply_len = 2;
+        }
+    } else if (os_strcmp(buf, "DETACH") == 0) {
+        if (stp_dump_ctrl_iface_detach(priv, &from, fromlen))
+            reply_len = 1;
+        else
+            reply_len = 2;
+    } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+        if (stp_dump_ctrl_iface_level(priv, &from, fromlen,
+                            buf + 6))
+            reply_len = 1;
+        else
+            reply_len = 2;
+    } else {
+        //stp_hexdump(MSG_INFO, "stp_dump_ctrl_iface_process", buf, 4);
+        //reply = stp_dump_ctrl_iface_process(stp_d, buf,
+        //                      &reply_len);
+    }
+#if 0
+    if (reply) {
+       if ( 0 > sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen))
+           perror("send reply error\n");
+        os_free(reply);
+    } else if (reply_len == 1) {
+#else
+    if (reply_len == 1) {
+#endif
+       if (0 > sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, fromlen))
+           perror("send string 'FAIL' to sock error\n");
+    } else if (reply_len == 2) {
+        if ( 0 > sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen))
+            perror("send string 'OK' to sock error\n");
+    }
+}
+
+
+static char * stp_dump_ctrl_iface_path(struct stp_dump *stp_d)
+{
+    char *buf;
+    size_t len;
+    char *pbuf, *dir = NULL, *gid_str = NULL;
+    int res;
+
+    if (stp_d->ctrl_interface == NULL)
+    {
+        stp_printf(MSG_ERROR, "stp_d->ctrl_interface = NULL\n");
+        return NULL;
+    }
+    pbuf = os_strdup(stp_d->ctrl_interface);
+
+    if (pbuf == NULL)
+    {
+        stp_printf(MSG_ERROR, "copy string failed\n");
+        return NULL;
+    }
+    if (os_strncmp(pbuf, "DIR=", 4) == 0) {
+        dir = pbuf + 4;
+        gid_str = os_strstr(dir, " GROUP=");
+        if (gid_str) {
+            *gid_str = '\0';
+            gid_str += 7;
+        }
+    } else
+        dir = pbuf;
+
+    len = os_strlen(dir) + os_strlen(stp_d->ifname) + 2;
+    buf = os_malloc(len);
+    if (buf == NULL)
+    {
+        stp_printf(MSG_ERROR, "memory allocation failed\n");
+        os_free(pbuf);
+        return NULL;
+    }
+
+    res = os_snprintf(buf, len, "%s/%s", dir, stp_d->ifname);
+    if (res < 0 || (size_t) res >= len)
+    {
+        stp_printf(MSG_ERROR, "os_snprintf failed\n");
+        os_free(pbuf);
+        os_free(buf);
+        return NULL;
+    }
+    os_free(pbuf);
+    return buf;
+}
+
+int stp_dump_ctrl_iface_trace_logger_init(struct trace_iface_priv *tr_priv) {
+    char str[100] = {""};
+    char *file_name[50] = {NULL};
+    int i = 0;
+    struct dirent *pDirent = NULL;
+    DIR *pDir = NULL;
+    struct list_head *node;
+
+    sprintf(str, "%s%s%s", COMBO_T32_DIR, COMBO_T32_NAME, COMBO_T32_ENAME);
+    tr_priv->log_f.fp_t32 = fopen(str, "a+");
+    if (tr_priv->log_f.fp_t32 == NULL) {
+        stp_printf(MSG_ERROR, "create combo_fw.log fails, exit errno:%d\n", errno);
+        exit(EXIT_FAILURE);
+    }
+    if (0 != remove(str))
+        perror("remove combo_fw fails\n");
+
+    pDir = opendir(COMBO_T32_DIR);
+    if (NULL == pDir) {
+        stp_printf(MSG_ERROR, "coredump patch cannot be opened\n");
+        exit(EXIT_FAILURE);
+    }
+    /* stp_printf(MSG_ERROR, "coreduzmp patch opened\n"); */
+
+    while (NULL != (pDirent = readdir(pDir))) {
+        char *dot = strrchr(pDirent->d_name, '.');
+        /* combo_t32_xxxx.cmm */
+        if (0 == strncmp(pDirent->d_name, COMBO_T32_NAME, sizeof(COMBO_T32_NAME)-1) && dot &&
+            0 == strncmp(dot, COMBO_T32_ENAME, sizeof(COMBO_T32_ENAME)-1)) {
+            if (combo_t32_num < COMBO_T32_NUM_MAX) {
+                int file_name_len = 0;
+
+                file_name_len = strlen(pDirent->d_name) + 1;
+                if (file_name_len > 100) {
+                    stp_printf(MSG_ERROR, "combo_t32 length %d over 100\n", file_name_len);
+                    break;
+                }
+                file_name[combo_t32_num] = malloc(100);
+                strncpy(file_name[combo_t32_num], pDirent->d_name, file_name_len);
+                /* stp_printf(MSG_ERROR, "file name:%s\n", file_name[combo_t32_num]); */
+                combo_t32_num++;
+                /* stp_printf(MSG_ERROR, "combo_t32_num:%d\n", combo_t32_num); */
+            } else {
+                /* stp_printf(MSG_ERROR, "file num more than the max\n"); */
+                break;
+            }
+        }
+    }
+    closedir(pDir);
+    bubble_sort(file_name, combo_t32_num);
+
+    INIT_LIST_HEAD(&list_head);
+    for (i = 0; i < combo_t32_num; i++) {
+        node = malloc(sizeof(struct list_head));
+        sprintf(node->file_name, "%s%s", COMBO_T32_DIR, file_name[i]);
+        list_add_tail(node, &list_head);
+        /* stp_printf(MSG_ERROR, "file name:%s\n", node->file_name); */
+        free(file_name[i]);
+    }
+    fclose(tr_priv->log_f.fp_t32);
+    stp_printf(MSG_INFO, "close file combo_t32\n");
+    return 0;
+}
+
+void stp_dump_ctrl_iface_trace_logger_decode(int sock, __attribute__((unused))void *eloop_ctx,
+                          void *sock_ctx)
+{
+    struct nlattr *na;
+    char *stpmsghdr = NULL;
+    int size;
+    struct trace_iface_priv *tr_priv = sock_ctx;
+    GENERIC_NETLINK_PACKET mBuffer;
+    GENERIC_NETLINK_PACKET *prBuffer;
+    int i;
+    int len;
+
+    if ((size = recv(sock, &mBuffer, sizeof(mBuffer), 0)) < 0)
+    {
+        LOGE("recv failed (%s)\n", strerror(errno));
+        return ;
+    }
+
+    prBuffer = &mBuffer;
+
+    /* Validate response message */
+    if (!NLMSG_OK(&(prBuffer->n), (unsigned int)size))
+    {
+        LOGE("invalid reply message\n");
+        return ;
+    }
+    else if (prBuffer->n.nlmsg_type == NLMSG_ERROR)
+    { /* error */
+        LOGE("received error\n");
+        return ;
+    }
+    else if (!NLMSG_OK((&prBuffer->n), (unsigned int)size))
+    {
+        LOGE("invalid reply message received via Netlink\n");
+        return ;
+    }
+
+    size = GENLMSG_PAYLOAD(&prBuffer->n);
+    na = (struct nlattr *) GENLMSG_DATA(prBuffer);
+
+    stpmsghdr = (char *)NLA_DATA(na);
+    if ((stpmsghdr[0] == '[') &&
+        (stpmsghdr[1] == 'M') &&
+        (stpmsghdr[2] == ']')) {
+        static char start_dump = 1;
+
+        /* TODO: parsing message to know the action to start dump */
+        if (start_dump) {
+            char combo_t32[100] = {""};
+            char date[64];
+            time_t t = time(0);
+            struct list_head *node;
+            int file_name_len = 0; // combo_t32 length
+
+            strftime(date, sizeof(date), "%Y%m%d%H%M%S", localtime(&t));
+            file_name_len = strlen(COMBO_T32_DIR) + strlen(COMBO_T32_NAME) + strlen(date) +
+                    strlen(COMBO_T32_ENAME) + 2;
+            if (file_name_len > 100) {
+                stp_printf(MSG_ERROR, "combo_t32 length %d over 100\n", file_name_len);
+                return ;
+            }
+            /*fclose(tr_priv->log_f.fp_t32);*/
+            /*tr_priv->log_f.fp_t32 = 0;*/
+            if (check_log_folder_exit() != 0)
+            {
+                stp_printf(MSG_ERROR, "####log folder %s not exist####", COMBO_T32_DIR);
+                return;
+            }
+            memset(combo_emi, 0, sizeof(combo_emi));
+            sprintf(combo_emi, "%s%s_%s%s", COMBO_T32_DIR, COMBO_T32_NAME, date, EMI_ENAME);
+            if (1) {
+                sprintf(combo_t32, "%s%s_%s%s", COMBO_T32_DIR, COMBO_T32_NAME, date, COMBO_T32_ENAME);
+
+                tr_priv->log_f.fp_t32 = fopen(combo_t32, "w");
+                if (tr_priv->log_f.fp_t32 == NULL) {
+                    stp_printf(MSG_ERROR, "####open %s fail####,%s", combo_t32, strerror(errno));
+                    return;
+                }
+                if (0 != chmod(combo_t32, 00664)) {
+                    perror("chmod combo_t32 error\n");
+                }
+                /* stp_printf(MSG_DEBUG, "create a new file %s\n", combo_t32); */
+                combo_t32_num++;
+
+                if (combo_t32_num < COMBO_T32_NUM_MAX) {
+                    node = malloc(sizeof(struct list_head));
+                    /* stp_printf(MSG_ERROR, "create a new node\n"); */
+                } else {
+                    char tmp[100] = {0};
+                    char *dot;
+
+                    node = list_head.next;
+                    dot = strrchr(node->file_name, '.');
+                    if (dot) {
+                        strncpy(tmp, node->file_name, dot - node->file_name);
+                        strncpy(tmp + (dot - node->file_name), EMI_ENAME, sizeof(EMI_ENAME));
+                    }
+                    list_del(list_head.next);
+                    stp_printf(MSG_ERROR, "combo_t32_num more than max, delete %s and %s\n", node->file_name, tmp);
+                    if (remove(node->file_name))
+                        stp_printf(MSG_ERROR, "combo_t32_num more than max, Unable to delete the %s(%d))\n",
+                                   node->file_name, errno);
+                    if (remove(tmp))
+                        stp_printf(MSG_ERROR, "combo_t32_num more than max, Unable to delete the %s(%d))\n",
+                                   tmp, errno);
+                }
+                strncpy(node->file_name, combo_t32, file_name_len);
+                list_add_tail(node, &list_head);
+
+                /* stp_printf(MSG_DEBUG, "rev coredump len:%d\n", len); */
+                /* stp_printf(MSG_DEBUG, "rev coredump date:%s\n", &stpmsghdr[5]); */
+            }
+
+            ioctl(tr_priv->stp_d->wmt_fd, 10, &stpmsghdr[5]);
+            start_dump = 0;
+        }
+
+        if (strstr(&stpmsghdr[5], EMICOREDUMP_CMD)) {
+            void *map_memory;
+            unsigned int emi_size;
+            FILE *fp_emi;
+            char aee_emi[100] = {""};
+
+            /* Get connsys EMI reserve memory size */
+            emi_size = ioctl(tr_priv->stp_d->wmt_fd, WMT_IOCTL_GET_EMI_PHY_SIZE, 0);
+            stp_printf(MSG_INFO, "emi_size: %d\n", emi_size);
+            fp_emi = fopen(combo_emi, "w");
+            if (fp_emi == NULL) {
+                stp_printf(MSG_ERROR, "####open %s fail####,%s", combo_emi, strerror(errno));
+                start_dump = 1;
+                return;
+            }
+            if (0 != chmod(combo_emi, 00664)) {
+                perror("chmod combo_emi error\n");
+            }
+
+            map_memory = mmap(NULL, emi_size, PROT_READ, MAP_SHARED, tr_priv->stp_d->wmt_fd, 0);
+            if (map_memory == MAP_FAILED)
+                stp_printf(MSG_INFO, "mmap failed\n");
+            else {
+                fwrite(map_memory, 1, emi_size, fp_emi);
+                munmap(map_memory, emi_size);
+            }
+
+            fclose(fp_emi);
+            stp_printf(MSG_INFO, "Dump EMI memory Successfully.\n");
+            /* For AEE, rename file name to SYS_WCN_EMI_DUMP */
+            if (0) {
+                sprintf(aee_emi, "%s%s", COMBO_T32_DIR, EMI_FILE_NAME);
+                if (remove(aee_emi) && errno != ENOENT)
+                    stp_printf(MSG_ERROR, "Unable to delete the %s(%d))\n", aee_emi, errno);
+
+                if (rename(combo_emi, aee_emi))
+                    stp_printf(MSG_ERROR, "Unable to rename the file %s to %s\n", combo_emi, aee_emi);
+                else
+                    stp_printf(MSG_ERROR, "Rename the file %s to %s\n", combo_emi, aee_emi);
+            }
+            ioctl(tr_priv->stp_d->wmt_fd, 11, 0);
+            start_dump = 1;
+            return;
+        }
+
+        len = stpmsghdr[4];
+        len <<= 8;
+        len += stpmsghdr[3];
+        for (i = 0; i < len; i++)
+            fprintf(tr_priv->log_f.fp_t32, "%c",  stpmsghdr[5+i]);
+        fflush(tr_priv->log_f.fp_t32);
+        /* stp_printf(MSG_DEBUG, "rev coredump len:%d\n", len); */
+        /* stp_printf(MSG_DEBUG, "rev coredump date:%s\n", &stpmsghdr[5]); */
+
+        if (len < 1024) {
+            i = 0;
+            do {
+                i++;
+            }while(('c' != stpmsghdr[len - i]) && (i < 50));
+        }
+        if (strstr(&stpmsghdr[5], "coredump end") || strstr(&stpmsghdr[len - i], "coredump end")) {
+            /* inform user to dump action is done */
+            stp_printf(MSG_DEBUG, "coredump end\n");
+            fclose(tr_priv->log_f.fp_t32);
+            tr_priv->log_f.fp_t32 = 0;
+            if (tr_priv->stp_d->chip_type == WMT_CHIP_TYPE_COMBO) {
+                ioctl(tr_priv->stp_d->wmt_fd, 11, 0);
+                start_dump = 1;
+            }
+        }
+    } else
+    {
+        LOGE("invalid dump data\n");
+    }
+
+}
+
+int stp_dump_ctrl_iface_trace_logger_sendto_fd(int s, const char *buf, int bufLen)
+{
+    struct sockaddr_nl nladdr;
+    int r;
+
+    memset(&nladdr, 0, sizeof(nladdr));
+    nladdr.nl_family = AF_NETLINK;
+
+    while ((r = sendto(s, buf, bufLen, 0, (struct sockaddr *) &nladdr,
+                    sizeof(nladdr))) < bufLen)
+    {
+        if (r > 0)
+        {
+            buf += r;
+            bufLen -= r;
+        }
+        else if (errno != EAGAIN)
+        {
+            stp_printf(MSG_ERROR, "%s failed\n", __func__);
+            return -1;
+        }
+    }
+	stp_printf(MSG_INFO, "%s succeed\n", __func__);
+    return 0;
+}
+
+/*
+ * Probe the controller in genetlink to find the family id
+ */
+int stp_dump_ctrl_iface_trace_logger_get_family_id(int sk, const char *family_name)
+{
+    struct nlattr *na;
+    int rep_len;
+    int id = -1;
+    GENERIC_NETLINK_PACKET family_req, ans;
+
+    /* Get family name */
+    family_req.n.nlmsg_type = GENL_ID_CTRL;
+    family_req.n.nlmsg_flags = NLM_F_REQUEST;
+    family_req.n.nlmsg_seq = 0;
+    family_req.n.nlmsg_pid = getpid();
+    family_req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+    family_req.g.cmd = CTRL_CMD_GETFAMILY;
+    family_req.g.version = 0x1;
+
+    na = (struct nlattr *) GENLMSG_DATA(&family_req);
+    na->nla_type = CTRL_ATTR_FAMILY_NAME;
+    na->nla_len = strlen(family_name) + 1 + NLA_HDRLEN;
+    strncpy((char *)NLA_DATA(na), family_name, (strlen(family_name) + 1));
+
+    family_req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
+
+    if (stp_dump_ctrl_iface_trace_logger_sendto_fd(sk, (char *) &family_req, family_req.n.nlmsg_len) < 0)
+    {
+        stp_printf(MSG_ERROR, "%s failed\n", __func__);
+        return -1;
+    }
+
+    rep_len = recv(sk, &ans, sizeof(ans), 0);
+    if (rep_len < 0)
+    {
+        stp_printf(MSG_ERROR, "no response\n");
+        return -1;
+    }
+    /* Validate response message */
+    else if (!NLMSG_OK((&ans.n), (unsigned int)rep_len))
+    {
+        stp_printf(MSG_ERROR,"invalid reply message\n");
+        return -1;
+    }
+    else if (ans.n.nlmsg_type == NLMSG_ERROR)
+    { /* error */
+        stp_printf(MSG_ERROR, "received error\n");
+        return -1;
+    }
+
+    na = (struct nlattr *) GENLMSG_DATA(&ans);
+    na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
+    if (na->nla_type == CTRL_ATTR_FAMILY_ID)
+    {
+        id = *(__u16 *) NLA_DATA(na);
+    }
+
+    return id;
+}
+
+int stp_dump_ctrl_iface_trace_logger_start(struct trace_iface_priv *tr_priv){
+
+    struct sockaddr_nl nladdr;
+    int sz = 64 * 1024;
+    GENERIC_NETLINK_PACKET req;
+    struct nlattr *na;
+    int id;
+    int mlength = 14;
+    const char *message = "HELLO"; //message
+    int rc;
+    int count = 100;
+
+    if (stp_dump_ctrl_iface_trace_logger_init(tr_priv))
+        return -1;
+
+    memset(&nladdr, 0, sizeof(nladdr));
+    nladdr.nl_family = AF_NETLINK;
+    nladdr.nl_pid = getpid();
+
+    if ((tr_priv->sock= socket(AF_NETLINK,
+                        SOCK_RAW,NETLINK_GENERIC)) < 0)
+    {
+        stp_printf(MSG_ERROR, "Unable to create uevent socket: %s", strerror(errno));
+        return -1;
+    }
+
+    if (setsockopt(tr_priv->sock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0)
+    {
+        stp_printf(MSG_ERROR,"Unable to set uevent socket options: %s", strerror(errno));
+        return -1;
+    }
+
+    if (bind(tr_priv->sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0)
+    {
+        stp_printf(MSG_ERROR,"Unable to bind uevent socket: %s", strerror(errno));
+        return -1;
+    }
+
+    while(count--)
+    {
+        id = stp_dump_ctrl_iface_trace_logger_get_family_id(tr_priv->sock, "STP_DBG");
+        if (-1 == id)
+        {
+            stp_printf(MSG_ERROR,"Unable to get family id, Retry");
+            sleep(3);
+        }
+        else
+        {
+            stp_printf(MSG_INFO,"[STP_DBG] family id = %d\n", id);
+            printf("[STP_DBG] family id = %d\n", id);
+            break;
+        }
+    }
+
+    req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+    req.n.nlmsg_type = id;
+    req.n.nlmsg_flags = NLM_F_REQUEST;
+    req.n.nlmsg_seq = 60;
+    req.n.nlmsg_pid = getpid();
+    req.g.cmd = 1;
+
+    na = (struct nlattr *) GENLMSG_DATA(&req);
+    na->nla_type = 1; //MTK_WIFI_ATTR_MSG
+    na->nla_len = mlength + NLA_HDRLEN; //message length
+    memcpy(NLA_DATA(na), message, strlen(message));
+    req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
+
+    stp_printf(MSG_INFO, "sending dummy command\n");
+
+    memset(&nladdr, 0, sizeof(nladdr));
+    nladdr.nl_family = AF_NETLINK;
+
+    rc = sendto(tr_priv->sock, (char *)&req, req.n.nlmsg_len, 0,
+            (struct sockaddr *) &nladdr, sizeof(nladdr));
+#if 0
+    if (rc > 0)
+    {
+        stp_printf(MSG_INFO, "sending dummy command okay\n");
+    }
+    else if (errno != EAGAIN)
+    {
+        stp_printf(MSG_ERROR, "%s failed\n", __func__);
+        return -1;
+    }
+#endif
+    eloop_register_read_sock(tr_priv->sock, stp_dump_ctrl_iface_trace_logger_decode,
+                 tr_priv->stp_d, tr_priv);
+    return 0;
+}
+
+struct ctrl_iface_priv *
+stp_dump_ctrl_iface_init(struct stp_dump *stp_d)
+{
+    struct ctrl_iface_priv *priv;
+    struct trace_iface_priv *tr_priv;
+    struct sockaddr_un addr;
+    char *fname = NULL;
+    gid_t gid = 0;
+    int gid_set = 0;
+    char *buf, *dir = NULL, *gid_str = NULL;
+    struct group *grp;
+    char *endp;
+
+    priv = os_zalloc(sizeof(*priv));
+    if (priv == NULL)
+    {
+        stp_printf(MSG_ERROR, "memory allocation for priv failed\n");
+        return NULL;
+    }
+
+    tr_priv = os_zalloc(sizeof(*tr_priv));
+    if(tr_priv == NULL)
+    {
+        stp_printf(MSG_ERROR, "memory allocation for tr_priv failed\n");
+        os_free(priv);
+        priv = NULL;
+        return NULL;
+    }
+
+    priv->stp_d = stp_d;
+    priv->sock = -1;
+
+    tr_priv->stp_d = stp_d;
+    tr_priv->sock = -1;
+
+    if (stp_d->ctrl_interface == NULL)
+    {
+        stp_printf(MSG_ERROR, "stp_d->ctrl_interface = NULL\n");
+        os_free(priv);
+        priv = NULL;
+        os_free(tr_priv);
+        tr_priv = NULL;
+        return priv;
+    }
+
+    buf = os_strdup(stp_d->ctrl_interface);
+    if (buf == NULL)
+    {
+        stp_printf(MSG_ERROR, "os_strdup\n");
+        goto fail;
+    }
+
+    os_snprintf(addr.sun_path, sizeof(addr.sun_path), "stp_%s",
+            stp_d->ctrl_interface);
+    stp_printf(MSG_INFO, "addr.sun_path:%s\n", addr.sun_path);
+/*
+	priv->sock = android_get_control_socket(addr.sun_path);
+    if (priv->sock >= 0)
+    {
+        stp_printf(MSG_INFO, "priv->sock already exist\n");
+        goto havesock;
+    }
+*/
+    if (os_strncmp(buf, "DIR=", 4) == 0) {
+        dir = buf + 4;
+        gid_str = os_strstr(dir, " GROUP=");
+        if (gid_str) {
+            *gid_str = '\0';
+            gid_str += 7;
+        }
+    } else {
+        dir = buf;
+        gid_str = stp_d->ctrl_interface_group;
+    }
+
+    if (mkdir(dir, 00777) < 0)
+    {
+        if (errno == EEXIST)
+        {
+            stp_printf(MSG_INFO, "Using existing control "
+                   "interface directory.\n");
+        }
+        else
+        {
+            stp_printf(MSG_ERROR, "mkdir (%s) failed:(%s)\n", dir, strerror(errno));
+            perror("mkdir[ctrl_interface]");
+            goto fail;
+        }
+    }
+    stp_printf(MSG_INFO, "mkdir (%s) succeed\n", dir);
+    if (gid_str)
+    {
+        //grp = getgrnam("system");
+        grp = getgrnam("sys");
+        if (grp)
+        {
+            gid = grp->gr_gid;
+            gid_set = 1;
+            stp_printf(MSG_INFO, "ctrl_interface_group=%d"
+                   " (from group name '%s')\n",
+                   (int) gid, gid_str);
+        }
+        else
+        {
+            /* Group name not found - try to parse this as gid */
+            gid = strtol(gid_str, &endp, 10);
+            if (*gid_str == '\0' || *endp != '\0') {
+                stp_printf(MSG_ERROR, "CTRL: Invalid group "
+                       "'%s'\n", gid_str);
+                goto fail;
+            }
+            gid_set = 1;
+            stp_printf(MSG_INFO, "ctrl_interface_group=%d\n",
+                   (int) gid);
+        }
+    }
+
+    if (gid_set && chown(dir,  getuid(), gid) < 0)
+    {
+        perror("chown[ctrl_interface]");
+		stp_printf(MSG_ERROR, "chown (%s) failed\n", dir);
+        goto fail;
+    }
+    stp_printf(MSG_INFO, "chown (%s) succeed\n", dir);
+
+    /* Make sure the group can enter and read the directory */
+    if (gid_set &&
+    chmod(dir, 00775) < 0)
+    {
+        stp_printf(MSG_ERROR, "CTRL: chmod[%s]: %s\n", dir, strerror(errno));
+        goto fail;
+    }
+    stp_printf(MSG_INFO, "CTRL: chmod[%s] succeed\n", dir);
+    if (os_strlen(dir) + 1 + os_strlen(stp_d->ifname) >=
+        sizeof(addr.sun_path))
+    {
+        stp_printf(MSG_ERROR, "ctrl_iface path limit exceeded\n");
+        goto fail;
+    }
+
+    if (stp_dump_ctrl_iface_trace_logger_start(tr_priv))
+        goto fail;
+    priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+    if (priv->sock < 0)
+    {
+        perror("socket(PF_UNIX)");
+		stp_printf(MSG_ERROR, "create socket failed\n");
+        goto fail;
+    }
+
+    os_memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+
+    fname = stp_dump_ctrl_iface_path(stp_d);
+
+    if (fname == NULL)
+    {
+        stp_printf(MSG_ERROR, "stp_dump_ctrl_iface_path failed\n");
+        goto fail;
+    }
+    os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+    if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        stp_printf(MSG_ERROR, "ctrl_iface bind(PF_UNIX) failed: %s\n",
+               strerror(errno));
+        if (connect(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+            stp_printf(MSG_ERROR, "ctrl_iface exists, but does not"
+                   " allow connections - assuming it was left"
+                   "over from forced program termination\n");
+            if (unlink(fname) < 0) {
+                perror("unlink[ctrl_iface]");
+                stp_printf(MSG_ERROR, "Could not unlink "
+                       "existing ctrl_iface socket '%s'\n",
+                       fname);
+                goto fail;
+            }
+            if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+                perror("bind(PF_UNIX)");
+                goto fail;
+            }
+            stp_printf(MSG_DEBUG, "Successfully replaced leftover " "ctrl_iface socket '%s'\n", fname);
+        } else {
+            stp_printf(MSG_INFO, "ctrl_iface exists and seems to " "be in use - cannot override it\n");
+            stp_printf(MSG_INFO, "Delete '%s' manually if it is "
+                   "not used anymore\n", fname);
+            os_free(fname);
+            fname = NULL;
+            goto fail;
+        }
+    }
+    if (gid_set && chown(fname, -1, gid) < 0) {
+        perror("chown[ctrl_interface/ifname]");
+		stp_printf(MSG_ERROR, "chown(%s) failed, ", fname);
+        goto fail;
+    }
+
+    if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+        perror("chmod[ctrl_interface/ifname]");
+		stp_printf(MSG_ERROR, "chmod(%s) failed, ", fname);
+        goto fail;
+    }
+    os_free(fname);
+    fname = NULL;
+    /* open wmt dev */
+    stp_d->wmt_fd = open("/dev/stpwmt", O_RDWR | O_NOCTTY);
+    if (stp_d->wmt_fd < 0) {
+        stp_printf(MSG_ERROR, "[%s] Can't open stpwmt \n", __FUNCTION__);
+        goto fail;
+    }
+    tr_priv->stp_d->chip_type = ioctl(tr_priv->stp_d->wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 4);
+
+havesock:
+    eloop_register_read_sock(priv->sock, stp_dump_ctrl_iface_receive,
+                 stp_d, priv);
+
+    os_free(buf);
+    buf = NULL;
+    return priv;
+
+fail:
+    if (priv->sock >= 0)
+        close(priv->sock);
+    os_free(priv);
+    os_free(tr_priv);
+    priv = NULL;
+    tr_priv = NULL;
+    if (fname) {
+        unlink(fname);
+        os_free(fname);
+        fname = NULL;
+    }
+    os_free(buf);
+    buf = NULL;
+    return NULL;
+}
+
+
+void stp_dump_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+#if 0
+    struct wpa_ctrl_dst *dst, *prev;
+#endif
+    struct stp_ctrl_dst *dst, *prev;
+    stp_printf(MSG_INFO, "%s\n", __func__);
+    os_sleep(1, 0);
+    /* close wmt dev */
+    if (priv->stp_d->wmt_fd >= 0) {
+        close(priv->stp_d->wmt_fd);
+    }
+
+    if (priv->sock > -1) {
+        char *fname;
+        char *buf, *dir = NULL, *gid_str = NULL;
+        eloop_unregister_read_sock(priv->sock);
+        if (priv->ctrl_dst) {
+            /*
+             * Wait a second before closing the control socket if
+             * there are any attached monitors in order to allow
+             * them to receive any pending messages.
+             */
+            stp_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
+                   "monitors to receive messages\n");
+            os_sleep(1, 0);
+        }
+        close(priv->sock);
+        priv->sock = -1;
+#if 0
+        fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s);
+#endif
+        fname = stp_dump_ctrl_iface_path(priv->stp_d);
+        if (fname) {
+            unlink(fname);
+            os_free(fname);
+            fname = NULL;
+        }
+#if 0
+        buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
+#endif
+        buf = os_strdup(priv->stp_d->ctrl_interface);
+        if (buf == NULL)
+            goto free_dst;
+        if (os_strncmp(buf, "DIR=", 4) == 0) {
+            dir = buf + 4;
+            gid_str = os_strstr(dir, " GROUP=");
+            if (gid_str) {
+                *gid_str = '\0';
+                gid_str += 7;
+            }
+        } else
+            dir = buf;
+
+        if (rmdir(dir) < 0) {
+            if (errno == ENOTEMPTY) {
+                stp_printf(MSG_DEBUG, "Control interface "
+                       "directory not empty - leaving it "
+                       "behind\n");
+            } else {
+                perror("rmdir[ctrl_interface]");
+            }
+        }
+        os_free(buf);
+    }
+
+free_dst:
+    dst = priv->ctrl_dst;
+    while (dst) {
+        prev = dst;
+        dst = dst->next;
+        os_free(prev);
+    }
+    os_free(priv);
+}
+
+void stp_dump_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+    char buf[256];
+    int res;
+    struct sockaddr_un from;
+    socklen_t fromlen = sizeof(from);
+
+    for (;;) {
+        stp_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
+               "attach\n", priv->stp_d->ifname);
+        eloop_wait_for_read_sock(priv->sock);
+
+        res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
+                   (struct sockaddr *) &from, &fromlen);
+        if (res < 0) {
+            perror("recvfrom(ctrl_iface)");
+            continue;
+        }
+        buf[res] = '\0';
+
+        if (os_strcmp(buf, "ATTACH") == 0) {
+            /* handle ATTACH signal of first monitor interface */
+            if (!stp_dump_ctrl_iface_attach(priv, &from,
+                                  fromlen)) {
+               if (0 > sendto(priv->sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen))
+                   perror("send string 'OK' to sock error\n");
+                /* OK to continue */
+                return;
+            } else {
+                if (0 > sendto(priv->sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, fromlen))
+                    perror("send string 'FAIL' to sock error\n");
+            }
+        } else {
+            /* return FAIL for all other signals */
+           if (0 > sendto(priv->sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, fromlen))
+                perror("send string 'FAIL' to sock error\n");
+        }
+    }
+}
+
+static void stp_dump_terminate(__attribute__((unused))int sig, __attribute__((unused))void *eloop_ctx,
+                     __attribute__((unused))void *signal_ctx)
+{
+    eloop_terminate();
+}
+
+int stp_dump_run(void)
+{
+    eloop_register_signal_terminate(stp_dump_terminate, NULL);
+    eloop_run();
+    return 0;
+}
+
+void set_sched_prio(void)
+{
+    struct sched_param sched, test_sched;
+    int policy = 0xff;
+    int err=0xff;
+
+    policy = sched_getscheduler(0);
+    sched_getparam(0, &test_sched);
+    printf("Before %s policy = %d, priority = %d\n", "main" , policy, test_sched.sched_priority);
+
+    sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
+    err = sched_setscheduler(0, SCHED_FIFO, &sched);
+    if(err == 0){
+         printf("pthread_setschedparam SUCCESS \n");
+         policy = sched_getscheduler(0);
+         sched_getparam(0, &test_sched);
+         printf("After %s policy = %d, priority = %d\n", "main" ,policy , test_sched.sched_priority);
+    }
+    else{
+         if(err == EINVAL) printf("policy is not one of SCHED_OTHER, SCHED_RR, SCHED_FIFO\n");
+         if(err == EINVAL) printf("the  priority  value  specified by param is not valid for the specified policy\n");
+         if(err == EPERM) printf("the calling process does not have superuser permissions\n");
+         if(err == ESRCH) printf("the target_thread is invalid or has already terminated\n");
+         if(err == EFAULT)  printf("param points outside the process memory space\n");
+         printf("pthread_setschedparam FAIL \n");
+    }
+}
+
+int main(__attribute__((unused))int argc, __attribute__((unused))char *argv[]){
+
+    struct stp_dump *stp_d = NULL;
+    /* This folder is created by init_connectivity.rc*/
+    const char *conf ="DIR=/data/misc/stp_dump GROUP=stp";
+    const char *ifname = "stpd";
+    const char *sname = "data/misc";
+    char value[PROPERTY_VALUE_MAX];
+
+    stp_printf(MSG_INFO, "==>%s \n", __func__ );
+
+/*
+    wait_sdcard_ready();
+
+    property_get("ro.crypto.state", value, "");
+    if (!strcmp(value, "")) {
+            do {
+                    stp_printf(MSG_INFO, "ro.crypto.state is NULL, Retry");
+                    sleep(1);
+                    property_get("ro.crypto.state", value, "");
+                    stp_printf(MSG_INFO, "ro.crypto.state: %s!", value);
+            }while(!strcmp(value, ""));
+    }
+    stp_printf(MSG_INFO, "ro.crypto.state: %s!", value);
+    if (0 == strcmp(value, "encrypted")) {
+        property_get("ro.crypto.type", value, "");
+        if (!strcmp(value, "file")) {
+            do {
+                stp_printf(MSG_INFO, "FBE feature is open, waiting for decrypt done");
+                sleep(1);
+                if (access(sname, F_OK|R_OK|W_OK) == 0)
+                    break;
+            } while (1);
+        } else {
+            property_get("vold.decrypt", value, "");
+            if (strcmp(value, "trigger_restart_framework")) {
+                do {
+                    stp_printf(MSG_INFO, "Waiting for decrypt done");
+                    sleep(1);
+                    property_get("vold.decrypt", value, "");
+                    stp_printf(MSG_INFO, "vold.decrypt: %s!", value);
+                }while(strcmp(value, "trigger_restart_framework"));
+            }
+            stp_printf(MSG_INFO, "vold.decrypt: %s!", value);
+        }
+            stp_printf(MSG_INFO, "Decrypt done!");
+    } else
+            stp_printf(MSG_INFO, "Device is unencrypted!");
+*/
+    stp_d = os_zalloc(sizeof(struct stp_dump));
+    if (stp_d == NULL)
+    {
+        stp_printf(MSG_ERROR, "memory allocation for stp_dump failed\n");
+        return -1;
+    }
+    stp_d->ctrl_interface = conf;
+    stp_d->ifname = ifname;
+    stp_d->ctrl_iface = stp_dump_ctrl_iface_init(stp_d);
+    if (stp_d->ctrl_iface == NULL)
+    {
+        stp_printf(MSG_ERROR,
+               "Failed to initialize control interface '%s'.\n"
+               "You may have another stp_dump process "
+               "already running or the file was\n"
+               "left by an unclean termination of stp_dump "
+               "in which case you will need\n"
+               "to manually remove this file before starting "
+               "wpa_supplicant again.\n",
+               "used by stp_dump\n");
+        return -1;
+    }
+    else
+    {
+        stp_printf(MSG_INFO, "stp_dump_ctrl_iface_init succeed.\n");
+    }
+    stp_printf(MSG_INFO, "==>%s222 \n", __func__ );
+
+    //set_sched_prio();
+
+    bt_fw_logger_start();
+
+	wifi_fw_logger_start();
+
+    stp_dump_run();
+
+    stp_dump_ctrl_iface_deinit(stp_d->ctrl_iface);
+
+	wifi_fw_logger_stop();
+
+    bt_fw_logger_stop();
+    os_free(stp_d);
+
+    return 0;
+}
+
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/stp_dump.h b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/stp_dump.h
new file mode 100644
index 0000000..c5fad81
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/stp_dump.h
@@ -0,0 +1,65 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ * 
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ * 
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef STP_DUMP_H
+#define STP_DUMP_H
+extern int stp_debug_level;
+
+#ifndef ALOGI
+#define ALOGI printf
+#endif
+#ifndef ALOGE
+#define ALOGE printf
+#endif
+#ifndef ALOGD
+#define ALOGD printf
+#endif
+
+#ifndef PROPERTY_VALUE_MAX
+#define PROPERTY_VALUE_MAX (128)
+#endif
+
+
+enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
+extern void android_printf(int level, char *format, ...);
+#define stp_printf(level, ...) \
+        do {                                            \
+            printf(__VA_ARGS__);  \
+        } while (0)
+
+#endif
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/wifi_fw_logger.c b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/wifi_fw_logger.c
new file mode 100644
index 0000000..e4e6e84
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/wifi_fw_logger.c
@@ -0,0 +1,311 @@
+/**
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2016. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#define WIFI_FW_LOG_NODE  "/dev/fw_log_wifi"
+#define WIFI_FW_LOG_PATH  "/data/misc/stp_dump"
+#define DUMP_WIFI_FW_NAME_EXT ".wifi"
+#define DUMP_WIFI_FW_NAME_PREFIX "dump_"
+#define WIFI_FW_LOG_SIZE  (1 * 1024 * 1024)
+#define WIFI_FW_LOG_BUF_SIZE  (1944)    // Cover old WIFI driver return size
+#define LOG_VERSION 0x100
+
+#define TRUE    (1)
+#define FALSE   (0)
+
+static const unsigned long BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
+static unsigned long timestamp = 0;
+static unsigned int dump_file_seq_num = 0;
+static int file_size_remain_to_switch = 0;
+static uint8_t buffer[WIFI_FW_LOG_BUF_SIZE] = {0};
+static int log_file_num = 6;
+static int logger_on = 1;
+
+static pthread_t wifi_fw_logger_thread = 0;
+static int wifi_fw_log_fd = 0;
+
+static void remove_old_log_files(int all, int index)
+{
+    /* check already exist file under log_path */
+    char temp_wifi_fw_filename[36] = {0};
+    char wifi_fw_fullname[256] = {0};
+
+    DIR *p_dir = opendir(WIFI_FW_LOG_PATH);
+    if (p_dir != NULL)
+    {
+        struct dirent *p_file;
+        while ((p_file = readdir(p_dir)) != NULL)
+        {
+            /* ignore . and .. directory */
+            if (strncmp(p_file->d_name, "..", 2) == 0
+                || strncmp(p_file->d_name, ".", 1) == 0)
+            {
+                continue;
+            }
+            memset(temp_wifi_fw_filename, 0, sizeof(temp_wifi_fw_filename));
+            memset(wifi_fw_fullname, 0, sizeof(wifi_fw_fullname));
+            if (strstr(p_file->d_name, DUMP_WIFI_FW_NAME_EXT) != NULL)
+            {
+                if (all)    //remove all old log files
+                {
+                    snprintf(wifi_fw_fullname, sizeof(wifi_fw_fullname), "%s/%s", WIFI_FW_LOG_PATH, p_file->d_name);
+                    if (remove(wifi_fw_fullname)) {
+                        printf("[wifi_fw_logger]The old log:%s can't remove, errno: %d\n", p_file->d_name, errno);
+                    }
+                    else {
+                        printf("[wifi_fw_logger]The old log: %s is removed\n", p_file->d_name);
+                    }
+                }
+                else    //remove a specific log file
+                {
+                    snprintf(temp_wifi_fw_filename, sizeof(temp_wifi_fw_filename), "_%d.wifi", index);
+                    if (strstr(p_file->d_name, temp_wifi_fw_filename) != NULL) {
+                        snprintf(wifi_fw_fullname, sizeof(wifi_fw_fullname), "%s/%s", WIFI_FW_LOG_PATH, p_file->d_name);
+                        if (remove(wifi_fw_fullname)) {
+                        printf("[wifi_fw_logger]The old log: %s can't remove, errno: %d\n", p_file->d_name, errno);
+                        } else {
+                            printf("[wifi_fw_logger]The old log: %s is removed\n", p_file->d_name);
+                        }
+                    }
+                }
+            }
+        }
+        closedir(p_dir);
+    }
+    else
+    {
+        printf("[wifi_fw_logger]readdir fail, errno: %d\n", errno);
+    }
+}
+
+static unsigned long btsnoop_timestamp(void)
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    // Timestamp is in microseconds.
+    timestamp = tv.tv_sec * 1000000ULL;
+    timestamp += tv.tv_usec;
+    timestamp += BTSNOOP_EPOCH_DELTA;
+    return timestamp;
+}
+
+static void fillheader(unsigned char *header, int headerlen,
+        unsigned short int dump_file_seq_num)
+{
+    int copy_header_len = 0;
+    unsigned int logversion = htobe32(LOG_VERSION);
+    memset(header, 0, headerlen);
+    memcpy(header, &logversion, sizeof(logversion));
+    copy_header_len += 4;   /** 4 byte for logversion */
+    copy_header_len += 4;   /** 4 byte for chip id, not implement yet */
+    dump_file_seq_num = htobe16(dump_file_seq_num);
+    memcpy(header + copy_header_len, &dump_file_seq_num, sizeof(dump_file_seq_num));
+    copy_header_len += 2;   /** 2 byte for sequence number */
+    copy_header_len += 6;   /** first hci log length(2), zero(4) */
+    btsnoop_timestamp();
+    timestamp = htobe64(timestamp);
+    memcpy(header + copy_header_len, &timestamp, sizeof(timestamp));
+}
+
+static FILE * create_new_log_file(int index)
+{
+    time_t local_timestamp;
+    char timestamp_buffer[24];
+    char dump_file_name[128] = {0};
+    unsigned char header[24] = {0};
+    unsigned char padding[8] = {0};
+    FILE *fp = NULL;
+
+    /* get current timestamp */
+    time(&local_timestamp);
+    strftime(timestamp_buffer, 24, "%Y%m%d%H%M%S", localtime(&local_timestamp));
+    snprintf(dump_file_name, sizeof(dump_file_name), "%s/" DUMP_WIFI_FW_NAME_PREFIX "%s_%d" DUMP_WIFI_FW_NAME_EXT, WIFI_FW_LOG_PATH, timestamp_buffer, index);
+
+    /* dump file for picus log */
+    if ((fp = fopen(dump_file_name, "wb")) == NULL) {
+        printf("[wifi_fw_logger]create log file %s fail [%s] errno %d\n", dump_file_name, strerror(errno), errno);
+        return NULL;
+    } else {
+        printf("[wifi_fw_logger]log file %s is created, dumping...\n", dump_file_name);
+    }
+
+    fillheader(header, sizeof(header), index);
+    fwrite(header, 1, sizeof(header), fp);
+    fwrite(padding, 1, sizeof(padding), fp);
+    file_size_remain_to_switch = WIFI_FW_LOG_SIZE;
+
+    return fp;
+}
+
+static void *wifi_fw_logger_main(void *arg)
+{
+    int nRead = 0;
+    int nWritten = 0;
+    fd_set rset;    /** For select */
+    struct timeval tv;
+    FILE *current_fp = NULL;
+    int current_index = 0;
+
+    printf("[wifi_fw_logger]%s, thread_id: 0x%x\n", __func__, pthread_self());
+
+    current_fp = create_new_log_file(0);
+    if (NULL == current_fp)
+    {
+        printf("[wifi_fw_logger]fatal error: create new log file fail\n");
+        return NULL;
+    }
+
+    do
+    {
+        FD_ZERO(&rset);
+        FD_SET(wifi_fw_log_fd, &rset);
+        tv.tv_sec = 10; /* timeout is 10s for select method */
+        tv.tv_usec = 0;
+        if (select(wifi_fw_log_fd + 1, &rset, NULL, NULL, &tv) == 0) {
+            printf("[wifi_fw_logger]Read data timeout(10s) from fw_log_wifi\n");
+            continue;
+        }
+
+        if (!FD_ISSET(wifi_fw_log_fd, &rset))
+            continue;
+        /* Read all packet from driver fwlog queue */
+        nRead = read(wifi_fw_log_fd, buffer, sizeof(buffer));
+        if (nRead > 0)
+        {
+            nWritten = fwrite(buffer, 1, nRead, current_fp);
+            if (nWritten != nRead)
+            {
+                printf("[wifi_fw_logger]write may fail, nRead(%d) != nWritten(%d)\n", nRead, nWritten);
+            }
+            file_size_remain_to_switch -= nWritten;
+        }
+        else if (nRead < 0)
+        {
+            printf("[wifi_fw_logger]read fail, errno=%d\n", errno);
+            continue;
+        }
+        /* switch file name if file size is over file_size */
+        if (file_size_remain_to_switch <= 0) {
+            file_size_remain_to_switch = WIFI_FW_LOG_SIZE;
+            fclose(current_fp);
+            if (log_file_num - 1 > current_index) {
+                current_index++;
+            } else {
+                current_index = 0;
+            }
+            /* remove the file before creating */
+            remove_old_log_files(FALSE, current_index);
+            current_fp = create_new_log_file(current_index);
+            if (NULL == current_fp)
+            {
+                printf("[wifi_fw_logger]create new log file fail\n");
+                //TODO
+            }
+        }
+        fflush(current_fp);
+    } while (logger_on);
+
+
+    printf("[wifi_fw_logger]%s exit, thread_id: 0x%x\n", __func__, pthread_self());
+
+    return NULL;
+}
+
+
+void wifi_fw_logger_start(void)
+{
+    printf("[wifi_fw_logger]%s\n", __func__);
+    if (wifi_fw_log_fd > 0)
+    {
+        printf("%s, device is already opened\n", __func__);
+        return;
+    }
+    //1. open device
+    wifi_fw_log_fd = open(WIFI_FW_LOG_NODE, O_RDWR | O_NOCTTY | O_NONBLOCK);
+    if (wifi_fw_log_fd <= 0) {
+        printf("[wifi_fw_logger]Can't open device node %s, errno: %d\n", WIFI_FW_LOG_NODE, errno);
+        return;
+    } else {
+        printf("[wifi_fw_logger]Open device node successfully wifi_fw_log_fd = %d\n", wifi_fw_log_fd);
+    }
+
+    remove_old_log_files(TRUE, 0);
+
+    //2. create logger thread
+    if (wifi_fw_logger_thread == 0)
+    {
+        pthread_attr_t thread_attr;
+
+        pthread_attr_init(&thread_attr);
+        pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+        if (pthread_create(&wifi_fw_logger_thread, &thread_attr, wifi_fw_logger_main, NULL))
+        {
+            printf("[wifi_fw_logger]create logger thread fail\n",__func__);
+            wifi_fw_logger_thread = 0;
+            return;
+        }
+        pthread_attr_destroy(&thread_attr);
+    }
+}
+
+void wifi_fw_logger_stop(void)
+{
+    //disable fw log first
+    //system("echo raw-hex, 01 5d fc 04 02 00 01 00 > /dev/fw_log_bt");
+
+    if (wifi_fw_log_fd > 0)
+    {
+        close(wifi_fw_log_fd);
+    }
+
+    //thread exit
+    logger_on = 0;
+    wifi_fw_logger_thread = 0;
+    printf("[wifi_fw_logger]%s\n", __func__);
+
+}
+//---------------------------------------------------------------------------
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/wifi_fw_logger.h b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/wifi_fw_logger.h
new file mode 100644
index 0000000..4a6814b
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_dump/wifi_fw_logger.h
@@ -0,0 +1,40 @@
+/**
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2016. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+void wifi_fw_logger_start(void);
+void wifi_fw_logger_stop(void);
+
+
+//---------------------------------------------------------------------------
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/stp_uart_launcher.c b/src/connectivity/combo_tool/6631_combo_tool/src/stp_uart_launcher.c
new file mode 100644
index 0000000..cc489a9
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/stp_uart_launcher.c
@@ -0,0 +1,1831 @@
+
+/******************************************************************************
+*                         C O M P I L E R   F L A G S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                    E X T E R N A L   R E F E R E N C E S
+*******************************************************************************
+*/
+#include "wmt_ioctl.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <pthread.h>
+/*#include <syslog.h>*/
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/endian.h>
+#include <sys/uio.h>
+#include <linux/serial.h> /* struct serial_struct  */
+#include <log/log.h>
+
+#include <dirent.h>
+#include <cutils/properties.h>
+
+
+/******************************************************************************
+*                              M A C R O S
+*******************************************************************************
+*/
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG    "wmt_launcher"
+
+#define  WCN_COMBO_CHIP_ID_PROP             "persist.vendor.connsys.chipid"
+#define  WCN_DRIVER_READY_PROP              "vendor.connsys.driver.ready"
+#define  WCN_FORMETA_READY_PROP             "vendor.connsys.formeta.ready"
+#define  WCN_FW_DBG_LOG_PROP                "persist.vendor.connsys.fwlog.status"
+#define  WCN_DYNAMIC_DUMP_PROP              "persist.vendor.connsys.dynamic.dump"
+#define  WCN_COMBO_PATCH_BUILD_VER_PROP     "persist.vendor.connsys.patch.version"
+#define  WCN_FW_DEBUG_CLRL_RETRY_LIMIT      (5)
+
+//#include "cust_mt6620_test.h" /* project custom header file */
+
+#ifndef N_MTKSTP
+#define N_MTKSTP                (15 + 1)  /* MediaTek WCN Serial Transport Protocol */
+#endif
+#define HCIUARTSETPROTO          _IOW('U', 200, int)
+#define CUST_COMBO_WMT_DEV       "/dev/stpwmt"
+#define CUST_COMBO_STP_DEV       "/dev/ttyMT2"
+#define CUST_COMBO_PATCH_PATH    "/vendor/firmware"
+#define CUST_COMBO_CFG_FILE      "/system/vendor/firmware/WMT.cfg"
+
+#define CUST_BAUDRATE_DFT        (115200)
+#define CUST_MULTI_PATCH         (1)
+#define CUST_PATCH_SEARCH        (1)
+#define PATCH_BUILD_VER_LEN      (16)
+#define MAX_CMD_LEN              (NAME_MAX+1)
+
+#define LAUNCHER_DEBUG           (0)
+
+/******************************************************************************
+*                             D A T A   T Y P E S
+*******************************************************************************
+*/
+
+enum stp_modes {
+    STP_MIN = 0x0,
+    STP_UART_FULL = 0x1,
+    STP_UART_MAND = 0x2,
+    STP_BTIF_FULL = 0x3,
+    STP_SDIO = 0x4,
+    STP_MAX = 0x5,
+};
+
+enum stp_uart_fc {
+    UART_DISABLE_FC = 0, /*NO flow control*/
+    UART_MTK_SW_FC = 1,  /*MTK SW Flow Control, differs from Linux Flow Control*/
+    UART_LINUX_FC = 2,   /*Linux SW Flow Control*/
+    UART_HW_FC = 3,      /*HW Flow Control*/
+};
+
+struct sys_property {
+    const char *key;
+    const char *def_value;
+    char value[PROPERTY_VALUE_MAX];
+};
+
+
+struct stp_uart_config {
+    enum stp_uart_fc fc;
+    int parity;
+    int stop_bit;
+    int baud_rate;
+};
+
+struct stp_params_config {
+    enum stp_modes stp_mode;
+    int fm_mode;
+    char patch_path[NAME_MAX + 1];
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+    char patch_name[NAME_MAX + 1];
+#endif
+    char stp_dev[NAME_MAX + 1];
+    struct stp_uart_config uart_config;
+};
+
+
+#if CUST_MULTI_PATCH
+struct stp_patch_info {
+    int download_seq;
+    char address[4];
+    char patch_name[NAME_MAX + 1];
+};
+
+struct stp_rom_patch_info {
+    int type;
+    char address[4];
+    char patch_name[NAME_MAX + 1];
+};
+#endif
+
+struct chip_ant_mode_info {
+    const char *cfg_item;
+    char cfg_item_value[NAME_MAX + 1];
+};
+
+struct chip_mode_info {
+    int chip_id;
+    enum stp_modes stp_mode;
+    struct chip_ant_mode_info ant_mode;
+};
+
+#ifndef WMT_PLAT_APEX
+struct chip_mode_info g_chip_mode_info[] = {
+    {0x6620, STP_UART_FULL, {"mt6620.defAnt", "mt6620_ant_m3.cfg"}},
+    {0x6628, STP_UART_FULL, {"mt6628.defAnt", "mt6628_ant_m1.cfg"}},
+    {0x6630, STP_SDIO,      {"mt6630.defAnt", "mt6630_ant_m1.cfg"}},
+    {0x6632, STP_SDIO,      {"mt6632.defAnt", "mt6632_ant_m1.cfg"}},
+};
+#else
+struct chip_mode_info g_chip_mode_info[] = {
+    {0x6620, STP_UART_FULL, {"mt6620.defAnt", "WMT.cfg"}},
+    {0x6628, STP_UART_FULL, {"mt6628.defAnt", "WMT.cfg"}},
+    {0x6630, STP_SDIO,      {"mt6630.defAnt", "WMT.cfg"}},
+    {0x6632, STP_SDIO,      {"mt6632.defAnt", "WMT.cfg"}},
+};
+#endif
+
+struct fw_debug_infor {
+    int log_retry; /* for polling log property retry */
+    int dump_retry; /*for polling dump property retry */
+
+    int fw_log_ctrl; /* fw log output by emi ctrl */
+    int fw_dynamic_dump; /*fw coredump dynamic regin dump*/
+
+    /* fw log output by emi state ctrl */
+    char fw_log_state_orig[PROPERTY_VALUE_MAX];
+    char fw_log_state_new[PROPERTY_VALUE_MAX];
+
+    /* fw coredump dynamic regin dump state ctrl */
+    char fw_dump_state_orig[PROPERTY_VALUE_MAX];
+    char fw_dump_state_new[PROPERTY_VALUE_MAX];
+
+    unsigned int bitmap;
+};
+
+struct cmd_hdr{
+    char *cmd;
+    int (*hdr_func)(struct stp_params_config *configs);
+};
+
+struct speed_map {
+    unsigned int baud;
+    speed_t      speed;
+};
+
+/******************************************************************************
+*                   F U N C T I O N   D E C L A R A T I O N S
+*******************************************************************************
+*/
+static int cmd_hdr_baud_115k(struct stp_params_config *configs);
+static int cmd_hdr_baud_921k(struct stp_params_config *configs);
+static int cmd_hdr_baud_2kk(struct stp_params_config *configs);
+static int cmd_hdr_baud_2_5kk(struct stp_params_config *configs);
+static int cmd_hdr_baud_3kk(struct stp_params_config *configs);
+static int cmd_hdr_baud_3_5kk(struct stp_params_config *configs);
+static int cmd_hdr_baud_4kk(struct stp_params_config *configs);
+static int cmd_hdr_stp_open(struct stp_params_config *configs);
+static int cmd_hdr_stp_close(struct stp_params_config *configs);
+static int cmd_hdr_stp_rst(struct stp_params_config *configs);
+static int cmd_hdr_sch_patch(struct stp_params_config *configs);
+static int cmd_hdr_sch_rom_patch(struct stp_params_config *configs);
+
+
+/******************************************************************************
+*                            P U B L I C   D A T A
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                           P R I V A T E   D A T A
+*******************************************************************************
+*/
+static struct speed_map g_speeds[] = {
+    {115200,    B115200},
+    {921600,    B921600},
+    {1000000,    B1000000},
+    {1152000,    B1152000},
+    {2000000,    B2000000},
+    {2500000,    B2500000},
+    {3000000,    B3000000},
+    {3500000,    B3500000},
+    {4000000,    B4000000},
+};
+
+struct cmd_hdr g_cmd_hdr_table[] = {
+    { "baud_115200_0", cmd_hdr_baud_115k},
+    { "baud_921600_0", cmd_hdr_baud_921k},
+    { "baud_2000000_0", cmd_hdr_baud_2kk},
+    { "baud_2500000_0", cmd_hdr_baud_2_5kk},
+    { "baud_3000000_0", cmd_hdr_baud_3kk},
+    { "baud_3500000_0", cmd_hdr_baud_3_5kk},
+    { "baud_4000000_0", cmd_hdr_baud_4kk},
+    { "open_stp", cmd_hdr_stp_open},
+    { "close_stp", cmd_hdr_stp_close},
+    { "rst_stp", cmd_hdr_stp_rst},
+    { "srh_patch", cmd_hdr_sch_patch},
+    { "srh_rom_patch", cmd_hdr_sch_rom_patch},
+};
+
+static volatile sig_atomic_t __io_canceled = 0;
+static char g_wmt_cfg_name[NAME_MAX + 1] = {0};
+static int g_wmt_fd = -1;
+static int g_tty_fd = -1;
+static char g_cmd_str[MAX_CMD_LEN]= {0};
+static char g_resp_str[MAX_CMD_LEN]= {0};
+static struct stp_params_config g_stp_param_config;
+
+pthread_t g_thread_handle = -1;
+static struct fw_debug_infor g_fw_debug_infor;
+
+#if CUST_MULTI_PATCH
+static char g_patch_prefix[16];
+#endif
+/******************************************************************************
+*                              F U N C T I O N S
+*******************************************************************************
+*/
+
+static speed_t get_speed(int baud_rate) {
+    unsigned int idx;
+    for (idx = 0; idx < sizeof(g_speeds)/sizeof(g_speeds[0]); idx++) {
+        if (baud_rate == (int)g_speeds[idx].baud) {
+            return g_speeds[idx].speed;
+        }
+    }
+    return CBAUDEX;
+}
+
+static int set_speed(int fd, struct termios *ti, int speed) {
+    struct serial_struct ss;
+    int baudenum = get_speed(speed);
+
+    if (speed != CBAUDEX) {
+        /*printf("%s: standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum);*/
+        if ((ioctl(fd, TIOCGSERIAL, &ss)) < 0) {
+            ALOGE("%s: BAUD: error to get the serial_struct info:%s\n", __FUNCTION__, strerror(errno));
+            return -1;
+        }
+        ss.flags &= ~ASYNC_SPD_CUST;
+#if defined(SERIAL_STRUCT_EXT) /*modified in serial_struct.h*/
+        memset(ss.reserved, 0x00, sizeof(ss.reserved));
+#endif
+        ss.flags |= (1 << 13);    /*set UPFLOWLATENCY flat to tty, or serial_core will reset tty->low_latency to 0*/
+        /*set standard buadrate setting*/
+        if ((ioctl(fd, TIOCSSERIAL, &ss)) < 0) {
+            ALOGE("%s: BAUD: error to set serial_struct:%s\n", __FUNCTION__, strerror(errno));
+            return -2;
+        }
+        cfsetospeed(ti, baudenum);
+        cfsetispeed(ti, baudenum);
+        return tcsetattr(fd, TCSANOW, ti);
+    }
+    else {
+        ALOGE("%s: unsupported non-standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum);
+        return -3;
+    }
+}
+/* Used as host uart param setup callback */
+static int launcher_setup_uart_param(int com_port, struct stp_uart_config *uart_config)
+{
+    struct termios ti;
+    int  fd;
+
+    if (!uart_config) {
+        ALOGE("Invalid stpUartConfig");
+        return -2;
+    }
+
+    ALOGI("setup_uart_param %d %d\n", uart_config->baud_rate, uart_config->fc);
+
+    fd = com_port;
+    if (fd < 0) {
+        ALOGE("Invalid serial port");
+        return -2;
+    }
+
+    tcflush(fd, TCIOFLUSH);
+
+    if (tcgetattr(fd, &ti) < 0) {
+        ALOGE("Can't get port settings");
+        return -3;
+    }
+
+    cfmakeraw(&ti);
+
+    ALOGI("ti.c_cflag = 0x%08x\n", ti.c_cflag);
+    ti.c_cflag |= CLOCAL;
+    ALOGI("CLOCAL = 0x%x\n", CLOCAL);
+    ALOGI("(ori)ti.c_iflag = 0x%08x\n", ti.c_iflag);
+    ALOGI("(ori)ti.c_cflag = 0x%08x\n", ti.c_cflag);
+    ALOGI("stpuartconfig->fc= %d (0:none,sw,hw,linux)\n", uart_config->fc);
+
+    if (uart_config->fc == UART_DISABLE_FC) {
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    } else if (uart_config->fc == UART_MTK_SW_FC) {
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag |= 0x80000000;   /*MTK Software FC*/
+    } else if (uart_config->fc == UART_HW_FC) {
+        ti.c_cflag |= CRTSCTS;      /*RTS, CTS Enable*/
+        ti.c_iflag &= ~(0x80000000);
+    } else if (uart_config->fc == UART_LINUX_FC) {
+        ti.c_iflag |= (IXON | IXOFF | IXANY); /*Linux Software FC*/
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    }else {
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    }
+
+    ALOGI("c_c CRTSCTS = 0x%16x\n", CRTSCTS);
+    ALOGI("c_i IXON = 0x%08x\n", IXON);
+    ALOGI("c_i IXOFF = 0x%08x\n", IXOFF);
+    ALOGI("c_i IXANY = 0x%08x\n", IXANY);
+    ALOGI("(aft)ti.c_iflag = 0x%08x\n", ti.c_iflag);
+    ALOGI("(aft)ti.c_cflag = 0x%08x\n\n", ti.c_cflag);
+
+    if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+        ALOGE("Can't set port settings");
+        return -4;
+    }
+
+    /* Set baudrate */
+    if (set_speed(fd, &ti, uart_config->baud_rate) < 0) {
+        ALOGE("Can't set initial baud rate");
+        return -5;
+    }
+
+    tcflush(fd, TCIOFLUSH);
+
+    return 0;
+}
+static int cmd_hdr_baud_115k(struct stp_params_config *config)
+{
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 115200;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_921k(struct stp_params_config *config)
+{
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 921600;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_2kk(struct stp_params_config *config) {
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 2000000;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_2_5kk(struct stp_params_config *config)
+{
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 2500000;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_3kk(struct stp_params_config *config) {
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 3000000;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_3_5kk(struct stp_params_config *config) {
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 3500000;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_4kk(struct stp_params_config *config) {
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 4000000;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_stp_open(struct stp_params_config *config) {
+    int ld;
+
+    ALOGV("%p\n", config);
+    if ((STP_UART_FULL == g_stp_param_config.stp_mode) && (-1 == g_tty_fd)) {
+        g_tty_fd = open(g_stp_param_config.stp_dev, O_RDWR | O_NOCTTY);
+        if (g_tty_fd < 0) {
+            fprintf(stderr, "Can't open serial port %s\n", g_stp_param_config.stp_dev);
+            return -2;
+        }
+        ALOGI("real_tty(%s) opened(%d)\n", g_stp_param_config.stp_dev, g_tty_fd);
+
+        /* Set TTY to N_MTKSTP line discipline */
+        ld = N_MTKSTP;
+        if (ioctl(g_tty_fd, TIOCSETD, &ld) < 0) {
+            fprintf(stderr, "Can't set ldisc to N_MTKSTP\n");
+            return -3;
+        }
+
+         //printf("Set tty->low_latency\n");
+         if (ioctl(g_tty_fd, HCIUARTSETPROTO, 0) < 0) {
+            ALOGE("Can't set HCIUARTSETPROTO\n");
+            return -4;
+        }
+        return 0;
+    }
+    else {
+        fprintf(stderr, "stp_open fail: stp_mode(%d) real_tty_fd(%d) \n",
+                g_stp_param_config.stp_mode, g_tty_fd);
+        return -1;
+    }
+}
+
+static int cmd_hdr_stp_close(struct stp_params_config *config) {
+    int ld;
+
+    ALOGV("%p\n", config);
+    if ((STP_UART_FULL == g_stp_param_config.stp_mode) && (0 <= g_tty_fd)) {
+        /* Restore TTY line discipline */
+        ld = N_TTY;
+        if (ioctl(g_tty_fd, TIOCSETD, &ld) < 0) {
+            ALOGE("Can't restore line discipline");
+            return -2;
+        }
+
+        close(g_tty_fd);
+        g_tty_fd = -1;
+        return 0;
+    } else if (g_tty_fd == -1)
+        return 0;
+    else {
+        fprintf(stderr, "stp_close fail: stp_mode(%d) real_tty_fd(%d) \n", g_stp_param_config.stp_mode, g_tty_fd);
+        return -1;
+    }
+}
+
+static int cmd_hdr_stp_rst(struct stp_params_config *config) {
+    int ret = 0;
+    /*this step fail?*/
+    ret = cmd_hdr_stp_close(config);
+    /*here, launcher is close state*/
+    ret = cmd_hdr_stp_open(config);
+    return ret;
+}
+
+static void launcher_set_patch_version(int fd)
+{
+    int ret = 0;
+    struct sys_property patch_ver_prop;
+    int bytes;
+    char patch_build_ver[PATCH_BUILD_VER_LEN] = {0};
+
+    /*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */
+    bytes = read(fd, patch_build_ver, PATCH_BUILD_VER_LEN);
+    if (-1 == bytes)
+        ALOGE("read patch_build_ver failed!\n");
+
+    patch_build_ver[PATCH_BUILD_VER_LEN - 1] = '\0';
+
+    patch_ver_prop.key = WCN_COMBO_PATCH_BUILD_VER_PROP;
+    sprintf(patch_ver_prop.value, "%s", patch_build_ver);
+
+    ret = property_set(patch_ver_prop.key, patch_ver_prop.value);
+    if (0 != ret)
+        ALOGE("set property(%s) to %s failed,ret:%d, errno:%d\n",
+               patch_ver_prop.key, patch_ver_prop.value, ret, errno);
+    else
+        ALOGI("set property(%s) to %s succeed.\n",
+               patch_ver_prop.key, patch_ver_prop.value);
+}
+
+
+#if CUST_MULTI_PATCH
+static int launcher_get_patch_prefix(int chip_id, char **patch_prefix) {
+    /* use malloc for alloc memory is better*/
+    int chip = chip_id;
+
+    if (!patch_prefix) {
+        ALOGE("invalid pointer\n");
+        return -1;
+    }
+
+    if ((0x0321 == chip) || (0x0335 == chip) || (0x0337 == chip)) {
+        chip = 0x6735;
+        ALOGI("for denali chipid convert\n");
+    }
+    if (0x0326 == chip) {
+        chip = 0x6755;
+        ALOGI("for jade chipid convert\n");
+    }
+    if (0x0279 == chip) {
+        chip = 0x6797;
+        ALOGI("for everest chipid convert\n");
+    }
+    if (0x0551 == chip) {
+        chip = 0x6757;
+        ALOGI("for olympus chipid convert\n");
+    }
+    if (0x0633 == chip) {
+        chip = 0x6570;
+        ALOGI("for rushmore chipid convert\n");
+    }
+    if (0x0690 == chip) {
+        chip = 0x6763;
+        ALOGI("for bianco chipid convert\n");
+    }
+    if (0x0507 == chip) {
+        chip = 0x6759;
+        ALOGI("for alaska chipid convert\n");
+    }
+    if (0x0699 == chip) {
+        chip = 0x6739;
+        ALOGI("for zion chipid convert\n");
+    }
+    if (0x0713 == chip) {
+        chip = 0x6775;
+        ALOGI("for cannon chipid convert\n");
+    }
+    if (0x0788 == chip) {
+        chip = 0x6771;
+        ALOGI("for sylvia chipid convert\n");
+    }
+
+    memset(g_patch_prefix, '\0', sizeof(g_patch_prefix));
+
+    switch (chip) {
+        case 0x6572:
+        case 0x6582:
+        case 0x6592:
+            strncpy(g_patch_prefix, "ROMv1", strlen("ROMv1"));
+        break;
+        case 0x8127:
+        case 0x6571:
+            strncpy(g_patch_prefix, "ROMv2", strlen("ROMv2"));
+        break;
+        case 0x6755:
+        case 0x6752:
+        case 0x8163:
+        case 0x7623:
+        case 0x6735:
+        case 0x6570:
+        case 0x6580:
+        case 0x6757:
+        case 0x6763:
+        case 0x6739:
+        case 0x8167:
+            strncpy(g_patch_prefix, "ROMv2_lm", strlen("ROMv2_lm"));
+        break;
+        case 0x6797:
+            strncpy(g_patch_prefix, "ROMv3", strlen("ROMv3"));
+        break;
+        case 0x6759:
+            strncpy(g_patch_prefix, "ROMv4", strlen("ROMv4"));
+        break;
+        case 0x6775:
+        case 0x6771:
+            strncpy(g_patch_prefix, "ROMv4_be", strlen("ROMv4_be"));
+        break;
+        case 0x6765:
+        case 0x3967:
+        case 0x6761:
+        case 0x8168:
+            strncpy(g_patch_prefix, "soc1_0", strlen("soc1_0"));
+        break;
+        default:
+            strncpy(g_patch_prefix, "mt", strlen("mt"));
+            sprintf(g_patch_prefix + strlen("mt"), "%04x", chip);
+        break;
+    }
+    strncat(g_patch_prefix, "_patch", strlen("_patch"));
+
+    ALOGI("patch name pre-fix:%s\n", g_patch_prefix);
+
+    *patch_prefix = g_patch_prefix;
+    return 0;
+}
+
+static int launcher_get_patch_version(int patch_fd, unsigned int *patch_ver)
+{
+    int bytes = -1;
+    int ret = 0;
+
+    bytes = read(patch_fd, ((char *)patch_ver) + 1, 1);
+    if (-1 == bytes) {
+        ALOGE("read patch_ver failed!\n");
+        ret = -1;
+    }
+    bytes = read(patch_fd, ((char *)patch_ver), 1);
+    if (-1 == bytes) {
+        ALOGE("read patch_ver failed!\n");
+        ret = -2;
+    }
+
+    return ret;
+}
+
+static int launcher_set_patch_info(int fd, char *patch_info, char *full_name, int is_first) {
+    int patch_num = -1;
+    int patch_seq = -1;
+    struct stp_patch_info pi;
+
+    if (!patch_info) {
+        ALOGE("invalid patch infor!\n");
+        return -1;
+    }
+    if (!full_name) {
+        ALOGE("invalid patch full name!\n");
+        return -2;
+    }
+
+    if (is_first) {
+        patch_num = (patch_info[0] & 0xF0) >> 4;
+        ALOGI("patch num = [%d]\n", patch_num);
+        ioctl(fd, WMT_IOCTL_SET_PATCH_NUM, patch_num);
+    }
+
+    patch_seq = (patch_info[0] & 0x0F);
+    ALOGI("patch seq = [%d]\n", patch_seq);
+    pi.download_seq = patch_seq;
+    memcpy(pi.address, patch_info, sizeof(pi.address));
+    pi.address[0] = 0x00;
+    strncpy(pi.patch_name, full_name, sizeof(pi.patch_name) - 1);
+    pi.patch_name[sizeof(pi.patch_name) - 1] = '\0';
+
+    ioctl(fd, WMT_IOCTL_SET_PATCH_INFO, &pi);
+
+    return 0;
+}
+
+static int cmd_hdr_sch_patch(struct stp_params_config *config) {
+    int chip_id = 0;
+    int fw_version = 0;
+    char *patch_prefix = NULL;
+    char patch_full_name[256] = {0};
+    char patchName[128] = {0};
+    unsigned int patch_ver = 0;
+    DIR *dir = NULL;
+    int patch_fd = -1;
+    int ret = 0;
+    int bytes;
+    char patch_info[8] = {0};
+    unsigned int is_first = 1;
+    struct dirent* dirent = NULL;
+    int flag;
+
+    if (g_wmt_fd <= 0) {
+        ALOGE("file descriptor is not valid\n");
+        return -1;
+    }
+    /*1. ioctl to get CHIP ID*/
+    chip_id = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 0);
+    if (launcher_get_patch_prefix(chip_id, &patch_prefix)) {
+        ALOGE("launcher_get_patch_prefix fail\n");
+        return -2;
+    }
+
+    /*2. ioctl to get FIRMWARE VERSION*/
+    if (chip_id == 0x6765 || chip_id == 0x3967 ||
+        chip_id == 0x6761 || chip_id == 0x8168 ) {
+#if 0
+        ip_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 3);
+        ALOGI("ip_version:0x%08x\n", ip_version);
+#else
+        fw_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 2);
+        ALOGI("fw_version:0x%04x\n", fw_version);
+#endif
+    } else {
+        fw_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 2);
+        ALOGI("fw_version:0x%04x\n", fw_version);
+    }
+    /*3. open directory patch located*/
+    strncpy(config->patch_path, CUST_COMBO_PATCH_PATH, strlen(CUST_COMBO_PATCH_PATH));
+    config->patch_path[strlen(CUST_COMBO_PATCH_PATH) + 1] = '\0';
+
+    dir = opendir(config->patch_path);
+    if (NULL == dir) {
+        ALOGE("patch path cannot be opened");
+        return -3;
+    }
+    while (NULL != (dirent = readdir(dir))) {
+        patch_ver = 0;
+        if (0 == (strncmp(dirent->d_name, patch_prefix, strlen(patch_prefix)))) {
+            /*4.1. search patch name begined with chip_name*/
+            strncpy(patch_full_name, config->patch_path, strlen(config->patch_path)+1);
+            /*robust, if input patch is /etc/firmwre/ no issue should be happened.*/
+            strncat(patch_full_name, "/", strlen("/"));
+            strncat(patch_full_name, dirent->d_name, strlen(dirent->d_name));
+            ALOGI("%s\n", patch_full_name);
+            strncpy (patchName, dirent->d_name, strlen(dirent->d_name)+1);
+            /*4.1. search patch name mt[CHIP ID]xxx.bin*/
+            if (0 <= (patch_fd = (open(patch_full_name, O_RDONLY)))) {
+                launcher_set_patch_version(patch_fd);
+
+                if (-1 != lseek(patch_fd, 22, SEEK_SET)) {
+                    if (launcher_get_patch_version(patch_fd, &patch_ver)) {
+                        ALOGE("read patch_ver failed!\n");
+                        ret = -4;
+                        goto read_fail;
+                    }
+                    /*print hardware version information in patch*/
+                    ALOGI("fw Ver in patch: 0x%08x\n", patch_ver);
+                    if (chip_id == 0x6765 || chip_id == 0x3967 ||
+                        chip_id == 0x6761 || chip_id == 0x8168 )
+#if 0
+                        flag = patch_ver == ip_version ? 1 : 0;
+#else
+                        flag = (0 == ((patch_ver ^ fw_version) & 0x00ff)) ? 1 : 0;
+#endif
+                    else
+                        flag = (0 == ((patch_ver ^ fw_version) & 0x00ff)) ? 1 : 0;
+                    if (flag) {
+                        memset(patch_info, 0, sizeof(patch_info));
+                        bytes = read(patch_fd, patch_info, 4);
+                        if (-1 == bytes) {
+                            ret = -5;
+                            ALOGE("read patch_info failed!\n");
+                            goto read_fail;
+                        }
+                        patch_info[4] = '\0';
+                        ALOGI("read patch info:0x%02x,0x%02x,0x%02x,0x%02x\n",
+                               patch_info[0], patch_info[1], patch_info[2], patch_info[3]);
+                        if (launcher_set_patch_info(g_wmt_fd, patch_info, patchName, is_first)) {
+                            ALOGE("launcher_set_patch_info fail\n");
+                            ret = -6;
+                            goto read_fail;
+                        }
+                        is_first = 0;
+                    }
+                } else
+                    ALOGE("seek failed\n");
+read_fail:
+                close(patch_fd);
+                patch_fd = -1;
+            } else
+                ALOGE("open patch file(%s) failed\n", patchName);
+        }
+    }
+    /*5. return value*/
+    closedir(dir);
+    dir = NULL;
+
+    return ret;
+}
+
+static int launcher_get_rom_patch_prefix(int chip_id, char **patch_prefix) {
+    /* use malloc for alloc memory is better*/
+    int chip = chip_id;
+
+    if (!patch_prefix) {
+        ALOGE("invalid pointer\n");
+        return -1;
+    }
+
+    memset(g_patch_prefix, '\0', sizeof(g_patch_prefix));
+
+    switch (chip) {
+        case 0x6765:
+        case 0x3967:
+        case 0x6761:
+        case 0x8168:
+            strncpy(g_patch_prefix, "soc1_0", strlen("soc1_0"));
+        break;
+        case 0x6779:
+            strncpy(g_patch_prefix, "soc2_0", strlen("soc2_0"));
+        break;
+        default:
+            strncpy(g_patch_prefix, "soc1_0", strlen("soc1_0"));
+        break;
+
+    }
+    strncat(g_patch_prefix, "_ram", strlen("_ram"));
+
+    ALOGI("patch name pre-fix:%s\n", g_patch_prefix);
+
+    *patch_prefix = g_patch_prefix;
+
+    return 0;
+}
+
+static int launcher_set_rom_patch_info(int fd, char *patch_info, char *full_name) {
+    struct stp_rom_patch_info pi;
+    int iRet = 0;
+
+    if (!patch_info) {
+        ALOGE("invalid patch infor!\n");
+        return -1;
+    }
+    if (!full_name) {
+        ALOGE("invalid patch full name!\n");
+        return -2;
+    }
+
+    pi.type = patch_info[7];
+    ALOGI("rom patch type = [%d]\n", pi.type);
+    memcpy(pi.address, patch_info, sizeof(pi.address));
+    pi.address[0] = 0x00;
+    strncpy(pi.patch_name, full_name, sizeof(pi.patch_name) - 1);
+    pi.patch_name[sizeof(pi.patch_name) - 1] = '\0';
+
+    iRet = ioctl(fd, WMT_IOCTL_SET_ROM_PATCH_INFO, &pi);
+    if (iRet != 0) {
+        ALOGE("ioctl WMT_IOCTL_SET_ROM_PATCH_INFO error (0x%x)\n", iRet);
+        return -3;
+    }
+
+    return 0;
+}
+
+static int cmd_hdr_sch_rom_patch(struct stp_params_config *config) {
+    int chip_id = 0;
+#if 0
+    unsigned int ip_version = 0;
+#else
+    unsigned int fw_version = 0;
+#endif
+    char *patch_prefix = NULL;
+    char patch_full_name[256] = {0};
+    char patchName[128] = {0};
+    unsigned int patch_ver = 0;
+    DIR *dir = NULL;
+    int patch_fd = -1;
+    int ret = 0;
+    int bytes;
+    char patch_info[8] = {0};
+    struct dirent* dirent = NULL;
+
+    if (g_wmt_fd <= 0) {
+        ALOGE("file descriptor is not valid\n");
+        return -1;
+    }
+    /*1. ioctl to get CHIP ID*/
+    chip_id = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 0);
+    if (launcher_get_rom_patch_prefix(chip_id, &patch_prefix)) {
+        ALOGE("launcher_get_rom_patch_prefix fail\n");
+        return -2;
+    }
+
+    /*2. ioctl to get FIRMWARE VERSION*/
+#if 0
+    ip_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 3);
+    ALOGI("ip_version:0x%04x\n", ip_version);
+#else
+    fw_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 2);
+    ALOGI("fw_version:0x%04x\n", fw_version);
+#endif
+    /*3. open directory patch located*/
+    strncpy(config->patch_path, CUST_COMBO_PATCH_PATH, strlen(CUST_COMBO_PATCH_PATH));
+    config->patch_path[strlen(CUST_COMBO_PATCH_PATH) + 1] = '\0';
+
+    dir = opendir(config->patch_path);
+    if (NULL == dir) {
+        ALOGE("patch path cannot be opened");
+        return -3;
+    }
+    while (NULL != (dirent = readdir(dir))) {
+        patch_ver = 0;
+        if (0 == (strncmp(dirent->d_name, patch_prefix, strlen(patch_prefix)))) {
+            /*4.1. search patch name begined with chip_name*/
+            strncpy(patch_full_name, config->patch_path, strlen(config->patch_path)+1);
+            /*robust, if input patch is /etc/firmwre/ no issue should be happened.*/
+            strncat(patch_full_name, "/", strlen("/"));
+            strncat(patch_full_name, dirent->d_name, strlen(dirent->d_name));
+            ALOGI("%s\n", patch_full_name);
+            strncpy(patchName, dirent->d_name, strlen(dirent->d_name)+1);
+            /*4.1. search patch name mt[CHIP ID]xxx.bin*/
+            if (0 <= (patch_fd = (open(patch_full_name, O_RDONLY)))) {
+                if (-1 != lseek(patch_fd, 22, SEEK_SET)) {
+                    if (launcher_get_patch_version(patch_fd, &patch_ver)) {
+                        ALOGE("read patch_ver failed!\n");
+                        ret = -4;
+                        goto read_fail;
+                    }
+                      /*print hardware version information in patch*/
+                    ALOGI("fw Ver in patch: 0x%04x\n", patch_ver);
+#if 0
+                    if (0 == ((patch_ver ^ ip_version) & 0xffffffff)) {
+#else
+                    if (0 == ((patch_ver ^ fw_version) & 0x00ff)) {
+#endif
+                        memset(patch_info, 0, sizeof(patch_info));
+                        bytes = read(patch_fd, patch_info, 8);
+                        if (-1 == bytes) {
+                            ret = -5;
+                            ALOGE("read patch_info failed!\n");
+                            goto read_fail;
+                        }
+                        if ((patch_info[3] & 0xF0) && (patch_info[7] >= 0 && patch_info[7] <= 5)) {
+                            ALOGI("patch info:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n",
+                                  patch_info[0], patch_info[1], patch_info[2], patch_info[3],
+                                  patch_info[4], patch_info[5], patch_info[6], patch_info[7]);
+                            if (launcher_set_rom_patch_info(g_wmt_fd, patch_info, patchName)) {
+                                ALOGE("launcher_set_rom_patch_info fail\n");
+                                ret = -6;
+                                goto read_fail;
+                            }
+                        }
+                    }
+                } else
+                    ALOGE("seek failed\n");
+read_fail:
+                close(patch_fd);
+                patch_fd = -1;
+            } else
+                ALOGE("open patch file(%s) failed\n", patchName);
+        }
+    }
+    /*5. return value*/
+    closedir(dir);
+    dir = NULL;
+
+    return ret;
+}
+#else
+static int cmd_hdr_sch_patch(struct stp_params_config *config) {
+    int chip_id = 0;
+    int fw_version = 0;
+    char chip_name[16] = {0};
+    char patch_full_name[256] = {0};
+    unsigned int patch_ver = 0;
+    DIR *dir = NULL;
+    int patch_fd = -1;
+    struct dirent* dirent = NULL;
+    int ret = -1;
+
+    if (g_wmt_fd <= 0) {
+        ALOGE("file descriptor is not valid\n");
+        return -1;
+    }
+
+    /*1. ioctl to get CHIP ID*/
+    chip_id = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 0);
+    strncpy(chip_name, "mt", strlen("mt")+1);
+    sprintf(chip_name + strlen(chip_name), "%04x", chip_id);
+    strncat(chip_name, "_patch", strlen("_patch"));
+    ALOGI("patch name pre-fix:%s\n", chip_name);
+
+    /*2. ioctl to get FIRMWARE VERSION*/
+    fw_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 2);
+    ALOGI("fwVersion:0x%04x\n", fw_version);
+
+    /*3. open directory patch located*/
+    strncpy(config->patch_path, CUST_COMBO_PATCH_PATH, strlen(CUST_COMBO_PATCH_PATH));
+    config->patch_path[strlen(CUST_COMBO_PATCH_PATH) + 1] = '\0';
+
+    dir = opendir(config->patch_path);
+    if (NULL == dir) {
+        ALOGE("patch path cannot be opened");
+        ret = -2;
+        return ret;
+    }
+    while (NULL != (dirent = readdir(dir))) {
+        patch_ver = 0;
+        if (0 == (strncmp(dirent->d_name, chip_name, strlen(chip_name)))) {
+            /*4.1. search patch name begined with chipName*/
+            strncpy(patch_full_name, config->patch_path, strlen(config->patch_path)+1);
+            /*robust, if input patch is /etc/firmwre/ no issue should be happened.*/
+            strncat(patch_full_name, "/", strlen("/"));
+            strncat(patch_full_name, dirent->d_name, strlen(dirent->d_name));
+            ALOGI("%s\n", patch_full_name);
+            /*4.1. search patch name mt[CHIP ID]xxx.bin*/
+            if (0 < (patch_fd = (open(patch_full_name, O_RDONLY)))) {
+              /*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */
+                if (-1 != lseek(patch_fd, 22, SEEK_SET)) {
+                    read(patch_fd, ((char *)&patch_ver) + 1, 1);
+                    read(patch_fd, ((char *)&patch_ver), 1);
+                    /*print firmware version information in patch*/
+                    ALOGI("fw Ver in patch: 0x%04x\n", patch_ver);
+                    if (0 == ((patch_ver ^ fw_version) & 0x00ff)) {
+                        ioctl(g_wmt_fd, WMT_IOCTL_SET_PATCH_NAME, patch_full_name);
+                        ALOGI("fw Ver in patch matches with firmware version\n");
+                        ret = 0;
+                        close(patch_fd);
+                        break;
+                    }
+                } else
+                    ALOGE("seek failed\n");
+
+                close(patch_fd);
+                patch_fd = -1;
+            } else
+                ALOGE("open patch file(%s) failed\n", patch_full_name);
+        }
+    }
+    /*5. return value*/
+    closedir(dir);
+    dir = NULL;
+
+    return ret;
+}
+#endif
+/*
+ret 0: success
+ret 1: cmd not found
+ret -x: handler return value
+*/
+static int launcher_handle_cmd(struct stp_params_config *stp_param_config, char *cmd, int len) {
+    int ret = 1;
+    int i;
+    int cmd_len;
+
+    for (i = 0; i < (int)(sizeof(g_cmd_hdr_table)/sizeof(g_cmd_hdr_table[0])); ++i) {
+        cmd_len = (int)strlen(g_cmd_hdr_table[i].cmd);
+        if (!strncmp(g_cmd_hdr_table[i].cmd, cmd, (len < cmd_len) ? len : cmd_len)) {
+            ret = (*g_cmd_hdr_table[i].hdr_func)(stp_param_config);
+        }
+    }
+
+    return ret;
+}
+
+static void launcher_display_usage(void)
+{
+    unsigned int index = 0;
+
+    char * usage[] = {
+        "MTK WCN combo tool set, version 1.0-release",
+        "Usage: wmt_launcher [-m mode] -p patchfolderpath [-d uartdevicenode] [-b baudrate] [-c uartflowcontrol]",
+        "    -m (BT/GPS/FM common interface mode selection, optional)",
+        "        -1: UART mode (common interface: UART)",
+        "        -3: BTIF mode (common interface: BTIF)",
+        "        -4: SDIO mode (common interface: SDIO)",
+        "    -p (MTK WCN chip firmware patch location, must)",
+        "        -e.g. /system/etc/firmware",
+        "    -n (MTK WCN chip firmware patch name, option)",
+        "        -e.g. /system/etc/firmware/firmware/mt6628_patch_hdr.bin",
+        "    if UART mode is set, you need config baud rate and tty device:",
+        "    -b (Baudrate set when BT/GPS/FM runs under UART mode, no needed under SDIO mode)",
+        "        -115200/921600/2000000/2500000/3000000/3500000/4000000",
+        "    -d (UART device node, when under UART mode, no needed under SDIO mode)",
+        "        -e.g. /dev/ttyMT1, /dev/ttyMT2, /dev/ttyHS2, etc.",
+        "    -c (UART flowcontrol set)",
+        "        -0, no flowcontrol default value, please donot modify this parameter",
+        "e.g. wmt_launcher -m 3 -p /system/etc/firmware/",
+        "e.g. wmt_launcher -m 1 -n /system/etc/firmware/mt6628_patch_hdr.bin",
+        "e.g. wmt_launcher -m 4 -d /dev/ttyMT2 -b 4000000 -n /system/etc/firmware/mt6628_patch_hdr.bin",
+    };
+
+    for (index = 0; index < sizeof(usage) / sizeof(usage[0]); index++ )
+        ALOGI("%s\n", usage[index]);
+
+    exit(EXIT_FAILURE);
+}
+
+
+static int launcher_stp_param_valid_check(struct stp_params_config *stp_param_configs, enum wmt_chip_type chip_type)
+{
+    int ret = 0;
+
+    /*fix me, check condition should be more reasonable*/
+    if ('\0' == stp_param_configs->patch_path[0]) {
+        ALOGE("MCU patch path not config,use /system/etc/firmware\n");
+        strncpy(stp_param_configs->patch_path, "/system/etc/firmware", strlen("/system/etc/firmware"));
+        stp_param_configs->patch_path[strlen("/system/etc/firmware") + 1] = '\0';
+        ret = -1;
+    }
+
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+    if ('\0' == stp_param_configs->patch_name[0]) {
+        ALOGE("MCU patch path not config,you need config it yourself\n");
+        ret = -2;
+    }
+#endif
+    if (stp_param_configs->stp_mode != STP_SDIO &&
+        stp_param_configs->stp_mode != STP_UART_MAND &&
+        stp_param_configs->stp_mode != STP_UART_FULL &&
+        stp_param_configs->stp_mode != STP_BTIF_FULL) {
+        if (WMT_CHIP_TYPE_COMBO == chip_type) {
+            ALOGE("Stp Mode is not set, common interface use default: SDIO Mode");
+            stp_param_configs->stp_mode = STP_SDIO;
+        } else {
+            ALOGE("Stp Mode is not set, common interface use default: BTIF Mode");
+            stp_param_configs->stp_mode = STP_BTIF_FULL;
+        }
+        ret = -3;
+    }
+
+    if (stp_param_configs->stp_mode == STP_UART_MAND || stp_param_configs->stp_mode == STP_UART_FULL) {
+        ALOGI ("Common Interface: UART mode\n");
+        if ('\0' == stp_param_configs->stp_dev[0]) {
+            strncpy(stp_param_configs->stp_dev, CUST_COMBO_STP_DEV, strlen(CUST_COMBO_STP_DEV)+1);
+            ALOGI("no uart device input, use default: %s\n", stp_param_configs->stp_dev);
+            ret = -4;
+        }
+        if (stp_param_configs->uart_config.baud_rate < 0) {
+            /* FixMe:Chaozhong, add baudrate validation check */
+            stp_param_configs->uart_config.baud_rate = 4000000;
+            ALOGI("no baudrate input, use default: %d\n", stp_param_configs->uart_config.baud_rate);
+            ret = -5;
+        }
+    }
+    return ret;
+}
+
+static int launcher_parser_wmt_cfg(char *item)
+{
+    int index = 0;
+    int length = 0;
+    char *str = NULL;
+    char *key = NULL;
+    char *value = NULL;
+    int max_index  = sizeof (g_chip_mode_info) / sizeof (g_chip_mode_info[0]);
+
+    if (NULL == item) {
+        ALOGE("Warning:item is NULL\n");
+        return -1;
+    }
+    /*all item must be start with mt66xx*/
+    str = strstr(item, "m");
+    if (NULL == str) {
+        ALOGE("Warning:no string start with 'm' found in %s\n", item);
+        return -2;
+    }
+
+    for (index = 0; index < max_index; index++) {
+        key = (char*)g_chip_mode_info[index].ant_mode.cfg_item;
+
+        if (0 == strncasecmp(str, key, strlen(key))) {
+            str = strstr(str, "=");
+            if (NULL == str) {
+                ALOGE("Warning:no '=' found in %s\n", str);
+                return -3;
+            }
+            str = strstr(str, "m");
+            if (NULL == str) {
+                ALOGE("Warning:no 'm' found in %s\n", str);
+                return -4;
+            }
+
+            while (((*str) == ' ') || ((*str) == '\t') || ((*str) == '\n')) {
+                if (str >= item + strlen(item))
+                    break;
+                str++;
+            }
+            value = str;
+
+            while (((*str) != ' ') && ((*str) != '\t') && ((*str) != '\0') && ((*str) != '\n') && ((*str) != '\r')) {
+                if (str >= item + strlen(item))
+                    break;
+                str++;
+            }
+            *str = '\0';
+            length = sizeof(g_chip_mode_info[index].ant_mode.cfg_item_value);
+            strncpy(g_chip_mode_info[index].ant_mode.cfg_item_value, value, length - 1);
+            g_chip_mode_info[index].ant_mode.cfg_item_value[length - 1] = '\0';
+            ALOGI("Info:key:%s value:%s\n", key, g_chip_mode_info[index].ant_mode.cfg_item_value);
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static int launcher_get_wmt_cfg_infor(void)
+{
+    FILE * file = NULL;
+    int ret = -1;
+    char *str = NULL;
+    char line[NAME_MAX];
+
+    file = fopen(CUST_COMBO_CFG_FILE, "r");
+    if (NULL == file) {
+        ALOGE("%s cannot be opened, errno:%d\n", CUST_COMBO_CFG_FILE, errno);
+        return -2;
+    }
+    ret = 0;
+    do {
+        str = fgets(line, NAME_MAX, file);
+        if (NULL == str) {
+            ALOGI("NULL is returned, eighter EOF or error maybe found\n");
+            break;
+        }
+        launcher_parser_wmt_cfg(line);
+        memset(line, 0, NAME_MAX);
+
+    } while (str != NULL);
+
+    if (NULL != file) {
+        if (0 == fclose(file))
+            ALOGI("close %s succeed\n", CUST_COMBO_CFG_FILE);
+        else
+            ALOGI("close %s failed, errno:%d\n", CUST_COMBO_CFG_FILE, errno);
+    }
+    return ret;
+}
+
+
+static int launcher_get_chip_info_index(int chip_id)
+{
+    int index = -1;
+    int left = 0;
+    int middle = 0;
+    int right = sizeof (g_chip_mode_info) / sizeof (g_chip_mode_info[0]) - 1;
+
+    if ((chip_id < g_chip_mode_info[left].chip_id) || (chip_id > g_chip_mode_info[right].chip_id))
+        return index;
+
+    middle = (left + right) / 2;
+
+    while (left <= right) {
+        if (chip_id > g_chip_mode_info[middle].chip_id)
+            left = middle + 1;
+        else if (chip_id < g_chip_mode_info[middle].chip_id)
+            right = middle - 1;
+        else {
+            index = middle;
+            break;
+        }
+        middle = (left + right) / 2;
+    }
+
+    if (0 > index)
+        ALOGE("no supported chip_id found\n");
+    else
+        ALOGI("index:%d, chip_id:0x%x\n", index, g_chip_mode_info[index].chip_id);
+
+    return index;
+}
+
+static void launcher_combine_cfg_name(int chip_id, char *cfg_file_path)
+{
+    int index = -1;
+    int stp_mode = g_stp_param_config.stp_mode;
+
+    index = launcher_get_chip_info_index(chip_id);
+    if ((stp_mode <= STP_MIN) || (STP_SDIO < stp_mode)) {
+        ALOGI("STP Mode is not set, fetching default mode...\n");
+        if (0 <= index)
+            g_stp_param_config.stp_mode = g_chip_mode_info[index].stp_mode;
+        else
+            g_stp_param_config.stp_mode = -1;
+    }
+
+    if ((0 <= index) && (NULL != cfg_file_path)) {
+        memset(g_wmt_cfg_name, 0, sizeof(g_wmt_cfg_name));
+        strncpy(g_wmt_cfg_name, g_chip_mode_info[index].ant_mode.cfg_item_value, sizeof(g_wmt_cfg_name) - 1);
+        g_wmt_cfg_name[strlen(g_chip_mode_info[index].ant_mode.cfg_item_value)] = '\0';
+    } else
+        memset(g_wmt_cfg_name, 0, sizeof(g_wmt_cfg_name));
+
+    ALOGI("chip_id(0x%04x), default Mode(%d), strlen(g_wmt_cfg_name)(%zd), g_wmt_cfg_name(%s)\n",
+           chip_id, g_stp_param_config.stp_mode, strlen(g_wmt_cfg_name), g_wmt_cfg_name);
+
+}
+
+static void launcher_set_wmt_cfg_infor(int chip_id, char *cfg_file_path) {
+    if (!launcher_get_wmt_cfg_infor()) {
+        launcher_combine_cfg_name(chip_id, cfg_file_path);
+        /* send WMT config name configuration to driver */
+        ioctl(g_wmt_fd, WMT_IOCTL_WMT_CFG_NAME, g_wmt_cfg_name);
+    } else
+         ALOGE("launcher_get_wmt_cfg_infor fail\n");
+}
+
+static void launcher_set_uart_port_name(char *stp_dev) {
+    char *uart_name = NULL;
+
+    /* send uart name to driver*/
+    if (stp_dev) {
+        uart_name = strstr(stp_dev, "tty");
+        if (!uart_name)
+            ALOGE("no uart name found in %s\n", stp_dev);
+        else
+            ALOGI("uart name %s\n", uart_name);
+    }
+
+    if (!uart_name) {
+        uart_name = "ttyMT2";
+        ALOGI("use default uart %s\n", uart_name);
+    }
+
+    ioctl(g_wmt_fd, WMT_IOCTL_PORT_NAME, uart_name);
+}
+
+static void* launcher_pwr_on_thread(void * arg)
+{
+    int retry_counter = 0;
+    int ret = -1;
+    int chip_id = *(int*)arg;
+
+    pthread_setname_np(pthread_self(), "pwr_on_conn");
+
+    ALOGI("enter power on connsys flow");
+    do {
+        ret = ioctl(g_wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 1);
+        if (0 == ret)
+            break;
+        ioctl(g_wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 0);
+        ALOGI("power on %x failed, retrying, retry counter:%d\n", chip_id, retry_counter);
+        usleep(1000000);
+        retry_counter++;
+    } while (retry_counter < 20);
+
+    pthread_detach(g_thread_handle);
+    g_thread_handle = -1;
+
+    return NULL;
+}
+
+static void launcher_pwr_on_chip(int *chip_id) {
+    if (pthread_create(&g_thread_handle, NULL, launcher_pwr_on_thread, chip_id)) {
+        ALOGE("create pwr on thread fail\n");
+    } else
+        ALOGI("create pwr on thread ok\n");
+}
+static void* launcher_set_fwdbg_thread(void * arg) {
+    int i_ret = -1;
+    int flag = *(int*)arg;
+
+    pthread_setname_np(pthread_self(), "dump_fwemi_log");
+    ALOGI("dump firmware dbg log from emi buffer ");
+    i_ret = ioctl(g_wmt_fd, WMT_IOCTL_FW_DBGLOG_CTRL, flag);
+    if (i_ret < 0) {
+        ALOGI("ioctl error: err msg: %s\n", strerror(errno));
+        pthread_detach(g_thread_handle);
+        g_thread_handle = -1;
+    }
+    return NULL;
+}
+
+static void sig_hup(int sig) {
+    fprintf(stderr, "sig_hup...(%d)\n", sig);
+}
+
+static void sig_term(int sig)
+{
+    fprintf(stderr, "sig_term...(%d)\n", sig);
+    __io_canceled = 1;
+    ioctl(g_wmt_fd, WMT_IOCTL_SET_LAUNCHER_KILL, 1);
+}
+
+static void launcher_set_signal_handler(void) {
+    struct sigaction sa;
+
+    /*set signal handler*/
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_flags   = SA_NOCLDSTOP;
+    sa.sa_handler = SIG_IGN;
+    sigaction(SIGCHLD, &sa, NULL);
+    sigaction(SIGPIPE, &sa, NULL);
+
+    sa.sa_handler = sig_term;
+    sigaction(SIGTERM, &sa, NULL);
+    sigaction(SIGINT,  &sa, NULL);
+
+    sa.sa_handler = sig_hup;
+    sigaction(SIGHUP, &sa, NULL);
+}
+
+static void launcher_check_driver_ready(void) {
+    int ret = -1;
+    struct sys_property sp;
+
+    sp.key = WCN_DRIVER_READY_PROP;
+    sp.def_value = NULL;
+
+    do {
+        ret = property_get(sp.key, sp.value, sp.def_value);
+        if (0 >= ret)
+            ALOGE("get property(%s) failed i_ret:%d\n", sp.key, ret);
+        else {
+            ALOGI("get property(%s) is %s\n", sp.key, sp.value);
+            if (!strcmp(sp.value, "yes"))
+                break;
+        }
+        usleep(300000);
+    } while (1);
+}
+
+static void launcher_open_wmt_device(void) {
+    do {
+        g_wmt_fd = open(CUST_COMBO_WMT_DEV, O_RDWR | O_NOCTTY);
+        if (g_wmt_fd < 0) {
+            ALOGE("Can't open device node(%s) error:%d \n", CUST_COMBO_WMT_DEV, g_wmt_fd);
+            usleep(300000);
+        } else
+            break;
+    }while(1);
+
+    ALOGI("open device node succeed.(Node:%s, fd:%d) \n", CUST_COMBO_WMT_DEV, g_wmt_fd);
+}
+
+static int launcher_query_chip_id(void) {
+    int chip_id = -1;
+    int ret = -1;
+    struct sys_property chipid_prop;
+
+    chipid_prop.key = WCN_COMBO_CHIP_ID_PROP;
+    chipid_prop.def_value = NULL;
+
+    do {
+        /*read from system property*/
+        ret = property_get(chipid_prop.key, chipid_prop.value, chipid_prop.def_value);
+        if (0 != ret) {
+            chip_id = strtoul(chipid_prop.value, NULL, 16);
+            ALOGI("key:(%s)-value:(%s),chip_id:0x%04x\n",
+                   chipid_prop.key, chipid_prop.value, chip_id);
+        } else {
+            ALOGE("get chip_id property(%s) failed\n", chipid_prop.key);
+            /* we do not return here, use another way to get chip id*/
+        }
+
+        if (-1 != chip_id)
+            break;
+
+        chip_id = ioctl(g_wmt_fd, WMT_IOCTL_WMT_QUERY_CHIPID, NULL);
+        ALOGI("chip_id from kernel by ioctl:0x%04x\n", chip_id);
+        if (-1 != chip_id)
+            break;
+        usleep(300000);
+    }while(1);
+
+    ALOGI("chip_id:0x%04x\n", chip_id);
+
+    return chip_id;
+}
+
+static enum wmt_chip_type launcher_check_chip_type(int chip_id)
+{
+    enum wmt_chip_type chip_type = WMT_CHIP_TYPE_INVALID;
+
+    if (chip_id <= 0) {
+        ALOGE("invalid chip id(%d)\n", chip_id);
+        goto done;
+    }
+    if ((0x6620 == chip_id) || (0x6628 == chip_id) ||
+        (0x6630 == chip_id) || (0x6632 == chip_id))
+        chip_type = WMT_CHIP_TYPE_COMBO;
+    else
+        chip_type = WMT_CHIP_TYPE_SOC;
+done:
+    return chip_type;
+}
+static void launcher_init_stp_parameter(struct stp_params_config *stp_param_config, enum wmt_chip_type chip_type) {
+    stp_param_config->fm_mode = 2;
+
+    if (WMT_CHIP_TYPE_SOC == chip_type)
+        stp_param_config->stp_mode = STP_BTIF_FULL;
+    if (WMT_CHIP_TYPE_COMBO == chip_type) {
+        stp_param_config->stp_mode = STP_SDIO;
+        stp_param_config->uart_config.baud_rate = 4000000;
+        stp_param_config->uart_config.fc = UART_DISABLE_FC;
+        stp_param_config->uart_config.parity = 0;
+        stp_param_config->uart_config.stop_bit = 0;
+        memset(stp_param_config->stp_dev, '\0', sizeof(stp_param_config->stp_dev));
+    }
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+    memset(stp_param_config->patch_name, '\0', sizeof(stp_param_config->patch_name));
+#endif
+    memset(stp_param_config->patch_path, '\0', sizeof(stp_param_config->patch_path));
+}
+
+static void launcher_print_stp_parameter(struct stp_params_config *stp_param_config) {
+    ALOGI("fm mode:%d\n", stp_param_config->fm_mode);
+    ALOGI("stp mode:%d\n", stp_param_config->stp_mode);
+    ALOGI("patch path:%s\n", stp_param_config->patch_path);
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+    ALOGI("patch name:%d\n", stp_param_config->patch_name);
+#endif
+    if ((stp_param_config->stp_mode == STP_UART_FULL) ||
+        (stp_param_config->stp_mode == STP_UART_MAND)) {
+        ALOGI("stp uart dev:%s\n", stp_param_config->stp_dev);
+        ALOGI("stp uart baud rate:%d\n", stp_param_config->uart_config.baud_rate);
+        ALOGI("stp uart fc:%d\n", stp_param_config->uart_config.fc);
+        ALOGI("stp uart parity:%d\n", stp_param_config->uart_config.parity);
+        ALOGI("stp uart stop bit:%d\n", stp_param_config->uart_config.stop_bit);
+    }
+}
+/*
+ * -m: mode (SDIO/UART)
+ * -d: uart device node
+ * -b: baudrate
+ * -c: enable SW FC or not
+ * -p: patch folder path
+ * -n: patch file name (fullpath)
+ *
+ */
+static void launcher_set_parameter_to_driver(int argc, char *argv[], int chip_id)
+{
+    int opt;
+    static const char *op_string = "m:d:b:c:p:n:?";
+    enum wmt_chip_type chip_type;
+
+    chip_type = launcher_check_chip_type(chip_id);
+    if (chip_type == WMT_CHIP_TYPE_INVALID) {
+        ALOGE("unknow chip type, may be chid id is invalid\n");
+        chip_type = WMT_CHIP_TYPE_SOC;
+    }
+    launcher_init_stp_parameter(&g_stp_param_config, chip_type);
+
+    opt = getopt(argc, argv, op_string);
+    while (opt != -1) {
+        switch (opt) {
+            case 'm':
+                g_stp_param_config.stp_mode = atoi(optarg);
+            break;
+            case 'd':
+                strncpy(g_stp_param_config.stp_dev, optarg, strlen(optarg)+1);
+            break;
+            case 'b':
+                g_stp_param_config.uart_config.baud_rate = atoi(optarg);
+            break;
+            case 'c':
+                g_stp_param_config.uart_config.fc = atoi(optarg);
+            break;
+            case 'p':
+                strncpy(g_stp_param_config.patch_path, optarg, strlen(optarg)+1);
+                ALOGI("patch path:%s\n", g_stp_param_config.patch_path);
+            break;
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+            case 'n':
+                strncpy(g_stp_param_config.patch_name, optarg, strlen(optarg)+1);
+            break;
+#endif
+            case '?':
+            default:
+                launcher_display_usage();
+            break;
+        }
+        opt = getopt(argc, argv, op_string);
+    }
+
+#if LAUNCHER_DEBUG
+    ALOGI("argc = %d, optind= %d\n", argc, optind);
+    {
+        int i = 0;
+        for (i = 0; i < argc; i++)
+            ALOGI("arg[%d] = %s\n", i, argv[i]);
+    }
+#endif
+
+    if (0 != launcher_stp_param_valid_check(&g_stp_param_config, chip_type)) {
+        ALOGE("stp param is invalid, use default:\n");
+        launcher_print_stp_parameter(&g_stp_param_config);
+        ALOGE("if this default param is not correct,please see usage help:\n");
+        launcher_display_usage();
+    }
+    if (WMT_CHIP_TYPE_COMBO == chip_type) {
+        ioctl(g_wmt_fd, WMT_IOCTL_WMT_TELL_CHIPID, chip_id);
+        ALOGI("set chip_id(0x%x) to driver\n", chip_id);
+        launcher_set_wmt_cfg_infor(chip_id, &g_stp_param_config.patch_path[0]);
+        if ((g_stp_param_config.stp_mode == STP_UART_FULL) ||
+            (g_stp_param_config.stp_mode == STP_UART_MAND))
+            launcher_set_uart_port_name(&g_stp_param_config.stp_dev[0]);
+    }
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+    /* send default patch file name path to driver */
+    ioctl(g_wmt_fd, WMT_IOCTL_SET_PATCH_NAME, g_stp_param_config.patch_name);
+#endif
+    /* send hardware interface configuration to driver */
+    ioctl(g_wmt_fd, WMT_IOCTL_SET_STP_MODE,
+          ((g_stp_param_config.uart_config.baud_rate & 0xFFFFFF) << 8) |
+          ((g_stp_param_config.fm_mode & 0x0F) << 4) |
+          (g_stp_param_config.stp_mode & 0x0F));
+
+    ioctl(g_wmt_fd, WMT_IOCTL_SET_LAUNCHER_KILL, 0);
+
+}
+
+static int launcher_get_fw_debug_orign_infor(int chip_id) {
+    int ret = -1;
+    enum wmt_chip_type chip_type;
+    char readyStr[PROPERTY_VALUE_MAX] = {0};
+
+    chip_type = launcher_check_chip_type(chip_id);
+
+    if (chip_type == WMT_CHIP_TYPE_SOC) {
+        g_fw_debug_infor.log_retry = 0;
+        g_fw_debug_infor.dump_retry = 0;
+        g_fw_debug_infor.fw_log_ctrl = 0;
+        g_fw_debug_infor.fw_dynamic_dump = 0;
+        g_fw_debug_infor.bitmap = 0;
+        memset(g_fw_debug_infor.fw_log_state_orig, '\0', sizeof(g_fw_debug_infor.fw_log_state_orig));
+        memset(g_fw_debug_infor.fw_log_state_new, '\0', sizeof(g_fw_debug_infor.fw_log_state_new));
+        memset(g_fw_debug_infor.fw_dump_state_orig, '\0', sizeof(g_fw_debug_infor.fw_dump_state_orig));
+        memset(g_fw_debug_infor.fw_dump_state_new, '\0', sizeof(g_fw_debug_infor.fw_dump_state_new));
+
+        ret = property_get(WCN_FW_DBG_LOG_PROP, g_fw_debug_infor.fw_log_state_orig, NULL);
+        if (0 > ret)
+            ALOGE("get property(%s) failed ret:%d\n", WCN_FW_DBG_LOG_PROP, ret);
+        else if (0 == ret)
+            ALOGI("(%s) is not supported\n", WCN_FW_DBG_LOG_PROP);
+        else
+            ALOGI("get property (%s) is %s\n", WCN_FW_DBG_LOG_PROP, g_fw_debug_infor.fw_log_state_orig);
+
+        ret = property_get(WCN_DYNAMIC_DUMP_PROP, g_fw_debug_infor.fw_dump_state_orig, NULL);
+        if (0 > ret)
+            ALOGE("get property(%s) failed ret:%d\n", WCN_DYNAMIC_DUMP_PROP, ret);
+        else if (0 == ret)
+            ALOGI("(%s) is not supported\n", WCN_DYNAMIC_DUMP_PROP);
+        else
+            ALOGI("get property (%s) is %s\n", WCN_DYNAMIC_DUMP_PROP, g_fw_debug_infor.fw_dump_state_orig);
+    }
+
+    /*meta tool may turn on wifi very early, this property is used to protect turn on wifi.*/
+    ret= property_get(WCN_FORMETA_READY_PROP, readyStr, NULL);
+    if ((0 >= ret) || (0 == strcmp(readyStr, "yes"))) {
+            ALOGI("get property(%s) failed iRet:%d or property is %s\n", WCN_FORMETA_READY_PROP, ret, readyStr);
+    }
+
+    sprintf(readyStr, "%s", "yes");
+    ret = property_set(WCN_FORMETA_READY_PROP, readyStr);
+    if (0 != ret) {
+            ALOGI("set property(%s) to %s failed iRet:%d\n", WCN_FORMETA_READY_PROP, readyStr, ret);
+    } else {
+            ALOGI("set property(%s) to %s succeed\n", WCN_FORMETA_READY_PROP, readyStr);
+    }
+
+    return 0;
+}
+
+static int launcher_set_fw_log_ctrl(void) {
+    int ret = -1;
+    int fw_debug_enable = 0;
+
+    if (g_fw_debug_infor.bitmap & 0x1) {
+        ALOGV("fw log ctrl flag has been set\n");
+        return 0;
+    }
+
+    if ((g_fw_debug_infor.fw_log_ctrl == 1) ||
+         (g_fw_debug_infor.log_retry > WCN_FW_DEBUG_CLRL_RETRY_LIMIT)) {
+        ALOGV("retry: %d\n", g_fw_debug_infor.log_retry);
+
+        if (!strcmp(g_fw_debug_infor.fw_log_state_new, "yes")) {
+            fw_debug_enable = 1;
+            if (pthread_create(&g_thread_handle, NULL, launcher_set_fwdbg_thread, &fw_debug_enable))
+                ALOGE("create enable firmware dbglog thread fail\n");
+        } else {
+            ret = ioctl(g_wmt_fd, WMT_IOCTL_FW_DBGLOG_CTRL, fw_debug_enable);
+            /* if do this jude,it will confuse user beacuse kernel return -1 */
+            /* if (ret < 0)*/
+            /*   ALOGE("ioctl error: err msg: %s\n", strerror(errno));*/
+        }
+        g_fw_debug_infor.bitmap |= (0x1 << 0);
+    } else if (g_fw_debug_infor.log_retry++ <= WCN_FW_DEBUG_CLRL_RETRY_LIMIT) {
+        ret = property_get(WCN_FW_DBG_LOG_PROP, g_fw_debug_infor.fw_log_state_new, NULL);
+        if (0 > ret)
+            ALOGE("get property(%s) failed ret:%d\n", WCN_FW_DBG_LOG_PROP, ret);
+        else if (0 == ret)
+            ALOGI("(%s) is not supported\n", WCN_FW_DBG_LOG_PROP);
+        else {
+            ALOGV("get property(%s) is %s\n", WCN_FW_DBG_LOG_PROP, g_fw_debug_infor.fw_log_state_new);
+            if (strcmp(g_fw_debug_infor.fw_log_state_new, g_fw_debug_infor.fw_log_state_orig))
+                g_fw_debug_infor.fw_log_ctrl = 1;
+        }
+    } else
+        ALOGV("retry finish\n");
+    return 0;
+}
+
+static int launcher_set_fw_dynamic_dump(void) {
+    int ret = -1;
+
+    if (g_fw_debug_infor.bitmap & (0x1 << 1)) {
+        ALOGV("fw dynamic ctrl flag has been set\n");
+        return 0;
+    }
+
+    if ((g_fw_debug_infor.fw_dynamic_dump == 1) ||
+         (g_fw_debug_infor.dump_retry > WCN_FW_DEBUG_CLRL_RETRY_LIMIT)) {
+        ALOGV("dump_retry: %d\n", g_fw_debug_infor.dump_retry);
+
+        if (g_fw_debug_infor.fw_dynamic_dump == 1) {
+        /* it is only meaningfull to do ioctl in this case*/
+            ret = ioctl(g_wmt_fd, WMT_IOCTL_DYNAMIC_DUMP_CTRL, g_fw_debug_infor.fw_dump_state_new);
+            ALOGV("%d, %zd,\n", PROPERTY_VALUE_MAX, strlen(g_fw_debug_infor.fw_dump_state_new));
+            if (ret < 0)
+                ALOGE("ioctl error: err msg: %s\n", strerror(errno));
+        }
+        g_fw_debug_infor.bitmap |= (0x1 << 1);
+    } else if (g_fw_debug_infor.dump_retry++ <= WCN_FW_DEBUG_CLRL_RETRY_LIMIT) {
+        ret = property_get(WCN_DYNAMIC_DUMP_PROP, g_fw_debug_infor.fw_dump_state_new, NULL);
+        if (0 > ret)
+            ALOGE("get property(%s) failed ret:%d\n", WCN_DYNAMIC_DUMP_PROP, ret);
+        else if (0 == ret)
+            ALOGI("(%s) is not supported\n", WCN_DYNAMIC_DUMP_PROP);
+        else {
+            ALOGV("get property(%s) is %s\n", WCN_DYNAMIC_DUMP_PROP, g_fw_debug_infor.fw_dump_state_new);
+            if (strcmp(g_fw_debug_infor.fw_dump_state_new, g_fw_debug_infor.fw_dump_state_orig))
+                g_fw_debug_infor.fw_dynamic_dump = 1;
+        }
+    } else
+        ALOGV("retry finish\n");
+
+    return 0;
+}
+
+static void launcher_set_fw_debug_infor(int chip_id) {
+    enum wmt_chip_type chip_type = WMT_CHIP_TYPE_INVALID;
+
+    chip_type = launcher_check_chip_type(chip_id);
+    if (chip_type == WMT_CHIP_TYPE_SOC) {
+        launcher_set_fw_log_ctrl();
+        launcher_set_fw_dynamic_dump();
+    }
+}
+
+int main(int argc, char *argv[]) {
+    int ld, err;
+    struct pollfd fds[2];
+    int fd_num = 0;
+    int len = 0;
+    int chip_id = -1;
+
+    launcher_check_driver_ready();
+    launcher_open_wmt_device();
+    chip_id = launcher_query_chip_id();
+
+    launcher_set_parameter_to_driver(argc, argv, chip_id);
+
+    launcher_set_signal_handler();
+
+    launcher_get_fw_debug_orign_infor(chip_id);
+
+    fds[0].fd = g_wmt_fd; /* stp_wmt fd */
+    fds[0].events = POLLIN | POLLRDNORM; /* wait read events */
+    ++fd_num;
+
+    launcher_pwr_on_chip(&chip_id);
+
+    while (!__io_canceled) {
+        launcher_set_fw_debug_infor(chip_id);
+        fds[0].revents = 0;
+        err = poll(fds, fd_num, 2000);  /* 2 seconds */
+        if (err < 0) {
+            if (errno == EINTR)
+                continue;
+            else {
+                ALOGE("poll error:%d errno:%d, %s\n", err, errno, strerror(errno));
+                break;
+            }
+        } else if (!err)
+            continue;
+
+
+        if (fds[0].revents & POLLIN) {
+            if (g_wmt_fd < 0)
+                break;
+            memset(g_cmd_str, 0, sizeof(g_cmd_str));
+            len = read(g_wmt_fd, g_cmd_str, sizeof(g_cmd_str)-1);
+            if (len <= 0 || len >= (int)sizeof(g_cmd_str)) {
+                ALOGE("POLLIN(%d) but read fail:%d\n", g_wmt_fd, len);
+                continue;
+            }
+            g_cmd_str[len] = '\0';
+            /*ALOGI("rx_cmd_str:%s\n", g_cmd_str);*/
+            err = launcher_handle_cmd(&g_stp_param_config, g_cmd_str, len);
+            if (!err) {
+                /* ALOGI("handle_cmd(%s), respond ok \n", g_cmd_str); */
+                snprintf(g_resp_str, sizeof(g_resp_str), "ok");
+            } else {
+                if (err == 1)
+                    snprintf(g_resp_str, sizeof(g_resp_str), "cmd not found");
+                else
+                    snprintf(g_resp_str, sizeof(g_resp_str), "resp_%d", err);
+            }
+            ALOGI("cmd(%s) resp(%s)\n", g_cmd_str, g_resp_str);
+            len = write(g_wmt_fd, g_resp_str, strlen(g_resp_str));
+            if (len != (int)strlen(g_resp_str))
+                fprintf(stderr, "write resp(%d) fail: len(%d), errno(%d, %s)\n",
+                        g_wmt_fd, len, errno, (len == -1) ? strerror(errno) : "");
+        }
+    }
+
+    if (g_wmt_fd >= 0) {
+        close(g_wmt_fd);
+        g_wmt_fd = -1;
+    }
+
+    if (((g_stp_param_config.stp_mode == STP_UART_MAND) ||
+        (g_stp_param_config.stp_mode == STP_UART_FULL)) && g_tty_fd >= 0) {
+        /* Restore TTY line discipline */
+        ld = N_TTY;
+        if (ioctl(g_tty_fd, TIOCSETD, &ld) < 0) {
+            ALOGE("Can't restore line discipline");
+            exit(1);
+        }
+
+        close(g_tty_fd);
+        g_tty_fd = -1;
+    }
+
+    if (g_thread_handle != -1) {
+        pthread_detach(g_thread_handle);
+        g_thread_handle = -1;
+    }
+
+    return 0;
+}
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/wmt_concurrency.c b/src/connectivity/combo_tool/6631_combo_tool/src/wmt_concurrency.c
new file mode 100644
index 0000000..22e0f9b
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/wmt_concurrency.c
@@ -0,0 +1,381 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ * 
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ * 
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#define _GNU_SOURCE
+#include "wmt_ioctl.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/endian.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <linux/serial.h> /* struct serial_struct  */
+#include <pthread.h>
+#include <sched.h>
+#define FIBER_STACK 8192
+
+pthread_mutex_t mutex;
+
+typedef enum DRV_INDEX
+{
+  DRV_BT = 0,
+  DRV_FM,  
+  DRV_GPS,
+  DRV_WIFI,
+  DRV_MAX,
+}ENUM_DRV_INDEX;
+
+typedef enum ARG_DRV_INDEX
+{
+  ARG_DRV_BT = 1 << DRV_BT,
+  ARG_DRV_FM = 1 << DRV_FM,  
+  ARG_DRV_GPS = 1 << DRV_GPS,
+  ARG_DRV_WIFI = 1 << DRV_WIFI,
+  ARG_DRV_ALL = ARG_DRV_BT + ARG_DRV_FM + ARG_DRV_GPS + ARG_DRV_WIFI,
+}ENUM_ARG_DRV_INDEX;
+
+#define is_bt_mask_on(a) ((a) & ARG_DRV_BT)
+#define is_fm_mask_on(a) ((a) & ARG_DRV_FM)
+#define is_gps_mask_on(a) ((a) & ARG_DRV_GPS)
+#define is_wifi_mask_on(a) ((a) & ARG_DRV_WIFI)
+
+#define QUICK_FUNC_ON_OFF_SUPPORT
+#ifdef QUICK_FUNC_ON_OFF_SUPPORT
+	#define MIN_INTERVAL 1
+#else 
+	#define MIN_FUNC_ON_TIME 4
+	#define MIN_FUNC_OFF_TIME 1
+	#define MIN_INTERVAL  MIN_FUNC_ON_TIME + MIN_FUNC_OFF_TIME
+#endif
+
+#define MAX_FUNC_ON_TIME 9
+#define MAX_FUNC_OFF_TIME 3
+#define MAX_INTERVAL  MAX_FUNC_ON_TIME + MAX_FUNC_OFF_TIME
+//enum bool {false = 0, true = !false};
+
+char *src_name[]={
+	"BT",  
+	"FM", 
+	"GPS", 
+	"WIFI",
+	"UNKNOWN DEVICE",
+	};
+
+static int g_wmt_fd = -1;
+static int g_reference = 0;
+static int g_count = 2;
+int g_on2off_interval = MAX_INTERVAL;
+int g_off2on_interval = MAX_INTERVAL;
+volatile int g_state[5] = {0};
+
+void dump_state(void)
+{
+	//printf("%s:++, pid =%d\n",  __FUNCTION__, getpid());
+	printf("%d: %s:g_state:[BT]%d, [FM]:%d, [GPS]:%d, [WIFI]:%d\n", getpid(),  __FUNCTION__, g_state[0], g_state[1], g_state[2], g_state[3]);
+	//printf("%s:--, pid =%d\n",  __FUNCTION__, getpid());
+}
+
+int read_reference(ENUM_DRV_INDEX index)
+{
+	volatile int flag = 0;
+	pthread_mutex_lock(&mutex);
+	if(index >= 4)
+	{
+		if(g_state[0] || g_state[1] || g_state[2] || g_state[3])
+		{
+			flag = 1;
+		}
+		else
+		{
+			flag = 0;
+		}
+	}
+	else
+	{
+		flag = g_state[index];
+	}
+	pthread_mutex_unlock(&mutex);
+	return flag;
+}
+
+void get_reference(ENUM_DRV_INDEX index)
+{
+	pthread_mutex_lock(&mutex);
+	g_reference++;
+	g_state[index] = 1;
+	dump_state();
+	pthread_mutex_unlock(&mutex);
+}
+
+
+void put_reference(ENUM_DRV_INDEX index)
+{
+	pthread_mutex_lock(&mutex);
+	g_reference--;
+	g_state[index] = 0;
+	dump_state();
+	pthread_mutex_unlock(&mutex);
+}
+
+int func_on_off(void * drv_index)
+{
+  ENUM_DRV_INDEX index = (ENUM_DRV_INDEX) drv_index;
+  int count = g_count;
+//  printf("%s:++, index =%d\n",  __FUNCTION__, index);
+  if(DRV_MAX > index && g_wmt_fd > 0)
+  {
+    while(count--)
+    {
+    	//turn on  src_name[index] function
+        if (0 == ioctl(g_wmt_fd, WMT_IOCTL_FUNC_ONOFF_CTRL, 0xBEEF0000 | index))
+    	{
+    		printf("pid:%d, turn on %s success.\n",   getpid(), src_name[index]);
+			//exit(0);
+    	}
+    	else
+    	{
+    		printf("pid:%d, turn on %s fail.\n",   getpid(), src_name[index]);
+    		exit(-1);
+    	}
+    	
+    	//printf("%s:-- pid: %d, finish turn on %s\n",  __FUNCTION__, getpid(), src_name[index]);
+    	/*
+    	//turn off  src_name[index] function
+    	*/
+    	sleep(g_on2off_interval);
+        if ( 0 == ioctl(g_wmt_fd, WMT_IOCTL_FUNC_ONOFF_CTRL, 0xDEAD0000 | index))
+    	{
+    		printf("pid:%d, turn off %s success.\n",   getpid(), src_name[index]);
+    		//exit(0);
+    	}
+    	else
+    	{
+    		printf("pid:%d, turn off %s fail.\n",   getpid(), src_name[index]);
+    		exit(-1);
+    	}
+    	printf("%d:%s test:left count = %d.\n",  getpid(), src_name[index], count);
+    	sleep(g_off2on_interval);
+    	
+    }
+  }
+  else
+  {
+  	printf("pid:%d, undnown device with index:%d.\n",  getpid(), index);
+  }
+ // printf("%s:--, index =%d\n",  __FUNCTION__, index);
+ //exit(-2);
+ //return;
+  exit(0);
+}
+
+
+static void sig_child_term(__attribute__((unused))int sig)
+{
+    printf("%s ++.\n", __FUNCTION__);
+    int pid = -1;
+    int stat;
+    while((pid = waitpid(0, &stat, WNOHANG)) != 0)
+    {
+    	printf("%s:pid = %d, exit event.\n", __FUNCTION__, pid);
+    }
+    printf("%s:pid = %d.\n", __FUNCTION__, pid);
+    printf("%s --.\n", __FUNCTION__);
+}
+
+int main(int argc, char *argv[])
+{
+	
+	int bitmask = ARG_DRV_ALL;
+	
+	int i = 0;
+	void *stack[8];
+	struct sigaction sa;
+	if(argc != 5)
+	{
+		printf("wmt_concurrency usage:\n\
+		wmt_concurrency looptimes  bitmask  on2offtime off2ontime\n\
+		  -looptimes	on<->off switch times (<1000000)\n\
+		  -bitmask\n\
+		    -1:BT on<->off test\n\
+		    -2:FM on<->off test\n\
+		    -4:GPS on<->off test\n\
+		    -8:WIFI on<->off test\n\
+		    -x: can be combination of the upper 4 bitmasks\n\
+		  -on2offtime	(0~12s)\n\
+		    -function on hold time before turn off\n\
+		  -off2ontime	(0~12s)\n\
+		    -function off hold time before turn on\n\
+		");
+		return -1;
+	}
+	if ((argc > 1) && (argv[1] != NULL)) {
+        
+        g_count = atoi(argv[1]);
+        printf("%s:argv[1] g_count param = %d\n",  __FUNCTION__, g_count);
+        if(g_count < 0)
+	    {
+	    	g_count = 2;
+	    }
+	   	g_count = g_count > 1000000 ? 1000000 : g_count;
+	    printf("%s:g_count = %d\n",  __FUNCTION__, g_count);
+    }
+    if ((argc > 2) && (argv[2] != NULL)) {
+        
+        bitmask = atoi(argv[2]);
+        printf("%s:argv[2] bitmask param = %d\n",  __FUNCTION__, bitmask);
+        if(bitmask <= 0 || bitmask > ARG_DRV_ALL)
+    	{
+    		bitmask = ARG_DRV_ALL;
+    	}
+    	printf("%s:bitmask = %d\n",  __FUNCTION__, bitmask);
+    }
+    
+    if ((argc > 3) && (argv[3] != NULL)) {
+        
+        g_on2off_interval = atoi(argv[3]);
+        printf("%s:argv[3] g_on2off_interval param = %d\n",  __FUNCTION__, g_on2off_interval);
+        if(g_on2off_interval < MIN_INTERVAL)
+    	{
+    		g_on2off_interval = MIN_INTERVAL;
+    	}
+    	if(g_on2off_interval > MAX_INTERVAL)
+    	{
+    		g_on2off_interval = MAX_INTERVAL;
+    	}
+		printf("%s:g_on2off_interval = %d\n",  __FUNCTION__, g_on2off_interval);
+    }
+    if ((argc > 4) && (argv[4] != NULL)) {
+        
+        g_off2on_interval = atoi(argv[4]);
+        printf("%s:argv[4] g_off2on_interval param = %d\n",  __FUNCTION__, g_off2on_interval);
+        if(g_off2on_interval < MIN_INTERVAL)
+    	{
+    		g_off2on_interval = MIN_INTERVAL;
+    	}
+    	if(g_off2on_interval > MAX_INTERVAL)
+    	{
+    		g_off2on_interval = MAX_INTERVAL;
+    	}
+		printf("%s:g_off2on_interval = %d\n",  __FUNCTION__, g_off2on_interval);
+    }
+    
+	for (i = sizeof(g_state)/sizeof(g_state[0]); i > 0; )
+	{
+		g_state[--i] = 0;
+	}
+
+	printf("pid = %d\n", getpid());
+	for(i = sizeof(stack)/sizeof(void *); i > 0; )
+	{
+		stack[--i] = malloc(FIBER_STACK);
+		if(stack[i] == NULL)
+		{
+			printf("pid = %d, malloc error\n", getpid());
+			goto out;
+		}
+	}
+
+    g_wmt_fd = open("/dev/stpwmt", O_RDWR | O_NOCTTY);	
+    printf("%s:argc = %d\n", __FUNCTION__,  argc);
+    
+    if(pthread_mutex_init(&mutex, NULL) != 0)
+    {
+    	printf("%s:pthread_mutex_init fail\n",  __FUNCTION__);
+    	goto out;	
+    }
+    if(g_wmt_fd > 0)
+    {
+    	memset(&sa, 0, sizeof(sa));
+    	//signal(SIGCHLD, sig_child_term);
+		sa.sa_handler = sig_child_term;
+		sa.sa_flags = SA_NOCLDSTOP;
+		sigaction(SIGCHLD, &sa, 0);
+    	int sleepCOunter = g_count;
+    	    	
+    		if(is_bt_mask_on(bitmask) && read_reference(DRV_BT) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[0] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_BT);
+    			//clone(&func_off, (char *)stack[4] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_BT);
+    		}
+    		
+    		if(is_wifi_mask_on(bitmask) && read_reference(DRV_WIFI) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[1] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_WIFI);
+    			//clone(&func_off, (char *)stack[5] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_WIFI);
+    		}	
+    		if(is_fm_mask_on(bitmask) && read_reference(DRV_FM) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[2] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_FM);
+    			//clone(&func_off, (char *)stack[6] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_FM);
+    		}
+    		if(is_gps_mask_on(bitmask) && read_reference(DRV_GPS) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[3] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_GPS);
+  				//clone(&func_off, (char *)stack[7] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_GPS);
+  			}
+    		//printf("%s:left g_count = %d.\n",  __FUNCTION__, g_count);
+    		sleep(sleepCOunter * (g_on2off_interval + g_off2on_interval));
+    }
+out:
+	
+	for(i = sizeof(stack)/sizeof(void *); i > 0; )
+	{
+		printf("%s:pid = %d, free stack information.\n",  __FUNCTION__, getpid());
+		if (NULL != stack[--i])
+		{
+			free(stack[i]);
+		}
+		stack[i] = NULL;
+	}
+    if(g_wmt_fd > 0)
+    {
+    	close(g_wmt_fd);
+    	g_wmt_fd  = -1;
+    }
+    printf("%s:pid = %d, exit.\n",  __FUNCTION__, getpid());
+    return 0;
+}
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/wmt_ioctl.h b/src/connectivity/combo_tool/6631_combo_tool/src/wmt_ioctl.h
new file mode 100644
index 0000000..54731bc
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/wmt_ioctl.h
@@ -0,0 +1,52 @@
+#ifndef _WMT_IOCTL_H_
+#define _WMT_IOCTL_H_
+
+#include <sys/ioctl.h>
+
+#define WMT_IOC_MAGIC 0xa0
+#define WMT_IOCTL_SET_PATCH_NAME	 	_IOW(WMT_IOC_MAGIC,4,char*)
+#define WMT_IOCTL_SET_STP_MODE		 	_IOW(WMT_IOC_MAGIC,5,int)
+#define WMT_IOCTL_FUNC_ONOFF_CTRL		_IOW(WMT_IOC_MAGIC,6,int)
+#define WMT_IOCTL_LPBK_POWER_CTRL		_IOW(WMT_IOC_MAGIC,7,int)
+#define WMT_IOCTL_LPBK_TEST				_IOWR(WMT_IOC_MAGIC,8,char*)
+#define WMT_IOCTL_GET_CHIP_INFO			_IOR(WMT_IOC_MAGIC,12,int)
+#define WMT_IOCTL_SET_LAUNCHER_KILL		_IOW(WMT_IOC_MAGIC,13,int)
+#define WMT_IOCTL_SET_PATCH_NUM			_IOW(WMT_IOC_MAGIC,14,int)
+#define WMT_IOCTL_SET_PATCH_INFO		_IOW(WMT_IOC_MAGIC,15,char*)
+#define WMT_IOCTL_PORT_NAME          	_IOWR(WMT_IOC_MAGIC, 20, char*)
+#define WMT_IOCTL_WMT_CFG_NAME       	_IOWR(WMT_IOC_MAGIC, 21, char*)
+#define WMT_IOCTL_WMT_QUERY_CHIPID   	_IOR(WMT_IOC_MAGIC,  22, int)
+#define WMT_IOCTL_WMT_TELL_CHIPID    	_IOW(WMT_IOC_MAGIC,  23, int)
+#define WMT_IOCTL_WMT_COREDUMP_CTRL  	_IOW(WMT_IOC_MAGIC, 24, int)
+#define WMT_IOCTL_SEND_BGW_DS_CMD		_IOW(WMT_IOC_MAGIC,25,char*)
+#define WMT_IOCTL_ADIE_LPBK_TEST		_IOWR(WMT_IOC_MAGIC,26,char*)
+#define WMT_IOCTL_GET_APO_FLAG          _IOR(WMT_IOC_MAGIC, 28, int)
+#define WMT_IOCTL_FW_DBGLOG_CTRL        _IOR(WMT_IOC_MAGIC, 29, int)
+#define WMT_IOCTL_DYNAMIC_DUMP_CTRL     _IOR(WMT_IOC_MAGIC, 30, char*)
+#define WMT_IOCTL_SET_ROM_PATCH_INFO    _IOW(WMT_IOC_MAGIC,31,char*)
+#define WMT_IOCTL_FDB_CTRL              _IOW(WMT_IOC_MAGIC,32,char*)
+#define WMT_IOCTL_GET_EMI_PHY_SIZE      _IOR(WMT_IOC_MAGIC, 33, unsigned int)
+
+typedef enum _CONSYS_BASE_ADDRESS_INDEX_ {
+        MCU_BASE_INDEX = 0,
+        TOP_RGU_BASE_INDEX,
+        INFRACFG_AO_BASE_INDEX,
+        SPM_BASE_INDEX,
+        MCU_CFG_ON_BASE_INDEX,
+        MCU_CIRQ_BASE_INDEX,
+} ENUM_CONSYS_BASE_ADDRESS_INDEX, *P_ENUM_CONSYS_BASE_ADDRESS_INDEX;
+
+typedef struct {
+        unsigned int is_write;
+        ENUM_CONSYS_BASE_ADDRESS_INDEX base_index;
+        unsigned int offset;
+        unsigned int value;
+} WMT_FDB_CTRL, *P_WMT_FDB_CTRL;
+
+enum wmt_chip_type {
+    WMT_CHIP_TYPE_COMBO,
+    WMT_CHIP_TYPE_SOC,
+    WMT_CHIP_TYPE_INVALID
+};
+
+#endif
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/wmt_loopback.c b/src/connectivity/combo_tool/6631_combo_tool/src/wmt_loopback.c
new file mode 100644
index 0000000..b79fd50
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/wmt_loopback.c
@@ -0,0 +1,333 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+#include "wmt_ioctl.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+//#include <sys/endian.h>
+#include <linux/serial.h> /* struct serial_struct  */
+
+#define LEN_MAX 1024
+
+typedef enum {
+    LEN_FIXED = 0,
+    LEN_INC   = 1,
+    LEN_DEC   = 2,
+    LEN_RAND  = 3,
+    COMBO_POWER_ON  = 4, 
+    COMBO_POWER_OFF = 5,
+    ADIE_LPK = 6,
+    LPBK_OP_MAX
+} LPBK_OP_ENUM;
+
+unsigned char WMT_TEST_LPBK_CMD[] = {0x1, 0x2, 0x0, 0x0, 0x7};
+unsigned char WMT_TEST_LPBK_EVT[] = {0x2, 0x2, 0x0, 0x0, 0x0};
+/*
+unsigned char out_buf[2048] = {0};
+unsigned char in_buf[2048] = {0};
+*/
+struct lpbk_package{
+	long payload_length;
+	unsigned char out_payload[2048];
+	unsigned char in_payload[2048];
+};
+
+static int wmt_loopback(int type, int count, int max, int delay) {
+    int wmt_fd;
+    int ret = -1;
+    int loop = 0;
+    int offset;
+    unsigned short buf_length = 0;
+	struct lpbk_package lpbk_buffer;
+    printf("*type(%d) count(%d) max(%d) \n", type, count, max);
+
+    if(type >= LPBK_OP_MAX){
+        printf("[%s] cannot support %d opeartion\n", __FUNCTION__, type);
+    	return -1;
+    }
+    
+    /* open wmt dev */
+    wmt_fd = open("/dev/stpwmt", O_RDWR | O_NOCTTY);
+    if (wmt_fd < 0) {
+        printf("[%s] Can't open stpwmt \n", __FUNCTION__);
+    	return -1;
+    }
+
+    if(type == COMBO_POWER_ON){
+        printf("[power on combo chip]\n");
+        if(ioctl(wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 2) != 0)
+        {
+            printf("[%s] power on combo chip failed\n", __FUNCTION__);
+            close(wmt_fd);
+            wmt_fd = -1;
+            return -1;
+        } else {
+            close(wmt_fd);
+            printf("[power on combo chip ok!]\n");
+        }       
+        return 0;
+    }
+
+    if(type == COMBO_POWER_OFF){
+        printf("[power off combo chip]\n");
+        if(ioctl(wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 3) != 0)
+        {
+            printf("[%s] power off combo chip failed\n", __FUNCTION__);
+            close(wmt_fd);
+            ret = -1;
+        } else {
+            close(wmt_fd);
+            printf("[power off combo chip ok!]\n");
+        }
+        return 0;
+    }
+    
+    /*turn LPBK function on*/
+    printf("[power on combo chip]\n");
+    if(ioctl(wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 2) != 0)
+    {
+        printf("[%s] Can't power on combo chip ok! failed\n", __FUNCTION__);
+        close(wmt_fd);
+        wmt_fd = -1;
+        return -1;
+    } else {
+        printf("[power on combo chip ok!]\n");
+    }     
+		
+    /* init length */
+    switch (type) {
+        case LEN_FIXED:
+            buf_length = (unsigned short)max;
+            break;
+        case LEN_INC:
+            buf_length = 1;
+            break;
+        case LEN_DEC:
+            buf_length = max;
+            break;
+        default:
+            /* random */
+            break;
+    }
+
+    if( (type >= LEN_FIXED) && (type <= LEN_RAND) )
+    {
+        for (loop = 0; loop < count; loop++) {
+            //<1> init buffer
+            memset((void *)&lpbk_buffer, 0, sizeof(struct lpbk_package));
+            lpbk_buffer.payload_length = buf_length;
+            for (offset = 0; offset < buf_length; offset++) {
+                lpbk_buffer.out_payload[offset] = (offset + 1)/*for test use: begin from 1*/  & 0xFF;
+            }
+            
+            /*<2> do LPBK*/
+            usleep(delay * 1000);   
+
+            if(( ret = ioctl(wmt_fd, WMT_IOCTL_LPBK_TEST, &lpbk_buffer)) != lpbk_buffer.payload_length){
+                printf("[%s] LPBK operation failed, return length = %d\n", __FUNCTION__, ret);
+                break;
+            }
+
+            if(lpbk_buffer.payload_length < 0) {
+                printf("[%s] LPBK operation failed, return length = %ld\n",
+                        __FUNCTION__, lpbk_buffer.payload_length);
+                break;
+            }
+
+            /*<3> compare result*/
+            if (memcmp(lpbk_buffer.in_payload, lpbk_buffer.out_payload, lpbk_buffer.payload_length)) {
+                printf("[%s] WMT_TEST_LPBK_CMD payload compare error\n", __FUNCTION__);
+                break;
+            }
+            printf("[%s] exec WMT_TEST_LPBK_CMD succeed(loop = %d, size = %ld) \n", __FUNCTION__, loop, lpbk_buffer.payload_length);
+
+            /*<4> update buffer length */
+            switch (type) {
+            case LEN_INC:
+                buf_length = (buf_length == max) ? 1 : buf_length + 1;
+                break;
+            case LEN_DEC:
+                buf_length = (buf_length == 1) ? max : buf_length - 1;
+                break;
+            case LEN_RAND:
+                buf_length = rand() % max + 1;
+                break;
+            default:
+                /* no change */
+                break;
+            }
+        }
+    }
+    else if( type == ADIE_LPK )
+    {
+        int adie_chipID = 0;
+        for (loop = 0; loop < count; loop++) {
+            //<1> init buffer
+            memset((void *)&lpbk_buffer, 0, sizeof(struct lpbk_package));
+            adie_chipID = 0;
+            
+            /*<2> do LPBK*/
+            usleep(delay * 1000);   
+
+            if(( ret = ioctl(wmt_fd, WMT_IOCTL_ADIE_LPBK_TEST, &lpbk_buffer)) != 2){
+                printf("[%s] ADIE_LPK operation failed, return length = %d\n", __FUNCTION__, ret);
+                break;
+            }
+            adie_chipID = ((lpbk_buffer.out_payload[1] >> 4) & 0xf)*1000 + 
+                          (lpbk_buffer.out_payload[1] & 0xf)*100 + 
+                          ((lpbk_buffer.out_payload[0] >> 4) & 0xf)*10 + 
+                          (lpbk_buffer.out_payload[0] & 0xf);
+            
+            /*<3> compare result*/
+            if ( adie_chipID != max ) {
+                printf("[%s] ADIE_LPK payload compare error\n", __FUNCTION__);
+                break;
+            }
+            printf("[%s] exec ADIE_LPK succeed(loop = %d, ChipID = %d) \n", __FUNCTION__, 
+                loop, adie_chipID);
+        }
+    }
+    
+    /*Not to power off chip on default, please manually to do this*/
+#if 0    
+	/*turn off LPBK function*/
+    if(ioctl(wmt_fd, 7, 0) != 0)
+    {
+    	printf("[%s] turn lpbk function off failed\n", __FUNCTION__);
+		ret = -1;
+    }
+    else
+    {
+    	ret = 0;
+    }
+#endif 
+    ret = 0;
+
+    if (loop != count) {
+        printf("fail at loop(%d) buf_length(%d)\n", loop, buf_length);
+    }
+
+    /* close wmt dev */
+    if (wmt_fd >= 0) {
+        close(wmt_fd);
+    }
+
+    return ret;
+}
+static void print_usage(void)
+{
+    unsigned int usage_lines = 0;
+    static char *(usage[]) = {
+      "wmt_loopback type count length delay",
+      " --type: essential",
+      "         -0: loopback test  with fixed packet length",
+      "         -1: loopback test with packet length increase 1 per packet based on 1",
+      "         -2: loopback test packet length decrease 1 per packet based on 1024",
+      "         -3: loopback test with random packet length",
+      "         -4: only turn loopback function on without test",
+      "         -5: only turn loopback function off without test",
+      "         -6: loopback test spi bus by get Adie chpid in SOC chip",
+      " --count: optional, total packet count, 1000 by default",
+      " --length: optional, 1 ~ 1024, 1024 by default",
+      " --delay: optional, interval between packets (ms), 0 by default",
+
+    };
+
+    for (usage_lines = 0 ; usage_lines < sizeof (usage)/sizeof(usage[0]); usage_lines++)
+    {
+        printf("%s\n", usage[usage_lines]);
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    int type = LEN_FIXED;
+    int count = 1000;
+    int length = 1024;
+    int delay = 0;
+	if(argc <= 1)
+	{
+		printf ("Error lack of arguments\n");
+		print_usage();
+		return -1;
+	}
+	
+    if ((argc > 1) && (argv[1] != NULL)) {
+        printf("type: argv[1] %s %d\n", argv[1], atoi(argv[1]));
+        type = atoi(argv[1]);
+    }
+    if ((type < LEN_FIXED) || (type >= LPBK_OP_MAX))
+        type = LEN_FIXED;
+
+    if ((argc > 2) && (argv[2] != NULL)) {
+        printf("count: argv[2] %s %d\n", argv[2], atoi(argv[2]));
+        count = atoi(argv[2]);
+    }
+    if ((count <= 0) || (count > 10000))
+        count = 1000;
+
+    if ((argc > 3) && (argv[3] != NULL)) {
+        printf("count: argv[3] %s %d\n", argv[3], atoi(argv[3]));
+        length = atoi(argv[3]);
+        if (0 == length) {
+            printf("length is zero, reset default value 1024\n");
+            length = 1024;
+        }
+    }
+    if ((length <= 0) || (length > 2048))
+        length = 1024;
+
+    if ((argc > 4) && (argv[4] != NULL)) {
+        printf("count: argv[4] %s %d\n", argv[4], atoi(argv[4]));
+        delay = atoi(argv[4]);
+    }
+    if ((delay < 0) || (delay > 1000))
+        delay = 0;
+
+    return wmt_loopback(type, count, length, delay);
+}
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/yocto_stp_uart_launcher.c b/src/connectivity/combo_tool/6631_combo_tool/src/yocto_stp_uart_launcher.c
new file mode 100644
index 0000000..4b42bc2
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/yocto_stp_uart_launcher.c
@@ -0,0 +1,1911 @@
+
+/******************************************************************************
+*                         C O M P I L E R   F L A G S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                    E X T E R N A L   R E F E R E N C E S
+*******************************************************************************
+*/
+#include "wmt_ioctl.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <pthread.h>
+/*#include <syslog.h>*/
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+//#include <sys/endian.h>
+#include <sys/uio.h>
+#include <linux/serial.h> /* struct serial_struct  */
+//#include <log/log.h>
+
+#include <dirent.h>
+//#include <cutils/properties.h>
+
+
+/******************************************************************************
+*                              M A C R O S
+*******************************************************************************
+*/
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG    "wmt_launcher"
+#ifndef ALOGI
+#define ALOGI printf
+#endif
+#ifndef ALOGE
+#define ALOGE printf
+#endif
+#ifndef ALOGV
+#define ALOGV printf
+#endif
+#ifndef PROPERTY_VALUE_MAX
+#define PROPERTY_VALUE_MAX (128)
+#endif
+
+
+#define  WCN_COMBO_CHIP_ID_PROP             "persist.vendor.connsys.chipid"
+#define  WCN_DRIVER_READY_PROP              "vendor.connsys.driver.ready"
+#define  WCN_FORMETA_READY_PROP             "vendor.connsys.formeta.ready"
+#define  WCN_FW_DBG_LOG_PROP                "persist.vendor.connsys.fwlog.status"
+#define  WCN_DYNAMIC_DUMP_PROP              "persist.vendor.connsys.dynamic.dump"
+#define  WCN_COMBO_PATCH_BUILD_VER_PROP     "persist.vendor.connsys.patch.version"
+#define  WCN_FW_DEBUG_CLRL_RETRY_LIMIT      (5)
+
+//#include "cust_mt6620_test.h" /* project custom header file */
+
+#ifndef N_MTKSTP
+#define N_MTKSTP                (15 + 1)  /* MediaTek WCN Serial Transport Protocol */
+#endif
+#define HCIUARTSETPROTO          _IOW('U', 200, int)
+#define CUST_COMBO_WMT_DEV       "/dev/stpwmt"
+#define CUST_COMBO_STP_DEV       "/dev/ttyMT2"
+#define CUST_COMBO_PATCH_PATH    "/lib/firmware"
+#define CUST_COMBO_CFG_FILE      "/lib/firmware/WMT.cfg"
+
+#define CUST_BAUDRATE_DFT        (115200)
+#define CUST_MULTI_PATCH         (1)
+#define CUST_PATCH_SEARCH        (1)
+#define PATCH_BUILD_VER_LEN      (16)
+#define MAX_CMD_LEN              (NAME_MAX+1)
+
+#define LAUNCHER_DEBUG           (0)
+
+/******************************************************************************
+*                             D A T A   T Y P E S
+*******************************************************************************
+*/
+
+enum stp_modes {
+    STP_MIN = 0x0,
+    STP_UART_FULL = 0x1,
+    STP_UART_MAND = 0x2,
+    STP_BTIF_FULL = 0x3,
+    STP_SDIO = 0x4,
+    STP_MAX = 0x5,
+};
+
+enum stp_uart_fc {
+    UART_DISABLE_FC = 0, /*NO flow control*/
+    UART_MTK_SW_FC = 1,  /*MTK SW Flow Control, differs from Linux Flow Control*/
+    UART_LINUX_FC = 2,   /*Linux SW Flow Control*/
+    UART_HW_FC = 3,      /*HW Flow Control*/
+};
+
+struct sys_property {
+    const char *key;
+    const char *def_value;
+    char value[PROPERTY_VALUE_MAX];
+};
+
+
+struct stp_uart_config {
+    enum stp_uart_fc fc;
+    int parity;
+    int stop_bit;
+    int baud_rate;
+};
+
+struct stp_params_config {
+    enum stp_modes stp_mode;
+    int fm_mode;
+    char patch_path[NAME_MAX + 1];
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+    char patch_name[NAME_MAX + 1];
+#endif
+    char stp_dev[NAME_MAX + 1];
+    struct stp_uart_config uart_config;
+};
+
+
+#if CUST_MULTI_PATCH
+struct stp_patch_info {
+    int download_seq;
+    char address[4];
+    char patch_name[NAME_MAX + 1];
+};
+
+struct stp_rom_patch_info {
+    int type;
+    char address[4];
+    char patch_name[NAME_MAX + 1];
+};
+#endif
+
+struct chip_ant_mode_info {
+    const char *cfg_item;
+    char cfg_item_value[NAME_MAX + 1];
+};
+
+struct chip_mode_info {
+    int chip_id;
+    enum stp_modes stp_mode;
+    struct chip_ant_mode_info ant_mode;
+};
+
+#ifndef WMT_PLAT_APEX
+struct chip_mode_info g_chip_mode_info[] = {
+    {0x6620, STP_UART_FULL, {"mt6620.defAnt", "mt6620_ant_m3.cfg"}},
+    {0x6628, STP_UART_FULL, {"mt6628.defAnt", "mt6628_ant_m1.cfg"}},
+    {0x6630, STP_SDIO,      {"mt6630.defAnt", "mt6630_ant_m1.cfg"}},
+    {0x6632, STP_SDIO,      {"mt6632.defAnt", "mt6632_ant_m1.cfg"}},
+};
+#else
+struct chip_mode_info g_chip_mode_info[] = {
+    {0x6620, STP_UART_FULL, {"mt6620.defAnt", "WMT.cfg"}},
+    {0x6628, STP_UART_FULL, {"mt6628.defAnt", "WMT.cfg"}},
+    {0x6630, STP_SDIO,      {"mt6630.defAnt", "WMT.cfg"}},
+    {0x6632, STP_SDIO,      {"mt6632.defAnt", "WMT.cfg"}},
+};
+#endif
+
+struct fw_debug_infor {
+    int log_retry; /* for polling log property retry */
+    int dump_retry; /*for polling dump property retry */
+
+    int fw_log_ctrl; /* fw log output by emi ctrl */
+    int fw_dynamic_dump; /*fw coredump dynamic regin dump*/
+
+    /* fw log output by emi state ctrl */
+    char fw_log_state_orig[PROPERTY_VALUE_MAX];
+    char fw_log_state_new[PROPERTY_VALUE_MAX];
+
+    /* fw coredump dynamic regin dump state ctrl */
+    char fw_dump_state_orig[PROPERTY_VALUE_MAX];
+    char fw_dump_state_new[PROPERTY_VALUE_MAX];
+
+    unsigned int bitmap;
+};
+
+struct cmd_hdr{
+    char *cmd;
+    int (*hdr_func)(struct stp_params_config *configs);
+};
+
+struct speed_map {
+    unsigned int baud;
+    speed_t      speed;
+};
+
+/******************************************************************************
+*                   F U N C T I O N   D E C L A R A T I O N S
+*******************************************************************************
+*/
+static int cmd_hdr_baud_115k(struct stp_params_config *configs);
+static int cmd_hdr_baud_921k(struct stp_params_config *configs);
+static int cmd_hdr_baud_2kk(struct stp_params_config *configs);
+static int cmd_hdr_baud_2_5kk(struct stp_params_config *configs);
+static int cmd_hdr_baud_3kk(struct stp_params_config *configs);
+static int cmd_hdr_baud_3_5kk(struct stp_params_config *configs);
+static int cmd_hdr_baud_4kk(struct stp_params_config *configs);
+static int cmd_hdr_stp_open(struct stp_params_config *configs);
+static int cmd_hdr_stp_close(struct stp_params_config *configs);
+static int cmd_hdr_stp_rst(struct stp_params_config *configs);
+static int cmd_hdr_sch_patch(struct stp_params_config *configs);
+static int cmd_hdr_sch_rom_patch(struct stp_params_config *configs);
+
+
+/******************************************************************************
+*                            P U B L I C   D A T A
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                           P R I V A T E   D A T A
+*******************************************************************************
+*/
+static struct speed_map g_speeds[] = {
+    {115200,    B115200},
+    {921600,    B921600},
+    {1000000,    B1000000},
+    {1152000,    B1152000},
+    {2000000,    B2000000},
+    {2500000,    B2500000},
+    {3000000,    B3000000},
+    {3500000,    B3500000},
+    {4000000,    B4000000},
+};
+
+struct cmd_hdr g_cmd_hdr_table[] = {
+    { "baud_115200_0", cmd_hdr_baud_115k},
+    { "baud_921600_0", cmd_hdr_baud_921k},
+    { "baud_2000000_0", cmd_hdr_baud_2kk},
+    { "baud_2500000_0", cmd_hdr_baud_2_5kk},
+    { "baud_3000000_0", cmd_hdr_baud_3kk},
+    { "baud_3500000_0", cmd_hdr_baud_3_5kk},
+    { "baud_4000000_0", cmd_hdr_baud_4kk},
+    { "open_stp", cmd_hdr_stp_open},
+    { "close_stp", cmd_hdr_stp_close},
+    { "rst_stp", cmd_hdr_stp_rst},
+    { "srh_patch", cmd_hdr_sch_patch},
+    { "srh_rom_patch", cmd_hdr_sch_rom_patch},
+};
+
+static volatile sig_atomic_t __io_canceled = 0;
+static char g_wmt_cfg_name[NAME_MAX + 1] = {0};
+static int g_wmt_fd = -1;
+static int g_tty_fd = -1;
+static char g_cmd_str[MAX_CMD_LEN]= {0};
+static char g_resp_str[MAX_CMD_LEN]= {0};
+static struct stp_params_config g_stp_param_config;
+
+pthread_t g_thread_handle = -1;
+static struct fw_debug_infor g_fw_debug_infor;
+
+#if CUST_MULTI_PATCH
+static char g_patch_prefix[16];
+#endif
+/******************************************************************************
+*                              F U N C T I O N S
+*******************************************************************************
+*/
+
+/* TBD in platform-specific way */
+static int get_persist_chip_id(void) { return -1; }
+static int set_persist_chip_id(const int id) { return 0; }
+
+/* return 0 for not ready, otherwise ready */
+static int get_drv_rdy(void) {
+    /* GeK: no property to communicate with wmt_loader, and we need another way
+     * to check driver ready. Maybe query ioctl(COMBO_IOCTL_DO_MODULE_INIT) to
+     * WCN_COMBO_LOADER_DEV is a possible way for both android and non-android.
+     */
+    ALOGI("WARNING!!! Need a correct way to check driver ready!!!");
+    return 1;
+}
+
+static speed_t get_speed(int baud_rate) {
+    unsigned int idx;
+    for (idx = 0; idx < sizeof(g_speeds)/sizeof(g_speeds[0]); idx++) {
+        if (baud_rate == (int)g_speeds[idx].baud) {
+            return g_speeds[idx].speed;
+        }
+    }
+    return CBAUDEX;
+}
+
+static int set_speed(int fd, struct termios *ti, int speed) {
+    struct serial_struct ss;
+    int baudenum = get_speed(speed);
+
+    if (speed != CBAUDEX) {
+        /*printf("%s: standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum);*/
+        if ((ioctl(fd, TIOCGSERIAL, &ss)) < 0) {
+            ALOGE("%s: BAUD: error to get the serial_struct info:%s\n", __FUNCTION__, strerror(errno));
+            return -1;
+        }
+        ss.flags &= ~ASYNC_SPD_CUST;
+#if defined(SERIAL_STRUCT_EXT) /*modified in serial_struct.h*/
+        memset(ss.reserved, 0x00, sizeof(ss.reserved));
+#endif
+        ss.flags |= (1 << 13);    /*set UPFLOWLATENCY flat to tty, or serial_core will reset tty->low_latency to 0*/
+        /*set standard buadrate setting*/
+        if ((ioctl(fd, TIOCSSERIAL, &ss)) < 0) {
+            ALOGE("%s: BAUD: error to set serial_struct:%s\n", __FUNCTION__, strerror(errno));
+            return -2;
+        }
+        cfsetospeed(ti, baudenum);
+        cfsetispeed(ti, baudenum);
+        return tcsetattr(fd, TCSANOW, ti);
+    }
+    else {
+        ALOGE("%s: unsupported non-standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum);
+        return -3;
+    }
+}
+/* Used as host uart param setup callback */
+static int launcher_setup_uart_param(int com_port, struct stp_uart_config *uart_config)
+{
+    struct termios ti;
+    int  fd;
+
+    if (!uart_config) {
+        ALOGE("Invalid stpUartConfig");
+        return -2;
+    }
+
+    ALOGI("setup_uart_param %d %d\n", uart_config->baud_rate, uart_config->fc);
+
+    fd = com_port;
+    if (fd < 0) {
+        ALOGE("Invalid serial port");
+        return -2;
+    }
+
+    tcflush(fd, TCIOFLUSH);
+
+    if (tcgetattr(fd, &ti) < 0) {
+        ALOGE("Can't get port settings");
+        return -3;
+    }
+
+    cfmakeraw(&ti);
+
+    ALOGI("ti.c_cflag = 0x%08x\n", ti.c_cflag);
+    ti.c_cflag |= CLOCAL;
+    ALOGI("CLOCAL = 0x%x\n", CLOCAL);
+    ALOGI("(ori)ti.c_iflag = 0x%08x\n", ti.c_iflag);
+    ALOGI("(ori)ti.c_cflag = 0x%08x\n", ti.c_cflag);
+    ALOGI("stpuartconfig->fc= %d (0:none,sw,hw,linux)\n", uart_config->fc);
+
+    if (uart_config->fc == UART_DISABLE_FC) {
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    } else if (uart_config->fc == UART_MTK_SW_FC) {
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag |= 0x80000000;   /*MTK Software FC*/
+    } else if (uart_config->fc == UART_HW_FC) {
+        ti.c_cflag |= CRTSCTS;      /*RTS, CTS Enable*/
+        ti.c_iflag &= ~(0x80000000);
+    } else if (uart_config->fc == UART_LINUX_FC) {
+        ti.c_iflag |= (IXON | IXOFF | IXANY); /*Linux Software FC*/
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    }else {
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    }
+
+    ALOGI("c_c CRTSCTS = 0x%16x\n", CRTSCTS);
+    ALOGI("c_i IXON = 0x%08x\n", IXON);
+    ALOGI("c_i IXOFF = 0x%08x\n", IXOFF);
+    ALOGI("c_i IXANY = 0x%08x\n", IXANY);
+    ALOGI("(aft)ti.c_iflag = 0x%08x\n", ti.c_iflag);
+    ALOGI("(aft)ti.c_cflag = 0x%08x\n\n", ti.c_cflag);
+
+    if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+        ALOGE("Can't set port settings");
+        return -4;
+    }
+
+    /* Set baudrate */
+    if (set_speed(fd, &ti, uart_config->baud_rate) < 0) {
+        ALOGE("Can't set initial baud rate");
+        return -5;
+    }
+
+    tcflush(fd, TCIOFLUSH);
+
+    return 0;
+}
+static int cmd_hdr_baud_115k(struct stp_params_config *config)
+{
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 115200;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_921k(struct stp_params_config *config)
+{
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 921600;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_2kk(struct stp_params_config *config) {
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 2000000;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_2_5kk(struct stp_params_config *config)
+{
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 2500000;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_3kk(struct stp_params_config *config) {
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 3000000;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_3_5kk(struct stp_params_config *config) {
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 3500000;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_baud_4kk(struct stp_params_config *config) {
+    struct stp_uart_config *uart_configs = &config->uart_config;
+    uart_configs->baud_rate = 4000000;
+    return (g_tty_fd != -1) ? launcher_setup_uart_param(g_tty_fd, uart_configs) : -1;
+}
+
+static int cmd_hdr_stp_open(struct stp_params_config *config) {
+    int ld;
+
+    ALOGV("%p\n", config);
+    if ((STP_UART_FULL == g_stp_param_config.stp_mode) && (-1 == g_tty_fd)) {
+        g_tty_fd = open(g_stp_param_config.stp_dev, O_RDWR | O_NOCTTY);
+        if (g_tty_fd < 0) {
+            fprintf(stderr, "Can't open serial port %s\n", g_stp_param_config.stp_dev);
+            return -2;
+        }
+        ALOGI("real_tty(%s) opened(%d)\n", g_stp_param_config.stp_dev, g_tty_fd);
+
+        /* Set TTY to N_MTKSTP line discipline */
+        ld = N_MTKSTP;
+        if (ioctl(g_tty_fd, TIOCSETD, &ld) < 0) {
+            fprintf(stderr, "Can't set ldisc to N_MTKSTP\n");
+            return -3;
+        }
+
+         //printf("Set tty->low_latency\n");
+         if (ioctl(g_tty_fd, HCIUARTSETPROTO, 0) < 0) {
+            ALOGE("Can't set HCIUARTSETPROTO\n");
+            return -4;
+        }
+        return 0;
+    }
+    else {
+        fprintf(stderr, "stp_open fail: stp_mode(%d) real_tty_fd(%d) \n",
+                g_stp_param_config.stp_mode, g_tty_fd);
+        return -1;
+    }
+}
+
+static int cmd_hdr_stp_close(struct stp_params_config *config) {
+    int ld;
+
+    ALOGV("%p\n", config);
+    if ((STP_UART_FULL == g_stp_param_config.stp_mode) && (0 <= g_tty_fd)) {
+        /* Restore TTY line discipline */
+        ld = N_TTY;
+        if (ioctl(g_tty_fd, TIOCSETD, &ld) < 0) {
+            ALOGE("Can't restore line discipline");
+            return -2;
+        }
+
+        close(g_tty_fd);
+        g_tty_fd = -1;
+        return 0;
+    } else if (g_tty_fd == -1)
+        return 0;
+    else {
+        fprintf(stderr, "stp_close fail: stp_mode(%d) real_tty_fd(%d) \n", g_stp_param_config.stp_mode, g_tty_fd);
+        return -1;
+    }
+}
+
+static int cmd_hdr_stp_rst(struct stp_params_config *config) {
+    int ret = 0;
+    /*this step fail?*/
+    ret = cmd_hdr_stp_close(config);
+    /*here, launcher is close state*/
+    ret = cmd_hdr_stp_open(config);
+    return ret;
+}
+#if 0
+static void launcher_set_patch_version(int fd)
+{
+    int ret = 0;
+    struct sys_property patch_ver_prop;
+    int bytes;
+    char patch_build_ver[PATCH_BUILD_VER_LEN] = {0};
+
+    /*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */
+    bytes = read(fd, patch_build_ver, PATCH_BUILD_VER_LEN);
+    if (-1 == bytes)
+        ALOGE("read patch_build_ver failed!\n");
+
+    patch_build_ver[PATCH_BUILD_VER_LEN - 1] = '\0';
+
+    patch_ver_prop.key = WCN_COMBO_PATCH_BUILD_VER_PROP;
+    sprintf(patch_ver_prop.value, "%s", patch_build_ver);
+
+    ret = property_set(patch_ver_prop.key, patch_ver_prop.value);
+    if (0 != ret)
+        ALOGE("set property(%s) to %s failed,ret:%d, errno:%d\n",
+               patch_ver_prop.key, patch_ver_prop.value, ret, errno);
+    else
+        ALOGI("set property(%s) to %s succeed.\n",
+               patch_ver_prop.key, patch_ver_prop.value);
+}
+#endif
+
+#if CUST_MULTI_PATCH
+static int launcher_get_patch_prefix(int chip_id, char **patch_prefix) {
+    /* use malloc for alloc memory is better*/
+    int chip = chip_id;
+
+    if (!patch_prefix) {
+        ALOGE("invalid pointer\n");
+        return -1;
+    }
+
+    if ((0x0321 == chip) || (0x0335 == chip) || (0x0337 == chip)) {
+        chip = 0x6735;
+        ALOGI("for denali chipid convert\n");
+    }
+    if (0x0326 == chip) {
+        chip = 0x6755;
+        ALOGI("for jade chipid convert\n");
+    }
+    if (0x0279 == chip) {
+        chip = 0x6797;
+        ALOGI("for everest chipid convert\n");
+    }
+    if (0x0551 == chip) {
+        chip = 0x6757;
+        ALOGI("for olympus chipid convert\n");
+    }
+    if (0x0633 == chip) {
+        chip = 0x6570;
+        ALOGI("for rushmore chipid convert\n");
+    }
+    if (0x0690 == chip) {
+        chip = 0x6763;
+        ALOGI("for bianco chipid convert\n");
+    }
+    if (0x0507 == chip) {
+        chip = 0x6759;
+        ALOGI("for alaska chipid convert\n");
+    }
+    if (0x0699 == chip) {
+        chip = 0x6739;
+        ALOGI("for zion chipid convert\n");
+    }
+    if (0x0713 == chip) {
+        chip = 0x6775;
+        ALOGI("for cannon chipid convert\n");
+    }
+    if (0x0788 == chip) {
+        chip = 0x6771;
+        ALOGI("for sylvia chipid convert\n");
+    }
+
+    memset(g_patch_prefix, '\0', sizeof(g_patch_prefix));
+
+    switch (chip) {
+        case 0x6572:
+        case 0x6582:
+        case 0x6592:
+            strncpy(g_patch_prefix, "ROMv1", strlen("ROMv1"));
+        break;
+        case 0x8127:
+        case 0x6571:
+            strncpy(g_patch_prefix, "ROMv2", strlen("ROMv2"));
+        break;
+        case 0x6755:
+        case 0x6752:
+        case 0x8163:
+        case 0x7623:
+        case 0x6735:
+        case 0x6570:
+        case 0x6580:
+        case 0x6757:
+        case 0x6763:
+        case 0x6739:
+        case 0x8167:
+            strncpy(g_patch_prefix, "ROMv2_lm", strlen("ROMv2_lm"));
+        break;
+        case 0x6797:
+            strncpy(g_patch_prefix, "ROMv3", strlen("ROMv3"));
+        break;
+        case 0x6759:
+            strncpy(g_patch_prefix, "ROMv4", strlen("ROMv4"));
+        break;
+        case 0x6775:
+        case 0x6771:
+            strncpy(g_patch_prefix, "ROMv4_be", strlen("ROMv4_be"));
+        break;
+        case 0x6765:
+        case 0x3967:
+        case 0x6761:
+        case 0x8168:
+            strncpy(g_patch_prefix, "soc1_0", strlen("soc1_0"));
+        break;
+        case 0x8512:
+            strncpy(g_patch_prefix, "soc2_1", strlen("soc2_1"));
+        break;
+        default:
+            strncpy(g_patch_prefix, "mt", strlen("mt"));
+            sprintf(g_patch_prefix + strlen("mt"), "%04x", chip);
+        break;
+    }
+    strncat(g_patch_prefix, "_patch", strlen("_patch"));
+
+    ALOGI("patch name pre-fix:%s\n", g_patch_prefix);
+
+    *patch_prefix = g_patch_prefix;
+    return 0;
+}
+
+static int launcher_get_patch_version(int patch_fd, unsigned int *patch_ver)
+{
+    int bytes = -1;
+    int ret = 0;
+
+    bytes = read(patch_fd, ((char *)patch_ver) + 1, 1);
+    if (-1 == bytes) {
+        ALOGE("read patch_ver failed!\n");
+        ret = -1;
+    }
+    bytes = read(patch_fd, ((char *)patch_ver), 1);
+    if (-1 == bytes) {
+        ALOGE("read patch_ver failed!\n");
+        ret = -2;
+    }
+
+    return ret;
+}
+
+static int launcher_set_patch_info(int fd, char *patch_info, char *full_name, int is_first) {
+    int patch_num = -1;
+    int patch_seq = -1;
+    struct stp_patch_info pi;
+
+    if (!patch_info) {
+        ALOGE("invalid patch infor!\n");
+        return -1;
+    }
+    if (!full_name) {
+        ALOGE("invalid patch full name!\n");
+        return -2;
+    }
+
+    if (is_first) {
+        patch_num = (patch_info[0] & 0xF0) >> 4;
+        ALOGI("patch num = [%d]\n", patch_num);
+        ioctl(fd, WMT_IOCTL_SET_PATCH_NUM, patch_num);
+    }
+
+    patch_seq = (patch_info[0] & 0x0F);
+    ALOGI("patch seq = [%d]\n", patch_seq);
+    pi.download_seq = patch_seq;
+    memcpy(pi.address, patch_info, sizeof(pi.address));
+    pi.address[0] = 0x00;
+    strncpy(pi.patch_name, full_name, sizeof(pi.patch_name) - 1);
+    pi.patch_name[sizeof(pi.patch_name) - 1] = '\0';
+
+    ioctl(fd, WMT_IOCTL_SET_PATCH_INFO, &pi);
+
+    return 0;
+}
+
+static int cmd_hdr_sch_patch(struct stp_params_config *config) {
+    int chip_id = 0;
+    int fw_version = 0;
+    char *patch_prefix = NULL;
+    char patch_full_name[256] = {0};
+    char patchName[128] = {0};
+    unsigned int patch_ver = 0;
+    DIR *dir = NULL;
+    int patch_fd = -1;
+    int ret = 0;
+    int bytes;
+    char patch_info[8] = {0};
+    unsigned int is_first = 1;
+    struct dirent* dirent = NULL;
+    int flag;
+
+    if (g_wmt_fd <= 0) {
+        ALOGE("file descriptor is not valid\n");
+        return -1;
+    }
+    /*1. ioctl to get CHIP ID*/
+    chip_id = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 0);
+    if (launcher_get_patch_prefix(chip_id, &patch_prefix)) {
+        ALOGE("launcher_get_patch_prefix fail\n");
+        return -2;
+    }
+
+    /*2. ioctl to get FIRMWARE VERSION*/
+    if (chip_id == 0x6765 || chip_id == 0x3967 ||
+        chip_id == 0x6761 || chip_id == 0x8168 ||
+        chip_id == 0x8512) {
+#if 0
+        ip_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 3);
+        ALOGI("ip_version:0x%08x\n", ip_version);
+#else
+        fw_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 2);
+        ALOGI("fw_version:0x%04x\n", fw_version);
+#endif
+    } else {
+        fw_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 2);
+        ALOGI("fw_version:0x%04x\n", fw_version);
+    }
+    /*3. open directory patch located*/
+    strncpy(config->patch_path, CUST_COMBO_PATCH_PATH, strlen(CUST_COMBO_PATCH_PATH));
+    config->patch_path[strlen(CUST_COMBO_PATCH_PATH) + 1] = '\0';
+
+    dir = opendir(config->patch_path);
+    if (NULL == dir) {
+        ALOGE("patch path cannot be opened");
+        return -3;
+    }
+    while (NULL != (dirent = readdir(dir))) {
+        patch_ver = 0;
+        if (0 == (strncmp(dirent->d_name, patch_prefix, strlen(patch_prefix)))) {
+            /*4.1. search patch name begined with chip_name*/
+            strncpy(patch_full_name, config->patch_path, strlen(config->patch_path)+1);
+            /*robust, if input patch is /etc/firmwre/ no issue should be happened.*/
+            strncat(patch_full_name, "/", strlen("/"));
+            strncat(patch_full_name, dirent->d_name,
+                sizeof(patch_full_name) - strlen(patch_full_name) - 1);
+            patch_full_name[sizeof(patch_full_name) - 1] = '\0';
+            ALOGI("%s\n", patch_full_name);
+            strncpy (patchName, dirent->d_name, strlen(dirent->d_name)+1);
+            /*4.1. search patch name mt[CHIP ID]xxx.bin*/
+            if (0 <= (patch_fd = (open(patch_full_name, O_RDONLY)))) {
+#if 0
+                launcher_set_patch_version(patch_fd);
+#endif
+
+                if (-1 != lseek(patch_fd, 22, SEEK_SET)) {
+                    if (launcher_get_patch_version(patch_fd, &patch_ver)) {
+                        ALOGE("read patch_ver failed!\n");
+                        ret = -4;
+                        goto read_fail;
+                    }
+                    /*print hardware version information in patch*/
+                    ALOGI("fw Ver in patch: 0x%08x\n", patch_ver);
+                    if (chip_id == 0x6765 || chip_id == 0x3967 ||
+                        chip_id == 0x6761 || chip_id == 0x8168 ||
+                        chip_id == 0x8512)
+#if 0
+                        flag = patch_ver == ip_version ? 1 : 0;
+#else
+                        flag = (0 == ((patch_ver ^ fw_version) & 0x00ff)) ? 1 : 0;
+#endif
+                    else
+                        flag = (0 == ((patch_ver ^ fw_version) & 0x00ff)) ? 1 : 0;
+                    if (flag) {
+                        memset(patch_info, 0, sizeof(patch_info));
+                        bytes = read(patch_fd, patch_info, 4);
+                        if (-1 == bytes) {
+                            ret = -5;
+                            ALOGE("read patch_info failed!\n");
+                            goto read_fail;
+                        }
+                        patch_info[4] = '\0';
+                        ALOGI("read patch info:0x%02x,0x%02x,0x%02x,0x%02x\n",
+                               patch_info[0], patch_info[1], patch_info[2], patch_info[3]);
+                        if (launcher_set_patch_info(g_wmt_fd, patch_info, patchName, is_first)) {
+                            ALOGE("launcher_set_patch_info fail\n");
+                            ret = -6;
+                            goto read_fail;
+                        }
+                        is_first = 0;
+                    }
+                } else
+                    ALOGE("seek failed\n");
+read_fail:
+                close(patch_fd);
+                patch_fd = -1;
+            } else
+                ALOGE("open patch file(%s) failed\n", patchName);
+        }
+    }
+    /*5. return value*/
+    closedir(dir);
+    dir = NULL;
+
+    return ret;
+}
+
+static int launcher_get_rom_patch_prefix(int chip_id, char **patch_prefix) {
+    /* use malloc for alloc memory is better*/
+    int chip = chip_id;
+
+    if (!patch_prefix) {
+        ALOGE("invalid pointer\n");
+        return -1;
+    }
+
+    memset(g_patch_prefix, '\0', sizeof(g_patch_prefix));
+
+    switch (chip) {
+        case 0x6765:
+        case 0x3967:
+        case 0x6761:
+        case 0x8168:
+            strncpy(g_patch_prefix, "soc1_0", strlen("soc1_0"));
+        break;
+        case 0x8512:
+            strncpy(g_patch_prefix, "soc2_1", strlen("soc2_1"));
+        break;
+        case 0x6779:
+            strncpy(g_patch_prefix, "soc2_0", strlen("soc2_0"));
+        break;
+        default:
+            strncpy(g_patch_prefix, "soc1_0", strlen("soc1_0"));
+        break;
+
+    }
+    strncat(g_patch_prefix, "_ram", strlen("_ram"));
+
+    ALOGI("patch name pre-fix:%s\n", g_patch_prefix);
+
+    *patch_prefix = g_patch_prefix;
+
+    return 0;
+}
+
+static int launcher_set_rom_patch_info(int fd, char *patch_info, char *full_name) {
+    struct stp_rom_patch_info pi;
+    int iRet = 0;
+
+    if (!patch_info) {
+        ALOGE("invalid patch infor!\n");
+        return -1;
+    }
+    if (!full_name) {
+        ALOGE("invalid patch full name!\n");
+        return -2;
+    }
+
+    pi.type = patch_info[7];
+    ALOGI("rom patch type = [%d]\n", pi.type);
+    memcpy(pi.address, patch_info, sizeof(pi.address));
+    pi.address[0] = 0x00;
+    strncpy(pi.patch_name, full_name, sizeof(pi.patch_name) - 1);
+    pi.patch_name[sizeof(pi.patch_name) - 1] = '\0';
+
+    iRet = ioctl(fd, WMT_IOCTL_SET_ROM_PATCH_INFO, &pi);
+    if (iRet != 0) {
+        ALOGE("ioctl WMT_IOCTL_SET_ROM_PATCH_INFO error (0x%x)\n", iRet);
+        return -3;
+    }
+
+    return 0;
+}
+
+static int cmd_hdr_sch_rom_patch(struct stp_params_config *config) {
+    int chip_id = 0;
+#if 0
+    unsigned int ip_version = 0;
+#else
+    unsigned int fw_version = 0;
+#endif
+    char *patch_prefix = NULL;
+    char patch_full_name[256] = {0};
+    char patchName[128] = {0};
+    unsigned int patch_ver = 0;
+    DIR *dir = NULL;
+    int patch_fd = -1;
+    int ret = 0;
+    int bytes;
+    char patch_info[8] = {0};
+    struct dirent* dirent = NULL;
+
+    if (g_wmt_fd <= 0) {
+        ALOGE("file descriptor is not valid\n");
+        return -1;
+    }
+    /*1. ioctl to get CHIP ID*/
+    chip_id = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 0);
+    if (launcher_get_rom_patch_prefix(chip_id, &patch_prefix)) {
+        ALOGE("launcher_get_rom_patch_prefix fail\n");
+        return -2;
+    }
+
+    /*2. ioctl to get FIRMWARE VERSION*/
+#if 0
+    ip_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 3);
+    ALOGI("ip_version:0x%04x\n", ip_version);
+#else
+    fw_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 2);
+    ALOGI("fw_version:0x%04x\n", fw_version);
+#endif
+    /*3. open directory patch located*/
+    strncpy(config->patch_path, CUST_COMBO_PATCH_PATH, strlen(CUST_COMBO_PATCH_PATH));
+    config->patch_path[strlen(CUST_COMBO_PATCH_PATH) + 1] = '\0';
+
+    dir = opendir(config->patch_path);
+    if (NULL == dir) {
+        ALOGE("patch path cannot be opened");
+        return -3;
+    }
+    while (NULL != (dirent = readdir(dir))) {
+        patch_ver = 0;
+        if (0 == (strncmp(dirent->d_name, patch_prefix, strlen(patch_prefix)))) {
+            /*4.1. search patch name begined with chip_name*/
+            strncpy(patch_full_name, config->patch_path, strlen(config->patch_path)+1);
+            /*robust, if input patch is /etc/firmwre/ no issue should be happened.*/
+            strncat(patch_full_name, "/", strlen("/"));
+            strncat(patch_full_name, dirent->d_name,
+				sizeof(patch_full_name) - strlen(patch_full_name) - 1);
+            ALOGI("%s\n", patch_full_name);
+            strncpy(patchName, dirent->d_name, strlen(dirent->d_name)+1);
+            /*4.1. search patch name mt[CHIP ID]xxx.bin*/
+            if (0 <= (patch_fd = (open(patch_full_name, O_RDONLY)))) {
+                if (-1 != lseek(patch_fd, 22, SEEK_SET)) {
+                    if (launcher_get_patch_version(patch_fd, &patch_ver)) {
+                        ALOGE("read patch_ver failed!\n");
+                        ret = -4;
+                        goto read_fail;
+                    }
+                      /*print hardware version information in patch*/
+                    ALOGI("fw Ver in patch: 0x%04x\n", patch_ver);
+#if 0
+                    if (0 == ((patch_ver ^ ip_version) & 0xffffffff)) {
+#else
+                    if (0 == ((patch_ver ^ fw_version) & 0x00ff)) {
+#endif
+                        memset(patch_info, 0, sizeof(patch_info));
+                        bytes = read(patch_fd, patch_info, 8);
+                        if (-1 == bytes) {
+                            ret = -5;
+                            ALOGE("read patch_info failed!\n");
+                            goto read_fail;
+                        }
+                        if ((patch_info[3] & 0xF0) && (patch_info[7] >= 0 && patch_info[7] <= 5)) {
+                            ALOGI("patch info:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n",
+                                  patch_info[0], patch_info[1], patch_info[2], patch_info[3],
+                                  patch_info[4], patch_info[5], patch_info[6], patch_info[7]);
+                            if (launcher_set_rom_patch_info(g_wmt_fd, patch_info, patchName)) {
+                                ALOGE("launcher_set_rom_patch_info fail\n");
+                                ret = -6;
+                                goto read_fail;
+                            }
+                        }
+                    }
+                } else
+                    ALOGE("seek failed\n");
+read_fail:
+                close(patch_fd);
+                patch_fd = -1;
+            } else
+                ALOGE("open patch file(%s) failed\n", patchName);
+        }
+    }
+    /*5. return value*/
+    closedir(dir);
+    dir = NULL;
+
+    return ret;
+}
+#else
+static int cmd_hdr_sch_patch(struct stp_params_config *config) {
+    int chip_id = 0;
+    int fw_version = 0;
+    char chip_name[16] = {0};
+    char patch_full_name[256] = {0};
+    unsigned int patch_ver = 0;
+    DIR *dir = NULL;
+    int patch_fd = -1;
+    struct dirent* dirent = NULL;
+    int ret = -1;
+
+    if (g_wmt_fd <= 0) {
+        ALOGE("file descriptor is not valid\n");
+        return -1;
+    }
+
+    /*1. ioctl to get CHIP ID*/
+    chip_id = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 0);
+    strncpy(chip_name, "mt", strlen("mt")+1);
+    sprintf(chip_name + strlen(chip_name), "%04x", chip_id);
+    strncat(chip_name, "_patch", strlen("_patch"));
+    ALOGI("patch name pre-fix:%s\n", chip_name);
+
+    /*2. ioctl to get FIRMWARE VERSION*/
+    fw_version = ioctl(g_wmt_fd, WMT_IOCTL_GET_CHIP_INFO, 2);
+    ALOGI("fwVersion:0x%04x\n", fw_version);
+
+    /*3. open directory patch located*/
+    strncpy(config->patch_path, CUST_COMBO_PATCH_PATH, strlen(CUST_COMBO_PATCH_PATH));
+    config->patch_path[strlen(CUST_COMBO_PATCH_PATH) + 1] = '\0';
+
+    dir = opendir(config->patch_path);
+    if (NULL == dir) {
+        ALOGE("patch path cannot be opened");
+        ret = -2;
+        return ret;
+    }
+    while (NULL != (dirent = readdir(dir))) {
+        patch_ver = 0;
+        if (0 == (strncmp(dirent->d_name, chip_name, strlen(chip_name)))) {
+            /*4.1. search patch name begined with chipName*/
+            strncpy(patch_full_name, config->patch_path, strlen(config->patch_path)+1);
+            /*robust, if input patch is /etc/firmwre/ no issue should be happened.*/
+            strncat(patch_full_name, "/", strlen("/"));
+            strncat(patch_full_name, dirent->d_name, strlen(dirent->d_name));
+            ALOGI("%s\n", patch_full_name);
+            /*4.1. search patch name mt[CHIP ID]xxx.bin*/
+            if (0 < (patch_fd = (open(patch_full_name, O_RDONLY)))) {
+              /*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */
+                if (-1 != lseek(patch_fd, 22, SEEK_SET)) {
+                    read(patch_fd, ((char *)&patch_ver) + 1, 1);
+                    read(patch_fd, ((char *)&patch_ver), 1);
+                    /*print firmware version information in patch*/
+                    ALOGI("fw Ver in patch: 0x%04x\n", patch_ver);
+                    if (0 == ((patch_ver ^ fw_version) & 0x00ff)) {
+                        ioctl(g_wmt_fd, WMT_IOCTL_SET_PATCH_NAME, patch_full_name);
+                        ALOGI("fw Ver in patch matches with firmware version\n");
+                        ret = 0;
+                        close(patch_fd);
+                        break;
+                    }
+                } else
+                    ALOGE("seek failed\n");
+
+                close(patch_fd);
+                patch_fd = -1;
+            } else
+                ALOGE("open patch file(%s) failed\n", patch_full_name);
+        }
+    }
+    /*5. return value*/
+    closedir(dir);
+    dir = NULL;
+
+    return ret;
+}
+#endif
+/*
+ret 0: success
+ret 1: cmd not found
+ret -x: handler return value
+*/
+static int launcher_handle_cmd(struct stp_params_config *stp_param_config, char *cmd, int len) {
+    int ret = 1;
+    int i;
+    int cmd_len;
+
+    for (i = 0; i < (int)(sizeof(g_cmd_hdr_table)/sizeof(g_cmd_hdr_table[0])); ++i) {
+        cmd_len = (int)strlen(g_cmd_hdr_table[i].cmd);
+        if (!strncmp(g_cmd_hdr_table[i].cmd, cmd, (len < cmd_len) ? len : cmd_len)) {
+            ret = (*g_cmd_hdr_table[i].hdr_func)(stp_param_config);
+        }
+    }
+
+    return ret;
+}
+
+static void launcher_display_usage(void)
+{
+    unsigned int index = 0;
+
+    char * usage[] = {
+        "MTK WCN combo tool set, version 1.0-release",
+        "Usage: wmt_launcher [-m mode] -p patchfolderpath [-d uartdevicenode] [-b baudrate] [-c uartflowcontrol]",
+        "    -m (BT/GPS/FM common interface mode selection, optional)",
+        "        -1: UART mode (common interface: UART)",
+        "        -3: BTIF mode (common interface: BTIF)",
+        "        -4: SDIO mode (common interface: SDIO)",
+        "    -p (MTK WCN chip firmware patch location, must)",
+        "        -e.g. /system/etc/firmware",
+        "    -n (MTK WCN chip firmware patch name, option)",
+        "        -e.g. /system/etc/firmware/firmware/mt6628_patch_hdr.bin",
+        "    if UART mode is set, you need config baud rate and tty device:",
+        "    -b (Baudrate set when BT/GPS/FM runs under UART mode, no needed under SDIO mode)",
+        "        -115200/921600/2000000/2500000/3000000/3500000/4000000",
+        "    -d (UART device node, when under UART mode, no needed under SDIO mode)",
+        "        -e.g. /dev/ttyMT1, /dev/ttyMT2, /dev/ttyHS2, etc.",
+        "    -c (UART flowcontrol set)",
+        "        -0, no flowcontrol default value, please donot modify this parameter",
+        "e.g. wmt_launcher -m 3 -p /system/etc/firmware/",
+        "e.g. wmt_launcher -m 1 -n /system/etc/firmware/mt6628_patch_hdr.bin",
+        "e.g. wmt_launcher -m 4 -d /dev/ttyMT2 -b 4000000 -n /system/etc/firmware/mt6628_patch_hdr.bin",
+    };
+
+    for (index = 0; index < sizeof(usage) / sizeof(usage[0]); index++ )
+        ALOGI("%s\n", usage[index]);
+
+    exit(EXIT_FAILURE);
+}
+
+
+static int launcher_stp_param_valid_check(struct stp_params_config *stp_param_configs, enum wmt_chip_type chip_type)
+{
+    int ret = 0;
+
+    /*fix me, check condition should be more reasonable*/
+    if ('\0' == stp_param_configs->patch_path[0]) {
+        ALOGE("MCU patch path not config,use /system/etc/firmware\n");
+        strncpy(stp_param_configs->patch_path, "/system/etc/firmware", strlen("/system/etc/firmware"));
+        stp_param_configs->patch_path[strlen("/system/etc/firmware") + 1] = '\0';
+        ret = -1;
+    }
+
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+    if ('\0' == stp_param_configs->patch_name[0]) {
+        ALOGE("MCU patch path not config,you need config it yourself\n");
+        ret = -2;
+    }
+#endif
+    if (stp_param_configs->stp_mode != STP_SDIO &&
+        stp_param_configs->stp_mode != STP_UART_MAND &&
+        stp_param_configs->stp_mode != STP_UART_FULL &&
+        stp_param_configs->stp_mode != STP_BTIF_FULL) {
+        if (WMT_CHIP_TYPE_COMBO == chip_type) {
+            ALOGE("Stp Mode is not set, common interface use default: SDIO Mode");
+            stp_param_configs->stp_mode = STP_SDIO;
+        } else {
+            ALOGE("Stp Mode is not set, common interface use default: BTIF Mode");
+            stp_param_configs->stp_mode = STP_BTIF_FULL;
+        }
+        ret = -3;
+    }
+
+    if (stp_param_configs->stp_mode == STP_UART_MAND || stp_param_configs->stp_mode == STP_UART_FULL) {
+        ALOGI ("Common Interface: UART mode\n");
+        if ('\0' == stp_param_configs->stp_dev[0]) {
+            strncpy(stp_param_configs->stp_dev, CUST_COMBO_STP_DEV, strlen(CUST_COMBO_STP_DEV)+1);
+            ALOGI("no uart device input, use default: %s\n", stp_param_configs->stp_dev);
+            ret = -4;
+        }
+        if (stp_param_configs->uart_config.baud_rate < 0) {
+            /* FixMe:Chaozhong, add baudrate validation check */
+            stp_param_configs->uart_config.baud_rate = 4000000;
+            ALOGI("no baudrate input, use default: %d\n", stp_param_configs->uart_config.baud_rate);
+            ret = -5;
+        }
+    }
+    return ret;
+}
+
+static int launcher_parser_wmt_cfg(char *item)
+{
+    int index = 0;
+    int length = 0;
+    char *str = NULL;
+    char *key = NULL;
+    char *value = NULL;
+    int max_index  = sizeof (g_chip_mode_info) / sizeof (g_chip_mode_info[0]);
+
+    if (NULL == item) {
+        ALOGE("Warning:item is NULL\n");
+        return -1;
+    }
+    /*all item must be start with mt66xx*/
+    str = strstr(item, "m");
+    if (NULL == str) {
+        ALOGE("Warning:no string start with 'm' found in %s\n", item);
+        return -2;
+    }
+
+    for (index = 0; index < max_index; index++) {
+        key = (char*)g_chip_mode_info[index].ant_mode.cfg_item;
+
+        if (0 == strncasecmp(str, key, strlen(key))) {
+            str = strstr(str, "=");
+            if (NULL == str) {
+                ALOGE("Warning:no '=' found in %s\n", str);
+                return -3;
+            }
+            str = strstr(str, "m");
+            if (NULL == str) {
+                ALOGE("Warning:no 'm' found in %s\n", str);
+                return -4;
+            }
+
+            while (((*str) == ' ') || ((*str) == '\t') || ((*str) == '\n')) {
+                if (str >= item + strlen(item))
+                    break;
+                str++;
+            }
+            value = str;
+
+            while (((*str) != ' ') && ((*str) != '\t') && ((*str) != '\0') && ((*str) != '\n') && ((*str) != '\r')) {
+                if (str >= item + strlen(item))
+                    break;
+                str++;
+            }
+            *str = '\0';
+            length = sizeof(g_chip_mode_info[index].ant_mode.cfg_item_value);
+            strncpy(g_chip_mode_info[index].ant_mode.cfg_item_value, value, length - 1);
+            g_chip_mode_info[index].ant_mode.cfg_item_value[length - 1] = '\0';
+            ALOGI("Info:key:%s value:%s\n", key, g_chip_mode_info[index].ant_mode.cfg_item_value);
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static int launcher_get_wmt_cfg_infor(void)
+{
+    FILE * file = NULL;
+    int ret = -1;
+    char *str = NULL;
+    char line[NAME_MAX];
+
+    file = fopen(CUST_COMBO_CFG_FILE, "r");
+    if (NULL == file) {
+        ALOGE("%s cannot be opened, errno:%d\n", CUST_COMBO_CFG_FILE, errno);
+        return -2;
+    }
+    ret = 0;
+    do {
+        str = fgets(line, NAME_MAX, file);
+        if (NULL == str) {
+            ALOGI("NULL is returned, eighter EOF or error maybe found\n");
+            break;
+        }
+        launcher_parser_wmt_cfg(line);
+        memset(line, 0, NAME_MAX);
+
+    } while (str != NULL);
+
+    if (NULL != file) {
+        if (0 == fclose(file))
+            ALOGI("close %s succeed\n", CUST_COMBO_CFG_FILE);
+        else
+            ALOGI("close %s failed, errno:%d\n", CUST_COMBO_CFG_FILE, errno);
+    }
+    return ret;
+}
+
+
+static int launcher_get_chip_info_index(int chip_id)
+{
+    int index = -1;
+    int left = 0;
+    int middle = 0;
+    int right = sizeof (g_chip_mode_info) / sizeof (g_chip_mode_info[0]) - 1;
+
+    if ((chip_id < g_chip_mode_info[left].chip_id) || (chip_id > g_chip_mode_info[right].chip_id))
+        return index;
+
+    middle = (left + right) / 2;
+
+    while (left <= right) {
+        if (chip_id > g_chip_mode_info[middle].chip_id)
+            left = middle + 1;
+        else if (chip_id < g_chip_mode_info[middle].chip_id)
+            right = middle - 1;
+        else {
+            index = middle;
+            break;
+        }
+        middle = (left + right) / 2;
+    }
+
+    if (0 > index)
+        ALOGE("no supported chip_id found\n");
+    else
+        ALOGI("index:%d, chip_id:0x%x\n", index, g_chip_mode_info[index].chip_id);
+
+    return index;
+}
+
+static void launcher_combine_cfg_name(int chip_id, char *cfg_file_path)
+{
+    int index = -1;
+    int stp_mode = g_stp_param_config.stp_mode;
+
+    index = launcher_get_chip_info_index(chip_id);
+    if ((stp_mode <= STP_MIN) || (STP_SDIO < stp_mode)) {
+        ALOGI("STP Mode is not set, fetching default mode...\n");
+        if (0 <= index)
+            g_stp_param_config.stp_mode = g_chip_mode_info[index].stp_mode;
+        else
+            g_stp_param_config.stp_mode = -1;
+    }
+
+    if ((0 <= index) && (NULL != cfg_file_path)) {
+        memset(g_wmt_cfg_name, 0, sizeof(g_wmt_cfg_name));
+        strncpy(g_wmt_cfg_name, g_chip_mode_info[index].ant_mode.cfg_item_value, sizeof(g_wmt_cfg_name) - 1);
+        g_wmt_cfg_name[strlen(g_chip_mode_info[index].ant_mode.cfg_item_value)] = '\0';
+    } else
+        memset(g_wmt_cfg_name, 0, sizeof(g_wmt_cfg_name));
+
+    ALOGI("chip_id(0x%04x), default Mode(%d), strlen(g_wmt_cfg_name)(%zd), g_wmt_cfg_name(%s)\n",
+           chip_id, g_stp_param_config.stp_mode, strlen(g_wmt_cfg_name), g_wmt_cfg_name);
+
+}
+
+static void launcher_set_wmt_cfg_infor(int chip_id, char *cfg_file_path) {
+    if (!launcher_get_wmt_cfg_infor()) {
+        launcher_combine_cfg_name(chip_id, cfg_file_path);
+        /* send WMT config name configuration to driver */
+        ioctl(g_wmt_fd, WMT_IOCTL_WMT_CFG_NAME, g_wmt_cfg_name);
+    } else
+         ALOGE("launcher_get_wmt_cfg_infor fail\n");
+}
+
+static void launcher_set_uart_port_name(char *stp_dev) {
+    char *uart_name = NULL;
+
+    /* send uart name to driver*/
+    if (stp_dev) {
+        uart_name = strstr(stp_dev, "tty");
+        if (!uart_name)
+            ALOGE("no uart name found in %s\n", stp_dev);
+        else
+            ALOGI("uart name %s\n", uart_name);
+    }
+
+    if (!uart_name) {
+        uart_name = "ttyMT2";
+        ALOGI("use default uart %s\n", uart_name);
+    }
+
+    ioctl(g_wmt_fd, WMT_IOCTL_PORT_NAME, uart_name);
+}
+
+#if (MTK_COMBO_ENABLE_WIFI_IN_LAUNCHER==1)
+#define CUST_COMBO_WIFI_DEV "/dev/wmtWifi"
+#define POWER_ON_WIFI "1"
+#define POWER_ON_WIFI_LEN 1
+static int gWifiFd = -1;
+
+static int enable_wifi(void) {
+    int retryCounter = 0;
+    int i_ret = -1;
+
+    gWifiFd = open(CUST_COMBO_WIFI_DEV, O_RDWR | O_NOCTTY);
+    do {
+        if (gWifiFd < 0) {
+            ALOGI("Can't open device node(%s) error:%d \n", CUST_COMBO_WIFI_DEV, gWifiFd);
+            usleep(300000);
+            gWifiFd = open(CUST_COMBO_WIFI_DEV, O_RDWR | O_NOCTTY);
+        } else {
+           break;
+        }
+        retryCounter++;
+    } while (retryCounter < 20);
+
+    if (gWifiFd > 0) {
+        do {
+            i_ret = write(gWifiFd, POWER_ON_WIFI, POWER_ON_WIFI_LEN);
+            if (i_ret == 1) {
+                    ALOGI("Power on device node(%s) gWifiFd:%d succeed !!\n", CUST_COMBO_WIFI_DEV, gWifiFd);
+                    break;
+            } else {
+                   ALOGI("Power on device node(%s) gWifiFd:%d Fail (%d) and retry\n", CUST_COMBO_WIFI_DEV, gWifiFd, i_ret);
+            }
+            retryCounter++;
+            usleep(300000);
+        } while (retryCounter < 20);
+    }
+    close(gWifiFd);
+
+    return 0;
+}
+#endif /* MTK_COMBO_ENABLE_WIFI_IN_LAUNCHER */
+
+static void* launcher_pwr_on_thread(void * arg)
+{
+    int retry_counter = 0;
+    int ret = -1;
+    int chip_id = *(int*)arg;
+
+    pthread_setname_np(pthread_self(), "pwr_on_conn");
+
+    ALOGI("enter power on connsys flow\n");
+    do {
+        ret = ioctl(g_wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 1);
+        if (0 == ret)
+            break;
+        ioctl(g_wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 0);
+        ALOGI("power on %x failed, retrying, retry counter:%d\n", chip_id, retry_counter);
+        usleep(1000000);
+        retry_counter++;
+    } while (retry_counter < 20);
+
+#if (MTK_COMBO_ENABLE_WIFI_IN_LAUNCHER==1)
+			ALOGI("enter enable wifi");
+			enable_wifi();
+#endif /* MTK_COMBO_ENABLE_WIFI_IN_LAUNCHER */
+
+    pthread_detach(g_thread_handle);
+    g_thread_handle = -1;
+
+    return NULL;
+}
+
+static void launcher_pwr_on_chip(int *chip_id) {
+    if (pthread_create(&g_thread_handle, NULL, launcher_pwr_on_thread, chip_id)) {
+        ALOGE("create pwr on thread fail\n");
+    } else
+        ALOGI("create pwr on thread ok\n");
+}
+static void* launcher_set_fwdbg_thread(void * arg) {
+    int i_ret = -1;
+    int flag = *(int*)arg;
+
+    pthread_setname_np(pthread_self(), "dump_fwemi_log");
+    ALOGI("dump firmware dbg log from emi buffer ");
+    i_ret = ioctl(g_wmt_fd, WMT_IOCTL_FW_DBGLOG_CTRL, flag);
+    if (i_ret < 0) {
+        ALOGI("ioctl error: err msg: %s\n", strerror(errno));
+        pthread_detach(g_thread_handle);
+        g_thread_handle = -1;
+    }
+    return NULL;
+}
+
+static void sig_hup(int sig) {
+    fprintf(stderr, "sig_hup...(%d)\n", sig);
+}
+
+static void sig_term(int sig)
+{
+    fprintf(stderr, "sig_term...(%d)\n", sig);
+    __io_canceled = 1;
+    ioctl(g_wmt_fd, WMT_IOCTL_SET_LAUNCHER_KILL, 1);
+}
+
+static void launcher_set_signal_handler(void) {
+    struct sigaction sa;
+
+    /*set signal handler*/
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_flags   = SA_NOCLDSTOP;
+    sa.sa_handler = SIG_IGN;
+    sigaction(SIGCHLD, &sa, NULL);
+    sigaction(SIGPIPE, &sa, NULL);
+
+    sa.sa_handler = sig_term;
+    sigaction(SIGTERM, &sa, NULL);
+    sigaction(SIGINT,  &sa, NULL);
+
+    sa.sa_handler = sig_hup;
+    sigaction(SIGHUP, &sa, NULL);
+}
+
+static void launcher_check_driver_ready(void) {
+    int ret = -1;
+
+#if 0
+    struct sys_property sp;
+
+    sp.key = WCN_DRIVER_READY_PROP;
+    sp.def_value = NULL;
+
+    do {
+        ret = property_get(sp.key, sp.value, sp.def_value);
+        if (0 >= ret)
+            ALOGE("get property(%s) failed i_ret:%d\n", sp.key, ret);
+        else {
+            ALOGI("get property(%s) is %s\n", sp.key, sp.value);
+            if (!strcmp(sp.value, "yes"))
+                break;
+        }
+        usleep(300000);
+    } while (1);
+#endif
+
+    do {
+        ret = get_drv_rdy();
+        if (ret)
+            break;
+        usleep(300000);
+    } while (1);
+}
+
+static void launcher_open_wmt_device(void) {
+    do {
+        g_wmt_fd = open(CUST_COMBO_WMT_DEV, O_RDWR | O_NOCTTY);
+        if (g_wmt_fd < 0) {
+            ALOGE("Can't open device node(%s) error:%d \n", CUST_COMBO_WMT_DEV, g_wmt_fd);
+            usleep(300000);
+        } else
+            break;
+    }while(1);
+
+    ALOGI("open device node succeed.(Node:%s, fd:%d) \n", CUST_COMBO_WMT_DEV, g_wmt_fd);
+}
+
+static int launcher_query_chip_id(void) {
+    int chip_id = -1;
+    int ret = -1;
+
+    do {
+        chip_id = ioctl(g_wmt_fd, WMT_IOCTL_WMT_QUERY_CHIPID, NULL);
+        ALOGI("chip_id from kernel by ioctl:0x%04x\n", chip_id);
+        if (-1 != chip_id)
+            break;
+        usleep(300000);
+    }while(1);
+
+    ALOGI("chip_id:0x%04x\n", chip_id);
+
+    return chip_id;
+}
+
+static enum wmt_chip_type launcher_check_chip_type(int chip_id)
+{
+    enum wmt_chip_type chip_type = WMT_CHIP_TYPE_INVALID;
+
+    if (chip_id <= 0) {
+        ALOGE("invalid chip id(%d)\n", chip_id);
+        goto done;
+    }
+    if ((0x6620 == chip_id) || (0x6628 == chip_id) ||
+        (0x6630 == chip_id) || (0x6632 == chip_id))
+        chip_type = WMT_CHIP_TYPE_COMBO;
+    else
+        chip_type = WMT_CHIP_TYPE_SOC;
+done:
+    return chip_type;
+}
+static void launcher_init_stp_parameter(struct stp_params_config *stp_param_config, enum wmt_chip_type chip_type) {
+    stp_param_config->fm_mode = 2;
+
+    if (WMT_CHIP_TYPE_SOC == chip_type)
+        stp_param_config->stp_mode = STP_BTIF_FULL;
+    if (WMT_CHIP_TYPE_COMBO == chip_type) {
+        stp_param_config->stp_mode = STP_SDIO;
+        stp_param_config->uart_config.baud_rate = 4000000;
+        stp_param_config->uart_config.fc = UART_DISABLE_FC;
+        stp_param_config->uart_config.parity = 0;
+        stp_param_config->uart_config.stop_bit = 0;
+        memset(stp_param_config->stp_dev, '\0', sizeof(stp_param_config->stp_dev));
+    }
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+    memset(stp_param_config->patch_name, '\0', sizeof(stp_param_config->patch_name));
+#endif
+    memset(stp_param_config->patch_path, '\0', sizeof(stp_param_config->patch_path));
+}
+
+static void launcher_print_stp_parameter(struct stp_params_config *stp_param_config) {
+    ALOGI("fm mode:%d\n", stp_param_config->fm_mode);
+    ALOGI("stp mode:%d\n", stp_param_config->stp_mode);
+    ALOGI("patch path:%s\n", stp_param_config->patch_path);
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+    ALOGI("patch name:%d\n", stp_param_config->patch_name);
+#endif
+    if ((stp_param_config->stp_mode == STP_UART_FULL) ||
+        (stp_param_config->stp_mode == STP_UART_MAND)) {
+        ALOGI("stp uart dev:%s\n", stp_param_config->stp_dev);
+        ALOGI("stp uart baud rate:%d\n", stp_param_config->uart_config.baud_rate);
+        ALOGI("stp uart fc:%d\n", stp_param_config->uart_config.fc);
+        ALOGI("stp uart parity:%d\n", stp_param_config->uart_config.parity);
+        ALOGI("stp uart stop bit:%d\n", stp_param_config->uart_config.stop_bit);
+    }
+}
+/*
+ * -m: mode (SDIO/UART)
+ * -d: uart device node
+ * -b: baudrate
+ * -c: enable SW FC or not
+ * -p: patch folder path
+ * -n: patch file name (fullpath)
+ *
+ */
+static void launcher_set_parameter_to_driver(int argc, char *argv[], int chip_id)
+{
+    int opt;
+    static const char *op_string = "m:d:b:c:p:n:?";
+    enum wmt_chip_type chip_type;
+
+    chip_type = launcher_check_chip_type(chip_id);
+    if (chip_type == WMT_CHIP_TYPE_INVALID) {
+        ALOGE("unknow chip type, may be chid id is invalid\n");
+        chip_type = WMT_CHIP_TYPE_SOC;
+    }
+    launcher_init_stp_parameter(&g_stp_param_config, chip_type);
+
+    opt = getopt(argc, argv, op_string);
+    while (opt != -1) {
+        switch (opt) {
+            case 'm':
+                g_stp_param_config.stp_mode = atoi(optarg);
+            break;
+            case 'd':
+                strncpy(g_stp_param_config.stp_dev, optarg, strlen(optarg)+1);
+            break;
+            case 'b':
+                g_stp_param_config.uart_config.baud_rate = atoi(optarg);
+            break;
+            case 'c':
+                g_stp_param_config.uart_config.fc = atoi(optarg);
+            break;
+            case 'p':
+                strncpy(g_stp_param_config.patch_path, optarg, strlen(optarg)+1);
+                ALOGI("patch path:%s\n", g_stp_param_config.patch_path);
+            break;
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+            case 'n':
+                strncpy(g_stp_param_config.patch_name, optarg, strlen(optarg)+1);
+            break;
+#endif
+            case '?':
+            default:
+                launcher_display_usage();
+            break;
+        }
+        opt = getopt(argc, argv, op_string);
+    }
+
+#if LAUNCHER_DEBUG
+    ALOGI("argc = %d, optind= %d\n", argc, optind);
+    {
+        int i = 0;
+        for (i = 0; i < argc; i++)
+            ALOGI("arg[%d] = %s\n", i, argv[i]);
+    }
+#endif
+
+    if (0 != launcher_stp_param_valid_check(&g_stp_param_config, chip_type)) {
+        ALOGE("stp param is invalid, use default:\n");
+        launcher_print_stp_parameter(&g_stp_param_config);
+        ALOGE("if this default param is not correct,please see usage help:\n");
+        launcher_display_usage();
+    }
+    if (WMT_CHIP_TYPE_COMBO == chip_type) {
+        ioctl(g_wmt_fd, WMT_IOCTL_WMT_TELL_CHIPID, chip_id);
+        ALOGI("set chip_id(0x%x) to driver\n", chip_id);
+        launcher_set_wmt_cfg_infor(chip_id, &g_stp_param_config.patch_path[0]);
+        if ((g_stp_param_config.stp_mode == STP_UART_FULL) ||
+            (g_stp_param_config.stp_mode == STP_UART_MAND))
+            launcher_set_uart_port_name(&g_stp_param_config.stp_dev[0]);
+    }
+#if (!CUST_MULTI_PATCH && !CUST_PATCH_SEARCH)
+    /* send default patch file name path to driver */
+    ioctl(g_wmt_fd, WMT_IOCTL_SET_PATCH_NAME, g_stp_param_config.patch_name);
+#endif
+    /* send hardware interface configuration to driver */
+    ioctl(g_wmt_fd, WMT_IOCTL_SET_STP_MODE,
+          ((g_stp_param_config.uart_config.baud_rate & 0xFFFFFF) << 8) |
+          ((g_stp_param_config.fm_mode & 0x0F) << 4) |
+          (g_stp_param_config.stp_mode & 0x0F));
+
+    ioctl(g_wmt_fd, WMT_IOCTL_SET_LAUNCHER_KILL, 0);
+
+}
+
+#if 0
+static int launcher_get_fw_debug_orign_infor(int chip_id) {
+    int ret = -1;
+    enum wmt_chip_type chip_type;
+    char readyStr[PROPERTY_VALUE_MAX] = {0};
+
+    chip_type = launcher_check_chip_type(chip_id);
+
+    if (chip_type == WMT_CHIP_TYPE_SOC) {
+        g_fw_debug_infor.log_retry = 0;
+        g_fw_debug_infor.dump_retry = 0;
+        g_fw_debug_infor.fw_log_ctrl = 0;
+        g_fw_debug_infor.fw_dynamic_dump = 0;
+        g_fw_debug_infor.bitmap = 0;
+        memset(g_fw_debug_infor.fw_log_state_orig, '\0', sizeof(g_fw_debug_infor.fw_log_state_orig));
+        memset(g_fw_debug_infor.fw_log_state_new, '\0', sizeof(g_fw_debug_infor.fw_log_state_new));
+        memset(g_fw_debug_infor.fw_dump_state_orig, '\0', sizeof(g_fw_debug_infor.fw_dump_state_orig));
+        memset(g_fw_debug_infor.fw_dump_state_new, '\0', sizeof(g_fw_debug_infor.fw_dump_state_new));
+
+        ret = property_get(WCN_FW_DBG_LOG_PROP, g_fw_debug_infor.fw_log_state_orig, NULL);
+        if (0 > ret)
+            ALOGE("get property(%s) failed ret:%d\n", WCN_FW_DBG_LOG_PROP, ret);
+        else if (0 == ret)
+            ALOGI("(%s) is not supported\n", WCN_FW_DBG_LOG_PROP);
+        else
+            ALOGI("get property (%s) is %s\n", WCN_FW_DBG_LOG_PROP, g_fw_debug_infor.fw_log_state_orig);
+
+        ret = property_get(WCN_DYNAMIC_DUMP_PROP, g_fw_debug_infor.fw_dump_state_orig, NULL);
+        if (0 > ret)
+            ALOGE("get property(%s) failed ret:%d\n", WCN_DYNAMIC_DUMP_PROP, ret);
+        else if (0 == ret)
+            ALOGI("(%s) is not supported\n", WCN_DYNAMIC_DUMP_PROP);
+        else
+            ALOGI("get property (%s) is %s\n", WCN_DYNAMIC_DUMP_PROP, g_fw_debug_infor.fw_dump_state_orig);
+    }
+
+    /*meta tool may turn on wifi very early, this property is used to protect turn on wifi.*/
+    ret= property_get(WCN_FORMETA_READY_PROP, readyStr, NULL);
+    if ((0 >= ret) || (0 == strcmp(readyStr, "yes"))) {
+            ALOGI("get property(%s) failed iRet:%d or property is %s\n", WCN_FORMETA_READY_PROP, ret, readyStr);
+    }
+
+    sprintf(readyStr, "%s", "yes");
+    ret = property_set(WCN_FORMETA_READY_PROP, readyStr);
+    if (0 != ret) {
+            ALOGI("set property(%s) to %s failed iRet:%d\n", WCN_FORMETA_READY_PROP, readyStr, ret);
+    } else {
+            ALOGI("set property(%s) to %s succeed\n", WCN_FORMETA_READY_PROP, readyStr);
+    }
+
+    return 0;
+}
+
+static int launcher_set_fw_log_ctrl(void) {
+    int ret = -1;
+    int fw_debug_enable = 0;
+
+    if (g_fw_debug_infor.bitmap & 0x1) {
+        ALOGV("fw log ctrl flag has been set\n");
+        return 0;
+    }
+
+    if ((g_fw_debug_infor.fw_log_ctrl == 1) ||
+         (g_fw_debug_infor.log_retry > WCN_FW_DEBUG_CLRL_RETRY_LIMIT)) {
+        ALOGV("retry: %d\n", g_fw_debug_infor.log_retry);
+
+        if (!strcmp(g_fw_debug_infor.fw_log_state_new, "yes")) {
+            fw_debug_enable = 1;
+            if (pthread_create(&g_thread_handle, NULL, launcher_set_fwdbg_thread, &fw_debug_enable))
+                ALOGE("create enable firmware dbglog thread fail\n");
+        } else {
+            ret = ioctl(g_wmt_fd, WMT_IOCTL_FW_DBGLOG_CTRL, fw_debug_enable);
+            /* if do this jude,it will confuse user beacuse kernel return -1 */
+            /* if (ret < 0)*/
+            /*   ALOGE("ioctl error: err msg: %s\n", strerror(errno));*/
+        }
+        g_fw_debug_infor.bitmap |= (0x1 << 0);
+    } else if (g_fw_debug_infor.log_retry++ <= WCN_FW_DEBUG_CLRL_RETRY_LIMIT) {
+        ret = property_get(WCN_FW_DBG_LOG_PROP, g_fw_debug_infor.fw_log_state_new, NULL);
+        if (0 > ret)
+            ALOGE("get property(%s) failed ret:%d\n", WCN_FW_DBG_LOG_PROP, ret);
+        else if (0 == ret)
+            ALOGI("(%s) is not supported\n", WCN_FW_DBG_LOG_PROP);
+        else {
+            ALOGV("get property(%s) is %s\n", WCN_FW_DBG_LOG_PROP, g_fw_debug_infor.fw_log_state_new);
+            if (strcmp(g_fw_debug_infor.fw_log_state_new, g_fw_debug_infor.fw_log_state_orig))
+                g_fw_debug_infor.fw_log_ctrl = 1;
+        }
+    } else
+        ALOGV("retry finish\n");
+    return 0;
+}
+
+static int launcher_set_fw_dynamic_dump(void) {
+    int ret = -1;
+
+    if (g_fw_debug_infor.bitmap & (0x1 << 1)) {
+        ALOGV("fw dynamic ctrl flag has been set\n");
+        return 0;
+    }
+
+    if ((g_fw_debug_infor.fw_dynamic_dump == 1) ||
+         (g_fw_debug_infor.dump_retry > WCN_FW_DEBUG_CLRL_RETRY_LIMIT)) {
+        ALOGV("dump_retry: %d\n", g_fw_debug_infor.dump_retry);
+
+        if (g_fw_debug_infor.fw_dynamic_dump == 1) {
+        /* it is only meaningfull to do ioctl in this case*/
+            ret = ioctl(g_wmt_fd, WMT_IOCTL_DYNAMIC_DUMP_CTRL, g_fw_debug_infor.fw_dump_state_new);
+            ALOGV("%d, %zd,\n", PROPERTY_VALUE_MAX, strlen(g_fw_debug_infor.fw_dump_state_new));
+            if (ret < 0)
+                ALOGE("ioctl error: err msg: %s\n", strerror(errno));
+        }
+        g_fw_debug_infor.bitmap |= (0x1 << 1);
+    } else if (g_fw_debug_infor.dump_retry++ <= WCN_FW_DEBUG_CLRL_RETRY_LIMIT) {
+        ret = property_get(WCN_DYNAMIC_DUMP_PROP, g_fw_debug_infor.fw_dump_state_new, NULL);
+        if (0 > ret)
+            ALOGE("get property(%s) failed ret:%d\n", WCN_DYNAMIC_DUMP_PROP, ret);
+        else if (0 == ret)
+            ALOGI("(%s) is not supported\n", WCN_DYNAMIC_DUMP_PROP);
+        else {
+            ALOGV("get property(%s) is %s\n", WCN_DYNAMIC_DUMP_PROP, g_fw_debug_infor.fw_dump_state_new);
+            if (strcmp(g_fw_debug_infor.fw_dump_state_new, g_fw_debug_infor.fw_dump_state_orig))
+                g_fw_debug_infor.fw_dynamic_dump = 1;
+        }
+    } else
+        ALOGV("retry finish\n");
+
+    return 0;
+}
+
+static void launcher_set_fw_debug_infor(int chip_id) {
+    enum wmt_chip_type chip_type = WMT_CHIP_TYPE_INVALID;
+
+    chip_type = launcher_check_chip_type(chip_id);
+    if (chip_type == WMT_CHIP_TYPE_SOC) {
+        launcher_set_fw_log_ctrl();
+        launcher_set_fw_dynamic_dump();
+    }
+}
+#endif
+
+int main(int argc, char *argv[]) {
+    int ld, err;
+    struct pollfd fds[2];
+    int fd_num = 0;
+    int len = 0;
+    int chip_id = -1;
+
+    launcher_check_driver_ready();
+    launcher_open_wmt_device();
+    chip_id = launcher_query_chip_id();
+
+    launcher_set_parameter_to_driver(argc, argv, chip_id);
+
+    launcher_set_signal_handler();
+
+    //launcher_get_fw_debug_orign_infor(chip_id);
+
+    fds[0].fd = g_wmt_fd; /* stp_wmt fd */
+    fds[0].events = POLLIN | POLLRDNORM; /* wait read events */
+    ++fd_num;
+
+    launcher_pwr_on_chip(&chip_id);
+
+    while (!__io_canceled) {
+        //launcher_set_fw_debug_infor(chip_id);
+        fds[0].revents = 0;
+        err = poll(fds, fd_num, 2000);  /* 2 seconds */
+        if (err < 0) {
+            if (errno == EINTR)
+                continue;
+            else {
+                ALOGE("poll error:%d errno:%d, %s\n", err, errno, strerror(errno));
+                break;
+            }
+        } else if (!err)
+            continue;
+
+
+        if (fds[0].revents & POLLIN) {
+            if (g_wmt_fd < 0)
+                break;
+            memset(g_cmd_str, 0, sizeof(g_cmd_str));
+            len = read(g_wmt_fd, g_cmd_str, sizeof(g_cmd_str)-1);
+            if (len <= 0 || len >= (int)sizeof(g_cmd_str)) {
+                ALOGE("POLLIN(%d) but read fail:%d\n", g_wmt_fd, len);
+                continue;
+            }
+            g_cmd_str[len] = '\0';
+            /*ALOGI("rx_cmd_str:%s\n", g_cmd_str);*/
+            err = launcher_handle_cmd(&g_stp_param_config, g_cmd_str, len);
+            if (!err) {
+                /* ALOGI("handle_cmd(%s), respond ok \n", g_cmd_str); */
+                snprintf(g_resp_str, sizeof(g_resp_str), "ok");
+            } else {
+                if (err == 1)
+                    snprintf(g_resp_str, sizeof(g_resp_str), "cmd not found");
+                else
+                    snprintf(g_resp_str, sizeof(g_resp_str), "resp_%d", err);
+            }
+            ALOGI("cmd(%s) resp(%s)\n", g_cmd_str, g_resp_str);
+            len = write(g_wmt_fd, g_resp_str, strlen(g_resp_str));
+            if (len != (int)strlen(g_resp_str))
+                fprintf(stderr, "write resp(%d) fail: len(%d), errno(%d, %s)\n",
+                        g_wmt_fd, len, errno, (len == -1) ? strerror(errno) : "");
+        }
+    }
+
+    if (g_wmt_fd >= 0) {
+        close(g_wmt_fd);
+        g_wmt_fd = -1;
+    }
+
+    if (((g_stp_param_config.stp_mode == STP_UART_MAND) ||
+        (g_stp_param_config.stp_mode == STP_UART_FULL)) && g_tty_fd >= 0) {
+        /* Restore TTY line discipline */
+        ld = N_TTY;
+        if (ioctl(g_tty_fd, TIOCSETD, &ld) < 0) {
+            ALOGE("Can't restore line discipline");
+            exit(1);
+        }
+
+        close(g_tty_fd);
+        g_tty_fd = -1;
+    }
+
+    if (g_thread_handle != -1) {
+        pthread_detach(g_thread_handle);
+        g_thread_handle = -1;
+    }
+
+    return 0;
+}
+
diff --git a/src/connectivity/combo_tool/6631_combo_tool/src/yocto_wmt_concurrency.c b/src/connectivity/combo_tool/6631_combo_tool/src/yocto_wmt_concurrency.c
new file mode 100644
index 0000000..ac10520
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/src/yocto_wmt_concurrency.c
@@ -0,0 +1,381 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ * 
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ * 
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#define _GNU_SOURCE
+#include "wmt_ioctl.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+//#include <sys/endian.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <linux/serial.h> /* struct serial_struct  */
+#include <pthread.h>
+#include <sched.h>
+#define FIBER_STACK 8192
+
+pthread_mutex_t mutex;
+
+typedef enum DRV_INDEX
+{
+  DRV_BT = 0,
+  DRV_FM,  
+  DRV_GPS,
+  DRV_WIFI,
+  DRV_MAX,
+}ENUM_DRV_INDEX;
+
+typedef enum ARG_DRV_INDEX
+{
+  ARG_DRV_BT = 1 << DRV_BT,
+  ARG_DRV_FM = 1 << DRV_FM,  
+  ARG_DRV_GPS = 1 << DRV_GPS,
+  ARG_DRV_WIFI = 1 << DRV_WIFI,
+  ARG_DRV_ALL = ARG_DRV_BT + ARG_DRV_FM + ARG_DRV_GPS + ARG_DRV_WIFI,
+}ENUM_ARG_DRV_INDEX;
+
+#define is_bt_mask_on(a) ((a) & ARG_DRV_BT)
+#define is_fm_mask_on(a) ((a) & ARG_DRV_FM)
+#define is_gps_mask_on(a) ((a) & ARG_DRV_GPS)
+#define is_wifi_mask_on(a) ((a) & ARG_DRV_WIFI)
+
+#define QUICK_FUNC_ON_OFF_SUPPORT
+#ifdef QUICK_FUNC_ON_OFF_SUPPORT
+	#define MIN_INTERVAL 1
+#else 
+	#define MIN_FUNC_ON_TIME 4
+	#define MIN_FUNC_OFF_TIME 1
+	#define MIN_INTERVAL  MIN_FUNC_ON_TIME + MIN_FUNC_OFF_TIME
+#endif
+
+#define MAX_FUNC_ON_TIME 9
+#define MAX_FUNC_OFF_TIME 3
+#define MAX_INTERVAL  MAX_FUNC_ON_TIME + MAX_FUNC_OFF_TIME
+//enum bool {false = 0, true = !false};
+
+char *src_name[]={
+	"BT",  
+	"FM", 
+	"GPS", 
+	"WIFI",
+	"UNKNOWN DEVICE",
+	};
+
+static int g_wmt_fd = -1;
+static int g_reference = 0;
+static int g_count = 2;
+int g_on2off_interval = MAX_INTERVAL;
+int g_off2on_interval = MAX_INTERVAL;
+volatile int g_state[5] = {0};
+
+void dump_state(void)
+{
+	//printf("%s:++, pid =%d\n",  __FUNCTION__, getpid());
+	printf("%d: %s:g_state:[BT]%d, [FM]:%d, [GPS]:%d, [WIFI]:%d\n", getpid(),  __FUNCTION__, g_state[0], g_state[1], g_state[2], g_state[3]);
+	//printf("%s:--, pid =%d\n",  __FUNCTION__, getpid());
+}
+
+int read_reference(ENUM_DRV_INDEX index)
+{
+	volatile int flag = 0;
+	pthread_mutex_lock(&mutex);
+	if(index >= 4)
+	{
+		if(g_state[0] || g_state[1] || g_state[2] || g_state[3])
+		{
+			flag = 1;
+		}
+		else
+		{
+			flag = 0;
+		}
+	}
+	else
+	{
+		flag = g_state[index];
+	}
+	pthread_mutex_unlock(&mutex);
+	return flag;
+}
+
+void get_reference(ENUM_DRV_INDEX index)
+{
+	pthread_mutex_lock(&mutex);
+	g_reference++;
+	g_state[index] = 1;
+	dump_state();
+	pthread_mutex_unlock(&mutex);
+}
+
+
+void put_reference(ENUM_DRV_INDEX index)
+{
+	pthread_mutex_lock(&mutex);
+	g_reference--;
+	g_state[index] = 0;
+	dump_state();
+	pthread_mutex_unlock(&mutex);
+}
+
+int func_on_off(void * drv_index)
+{
+  ENUM_DRV_INDEX index = (ENUM_DRV_INDEX) drv_index;
+  int count = g_count;
+//  printf("%s:++, index =%d\n",  __FUNCTION__, index);
+  if(DRV_MAX > index && g_wmt_fd > 0)
+  {
+    while(count--)
+    {
+    	//turn on  src_name[index] function
+        if (0 == ioctl(g_wmt_fd, WMT_IOCTL_FUNC_ONOFF_CTRL, 0xBEEF0000 | index))
+    	{
+    		printf("pid:%d, turn on %s success.\n",   getpid(), src_name[index]);
+			//exit(0);
+    	}
+    	else
+    	{
+    		printf("pid:%d, turn on %s fail.\n",   getpid(), src_name[index]);
+    		exit(-1);
+    	}
+    	
+    	//printf("%s:-- pid: %d, finish turn on %s\n",  __FUNCTION__, getpid(), src_name[index]);
+    	/*
+    	//turn off  src_name[index] function
+    	*/
+    	sleep(g_on2off_interval);
+        if ( 0 == ioctl(g_wmt_fd, WMT_IOCTL_FUNC_ONOFF_CTRL, 0xDEAD0000 | index))
+    	{
+    		printf("pid:%d, turn off %s success.\n",   getpid(), src_name[index]);
+    		//exit(0);
+    	}
+    	else
+    	{
+    		printf("pid:%d, turn off %s fail.\n",   getpid(), src_name[index]);
+    		exit(-1);
+    	}
+    	printf("%d:%s test:left count = %d.\n",  getpid(), src_name[index], count);
+    	sleep(g_off2on_interval);
+    	
+    }
+  }
+  else
+  {
+  	printf("pid:%d, undnown device with index:%d.\n",  getpid(), index);
+  }
+ // printf("%s:--, index =%d\n",  __FUNCTION__, index);
+ //exit(-2);
+ //return;
+  exit(0);
+}
+
+
+static void sig_child_term(__attribute__((unused))int sig)
+{
+    printf("%s ++.\n", __FUNCTION__);
+    int pid = -1;
+    int stat;
+    while((pid = waitpid(0, &stat, WNOHANG)) != 0)
+    {
+    	printf("%s:pid = %d, exit event.\n", __FUNCTION__, pid);
+    }
+    printf("%s:pid = %d.\n", __FUNCTION__, pid);
+    printf("%s --.\n", __FUNCTION__);
+}
+
+int main(int argc, char *argv[])
+{
+	
+	int bitmask = ARG_DRV_ALL;
+	
+	int i = 0;
+	void *stack[8];
+	struct sigaction sa;
+	if(argc != 5)
+	{
+		printf("wmt_concurrency usage:\n\
+		wmt_concurrency looptimes  bitmask  on2offtime off2ontime\n\
+		  -looptimes	on<->off switch times (<1000000)\n\
+		  -bitmask\n\
+		    -1:BT on<->off test\n\
+		    -2:FM on<->off test\n\
+		    -4:GPS on<->off test\n\
+		    -8:WIFI on<->off test\n\
+		    -x: can be combination of the upper 4 bitmasks\n\
+		  -on2offtime	(0~12s)\n\
+		    -function on hold time before turn off\n\
+		  -off2ontime	(0~12s)\n\
+		    -function off hold time before turn on\n\
+		");
+		return -1;
+	}
+	if ((argc > 1) && (argv[1] != NULL)) {
+        
+        g_count = atoi(argv[1]);
+        printf("%s:argv[1] g_count param = %d\n",  __FUNCTION__, g_count);
+        if(g_count < 0)
+	    {
+	    	g_count = 2;
+	    }
+	   	g_count = g_count > 1000000 ? 1000000 : g_count;
+	    printf("%s:g_count = %d\n",  __FUNCTION__, g_count);
+    }
+    if ((argc > 2) && (argv[2] != NULL)) {
+        
+        bitmask = atoi(argv[2]);
+        printf("%s:argv[2] bitmask param = %d\n",  __FUNCTION__, bitmask);
+        if(bitmask <= 0 || bitmask > ARG_DRV_ALL)
+    	{
+    		bitmask = ARG_DRV_ALL;
+    	}
+    	printf("%s:bitmask = %d\n",  __FUNCTION__, bitmask);
+    }
+    
+    if ((argc > 3) && (argv[3] != NULL)) {
+        
+        g_on2off_interval = atoi(argv[3]);
+        printf("%s:argv[3] g_on2off_interval param = %d\n",  __FUNCTION__, g_on2off_interval);
+        if(g_on2off_interval < MIN_INTERVAL)
+    	{
+    		g_on2off_interval = MIN_INTERVAL;
+    	}
+    	if(g_on2off_interval > MAX_INTERVAL)
+    	{
+    		g_on2off_interval = MAX_INTERVAL;
+    	}
+		printf("%s:g_on2off_interval = %d\n",  __FUNCTION__, g_on2off_interval);
+    }
+    if ((argc > 4) && (argv[4] != NULL)) {
+        
+        g_off2on_interval = atoi(argv[4]);
+        printf("%s:argv[4] g_off2on_interval param = %d\n",  __FUNCTION__, g_off2on_interval);
+        if(g_off2on_interval < MIN_INTERVAL)
+    	{
+    		g_off2on_interval = MIN_INTERVAL;
+    	}
+    	if(g_off2on_interval > MAX_INTERVAL)
+    	{
+    		g_off2on_interval = MAX_INTERVAL;
+    	}
+		printf("%s:g_off2on_interval = %d\n",  __FUNCTION__, g_off2on_interval);
+    }
+    
+	for (i = sizeof(g_state)/sizeof(g_state[0]); i > 0; )
+	{
+		g_state[--i] = 0;
+	}
+
+	printf("pid = %d\n", getpid());
+	for(i = sizeof(stack)/sizeof(void *); i > 0; )
+	{
+		stack[--i] = malloc(FIBER_STACK);
+		if(stack[i] == NULL)
+		{
+			printf("pid = %d, malloc error\n", getpid());
+			goto out;
+		}
+	}
+
+    g_wmt_fd = open("/dev/stpwmt", O_RDWR | O_NOCTTY);	
+    printf("%s:argc = %d\n", __FUNCTION__,  argc);
+    
+    if(pthread_mutex_init(&mutex, NULL) != 0)
+    {
+    	printf("%s:pthread_mutex_init fail\n",  __FUNCTION__);
+    	goto out;	
+    }
+    if(g_wmt_fd > 0)
+    {
+    	memset(&sa, 0, sizeof(sa));
+    	//signal(SIGCHLD, sig_child_term);
+		sa.sa_handler = sig_child_term;
+		sa.sa_flags = SA_NOCLDSTOP;
+		sigaction(SIGCHLD, &sa, 0);
+    	int sleepCOunter = g_count;
+    	    	
+    		if(is_bt_mask_on(bitmask) && read_reference(DRV_BT) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[0] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_BT);
+    			//clone(&func_off, (char *)stack[4] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_BT);
+    		}
+    		
+    		if(is_wifi_mask_on(bitmask) && read_reference(DRV_WIFI) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[1] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_WIFI);
+    			//clone(&func_off, (char *)stack[5] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_WIFI);
+    		}	
+    		if(is_fm_mask_on(bitmask) && read_reference(DRV_FM) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[2] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_FM);
+    			//clone(&func_off, (char *)stack[6] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_FM);
+    		}
+    		if(is_gps_mask_on(bitmask) && read_reference(DRV_GPS) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[3] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_GPS);
+  				//clone(&func_off, (char *)stack[7] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_GPS);
+  			}
+    		//printf("%s:left g_count = %d.\n",  __FUNCTION__, g_count);
+    		sleep(sleepCOunter * (g_on2off_interval + g_off2on_interval));
+    }
+out:
+	
+	for(i = sizeof(stack)/sizeof(void *); i > 0; )
+	{
+		printf("%s:pid = %d, free stack information.\n",  __FUNCTION__, getpid());
+		if (NULL != stack[--i])
+		{
+			free(stack[i]);
+		}
+		stack[i] = NULL;
+	}
+    if(g_wmt_fd > 0)
+    {
+    	close(g_wmt_fd);
+    	g_wmt_fd  = -1;
+    }
+    printf("%s:pid = %d, exit.\n",  __FUNCTION__, getpid());
+    return 0;
+}
diff --git a/src/connectivity/combo_tool/6631_combo_tool/stp_dump-service b/src/connectivity/combo_tool/6631_combo_tool/stp_dump-service
new file mode 100644
index 0000000..95352b1
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/stp_dump-service
@@ -0,0 +1,64 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides: stp_dump
+# Required-Start:	$syslog $local_fs $remote_fs 
+# Required-Stop:	$syslog $local_fs $remote_fs 
+# Default-Start:	2 3 4 5
+# Default-Stop:		0 1 6
+# Short-Description: stp dump Daemon
+### END INIT INFO
+
+. /etc/init.d/init-functions
+prog=stp_dump
+PIDFILE=/var/run/$prog.pid
+DESC="stp dump Daemon"
+start() {
+	log_daemon_msg "Starting $DESC" "$prog"
+	start_daemon_background -p $PIDFILE /usr/bin/stp_dump3
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+	exit 0
+}
+
+stop() {
+	log_daemon_msg "Stopping $DESC" "$prog"
+	killproc -p $PIDFILE /usr/bin/stp_dump3
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+}
+
+force_reload() {
+	stop
+	start
+
+}
+
+case "$1" in
+	start)
+		start
+		;;
+	stop)
+		stop
+		;;
+	force-reload)
+		force_reload
+		;;
+	restart)
+		stop
+		start
+		;;
+
+	*)
+		echo "$Usage: $prog {start|stop|force-reload|restart}"
+		exit 2
+esac
diff --git a/src/connectivity/combo_tool/6631_combo_tool/stp_dump.service b/src/connectivity/combo_tool/6631_combo_tool/stp_dump.service
new file mode 100644
index 0000000..815bc2f
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/stp_dump.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=stp dump Daemon
+After=launcher.service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/stp_dump3
+
+[Install]
+Alias=stp_dump
+WantedBy=multi-user.target
diff --git a/src/connectivity/combo_tool/6631_combo_tool/wmtd-service b/src/connectivity/combo_tool/6631_combo_tool/wmtd-service
new file mode 100644
index 0000000..c369f41
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/wmtd-service
@@ -0,0 +1,64 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides: wmtd
+# Required-Start:	$syslog $local_fs $remote_fs $network 
+# Required-Stop:	$syslog $local_fs $remote_fs $network 
+# Default-Start:	2 3 4 5
+# Default-Stop:		0 1 6
+# Short-Description: WMT Daemon
+### END INIT INFO
+
+. /etc/init.d/init-functions
+prog=wmtd
+PIDFILE=/var/run/$prog.pid
+DESC="WMT Daemon"
+start() {
+	log_daemon_msg "Starting $DESC" "$prog"
+	start_daemon_background -p $PIDFILE /usr/bin/wmt_loader
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+	exit 0
+}
+
+stop() {
+	log_daemon_msg "Stopping $DESC" "$prog"
+	killproc -p $PIDFILE /usr/bin/wmt_loader
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+}
+
+force_reload() {
+	stop
+	start
+
+}
+
+case "$1" in
+	start)
+		start
+		;;
+	stop)
+		stop
+		;;
+	force-reload)
+		force_reload
+		;;
+	restart)
+		stop
+		start
+		;;
+
+	*)
+		echo "$Usage: $prog {start|stop|force-reload|restart}"
+		exit 2
+esac
diff --git a/src/connectivity/combo_tool/6631_combo_tool/wmtd.service b/src/connectivity/combo_tool/6631_combo_tool/wmtd.service
new file mode 100644
index 0000000..c801191
--- /dev/null
+++ b/src/connectivity/combo_tool/6631_combo_tool/wmtd.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=WMT Daemon
+After=network.target
+Requires=nvram_daemon.service
+After=nvram_daemon.service
+
+[Service]
+ExecStart=/usr/bin/wmt_loader > ttyS0
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+
+[Install]
+Alias=wmtd
+WantedBy=multi-user.target
diff --git a/src/connectivity/combo_tool/LICENSE b/src/connectivity/combo_tool/LICENSE
new file mode 100755
index 0000000..77f59ed
--- /dev/null
+++ b/src/connectivity/combo_tool/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:
+
+This software/firmware and related documentation ("MediaTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+the prior written permission of MediaTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MediaTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MediaTek Inc. (C) 2015. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
diff --git a/src/connectivity/combo_tool/Makefile.am b/src/connectivity/combo_tool/Makefile.am
new file mode 100755
index 0000000..e25d3b8
--- /dev/null
+++ b/src/connectivity/combo_tool/Makefile.am
@@ -0,0 +1,10 @@
+bin_PROGRAMS = wmt_loader 6620_launcher power_on_wifi wmt_loopback stp_dump
+wmt_loader_SOURCES = combo_loader/yocto_loader.c
+wmt_loopback_SOURCES = src/wmt_loopback.c
+6620_launcher_SOURCES = src/yocto_stp_uart_launcher.c
+6620_launcher_LDADD = -lpthread
+
+power_on_wifi_SOURCES = src/power_on_wifi.c
+stp_dump_SOURCES = src/stp_dump/os_linux.c \
+                   src/stp_dump/eloop.c \
+                   src/stp_dump/stp_dump.c
diff --git a/src/connectivity/combo_tool/README b/src/connectivity/combo_tool/README
new file mode 100755
index 0000000..d4b3313
--- /dev/null
+++ b/src/connectivity/combo_tool/README
@@ -0,0 +1,22 @@
+This module serves the common part driver of connectivity
+
+WHAT IT DOES?
+=============
+This module creates some executable binary files for loading/configuring/testing 
+the common part driver, in addition, it installs the Firmware patch and common part 
+cfg files into device.
+
+HOW IT WAS BUILT?
+==================
+It needs the following library from AOSP:
+
+libcutils, libc
+
+HOW TO USE IT?
+==============
+The firmware patch and common part cfg file was installed into device directly when build.
+And the executable binary files will be started in init.rc when boot. they will work together
+to load/configure the common part driver of connectivity
+
+The majority of source code was written by MediaTek. Some code from open source codes are used.
+more detail info, pls ref the NOTICE under the specific sub folder.
diff --git a/src/connectivity/combo_tool/cfg_folder/WMT.cfg b/src/connectivity/combo_tool/cfg_folder/WMT.cfg
new file mode 100755
index 0000000..cd214d8
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/WMT.cfg
@@ -0,0 +1,3 @@
+mt6620.defAnt=mt6620_ant_m3.cfg
+mt6628.defAnt=mt6628_ant_m1.cfg
+mt6630.defAnt=mt6630_ant_m1.cfg
\ No newline at end of file
diff --git a/src/connectivity/combo_tool/cfg_folder/WMT_SOC.cfg b/src/connectivity/combo_tool/cfg_folder/WMT_SOC.cfg
new file mode 100755
index 0000000..3a155ab
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/WMT_SOC.cfg
@@ -0,0 +1,9 @@
+coex_wmt_ant_mode=1
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+co_clock_flag=0
+
+
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m1.cfg b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m1.cfg
new file mode 100755
index 0000000..2557394
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m1.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=1
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xCE
+coex_wifi_rssi_mid_limit=0xBB
+coex_wifi_rssi_lower_limit=0xBB
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m2.cfg b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m2.cfg
new file mode 100755
index 0000000..1801583
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m2.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=2
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xCE
+coex_wifi_rssi_mid_limit=0xBB
+coex_wifi_rssi_lower_limit=0xBB
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m3.cfg b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m3.cfg
new file mode 100755
index 0000000..c019bae
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m3.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=3
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xD2
+coex_wifi_rssi_mid_limit=0xC8
+coex_wifi_rssi_lower_limit=0xBF
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m4.cfg b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m4.cfg
new file mode 100755
index 0000000..8788db8
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m4.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=4
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xD2
+coex_wifi_rssi_mid_limit=0xC8
+coex_wifi_rssi_lower_limit=0xBF
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m5.cfg b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m5.cfg
new file mode 100755
index 0000000..44eb8c8
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m5.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=5
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xD2
+coex_wifi_rssi_mid_limit=0xC8
+coex_wifi_rssi_lower_limit=0xBF
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m6.cfg b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m6.cfg
new file mode 100755
index 0000000..0f9372c
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m6.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=6
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xD2
+coex_wifi_rssi_mid_limit=0xC8
+coex_wifi_rssi_lower_limit=0xBF
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m7.cfg b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m7.cfg
new file mode 100755
index 0000000..8b7d601
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6620_ant_m7.cfg
@@ -0,0 +1,33 @@
+coex_wmt_ant_mode=7
+coex_wmt_wifi_time_ctl=0
+coex_wmt_ext_pta_dev_on=0
+
+coex_bt_rssi_upper_limit=0xD2
+coex_bt_rssi_mid_limit=0xC8
+coex_bt_rssi_lower_limit=0xBA
+coex_bt_pwr_high=0x5
+coex_bt_pwr_mid=0x5
+coex_bt_pwr_low=0x5
+
+coex_wifi_rssi_upper_limit=0xD2
+coex_wifi_rssi_mid_limit=0xC8
+coex_wifi_rssi_lower_limit=0xBF
+coex_wifi_pwr_high=0xA
+coex_wifi_pwr_mid=0xA
+coex_wifi_pwr_low=0xA
+
+coex_ext_pta_hi_tx_tag=6
+coex_ext_pta_hi_rx_tag=6
+coex_ext_pta_lo_tx_tag=12
+coex_ext_pta_lo_rx_tag=12
+coex_ext_pta_sample_t1=10
+coex_ext_pta_sample_t2=4
+coex_ext_pta_wifi_bt_con_trx=0x0
+
+coex_misc_ext_pta_on=0
+coex_misc_ext_feature_set=0xFFFFFFFF
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m1.cfg b/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m1.cfg
new file mode 100755
index 0000000..346233d
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m1.cfg
@@ -0,0 +1,8 @@
+coex_wmt_ant_mode=1
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m2.cfg b/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m2.cfg
new file mode 100755
index 0000000..dba5e25
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m2.cfg
@@ -0,0 +1,6 @@
+coex_wmt_ant_mode=2
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m3.cfg b/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m3.cfg
new file mode 100755
index 0000000..1459ed0
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m3.cfg
@@ -0,0 +1,6 @@
+coex_wmt_ant_mode=3
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m4.cfg b/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m4.cfg
new file mode 100755
index 0000000..b3011f3
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6628_ant_m4.cfg
@@ -0,0 +1,7 @@
+coex_wmt_ant_mode=4
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m1.cfg b/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m1.cfg
new file mode 100755
index 0000000..346233d
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m1.cfg
@@ -0,0 +1,8 @@
+coex_wmt_ant_mode=1
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+
+
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m2.cfg b/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m2.cfg
new file mode 100755
index 0000000..dba5e25
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m2.cfg
@@ -0,0 +1,6 @@
+coex_wmt_ant_mode=2
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m3.cfg b/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m3.cfg
new file mode 100755
index 0000000..1459ed0
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m3.cfg
@@ -0,0 +1,6 @@
+coex_wmt_ant_mode=3
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
diff --git a/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m4.cfg b/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m4.cfg
new file mode 100755
index 0000000..b3011f3
--- /dev/null
+++ b/src/connectivity/combo_tool/cfg_folder/mt6630_ant_m4.cfg
@@ -0,0 +1,7 @@
+coex_wmt_ant_mode=4
+
+wmt_gps_lna_pin=0
+wmt_gps_lna_enable=0
+
+sdio_driving_cfg=0x00077777
+
diff --git a/src/connectivity/combo_tool/combo_loader/Android.mk b/src/connectivity/combo_tool/combo_loader/Android.mk
new file mode 100755
index 0000000..d0f51a2
--- /dev/null
+++ b/src/connectivity/combo_tool/combo_loader/Android.mk
@@ -0,0 +1,101 @@
+# Copyright Statement:
+#
+# This software/firmware and related documentation ("MediaTek Software") are
+# protected under relevant copyright laws. The information contained herein
+# is confidential and proprietary to MediaTek Inc. and/or its licensors.
+# Without the prior written permission of MediaTek inc. and/or its licensors,
+# any reproduction, modification, use or disclosure of MediaTek Software,
+# and information contained herein, in whole or in part, shall be strictly prohibited.
+#
+# MediaTek Inc. (C) 2010. All rights reserved.
+#
+# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+#
+# The following software/firmware and/or related documentation ("MediaTek Software")
+# have been modified by MediaTek Inc. All revisions are subject to any receiver's
+# applicable license agreements with MediaTek Inc.
+
+
+# Copyright (C) 2008 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.
+
+# Configuration
+BUILD_LOADER  := false
+BUILD_MT6582_CONSYS := false
+LOCAL_PATH := $(call my-dir)
+
+ifneq ($(MTK_COMBO_CHIP), )
+BUILD_LOADER  := true
+endif
+
+ifneq ($(filter CONSYS_6572,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6582,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6592,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6735,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6755,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6797,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifeq ($(BUILD_LOADER), true)
+$(warning build loader)
+include $(CLEAR_VARS)
+
+ifeq ($(BUILD_MT6582_CONSYS), true)
+LOCAL_CFLAGS := -DMTK_SOC_CONSYS_SUPPORT
+endif
+
+
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_SRC_FILES  := loader.c \
+                    load_fm.c \
+                    load_wifi.c \
+                    load_ant.c \
+                    loader_pwr.c
+LOCAL_MODULE := wmt_loader
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+endif
diff --git a/src/connectivity/combo_tool/combo_loader/README b/src/connectivity/combo_tool/combo_loader/README
new file mode 100755
index 0000000..053fc8b
--- /dev/null
+++ b/src/connectivity/combo_tool/combo_loader/README
@@ -0,0 +1,19 @@
+This module serves the common part driver of connectivity
+
+WHAT IT DOES?
+=============
+This module creates one executable binary files for loading/initializing the common part driver including 
+wifi, fm, gps and BT if needed.
+
+HOW IT WAS BUILT?
+==================
+It needs the following library from AOSP:
+
+libcutils
+
+HOW TO USE IT?
+==============
+the executable binary files, wmt_loader, will be started in init.rc when boot. it will load/initialize
+to load the common part drivers(common part/wifi/fm/gps/BT) of connectivity
+
+The source code was written by MediaTek.
diff --git a/src/connectivity/combo_tool/combo_loader/load_ant.c b/src/connectivity/combo_tool/combo_loader/load_ant.c
new file mode 100755
index 0000000..53438be
--- /dev/null
+++ b/src/connectivity/combo_tool/combo_loader/load_ant.c
@@ -0,0 +1,105 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein is
+* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+* the prior written permission of MediaTek inc. and/or its licensors, any
+* reproduction, modification, use or disclosure of MediaTek Software, and
+* information contained herein, in whole or in part, shall be strictly
+* prohibited.
+*
+* MediaTek Inc. (C) 2014. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek
+* Software") have been modified by MediaTek Inc. All revisions are subject to
+* any receiver's applicable license agreements with MediaTek Inc.
+*/
+
+/*
+*ANT radio driver kernel module insmod file for wmt dynamic loader
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <cutils/misc.h>
+
+//For directory operation
+#include <dirent.h>
+
+#define ANT_MODULES_PATH "/system/lib/modules/mtk_stp_ant.ko"
+extern int load_ant_module(int chip_id);
+extern int init_module(void *, unsigned long, const char *);
+
+//insmod
+static int insmod(const char *filename, const char *args)
+{
+    void *module;
+    unsigned int size;
+    int ret = -1;
+	int retry = 10;
+
+	printf("filename(%s)\n",filename);
+
+    module = load_file(filename, &size);
+    if (!module)
+    {
+    	printf("load file fail\n");
+        return -1;
+    }
+
+	while(retry-- > 0){
+	    ret = init_module(module, size, args);
+
+		if(ret < 0)
+		{
+			printf("insmod module fail(%d)\n",ret);
+			usleep(10000);
+		}
+		else
+			break;
+
+	}
+
+    free(module);
+
+    return ret;
+}
+
+
+int load_ant_module(int chip_id)
+{
+	int ret = -1;
+	ret = insmod(ANT_MODULES_PATH, "");
+	if(ret)
+    {
+        printf("insert mtk_ant_drv.ko fail(%d)\n",ret);
+    }
+    else
+    {
+        printf("insert mtk_ant_drv.ko ok\n");
+    }
+    return ret;
+}
+
diff --git a/src/connectivity/combo_tool/combo_loader/load_fm.c b/src/connectivity/combo_tool/combo_loader/load_fm.c
new file mode 100755
index 0000000..cf5411b
--- /dev/null
+++ b/src/connectivity/combo_tool/combo_loader/load_fm.c
@@ -0,0 +1,67 @@
+/*
+*FM radio driver kernel module insmod file for wmt dynamic loader
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <cutils/misc.h>
+
+//For directory operation
+#include <dirent.h>
+
+#define FMR_MODULES_PATH "/system/lib/modules/mtk_fm_drv.ko"
+extern int load_fm_module(int chip_id);
+extern int init_module(void *, unsigned long, const char *);
+
+//insmod
+static int insmod(const char *filename, const char *args)
+{
+    void *module;
+    unsigned int size;
+    int ret = -1;
+	int retry = 10;
+
+	printf("filename(%s)\n",filename);
+
+    module = load_file(filename, &size);
+    if (!module)
+    {
+    	printf("load file fail\n");
+        return -1;
+    }
+
+	while(retry-- > 0){
+	    ret = init_module(module, size, args);
+
+		if(ret < 0)
+		{
+			printf("insmod module fail(%d)\n",ret);
+			usleep(10000);
+		}
+		else
+			break;
+
+	}
+
+    free(module);
+
+    return ret;
+}
+
+int load_fm_module(int chip_id)
+{
+    int ret=-1;
+    ret = insmod(FMR_MODULES_PATH, "");
+    if(ret)
+    {
+        printf("insert mtk_fm_drv.ko fail(%d)\n",ret);
+    }
+    else
+    {
+        printf("insert mtk_fm_drv.ko ok\n");
+    }
+    return ret;
+}
+
diff --git a/src/connectivity/combo_tool/combo_loader/load_wifi.c b/src/connectivity/combo_tool/combo_loader/load_wifi.c
new file mode 100755
index 0000000..ac040b2
--- /dev/null
+++ b/src/connectivity/combo_tool/combo_loader/load_wifi.c
@@ -0,0 +1,113 @@
+/*
+*WIFI driver kernel module insmod file for wmt dynamic loader
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <cutils/log.h>
+#include <cutils/misc.h>
+#include <linux/module.h>
+//For directory operation
+#include <dirent.h>
+
+extern int load_wifi_module(int chip_id);
+extern int init_module(void *, unsigned long, const char *);
+extern int delete_module(const char *, unsigned int);
+
+static char DRIVER_MODULE_PATH[50]  = "/system/lib/modules/wlan_";
+static char DRIVER_MODULE_ARG[50] = "";
+#ifndef WIFI_DRIVER_MODULE_ARG
+#define WIFI_DRIVER_MODULE_ARG          ""
+#endif
+
+//insmod
+static int insmod(const char *filename, const char *args)
+{
+    void *module;
+    unsigned int size;
+    int ret;
+
+    module = load_file(filename, &size);
+    if (!module)
+        return -1;
+
+    ret = init_module(module, size, args);
+
+    free(module);
+
+    return ret;
+}
+
+static int rmmod(const char *modname)
+{
+    int ret = -1;
+    int maxtry = 10;
+
+    while (maxtry-- > 0) {
+        ret = delete_module(modname, O_NONBLOCK | O_EXCL);
+        if (ret < 0 && errno == EAGAIN)
+            usleep(500000);
+        else
+            break;
+    }
+
+    if (ret != 0)
+        ALOGD("Unable to unload driver module \"%s\": %s\n",
+             modname, strerror(errno));
+    return ret;
+}
+
+int load_wifi_module(int chip_id)
+{
+    int ret=-1;
+    
+    if(chip_id == 0x6630){
+        //insert 6630 driver
+		if(0 == insmod("/system/lib/modules/mtk_wmt_wifi.ko", DRIVER_MODULE_ARG)){  
+            ret = 0;
+            printf("Success to insmod wmt wifi module\n");
+        }else
+            printf("Fail to insmod wmt wifi module\n");	
+
+        if(0 == insmod("/system/lib/modules/wlan_mt6630.ko", DRIVER_MODULE_ARG)){  
+            ret = 0;
+            printf("Success to insmod wlan module\n");
+        }else
+            printf("Fail to insmod wlan module\n");	 
+    }
+    else if(chip_id == 0x6628){
+        //insert 6628 driver
+        if(0 == insmod("/system/lib/modules/mtk_wmt_wifi.ko", DRIVER_MODULE_ARG)){  
+            ret = 0;
+            printf("Success to insmod wmt wifi module\n");
+        }else
+            printf("Fail to insmod wmt wifi module\n");	
+
+        if(0 == insmod("/system/lib/modules/wlan_mt6628.ko", DRIVER_MODULE_ARG)){  
+            ret = 0;
+            printf("Success to insmod wlan module\n");
+        }else
+            printf("Fail to insmod wlan module\n");	 
+    }
+    else if(chip_id == 0x6620){
+        //insert 6620 driver
+    }else { //for soc chip, same naming
+        //insert wmt_wifi => for temp naming
+        if(0 == insmod("/system/lib/modules/mtk_wmt_wifi_soc.ko", DRIVER_MODULE_ARG)){  
+            ret = 0;
+            printf("Success to insmod wmt wifi module\n");
+        }else
+            printf("Fail to insmod wmt wifi module\n");	    
+
+        //insert wifi => for temp naming
+        if(0 == insmod("/system/lib/modules/wlan_mt.ko", DRIVER_MODULE_ARG)){  
+            ret = 0;
+            printf("Success to insmod the %s\n", DRIVER_MODULE_PATH);
+        }else
+            printf("Fail to insmod the %s\n", DRIVER_MODULE_PATH);	    
+    }
+    return ret;
+}
diff --git a/src/connectivity/combo_tool/combo_loader/loader.c b/src/connectivity/combo_tool/combo_loader/loader.c
new file mode 100755
index 0000000..7b639e0
--- /dev/null
+++ b/src/connectivity/combo_tool/combo_loader/loader.c
@@ -0,0 +1,740 @@
+
+#include "loader.h"
+#include "loader_pwr.h"
+//#include <syslog.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Log.h>
+#include <string.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "wmt_loader"
+
+#define WCN_COMBO_LOADER_CHIP_ID_PROP    	"persist.mtk.wcn.combo.chipid"
+#define WCN_DRIVER_READY_PROP                    "service.wcn.driver.ready"
+#define WCN_COMBO_LOADER_DEV				"/dev/wmtdetect"
+#define WCN_COMBO_DEF_CHIPID				"0x6582"
+#define WMT_MODULES_PRE						"/system/lib/modules/"
+#define WMT_MODULES_SUFF					".ko"
+#define WMT_IOC_MAGIC        				'w'
+#define COMBO_IOCTL_GET_CHIP_ID       _IOR(WMT_IOC_MAGIC, 0, int)
+#define COMBO_IOCTL_SET_CHIP_ID       _IOW(WMT_IOC_MAGIC, 1, int)
+#define COMBO_IOCTL_EXT_CHIP_DETECT   _IOR(WMT_IOC_MAGIC, 2, int)
+#define COMBO_IOCTL_GET_SOC_CHIP_ID   _IOR(WMT_IOC_MAGIC, 3, int)
+#define COMBO_IOCTL_DO_MODULE_INIT    _IOR(WMT_IOC_MAGIC, 4, int)
+#define COMBO_IOCTL_MODULE_CLEANUP    _IOR(WMT_IOC_MAGIC, 5, int)
+#define COMBO_IOCTL_EXT_CHIP_PWR_ON   _IOR(WMT_IOC_MAGIC, 6, int)
+#define COMBO_IOCTL_EXT_CHIP_PWR_OFF  _IOR(WMT_IOC_MAGIC, 7, int)
+#define COMBO_IOCTL_DO_SDIO_AUDOK     _IOR(WMT_IOC_MAGIC, 8, int)
+
+
+
+#define STP_WMT_MODULE_PRE_FIX "mtk_stp_wmt"
+#define STP_BT_MODULE_PRE_FIX "mtk_stp_bt"
+#define STP_GPS_MODULE_PRE_FIX "mtk_stp_gps"
+#define HIF_SDIO_MODULE_PRE_FIX "mtk_hif_sdio"
+#define STP_SDIO_MODULE_PRE_FIX "mtk_stp_sdio"
+#define STP_UART_MODULE_PRE_FIX "mtk_stp_uart"
+
+
+
+static int gLoaderFd = -1;
+
+static char DRIVER_MODULE_PATH[64]  = {0};
+static char DRIVER_MODULE_ARG[8] = "";
+static int chipid_array[] = {
+0x6620,
+0x6628,
+0x6630,
+0x6572,
+0x6582,
+0x6592,
+0x8127,
+0x6571,
+0x6752,
+0x6735,
+0x0321,
+0x0335,
+0x0337,
+0x8163,
+0x6580,
+0x6755,
+0x0326,
+0x6797,
+0x0279
+};
+static char chip_version[PROPERTY_VALUE_MAX] = {0};
+
+static int g_remove_ko_flag = 1;
+
+
+extern int init_module(void *, unsigned long, const char *);
+extern int delete_module(const char *, unsigned int);
+extern int load_fm_module(int chip_id);
+extern int load_wifi_module(int chip_id);
+extern int load_ant_module(int chip_id);
+//insmod
+static int insmod(const char *filename, const char *args)
+{
+    void *module;
+    unsigned int size;
+    int ret = -1;
+	int retry = 10;
+
+	ALOGI("filename(%s)\n",filename);
+
+    module = load_file(filename, &size);
+    if (!module)
+    {
+    	ALOGI("load file fail\n");
+        return -1;
+    }
+
+	while(retry-- > 0){
+	    ret = init_module(module, size, args);
+
+		if(ret < 0)
+		{
+			ALOGI("insmod module fail(%d)\n",ret);
+			usleep(30000);
+		}
+		else
+			break;
+
+	}
+
+    free(module);
+
+    return ret;
+}
+static int is_chipId_vaild(int chipid)
+{
+	int iret;
+	unsigned char i;
+	iret = -1;
+	
+	for(i = 0;i < sizeof(chipid_array)/sizeof(0x6630); i++){
+		if(chipid == chipid_array[i]){
+			ALOGI("is_chipId_vaild: %d :0x%x!\n",i,chipid);
+			iret = 0;
+			break;
+		}
+	}
+	return iret;
+}
+static int rmmod(const char *modname)
+{
+    int ret = -1;
+    int maxtry = 10;
+
+    while (maxtry-- > 0) {
+        ret = delete_module(modname, O_EXCL);//O_NONBLOCK | O_EXCL);
+        if (ret < 0 && errno == EAGAIN)
+            usleep(500000);
+        else
+            break;
+    }
+
+    if (ret != 0)
+        ALOGI("Unable to unload driver module \"%s\": %s,ret(%d)\n",
+             modname, strerror(errno),ret);
+    return ret;
+}
+
+static int insmod_by_path (char *nameBuf, char * modulePath, char *preFix, char *postFix )
+{
+	int iRet = -1;
+	int len = 0;
+	int path_len = 0;
+
+	/*no need to check, upper layer API will makesure this condition fullfill*/
+	strcat (nameBuf, modulePath);
+	strcat (nameBuf, preFix);
+	strcat (nameBuf, postFix);
+	strcat (nameBuf, WMT_MODULES_SUFF);
+
+	insmod_retry:
+	iRet = insmod(nameBuf, DRIVER_MODULE_ARG);
+	if(iRet)
+	{
+		ALOGI("insert <%s> failed, len(%d), iret(%d), retrying\n", nameBuf, sizeof(nameBuf), iRet);
+		/*break;*/
+		usleep(800000);
+		goto insmod_retry;
+	}else
+	{
+		ALOGI("insert <%s> succeed,len(%d)\n", nameBuf, len);
+		iRet = 0;
+	}
+	return 0;
+}
+
+
+static int insert_wmt_module_for_soc(int chipid, char *modulePath, char *nameBuf, int nameBufLen)
+{
+	int iRet = -1;
+	int len = 0;
+	int path_len = 0;
+	int i = 0;
+	char postFixStr[10] = {0};
+	int totalLen = 0;
+	char *soc_modulse[] = {
+		STP_WMT_MODULE_PRE_FIX,
+		STP_BT_MODULE_PRE_FIX,
+		STP_GPS_MODULE_PRE_FIX,
+	};
+
+#if 0
+	path_len = strlen(modulePath);
+	strncpy(nameBuf, modulePath,path_len);
+	ALOGI("module subpath1(%s),sublen1(%d)\n",nameBuf,path_len);
+	len = path_len;
+#endif
+
+	sprintf(postFixStr, "_%s", "soc");
+
+#if 0
+	switch (chipid)
+	{
+		case 0x6572:
+		case 0x6582:
+			strcpy(postFixStr, "_6582");
+			break;
+		case 0x6571:
+			strcpy(postFixStr, "_6592");
+		case 0x6592:
+			strcpy(postFixStr, "_6592");
+			break;
+		default:
+
+			break;
+	}
+#endif
+
+	if (NULL == modulePath || NULL == nameBuf || 0 >= nameBufLen)
+	{
+		ALOGI("invalid parameter:modulePath(%p), nameBuf(%p), nameBufLen(%d)\n", modulePath, nameBuf, nameBufLen);
+		return iRet;
+	}
+
+	for(i = 0;i < sizeof(soc_modulse)/sizeof(soc_modulse[0]);i++)
+	{
+		totalLen = sizeof (modulePath) + sizeof (soc_modulse[i]) + sizeof(postFixStr) + sizeof(WMT_MODULES_SUFF);
+		if (nameBufLen > totalLen)
+		{
+
+			memset (nameBuf, 0, nameBufLen);
+			insmod_by_path(nameBuf, modulePath, soc_modulse[i], postFixStr);
+		}
+		else
+		{
+			ALOGI("nameBuf length(%d) too short, (%d) needed\n", nameBufLen, totalLen);
+		}
+#if 0
+		len = path_len;
+		len += sprintf(nameBuf + len,"%s",soc_modulse[i]);
+		ALOGI("module subpath2(%s),sublen2(%d)\n",nameBuf,len);
+
+		len += sprintf(nameBuf + len,"%s", postFixStr);
+		ALOGI("module subpath3(%s),sublen3(%d)\n",nameBuf,len);
+
+		len += sprintf(nameBuf + len,"%s",WMT_MODULES_SUFF);
+		ALOGI("module subpath4(%s),sublen4(%d)\n",nameBuf,len);
+
+		nameBuf[len] = '\0';
+		ALOGI("module subpath5(%s),sublen5(%d)\n",nameBuf,len);
+
+		soc_retry:
+		iRet = insmod(nameBuf, DRIVER_MODULE_ARG);
+		if(iRet)
+		{
+			ALOGI("(%d):current modules(%s) insert fail,len(%d),iret(%d), retrying\n", i, nameBuf, len, iRet);
+			/*break;*/
+			usleep(300000);
+			goto soc_retry;
+		}else
+		{
+			ALOGI("(%d):current modules(%s) insert ok,len(%d)\n", i, nameBuf, len);
+		}
+#endif
+
+	}
+
+
+
+	return 0;
+}
+
+static int insert_wmt_module_for_combo(int chipid, char *modulePath, char *nameBuf, int nameBufLen)
+{
+	int iRet = -1;
+	int len = 0;
+	int path_len = 0;
+	int i = 0;
+	char postFixStr[10] = {0};
+	int totalLen = 0;
+
+	char *combo_modulse[] = {
+		HIF_SDIO_MODULE_PRE_FIX,
+		STP_WMT_MODULE_PRE_FIX,
+		STP_UART_MODULE_PRE_FIX,
+		STP_SDIO_MODULE_PRE_FIX,
+		STP_BT_MODULE_PRE_FIX,
+		STP_GPS_MODULE_PRE_FIX
+	};
+
+	if (NULL == modulePath || NULL == nameBuf || 0 >= nameBufLen)
+	{
+		ALOGI("invalid parameter:modulePath(%p), nameBuf(%p), nameBufLen(%d)\n", modulePath, nameBuf, nameBufLen);
+		return iRet;
+	}
+
+#if 0
+	path_len = strlen(modulePath);
+	strncpy(nameBuf, modulePath,path_len);
+	ALOGI("module subpath1(%s),sublen1(%d)\n",nameBuf,path_len);
+
+	len = path_len;
+#endif
+
+	switch (chipid)
+	{
+		case 0x6620:
+		case 0x6628:
+			/*strcpy(postFixStr, "_6620_28");*/
+			strcpy(postFixStr, "");
+			break;
+		case 0x6630:
+			//strcpy(postFixStr, "_6630");
+			strcpy(postFixStr, "");
+			break;
+		default:
+
+			break;
+	}
+
+	for(i = 0;i < sizeof(combo_modulse)/sizeof(combo_modulse[0]);i++)
+	{
+		totalLen = sizeof (modulePath) + sizeof (combo_modulse[i]) + sizeof(postFixStr) + sizeof(WMT_MODULES_SUFF);
+		if (nameBufLen > totalLen)
+		{
+			memset (nameBuf, 0, nameBufLen);
+			insmod_by_path(nameBuf, modulePath, combo_modulse[i], postFixStr);
+		}
+		else
+		{
+			ALOGI("nameBuf length(%d) too short, (%d) needed\n", nameBufLen, totalLen);
+		}
+#if 0
+		len = path_len;
+		len += sprintf(nameBuf + len,"%s",combo_modulse[i]);
+		ALOGI("module subpath2(%s),sublen2(%d)\n",nameBuf,len);
+
+		len += sprintf(nameBuf + len,"%s",postFixStr);
+		ALOGI("module subpath3(%s),sublen3(%d)\n",nameBuf,len);
+
+		len += sprintf(nameBuf + len,"%s",WMT_MODULES_SUFF);
+		ALOGI("module subpath4(%s),sublen4(%d)\n",nameBuf,len);
+
+		nameBuf[len] = '\0';
+		ALOGI("module subpath5(%s),sublen5(%d)\n",nameBuf,len);
+
+		combo_retry:
+		iRet = insmod(nameBuf, DRIVER_MODULE_ARG);
+		if(iRet)
+		{
+			ALOGI("(%d):current modules(%s) insert fail,len(%d),iret(%d), retrying\n", i, nameBuf, len, iRet);
+			/*break;*/
+			usleep(300000);
+			goto combo_retry;
+		}else
+		{
+			ALOGI("(%d):current modules(%s) insert ok,len(%d)\n",i, nameBuf, len);
+		}
+#endif
+	}
+
+
+	return 0;
+}
+
+
+
+/******************************************************
+arg1:
+= 0:there is already a valid chipid in peroperty or there is no external combo chip
+	chipid is just 	MT6582
+> 0:there is no valid chipid in peroperty, boot system firstly
+
+arg2: // handle combo chip (there is an external combo chip)
+= 0:insert mtk_hif_sdio.ko for detech combo chipid
+> 0:insert combo modules except mtk_hif_sdio.ko
+******************************************************/
+
+static int insert_wmt_modules(int chipid,int arg1,int arg2)
+{
+	int iRet = -1;
+
+	switch (chipid)
+	{
+		case 0x6582:
+		case 0x6572:
+		case 0x6571:
+		case 0x6592:
+		case 0x8127:
+		case 0x6752:
+		case 0x6735:
+		case 0x8163:
+		case 0x6580:
+        case 0x6755:
+        case 0x6797:
+			iRet = insert_wmt_module_for_soc(chipid, WMT_MODULES_PRE, DRIVER_MODULE_PATH, sizeof (DRIVER_MODULE_PATH));
+			break;
+		case 0x6620:
+		case 0x6628:
+		case 0x6630:
+			iRet = insert_wmt_module_for_combo(chipid, WMT_MODULES_PRE, DRIVER_MODULE_PATH, sizeof (DRIVER_MODULE_PATH));
+			break;
+		default:
+			break;
+	}
+
+	return iRet;
+}
+
+int do_kernel_module_init(int gLoaderFd, int chipId)
+{
+	int iRet = 0;
+	if (gLoaderFd < 0)
+	{
+		ALOGI("invalid gLoaderFd: %d\n", gLoaderFd);
+		return -1;
+	}
+
+	iRet = ioctl (gLoaderFd, COMBO_IOCTL_MODULE_CLEANUP, chipId);
+	if (iRet)
+	{
+		ALOGI("do WMT-DETECT module cleanup failed: %d\n", iRet);
+		return -2;
+	}
+ 	iRet = ioctl (gLoaderFd, COMBO_IOCTL_DO_MODULE_INIT, chipId);
+	if (iRet)
+	{
+		ALOGI("do kernel module init failed: %d\n", iRet);
+		return -3;
+	}
+	ALOGI("do kernel module init succeed: %d\n", iRet);
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	int iRet = -1;
+	int noextChip = -1;
+	int chipId = -1;
+	int count = 0;
+	char chipidStr[PROPERTY_VALUE_MAX] = {0};
+        char readyStr[PROPERTY_VALUE_MAX] = {0};
+	int loadFmResult = -1;
+	int loadAntResult = -1;
+	int loadWlanResult = -1;
+	int retryCounter = 1;
+	int autokRet = 0;
+	do{
+		gLoaderFd = open(WCN_COMBO_LOADER_DEV, O_RDWR | O_NOCTTY);
+		if(gLoaderFd < 0)
+		{
+			count ++;
+			ALOGI("Can't open device node(%s) count(%d)\n", WCN_COMBO_LOADER_DEV,count);
+			usleep(300000);
+		}
+		else
+			break;
+	}while(1);
+
+	//read from system property
+	iRet = property_get(WCN_COMBO_LOADER_CHIP_ID_PROP, chipidStr, NULL);
+	chipId = strtoul(chipidStr, NULL, 16);
+
+	if ((0 != iRet) && (-1 != is_chipId_vaild(chipId)))
+	{
+		/*valid chipid detected*/
+		ALOGI("key:(%s)-value:(%s),chipId:0x%04x,iRet(%d)\n", WCN_COMBO_LOADER_CHIP_ID_PROP, chipidStr, chipId,iRet);
+		if (0x6630 == chipId)
+		{
+			retryCounter = 10;
+			/*trigger autok process, incase last autok process is interrupted by abnormal power off or battery down*/
+			do {
+				/*power on combo chip*/
+				iRet = ioctl(gLoaderFd,COMBO_IOCTL_EXT_CHIP_PWR_ON);
+				if (0 != iRet)
+				{
+					ALOGI("external combo chip power on failed\n");
+					noextChip = 1;
+				}
+				else
+				{
+					/*detect is there is an external combo chip*/
+					noextChip = ioctl(gLoaderFd,COMBO_IOCTL_EXT_CHIP_DETECT,NULL);
+				}
+
+				if(noextChip)
+				{
+					 // do nothing
+					 ALOGI("no external combo chip detected\n");
+				}
+				else
+				{
+					ALOGI("external combo chip detected\n");
+
+					chipId = ioctl(gLoaderFd, COMBO_IOCTL_GET_CHIP_ID, NULL);
+					ALOGI("chipid (0x%x) detected\n", chipId);
+				}
+
+
+				if(0 == noextChip)
+				{
+					autokRet = ioctl(gLoaderFd,COMBO_IOCTL_DO_SDIO_AUDOK,chipId);
+					if (0 != autokRet)
+					{
+						ALOGI("do SDIO3.0 autok failed\n");
+					}
+					else
+					{
+						ALOGI("do SDIO3.0 autok succeed\n");
+					}
+				}
+				iRet = ioctl(gLoaderFd,COMBO_IOCTL_EXT_CHIP_PWR_OFF);
+				if (0 != iRet)
+				{
+					ALOGI("external combo chip power off failed\n");
+				}
+				else
+				{
+					ALOGI("external combo chip power off succeed\n");
+				}
+				if ((0 == noextChip) && (-1 == chipId))
+				{
+					/*extenral chip detected, but no valid chipId detected, retry*/
+					retryCounter--;
+					ALOGI("chipId detect failed, retrying, left retryCounter:%d\n", retryCounter);
+					usleep(500000);
+				}
+				else
+					break;
+			}while (0 < retryCounter);
+			chipId = 0x6630;
+		}
+	}
+	else
+	{
+		/*trigger external combo chip detect and chip identification process*/
+		do {
+			/*power on combo chip*/
+			iRet = ioctl(gLoaderFd,COMBO_IOCTL_EXT_CHIP_PWR_ON);
+			if (0 != iRet)
+			{
+				ALOGI("external combo chip power on failed\n");
+				noextChip = 1;
+			}
+			else
+			{
+				/*detect is there is an external combo chip*/
+				noextChip = ioctl(gLoaderFd,COMBO_IOCTL_EXT_CHIP_DETECT,NULL);
+			}
+
+			if(noextChip)// use soc itself
+			{
+				ALOGI("no external combo chip detected, get current soc chipid\n");
+				chipId = ioctl(gLoaderFd, COMBO_IOCTL_GET_SOC_CHIP_ID, NULL);
+				ALOGI("soc chipid (0x%x) detected\n", chipId);
+			}
+			else
+			{
+				ALOGI("external combo chip detected\n");
+
+				chipId = ioctl(gLoaderFd, COMBO_IOCTL_GET_CHIP_ID, NULL);
+				ALOGI("chipid (0x%x) detected\n", chipId);
+			}
+
+			sprintf (chipidStr, "0x%04x", chipId);
+			iRet = property_set(WCN_COMBO_LOADER_CHIP_ID_PROP,chipidStr);
+			if (0 != iRet)
+			{
+				ALOGI("set property(%s) to %s failed,iRet:%d, errno:%d\n", WCN_COMBO_LOADER_CHIP_ID_PROP, chipidStr, iRet, errno);
+			}
+			else
+			{
+				ALOGI("set property(%s) to %s succeed.\n", WCN_COMBO_LOADER_CHIP_ID_PROP, chipidStr);
+			}
+			if(0 == noextChip)
+			{
+				autokRet = ioctl(gLoaderFd,COMBO_IOCTL_DO_SDIO_AUDOK,chipId);
+				if (0 != autokRet)
+				{
+					ALOGI("do SDIO3.0 autok failed\n");
+				}
+				else
+				{
+					ALOGI("do SDIO3.0 autok succeed\n");
+				}
+			}
+			iRet = ioctl(gLoaderFd,COMBO_IOCTL_EXT_CHIP_PWR_OFF);
+			if (0 != iRet)
+			{
+				ALOGI("external combo chip power off failed\n");
+			}
+			else
+			{
+				ALOGI("external combo chip power off succeed\n");
+			}
+			if ((0 == noextChip) && (-1 == chipId))
+			{
+			    /*extenral chip detected, but no valid chipId detected, retry*/
+			    retryCounter--;
+			    usleep(500000);
+			    ALOGI("chipId detect failed, retrying, left retryCounter:%d\n", retryCounter);
+			}
+			else
+			    break;
+		}while (0 < retryCounter);
+	}
+
+	/*set chipid to kernel*/
+	ioctl(gLoaderFd,COMBO_IOCTL_SET_CHIP_ID,chipId);
+
+	if (g_remove_ko_flag)
+	{
+		if((0x0321 == chipId) || (0x0335 == chipId) || (0x0337 == chipId))
+		{
+			chipId = 0x6735;
+		}
+        if (0x0326 == chipId) {
+            chipId = 0x6755;
+        }
+        if (0x0279 == chipId) {
+            chipId = 0x6797;
+        }
+		do_kernel_module_init(gLoaderFd, chipId);
+		if(gLoaderFd >= 0)
+		{
+			close(gLoaderFd);
+			gLoaderFd = -1;
+		}
+
+	}
+	else
+	{
+		if(gLoaderFd >= 0)
+		{
+			close(gLoaderFd);
+			gLoaderFd = -1;
+		}
+		ALOGI("rmmod mtk_wmt_detect\n");
+		rmmod("mtk_wmt_detect");
+
+		/*INSERT TARGET MODULE TO KERNEL*/
+
+		iRet = insert_wmt_modules(chipId, 0, -1);
+		/*this process should never fail*/
+		if(iRet)
+		{
+			ALOGI("insert wmt modules fail(%d):(%d)\n",iRet,__LINE__);
+			/*goto done;*/
+		}
+
+
+		loadFmResult = load_fm_module(chipId);
+		if(loadFmResult)
+		{
+			ALOGI("load FM modules fail(%d):(%d)\n",iRet,__LINE__);
+			/*continue, we cannot let this process interrupted by subsystem module load fail*/
+			/*goto done;*/
+		}
+
+		loadAntResult = load_ant_module(chipId);
+		if(loadAntResult)
+		{
+			ALOGI("load ANT modules fail(%d):(%d)\n",iRet,__LINE__);
+			/*continue, we cannot let this process interrupted by subsystem module load fail*/
+			/*goto done;*/
+		}
+
+		loadWlanResult = load_wifi_module(chipId);
+		if(loadWlanResult)
+		{
+			ALOGI("load WIFI modules fail(%d):(%d)\n",iRet,__LINE__);
+			/*continue, we cannot let this process interrupted by subsystem module load fail*/
+			/*goto done;*/
+		}
+	}
+
+
+
+	if((chown("/proc/driver/wmt_dbg",AID_SHELL,AID_SYSTEM) == -1) || (chown("/proc/driver/wmt_aee",AID_SHELL,AID_SYSTEM) == -1))
+	{
+		ALOGI("chown wmt_dbg or wmt_aee fail:%s\n",strerror(errno));
+	}
+
+	if(chown("/proc/wmt_tm/wmt_tm",0,1000) == -1)
+	{
+		ALOGI("chown wmt_tm fail:%s\n",strerror(errno));
+	}
+	if (0/*0x6630 == chipId*/)
+	{
+		retryCounter = 0;
+		int i_ret = -1;
+		do {
+			i_ret = loader_wmt_pwr_ctrl(1);
+			if (0 == i_ret)
+				break;
+			else
+			{
+				loader_wmt_pwr_ctrl(0);
+				ALOGI("power on %x failed, retrying, retry counter:%d\n", chipId, retryCounter);
+				usleep(1000000);
+			}
+			retryCounter++;
+		} while (retryCounter < 20);
+        }
+        iRet = property_get(WCN_DRIVER_READY_PROP, readyStr, NULL);
+        if ((0 >= iRet) || (0 == strcmp(readyStr, "yes"))) {
+                ALOGI("get property(%s) failed iRet:%d or property is %s\n", WCN_DRIVER_READY_PROP, iRet, readyStr);
+        }
+        /*set it to yes anyway*/
+        sprintf(readyStr, "%s", "yes");
+        iRet = property_set(WCN_DRIVER_READY_PROP, readyStr);
+        if (0 != iRet) {
+                ALOGI("set property(%s) to %s failed iRet:%d\n", WCN_DRIVER_READY_PROP, readyStr, iRet);
+        } else {
+                ALOGI("set property(%s) to %s succeed\n", WCN_DRIVER_READY_PROP, readyStr);
+	}
+#if 0
+	while (loadWlanResult || loadFmResult)
+	{
+		if(loadFmResult)
+		{
+			static int retryCounter = 0;
+			retryCounter++;
+			ALOGI("retry loading fm module, retryCounter:%d\n", retryCounter);
+			loadFmResult = load_fm_module(chipId);
+		}
+
+		if(loadWlanResult)
+		{
+			static int retryCounter = 0;
+			retryCounter++;
+			ALOGI("retry loading wlan module, retryCounter:%d\n", retryCounter);
+			loadWlanResult = load_wifi_module(chipId);
+		}
+		usleep(1000000);
+	}
+#endif
+
+	return iRet;
+}
+
+
+
diff --git a/src/connectivity/combo_tool/combo_loader/loader.h b/src/connectivity/combo_tool/combo_loader/loader.h
new file mode 100755
index 0000000..6c7afab
--- /dev/null
+++ b/src/connectivity/combo_tool/combo_loader/loader.h
@@ -0,0 +1,16 @@
+#ifndef __WMT_LOADER_H_
+#define __WMT_LOADER_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+//For directory operation
+#include <dirent.h>
+
+#include <cutils/properties.h>
+#include <cutils/misc.h>
+#include <sys/ioctl.h>
+
+#endif
diff --git a/src/connectivity/combo_tool/combo_loader/loader_pwr.c b/src/connectivity/combo_tool/combo_loader/loader_pwr.c
new file mode 100755
index 0000000..a1f5257
--- /dev/null
+++ b/src/connectivity/combo_tool/combo_loader/loader_pwr.c
@@ -0,0 +1,30 @@
+#include "../src/wmt_ioctl.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+int loader_wmt_pwr_ctrl(int on)
+{
+    int i_ret = -1;
+    int wmt_fd;
+    int para = (on == 0) ? 0 : 1;
+    /* open wmt dev */
+    wmt_fd = open("/dev/stpwmt", O_RDWR | O_NOCTTY);
+    if (wmt_fd < 0) {
+        printf("[%s] Can't open stpwmt \n", __FUNCTION__);
+        return -1;
+    }
+    if(ioctl(wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, para) != 0)
+    {
+        printf("[%s] power on combo chip failed\n", __FUNCTION__);
+        i_ret = -2;
+    } else {
+        printf("[power %s combo chip ok!]\n", para == 0 ? "off" : "on");
+        i_ret = 0;
+    }
+    close(wmt_fd);
+    wmt_fd = -1;
+    
+    return i_ret;
+}
\ No newline at end of file
diff --git a/src/connectivity/combo_tool/combo_loader/loader_pwr.h b/src/connectivity/combo_tool/combo_loader/loader_pwr.h
new file mode 100755
index 0000000..bfe370d
--- /dev/null
+++ b/src/connectivity/combo_tool/combo_loader/loader_pwr.h
@@ -0,0 +1,4 @@
+#ifndef __WMT_LOADER_PWR_H_
+#define __WMT_LOADER_PWR_H_
+int loader_wmt_pwr_ctrl(int on);
+#endif /*__WMT_LOADER_PWR_H_*/
\ No newline at end of file
diff --git a/src/connectivity/combo_tool/combo_loader/yocto_loader.c b/src/connectivity/combo_tool/combo_loader/yocto_loader.c
new file mode 100755
index 0000000..34256a4
--- /dev/null
+++ b/src/connectivity/combo_tool/combo_loader/yocto_loader.c
@@ -0,0 +1,460 @@
+#include "loader_pwr.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+// For directory operation
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "wmt_loader"
+
+#define WCN_COMBO_LOADER_CHIP_ID_PROP    "persist.mtk.wcn.combo.chipid"
+#ifndef ALOGI
+#define ALOGI printf
+#endif
+#ifndef PROPERTY_VALUE_MAX
+#define PROPERTY_VALUE_MAX (128)
+#endif
+
+#define WCN_COMBO_LOADER_DEV    "/dev/wmtdetect"
+#define WCN_COMBO_DEF_CHIPID    "0x6582"
+#define WMT_MODULES_PRE         "/system/lib/modules/"
+#define WMT_KO_PATH_PREFIX      "/lib/modules/"
+#define WMT_WIFI_MODULE_PATH    "/kernel/drivers/misc/mediatek/connectivity/wlan/wmt_chrdev_wifi.ko"
+#define WMT_WLAN_MODULE_PATH    "/kernel/drivers/misc/mediatek/connectivity/wlan/gen3/wlan_gen3.ko"
+/* connectivity modules are built out of kernel tree */
+#define WMT_OUT_KO_PATH_PREFIX          "/lib/modules/mt66xx/"
+#define WMT_OUT_WMT_WIFI_MODULE_PATH    "wmt_chrdev_wifi.ko"
+#define WMT_OUT_WLAN_MODULE_PATH        "wlan_drv_gen3.ko"
+
+#define WMT_MODULES_SUFF        ".ko"
+#define WMT_IOC_MAGIC           'w'
+#define COMBO_IOCTL_GET_CHIP_ID       _IOR(WMT_IOC_MAGIC, 0, int)
+#define COMBO_IOCTL_SET_CHIP_ID       _IOW(WMT_IOC_MAGIC, 1, int)
+#define COMBO_IOCTL_EXT_CHIP_DETECT   _IOR(WMT_IOC_MAGIC, 2, int)
+#define COMBO_IOCTL_GET_SOC_CHIP_ID   _IOR(WMT_IOC_MAGIC, 3, int)
+#define COMBO_IOCTL_DO_MODULE_INIT    _IOR(WMT_IOC_MAGIC, 4, int)
+#define COMBO_IOCTL_MODULE_CLEANUP    _IOR(WMT_IOC_MAGIC, 5, int)
+#define COMBO_IOCTL_EXT_CHIP_PWR_ON   _IOR(WMT_IOC_MAGIC, 6, int)
+#define COMBO_IOCTL_EXT_CHIP_PWR_OFF  _IOR(WMT_IOC_MAGIC, 7, int)
+#define COMBO_IOCTL_DO_SDIO_AUDOK     _IOR(WMT_IOC_MAGIC, 8, int)
+
+
+
+#define STP_WMT_MODULE_PRE_FIX "mtk_stp_wmt"
+#define STP_BT_MODULE_PRE_FIX "mtk_stp_bt"
+#define STP_GPS_MODULE_PRE_FIX "mtk_stp_gps"
+#define HIF_SDIO_MODULE_PRE_FIX "mtk_hif_sdio"
+#define STP_SDIO_MODULE_PRE_FIX "mtk_stp_sdio"
+#define STP_UART_MODULE_PRE_FIX "mtk_stp_uart"
+
+
+
+static int gLoaderFd = -1;
+
+static char DRIVER_MODULE_PATH[64]  = {0};
+static char DRIVER_MODULE_ARG[8] = "";
+static int chipid_array[] = {
+0x6620,
+0x6628,
+0x6630,
+0x6572,
+0x6582,
+0x6592,
+0x8127,
+0x6571,
+0x6752,
+0x6735,
+0x0321,
+0x0335,
+0x0337,
+0x8163,
+0x6580,
+0x6755,
+0x0326,
+0x6797,
+0x0279
+};
+static char chip_version[PROPERTY_VALUE_MAX] = {0};
+
+static int g_remove_ko_flag = 1;
+
+
+extern int init_module(void *, unsigned long, const char *);
+extern int delete_module(const char *, unsigned int);
+extern int load_fm_module(int chip_id);
+//extern int load_wifi_module(int chip_id);
+extern int load_ant_module(int chip_id);
+// insmod
+static int is_chipId_vaild(int chipid) {
+        int iret;
+        unsigned char i;
+        iret = -1;
+
+        for (i = 0; i < sizeof(chipid_array)/sizeof(0x6630); i++) {
+                 if (chipid == chipid_array[i]) {
+                        ALOGI("is_chipId_vaild: %d :0x%x!\n", i, chipid);
+                        iret = 0;
+                        break;
+                 }
+        }
+        return iret;
+}
+
+int do_kernel_module_init(int gLoaderFd, int chipId) {
+        int iRet = 0;
+        if (gLoaderFd < 0) {
+                ALOGI("invalid gLoaderFd: %d\n", gLoaderFd);
+                return -1;
+        }
+
+        iRet = ioctl(gLoaderFd, COMBO_IOCTL_MODULE_CLEANUP, chipId);
+        if (iRet) {
+                ALOGI("do WMT-DETECT module cleanup failed: %d\n", iRet);
+                return -2;
+        }
+        iRet = ioctl(gLoaderFd, COMBO_IOCTL_DO_MODULE_INIT, chipId);
+        if (iRet) {
+                ALOGI("do kernel module init failed: %d\n", iRet);
+                return -3;
+        }
+        ALOGI("do kernel module init succeed: %d\n", iRet);
+        return 0;
+}
+
+void *load_file(const char *fn, unsigned *_sz)
+{
+	char *data;
+	int sz;
+	int fd;
+	data = 0;
+
+	fd = open(fn, O_RDONLY);
+	if(fd < 0) return 0;
+
+	sz = lseek(fd, 0, SEEK_END);
+	if(sz < 0)
+		goto oops;
+
+	if(lseek(fd, 0, SEEK_SET) != 0)
+		goto oops;
+
+	data = (char*) malloc(sz + 1);
+	if(data == 0)
+		goto oops;
+
+	if(read(fd, data, sz) != sz)
+		goto oops;
+
+	close(fd);    data[sz] = 0;
+
+	if(_sz)
+		*_sz = sz;
+
+	return data;
+
+oops:
+	close(fd);
+	if(data != 0)
+		free(data);
+
+	return 0;
+}
+
+//insmod
+static int insmod(const char *filename, const char *args)
+{
+	void *module;
+	unsigned int size;
+	int ret;
+
+	module = load_file(filename, &size);
+	if (!module)
+		return -1;
+
+	ret = init_module(module, size, args);
+
+	free(module);
+
+	return ret;
+}
+
+
+int load_wifi_module(int chip_id)
+{
+	int ret = -1;
+	struct utsname utsname;
+	char wifi_module_path[100] = "";
+	char wlan_module_path[100] = "";
+
+	if (!(uname(&utsname))) {
+		/* Use modules built within kernel tree */
+		sprintf(wifi_module_path, "%s%s%s", WMT_KO_PATH_PREFIX, utsname.release, WMT_WIFI_MODULE_PATH);
+		sprintf(wlan_module_path, "%s%s%s", WMT_KO_PATH_PREFIX, utsname.release, WMT_WLAN_MODULE_PATH);
+	} else
+		return -1;
+
+	if ((access(wifi_module_path,0) < 0) && (access(wlan_module_path,0) < 0))
+	{
+		/* Use modules built out of kernel tree */
+		printf("Use modules built out of kernel tree\n");
+		memset(wifi_module_path, 0, sizeof(wifi_module_path));
+		memset(wlan_module_path, 0, sizeof(wlan_module_path));
+		sprintf(wifi_module_path, "%s%s", WMT_OUT_KO_PATH_PREFIX, WMT_OUT_WMT_WIFI_MODULE_PATH);
+		sprintf(wlan_module_path, "%s%s", WMT_OUT_KO_PATH_PREFIX, WMT_OUT_WLAN_MODULE_PATH);
+	}
+
+	if (chip_id == 0x6630) {
+		//insert 6630 driver
+		if(0 == insmod(wifi_module_path, DRIVER_MODULE_ARG)){
+			ret = 0;
+			printf("Success to insmod wmt wifi module\n");
+		} else
+			printf("Fail to insmod wmt wifi module %s\n", wifi_module_path);
+
+		if(0 == insmod(wlan_module_path, DRIVER_MODULE_ARG)){
+			ret = 0;
+			printf("Success to insmod wlan module\n");
+		} else
+			printf("Fail to insmod wlan module %s\n", wlan_module_path);
+    }
+
+	return ret;
+}
+
+
+/* TBD in platform-specific way */
+static int get_persist_chip_id(char *str, size_t len) { return -1; }
+static int set_persist_chip_id(int id) { return 0; }
+static void set_proc_owner(void) { }
+static void update_driver_ready(void) { }
+
+int main(int argc, char *argv[]) {
+        int iRet = -1;
+        int noextChip = -1;
+        int chipId = -1;
+        int count = 0;
+        char chipidStr[PROPERTY_VALUE_MAX] = {0};
+        char readyStr[PROPERTY_VALUE_MAX] = {0};
+        int loadFmResult = -1;
+        int loadAntResult = -1;
+        int loadWlanResult = -1;
+        int retryCounter = 1;
+        int autokRet = 0;
+        do {
+                gLoaderFd = open(WCN_COMBO_LOADER_DEV, O_RDWR | O_NOCTTY);
+                if (gLoaderFd < 0) {
+                        count++;
+                        ALOGI("Can't open device node(%s) count(%d)\n", WCN_COMBO_LOADER_DEV, count);
+                        usleep(300000);
+                } else
+                        break;
+        } while (1);
+
+        // read from system property
+        chipId = get_persist_chip_id(chipidStr, sizeof(chipidStr));
+
+        if (-1 != is_chipId_vaild(chipId)) {
+                /*valid chipid detected*/
+                ALOGI("key:(%s)-value:(%s),chipId:0x%04x,iRet(%d)\n",
+                        WCN_COMBO_LOADER_CHIP_ID_PROP, chipidStr, chipId, iRet);
+                if (0x6630 == chipId) {
+                        retryCounter = 10;
+                        /*trigger autok process, incase last autok process is 
+                          interrupted by abnormal power off or battery down*/
+                        do {
+                                /*power on combo chip*/
+                                iRet = ioctl(gLoaderFd, COMBO_IOCTL_EXT_CHIP_PWR_ON);
+                                if (0 != iRet) {
+                                        ALOGI("external combo chip power on failed\n");
+                                        noextChip = 1;
+                                } else {
+                                        /*detect is there is an external combo chip*/
+                                        noextChip = ioctl(gLoaderFd, COMBO_IOCTL_EXT_CHIP_DETECT, NULL);
+                                }
+
+                                if (noextChip) {
+                                         // do nothing
+                                         ALOGI("no external combo chip detected\n");
+                                } else {
+                                         ALOGI("external combo chip detected\n");
+                                         chipId = ioctl(gLoaderFd, COMBO_IOCTL_GET_CHIP_ID, NULL);
+                                         ALOGI("chipid (0x%x) detected\n", chipId);
+                               }
+
+                                if (0 == noextChip) {
+                                        autokRet = ioctl(gLoaderFd, COMBO_IOCTL_DO_SDIO_AUDOK, chipId);
+                                        if (0 != autokRet) {
+                                                ALOGI("do SDIO3.0 autok failed\n");
+                                        } else {
+                                                ALOGI("do SDIO3.0 autok succeed\n");
+                                        }
+                                }
+                                iRet = ioctl(gLoaderFd, COMBO_IOCTL_EXT_CHIP_PWR_OFF);
+                                if (0 != iRet) {
+                                        ALOGI("external combo chip power off failed\n");
+                                } else {
+                                        ALOGI("external combo chip power off succeed\n");
+                                }
+                                if ((0 == noextChip) && (-1 == chipId)) {
+                                        /*extenral chip detected, but no valid chipId detected, retry*/
+                                        retryCounter--;
+                                        ALOGI("chipId detect failed, retrying, left retryCounter:%d\n", retryCounter);
+                                        usleep(500000);
+                                } else
+                                        break;
+                        }while (0 < retryCounter);
+                        chipId = 0x6630;
+                 }
+        } else {
+                /*trigger external combo chip detect and chip identification process*/
+                do {
+                        /*power on combo chip*/
+                        iRet = ioctl(gLoaderFd, COMBO_IOCTL_EXT_CHIP_PWR_ON);
+                        if (0 != iRet) {
+                                ALOGI("external combo chip power on failed\n");
+                                noextChip = 1;
+                        } else {
+                                /*detect is there is an external combo chip*/
+                                noextChip = ioctl(gLoaderFd, COMBO_IOCTL_EXT_CHIP_DETECT, NULL);
+                        }
+
+                        if (noextChip) {   // use soc itself
+                                ALOGI("no external combo chip detected, get current soc chipid\n");
+                                chipId = ioctl(gLoaderFd, COMBO_IOCTL_GET_SOC_CHIP_ID, NULL);
+                                ALOGI("soc chipid (0x%x) detected\n", chipId);
+                        } else {
+                                ALOGI("external combo chip detected\n");
+                                chipId = ioctl(gLoaderFd, COMBO_IOCTL_GET_CHIP_ID, NULL);
+                                ALOGI("chipid (0x%x) detected\n", chipId);
+                       }
+
+                        sprintf(chipidStr, "0x%04x", chipId);
+                        iRet = set_persist_chip_id(chipId);
+                        if (0 != iRet) {
+                                ALOGI("set property(%s) to %s failed,iRet:%d, errno:%d\n",
+                                    WCN_COMBO_LOADER_CHIP_ID_PROP, chipidStr, iRet, errno);
+                        } else {
+                               ALOGI("set property(%s) to %s succeed.\n", WCN_COMBO_LOADER_CHIP_ID_PROP, chipidStr);
+                        }
+                        if (0 == noextChip) {
+                                autokRet = ioctl(gLoaderFd, COMBO_IOCTL_DO_SDIO_AUDOK, chipId);
+                                if (0 != autokRet) {
+                                        ALOGI("do SDIO3.0 autok failed\n");
+                                } else {
+                                        ALOGI("do SDIO3.0 autok succeed\n");
+                                }
+                        }
+                        iRet = ioctl(gLoaderFd, COMBO_IOCTL_EXT_CHIP_PWR_OFF);
+                        if (0 != iRet) {
+                                ALOGI("external combo chip power off failed\n");
+                        } else {
+                                ALOGI("external combo chip power off succeed\n");
+                        }
+                        if ((0 == noextChip) && (-1 == chipId)) {
+                            /*extenral chip detected, but no valid chipId detected, retry*/
+                            retryCounter--;
+                            usleep(500000);
+                            ALOGI("chipId detect failed, retrying, left retryCounter:%d\n", retryCounter);
+                        } else
+                              break;
+                }while (0 < retryCounter);
+        }
+
+        /*set chipid to kernel*/
+        ioctl(gLoaderFd, COMBO_IOCTL_SET_CHIP_ID, chipId);
+
+        if (g_remove_ko_flag) {
+                if ((0x0321 == chipId) || (0x0335 == chipId) || (0x0337 == chipId)) {
+                        chipId = 0x6735;
+                }
+                if (0x0326 == chipId) {
+                        chipId = 0x6755;
+                }
+                if (0x0279 == chipId) {
+                        chipId = 0x6797;
+                }
+                do_kernel_module_init(gLoaderFd, chipId);
+                if (gLoaderFd >= 0) {
+                        close(gLoaderFd);
+                        gLoaderFd = -1;
+               }
+
+        } else {
+#if 0
+                if (gLoaderFd >= 0) {
+                        close(gLoaderFd);
+                        gLoaderFd = -1;
+                }
+                ALOGI("rmmod mtk_wmt_detect\n");
+                rmmod("mtk_wmt_detect");
+                /*INSERT TARGET MODULE TO KERNEL*/
+                iRet = insert_wmt_modules(chipId, 0, -1);
+                /*this process should never fail*/
+                if (iRet) {
+                        ALOGI("insert wmt modules fail(%d):(%d)\n", iRet, __LINE__);
+                        /*goto done;*/
+                }
+
+                loadFmResult = load_fm_module(chipId);
+                if (loadFmResult) {
+                        ALOGI("load FM modules fail(%d):(%d)\n", iRet, __LINE__);
+                        /*continue, we cannot let this process interrupted by subsystem module load fail*/
+                        /*goto done;*/
+                }
+
+                loadAntResult = load_ant_module(chipId);
+                if (loadAntResult) {
+                        ALOGI("load ANT modules fail(%d):(%d)\n", iRet, __LINE__);
+                        /*continue, we cannot let this process interrupted by subsystem module load fail*/
+                        /*goto done;*/
+                }
+
+                loadWlanResult = load_wifi_module(chipId);
+                if (loadWlanResult) {
+                        ALOGI("load WIFI modules fail(%d):(%d)\n", iRet, __LINE__);
+                        /*continue, we cannot let this process interrupted by subsystem module load fail*/
+                        /*goto done;*/
+                }
+#endif
+        }
+
+        // chown to set proc owner
+        set_proc_owner();
+        if (0/*0x6630 == chipId*/) {
+                retryCounter = 0;
+                int i_ret = -1;
+                do {
+                        i_ret = loader_wmt_pwr_ctrl(1);
+                        if (0 == i_ret)
+                                break;
+                        else {
+                                loader_wmt_pwr_ctrl(0);
+                                ALOGI("power on %x failed, retrying, retry counter:%d\n", chipId, retryCounter);
+                                usleep(1000000);
+                       }
+                       retryCounter++;
+                } while (retryCounter < 20);
+        }
+
+	//insmod wmt_chrdev_wifi.ko & wlan_gen3.ko
+	loadWlanResult = load_wifi_module(chipId);
+	if (loadWlanResult) {
+		ALOGI("load WIFI modules fail(%d):(%d)\n", iRet, __LINE__);
+	}
+
+        // update wmt driver ready
+        update_driver_ready();
+
+        return iRet;
+}
+
+
+
diff --git a/src/connectivity/combo_tool/configure.ac b/src/connectivity/combo_tool/configure.ac
new file mode 100755
index 0000000..dfe0c2c
--- /dev/null
+++ b/src/connectivity/combo_tool/configure.ac
@@ -0,0 +1,5 @@
+AC_INIT([wmt_loader], [1.0])
+AM_INIT_AUTOMAKE([foreign])
+AC_PROG_CC
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/src/connectivity/combo_tool/launcher-service b/src/connectivity/combo_tool/launcher-service
new file mode 100644
index 0000000..52846d3
--- /dev/null
+++ b/src/connectivity/combo_tool/launcher-service
@@ -0,0 +1,64 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides: launcher
+# Required-Start:	$syslog $local_fs $remote_fs 
+# Required-Stop:	$syslog $local_fs $remote_fs 
+# Default-Start:	2 3 4 5
+# Default-Stop:		0 1 6
+# Short-Description: 66xx launcher Daemon
+### END INIT INFO
+
+. /etc/init.d/init-functions
+prog=launcher
+PIDFILE=/var/run/$prog.pid
+DESC="66xx launcher Daemon"
+start() {
+	log_daemon_msg "Starting $DESC" "$prog"
+	start_daemon_background -p $PIDFILE /usr/bin/6620_launcher -m 4 -p /lib/firmware
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+	exit 0
+}
+
+stop() {
+	log_daemon_msg "Stopping $DESC" "$prog"
+	killproc -p $PIDFILE /usr/bin/6620_launcher
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+}
+
+force_reload() {
+	stop
+	start
+
+}
+
+case "$1" in
+	start)
+		start
+		;;
+	stop)
+		stop
+		;;
+	force-reload)
+		force_reload
+		;;
+	restart)
+		stop
+		start
+		;;
+
+	*)
+		echo "$Usage: $prog {start|stop|force-reload|restart}"
+		exit 2
+esac
diff --git a/src/connectivity/combo_tool/launcher.service b/src/connectivity/combo_tool/launcher.service
new file mode 100644
index 0000000..f2c5141
--- /dev/null
+++ b/src/connectivity/combo_tool/launcher.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=66xx launcher Daemon
+After=wmtd.service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/6620_launcher -m 4 -p /lib/firmware
+
+[Install]
+Alias=launcherd
+WantedBy=multi-user.target
diff --git a/src/connectivity/combo_tool/launcher_6627.service b/src/connectivity/combo_tool/launcher_6627.service
new file mode 100755
index 0000000..18c2158
--- /dev/null
+++ b/src/connectivity/combo_tool/launcher_6627.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=66xx launcher Daemon
+After=wmtd.service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/6620_launcher -p /lib/firmware
+
+[Install]
+Alias=launcherd
+WantedBy=multi-user.target
diff --git a/src/connectivity/combo_tool/patch_folder/LICENSE b/src/connectivity/combo_tool/patch_folder/LICENSE
new file mode 100755
index 0000000..77f59ed
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:
+
+This software/firmware and related documentation ("MediaTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+the prior written permission of MediaTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MediaTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MediaTek Inc. (C) 2015. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
diff --git a/src/connectivity/combo_tool/patch_folder/MNL.bin b/src/connectivity/combo_tool/patch_folder/MNL.bin
new file mode 100755
index 0000000..0b91cf4
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/MNL.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/ROMv1_patch_1_0_hdr.bin b/src/connectivity/combo_tool/patch_folder/ROMv1_patch_1_0_hdr.bin
new file mode 100755
index 0000000..9fa29dc
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/ROMv1_patch_1_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/ROMv1_patch_1_1_hdr.bin b/src/connectivity/combo_tool/patch_folder/ROMv1_patch_1_1_hdr.bin
new file mode 100755
index 0000000..179a1cd
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/ROMv1_patch_1_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_0.bin b/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_0.bin
new file mode 100755
index 0000000..39e50ed
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_0.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_0_hdr.bin b/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_0_hdr.bin
new file mode 100755
index 0000000..5b5685e
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_1.bin b/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_1.bin
new file mode 100755
index 0000000..95d8ddd
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_1.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_1_hdr.bin b/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_1_hdr.bin
new file mode 100755
index 0000000..8d479f8
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/ROMv2_lm_patch_1_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/ROMv2_patch_1_0_hdr.bin b/src/connectivity/combo_tool/patch_folder/ROMv2_patch_1_0_hdr.bin
new file mode 100755
index 0000000..8efc731
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/ROMv2_patch_1_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/ROMv2_patch_1_1_hdr.bin b/src/connectivity/combo_tool/patch_folder/ROMv2_patch_1_1_hdr.bin
new file mode 100755
index 0000000..733a65f
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/ROMv2_patch_1_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/ROMv3_patch_1_0_hdr.bin b/src/connectivity/combo_tool/patch_folder/ROMv3_patch_1_0_hdr.bin
new file mode 100755
index 0000000..e4318e6
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/ROMv3_patch_1_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/ROMv3_patch_1_1_hdr.bin b/src/connectivity/combo_tool/patch_folder/ROMv3_patch_1_1_hdr.bin
new file mode 100755
index 0000000..70b88c8
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/ROMv3_patch_1_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/WIFI_RAM_CODE_8167 b/src/connectivity/combo_tool/patch_folder/WIFI_RAM_CODE_8167
new file mode 100644
index 0000000..592698f
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/WIFI_RAM_CODE_8167
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/WIFI_RAM_CODE_MT6630 b/src/connectivity/combo_tool/patch_folder/WIFI_RAM_CODE_MT6630
new file mode 100644
index 0000000..9151d7e
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/WIFI_RAM_CODE_MT6630
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/audio/WIFI_RAM_CODE_MT6630 b/src/connectivity/combo_tool/patch_folder/audio/WIFI_RAM_CODE_MT6630
new file mode 100644
index 0000000..7a8026b
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/audio/WIFI_RAM_CODE_MT6630
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/mt2731/mt6630_patch_e3_0_hdr.bin b/src/connectivity/combo_tool/patch_folder/mt2731/mt6630_patch_e3_0_hdr.bin
new file mode 100644
index 0000000..fde7b9b
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/mt2731/mt6630_patch_e3_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/mt2731/mt6630_patch_e3_1_hdr.bin b/src/connectivity/combo_tool/patch_folder/mt2731/mt6630_patch_e3_1_hdr.bin
new file mode 100644
index 0000000..d82fc75
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/mt2731/mt6630_patch_e3_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/mt6630_patch_e3_0_hdr.bin b/src/connectivity/combo_tool/patch_folder/mt6630_patch_e3_0_hdr.bin
new file mode 100755
index 0000000..f1a9275
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/mt6630_patch_e3_0_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/patch_folder/mt6630_patch_e3_1_hdr.bin b/src/connectivity/combo_tool/patch_folder/mt6630_patch_e3_1_hdr.bin
new file mode 100755
index 0000000..19f679a
--- /dev/null
+++ b/src/connectivity/combo_tool/patch_folder/mt6630_patch_e3_1_hdr.bin
Binary files differ
diff --git a/src/connectivity/combo_tool/poweronwifi.service b/src/connectivity/combo_tool/poweronwifi.service
new file mode 100644
index 0000000..db06dce
--- /dev/null
+++ b/src/connectivity/combo_tool/poweronwifi.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=power on wifi Daemon
+After=wmtd.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/usr/bin/power_on_wifi
+
+[Install]
+Alias=pwrwifid
+WantedBy=multi-user.target
diff --git a/src/connectivity/combo_tool/product_package.mk b/src/connectivity/combo_tool/product_package.mk
new file mode 100755
index 0000000..326f19c
--- /dev/null
+++ b/src/connectivity/combo_tool/product_package.mk
@@ -0,0 +1,288 @@
+# Copyright Statement:
+#
+# This software/firmware and related documentation ("MediaTek Software") are
+# protected under relevant copyright laws. The information contained herein
+# is confidential and proprietary to MediaTek Inc. and/or its licensors.
+# Without the prior written permission of MediaTek inc. and/or its licensors,
+# any reproduction, modification, use or disclosure of MediaTek Software,
+# and information contained herein, in whole or in part, shall be strictly prohibited.
+#
+# MediaTek Inc. (C) 2010. All rights reserved.
+#
+# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+#
+# The following software/firmware and/or related documentation ("MediaTek Software")
+# have been modified by MediaTek Inc. All revisions are subject to any receiver's
+# applicable license agreements with MediaTek Inc.
+
+
+# Copyright (C) 2008 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.
+
+# Configuration
+BUILD_PATCH  := false
+BUILD_WMT_CFG_L2   := false
+BUILD_WMT_CFG_L1   := false
+BUILD_MT6620 := false
+BUILD_MT6628 := false
+BUILD_MT6630 := false
+BUILD_MT6582_CONSYS :=false
+BUILD_MT6571_CONSYS :=false
+BUILD_MT6752_CONSYS :=false
+BUILD_MT6797_CONSYS :=false
+
+ifeq ($(strip $(MTK_COMBO_SUPPORT)), yes)
+
+LOCAL_PATH := $(call my-dir)
+
+cfg_folder := vendor/mediatek/proprietary/hardware/connectivity/combo_tool/cfg_folder
+patch_folder := vendor/mediatek/proprietary/hardware/connectivity/combo_tool/patch_folder
+
+BUILD_PATCH := true
+BUILD_WMT_CFG_L2 := true
+
+ifneq ($(filter MT6620E3,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6620 := true
+    BUILD_WMT_CFG_L1 := true
+endif
+
+ifneq ($(filter MT6620,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6620 := true
+    BUILD_WMT_CFG_L1 := true
+endif
+
+ifneq ($(filter MT6628,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6628 := true
+    BUILD_WMT_CFG_L1 := true
+endif
+
+ifneq ($(filter MT6630,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6630 := true
+    BUILD_WMT_CFG_L1 := true
+endif
+
+ifneq ($(filter CONSYS_6572,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6582,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6592,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6582_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6571,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6571_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_8127,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6571_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6752,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6752_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6755,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6752_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6797,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6797_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6735,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6752_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_6580,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6752_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_8163,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6752_CONSYS := true
+endif
+
+ifneq ($(filter CONSYS_7623,$(MTK_COMBO_CHIP)),)
+    BUILD_MT6752_CONSYS := true
+endif
+
+##### INSTALL WMT.CFG FOR COMBO CONFIG #####
+ifeq ($(BUILD_WMT_CFG_L1), true)
+PRODUCT_COPY_FILES += $(cfg_folder)/WMT.cfg:system/etc/firmware/WMT.cfg
+endif
+
+ifeq ($(BUILD_MT6620), true)
+ifneq ($(filter mt6620_ant_m1,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6620_ant_m1.cfg:system/etc/firmware/mt6620_ant_m1.cfg
+endif
+
+ifneq ($(filter mt6620_ant_m2,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6620_ant_m2.cfg:system/etc/firmware/mt6620_ant_m2.cfg
+endif
+
+ifneq ($(filter mt6620_ant_m3,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6620_ant_m3.cfg:system/etc/firmware/mt6620_ant_m3.cfg
+endif
+
+ifneq ($(filter mt6620_ant_m4,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6620_ant_m4.cfg:system/etc/firmware/mt6620_ant_m4.cfg
+endif
+
+ifneq ($(filter mt6620_ant_m5,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6620_ant_m5.cfg:system/etc/firmware/mt6620_ant_m5.cfg
+endif
+
+ifneq ($(filter mt6620_ant_m6,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6620_ant_m6.cfg:system/etc/firmware/mt6620_ant_m6.cfg
+endif
+
+ifneq ($(filter mt6620_ant_m7,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6620_ant_m7.cfg:system/etc/firmware/mt6620_ant_m7.cfg
+endif 
+
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6620_patch_e3_0_hdr.bin:system/etc/firmware/mt6620_patch_e3_0_hdr.bin
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6620_patch_e3_1_hdr.bin:system/etc/firmware/mt6620_patch_e3_1_hdr.bin
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6620_patch_e3_2_hdr.bin:system/etc/firmware/mt6620_patch_e3_2_hdr.bin
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6620_patch_e3_3_hdr.bin:system/etc/firmware/mt6620_patch_e3_3_hdr.bin
+
+endif
+
+
+ifeq ($(BUILD_MT6628), true)
+
+ifneq ($(filter mt6628_ant_m1,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6628_ant_m1.cfg:system/etc/firmware/mt6628_ant_m1.cfg
+endif  
+
+ifneq ($(filter mt6628_ant_m2,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6628_ant_m2.cfg:system/etc/firmware/mt6628_ant_m2.cfg
+endif
+
+ifneq ($(filter mt6628_ant_m3,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6628_ant_m3.cfg:system/etc/firmware/mt6628_ant_m3.cfg
+endif
+
+ifneq ($(filter mt6628_ant_m4,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6628_ant_m4.cfg:system/etc/firmware/mt6628_ant_m4.cfg
+endif
+
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6628_patch_e1_hdr.bin:system/etc/firmware/mt6628_patch_e1_hdr.bin
+    
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6628_patch_e2_0_hdr.bin:system/etc/firmware/mt6628_patch_e2_0_hdr.bin
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6628_patch_e2_1_hdr.bin:system/etc/firmware/mt6628_patch_e2_1_hdr.bin
+    
+endif
+
+ifeq ($(BUILD_MT6630), true)
+
+ifneq ($(filter mt6630_ant_m1,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6630_ant_m1.cfg:system/etc/firmware/mt6630_ant_m1.cfg
+endif  
+
+ifneq ($(filter mt6630_ant_m2,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6630_ant_m2.cfg:system/etc/firmware/mt6630_ant_m2.cfg
+endif
+
+ifneq ($(filter mt6630_ant_m3,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6630_ant_m3.cfg:system/etc/firmware/mt6630_ant_m3.cfg
+endif
+
+ifneq ($(filter mt6630_ant_m4,$(CUSTOM_HAL_ANT)),)
+    PRODUCT_COPY_FILES += $(cfg_folder)/mt6630_ant_m4.cfg:system/etc/firmware/mt6630_ant_m4.cfg
+endif
+
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6630_patch_e1_hdr.bin:system/etc/firmware/mt6630_patch_e1_hdr.bin
+
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6630_patch_e2_hdr.bin:system/etc/firmware/mt6630_patch_e2_hdr.bin
+
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6630_patch_e3_0_hdr.bin:system/etc/firmware/mt6630_patch_e3_0_hdr.bin
+    PRODUCT_COPY_FILES += $(patch_folder)/mt6630_patch_e3_1_hdr.bin:system/etc/firmware/mt6630_patch_e3_1_hdr.bin
+endif
+
+
+ifeq ($(BUILD_MT6582_CONSYS), true)
+
+    PRODUCT_COPY_FILES += $(patch_folder)/ROMv1_patch_1_0_hdr.bin:system/etc/firmware/ROMv1_patch_1_0_hdr.bin
+    PRODUCT_COPY_FILES += $(patch_folder)/ROMv1_patch_1_1_hdr.bin:system/etc/firmware/ROMv1_patch_1_1_hdr.bin
+    
+endif
+
+ifeq ($(BUILD_MT6571_CONSYS), true)
+
+    PRODUCT_COPY_FILES += $(patch_folder)/ROMv2_patch_1_0_hdr.bin:system/etc/firmware/ROMv2_patch_1_0_hdr.bin
+    PRODUCT_COPY_FILES += $(patch_folder)/ROMv2_patch_1_1_hdr.bin:system/etc/firmware/ROMv2_patch_1_1_hdr.bin
+    
+endif
+
+ifeq ($(BUILD_MT6752_CONSYS), true)
+
+    PRODUCT_COPY_FILES += $(patch_folder)/ROMv2_lm_patch_1_0_hdr.bin:system/etc/firmware/ROMv2_lm_patch_1_0_hdr.bin
+    PRODUCT_COPY_FILES += $(patch_folder)/ROMv2_lm_patch_1_1_hdr.bin:system/etc/firmware/ROMv2_lm_patch_1_1_hdr.bin
+    
+endif
+
+ifeq ($(BUILD_MT6797_CONSYS), true)
+
+    PRODUCT_COPY_FILES += $(patch_folder)/ROMv3_patch_1_0_hdr.bin:system/etc/firmware/ROMv3_patch_1_0_hdr.bin
+    PRODUCT_COPY_FILES += $(patch_folder)/ROMv3_patch_1_1_hdr.bin:system/etc/firmware/ROMv3_patch_1_1_hdr.bin
+    PRODUCT_COPY_FILES += $(patch_folder)/MNL.bin:system/etc/firmware/MNL.bin
+    
+endif
+
+ifneq ($(wildcard device/mediatek/$(MTK_TARGET_PROJECT)/WMT_SOC.cfg),)
+  PRODUCT_COPY_FILES += device/mediatek/$(MTK_TARGET_PROJECT)/WMT_SOC.cfg:system/etc/firmware/WMT_SOC.cfg
+else
+  ifneq ($(wildcard device/mediatek/$(MTK_PLATFORM_DIR)/WMT_SOC.cfg),)
+    PRODUCT_COPY_FILES += device/mediatek/$(MTK_PLATFORM_DIR)/WMT_SOC.cfg:system/etc/firmware/WMT_SOC.cfg
+  else
+    PRODUCT_COPY_FILES += device/mediatek/common/WMT_SOC.cfg:system/etc/firmware/WMT_SOC.cfg
+  endif
+endif
+
+# PRODUCT_PACKAGES part
+
+  PRODUCT_PACKAGES += 6620_launcher \
+    6620_wmt_concurrency \
+    6620_wmt_lpbk \
+    wmt_loader \
+    stp_dump3
+
+
+PRODUCT_PROPERTY_OVERRIDES += persist.mtk.wcn.combo.chipid=-1
+PRODUCT_PROPERTY_OVERRIDES += persist.mtk.wcn.fwlog.status=no
+PRODUCT_PROPERTY_OVERRIDES += persist.mtk.wcn.dynamic.dump=0
+PRODUCT_PROPERTY_OVERRIDES += service.wcn.driver.ready=no
+PRODUCT_PROPERTY_OVERRIDES += service.wcn.coredump.mode=2
+
+endif
diff --git a/src/connectivity/combo_tool/src/Android.mk b/src/connectivity/combo_tool/src/Android.mk
new file mode 100755
index 0000000..c1359e1
--- /dev/null
+++ b/src/connectivity/combo_tool/src/Android.mk
@@ -0,0 +1,109 @@
+# Copyright Statement:
+#
+# This software/firmware and related documentation ("MediaTek Software") are
+# protected under relevant copyright laws. The information contained herein
+# is confidential and proprietary to MediaTek Inc. and/or its licensors.
+# Without the prior written permission of MediaTek inc. and/or its licensors,
+# any reproduction, modification, use or disclosure of MediaTek Software,
+# and information contained herein, in whole or in part, shall be strictly prohibited.
+#
+# MediaTek Inc. (C) 2010. All rights reserved.
+#
+# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+#
+# The following software/firmware and/or related documentation ("MediaTek Software")
+# have been modified by MediaTek Inc. All revisions are subject to any receiver's
+# applicable license agreements with MediaTek Inc.
+
+
+# Copyright (C) 2008 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.
+
+# Configuration
+BUILD_LAUNCHER  := false
+BUILD_WMT_LPBK  := false
+BUILD_WMT_CONCURRENCY := false
+BUILD_STP_DUMP := false
+LOCAL_PATH := $(call my-dir)
+
+
+#ifneq ($(MTK_COMBO_CHIP), )
+BUILD_LAUNCHER  := true
+BUILD_WMT_LPBK  := true
+BUILD_WMT_CONCURRENCY := true
+
+#ifneq ($(filter MT6620E3,$(MTK_COMBO_CHIP)),)
+    BUILD_STP_DUMP := true
+
+#endif
+#endif
+
+$(warning before build launcher)
+ifeq ($(BUILD_LAUNCHER), true)
+include $(CLEAR_VARS)
+
+$(warning after build launcher)
+LOCAL_SRC_FILES  := stp_uart_launcher.c
+LOCAL_MODULE := 6620_launcher
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libcutils
+include $(BUILD_EXECUTABLE)
+endif
+
+ifeq ($(BUILD_WMT_LPBK), true)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES  := wmt_loopback.c
+LOCAL_MODULE := 6620_wmt_lpbk
+LOCAL_MODULE_TAGS := eng
+include $(BUILD_EXECUTABLE)
+endif
+
+
+ifeq ($(BUILD_WMT_CONCURRENCY), true)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES  := wmt_concurrency.c
+LOCAL_MODULE := 6620_wmt_concurrency
+LOCAL_MODULE_TAGS := eng
+include $(BUILD_EXECUTABLE)
+endif
+
+ifeq ($(BUILD_STP_DUMP), true)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES :=                                      \
+		  stp_dump/stp_dump.c			\
+		  stp_dump/eloop.c	\
+		  stp_dump/os_linux.c	
+LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_MODULE := stp_dump3
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+endif
+
diff --git a/src/connectivity/combo_tool/src/README b/src/connectivity/combo_tool/src/README
new file mode 100755
index 0000000..5c3e03f
--- /dev/null
+++ b/src/connectivity/combo_tool/src/README
@@ -0,0 +1,20 @@
+This module serves the common part driver of connectivity
+
+WHAT IT DOES?
+=============
+This module creates four executable binary files for configuring/testing 
+the common part driver.
+
+HOW IT WAS BUILT?
+==================
+It needs the following library from AOSP:
+
+libcutils, libc
+
+HOW TO USE IT?
+==============
+The executable binary files will be started in init.rc when boot. they will work together
+with wmt_loader to load/configure the common part driver of connectivity, meanwhile some test
+tool was supplied.
+
+The majority of source code was written by MediaTek. Some code from open source codes are used.
diff --git a/src/connectivity/combo_tool/src/power_on_wifi.c b/src/connectivity/combo_tool/src/power_on_wifi.c
new file mode 100755
index 0000000..c913982
--- /dev/null
+++ b/src/connectivity/combo_tool/src/power_on_wifi.c
@@ -0,0 +1,117 @@
+
+/******************************************************************************
+*                         C O M P I L E R   F L A G S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                    E X T E R N A L   R E F E R E N C E S
+*******************************************************************************
+*/
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+/*#include <syslog.h>*/
+#include <time.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+
+
+/******************************************************************************
+*                              C O N S T A N T S
+*******************************************************************************
+*/
+/* !defined(ANDROID) */
+#ifndef ALOGI
+#define ALOGI printf
+#endif
+#ifndef ALOGE
+#define ALOGE printf
+#endif
+#ifndef ALOGD
+#define ALOGD printf
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "6620_launcher"
+
+#if TARGET_PLATFORM == mt2635
+#define CUST_COMBO_WIFI_DEV "/dev/wmtWifi"
+#define POWER_ON_WIFI "AP"
+#define POWER_ON_WIFI_LEN 2
+#else
+#define CUST_COMBO_WIFI_DEV "/dev/wmtWifi"
+#define POWER_ON_WIFI "1"
+#define POWER_ON_WIFI_LEN 1
+#endif
+
+/******************************************************************************
+*                             D A T A   T Y P E S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                                 M A C R O S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                   F U N C T I O N   D E C L A R A T I O N S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                            P U B L I C   D A T A
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                           P R I V A T E   D A T A
+*******************************************************************************
+*/
+
+static int gWifiFd = -1;
+
+/******************************************************************************
+*                              F U N C T I O N S
+*******************************************************************************
+*/
+int main(int argc, char *argv[]) {
+        int retryCounter = 0;
+        int i_ret = -1;
+
+        gWifiFd = open(CUST_COMBO_WIFI_DEV, O_RDWR | O_NOCTTY);
+        do {
+                if (gWifiFd < 0) {
+                        ALOGI("Can't open device node(%s) error:%d \n", CUST_COMBO_WIFI_DEV, gWifiFd);
+                        usleep(300000);
+                } else {
+                       break;
+                }
+                retryCounter++;
+        } while (retryCounter < 20);
+
+        if (gWifiFd > 0) {
+                do {
+                        i_ret = write(gWifiFd, POWER_ON_WIFI, POWER_ON_WIFI_LEN);
+                        if (i_ret == 1) {
+                                ALOGI("Power on device node(%s) gWifiFd:%d succeed !!\n", CUST_COMBO_WIFI_DEV, gWifiFd);
+                                break;
+                        } else {
+                               ALOGI("Power on device node(%s) gWifiFd:%d Fail (%d) and retry\n", CUST_COMBO_WIFI_DEV, gWifiFd, i_ret);
+                        }
+                        retryCounter++;
+                        usleep(1000000);
+                } while (retryCounter < 20);
+        }
+        close(gWifiFd);
+
+    return 0;
+}
diff --git a/src/connectivity/combo_tool/src/serial.h b/src/connectivity/combo_tool/src/serial.h
new file mode 100755
index 0000000..4e6b745
--- /dev/null
+++ b/src/connectivity/combo_tool/src/serial.h
@@ -0,0 +1,79 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein is
+* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+* the prior written permission of MediaTek inc. and/or its licensors, any
+* reproduction, modification, use or disclosure of MediaTek Software, and
+* information contained herein, in whole or in part, shall be strictly
+* prohibited.
+*
+* MediaTek Inc. (C) 2014. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek
+* Software") have been modified by MediaTek Inc. All revisions are subject to
+* any receiver's applicable license agreements with MediaTek Inc.
+*/
+
+#ifndef _LINUX_SERIAL_H
+#define _LINUX_SERIAL_H
+
+struct serial_struct {
+ int type;
+ int line;
+ unsigned int port;
+ int irq;
+ int flags;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int baud_base;
+ unsigned short close_delay;
+ char io_type;
+ char reserved_char[1];
+ int hub6;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ unsigned char *iomem_base;
+ unsigned short iomem_reg_shift;
+ unsigned int port_high;
+ unsigned long iomap_base;
+};
+
+#define ASYNCB_HUP_NOTIFY  0
+#define ASYNCB_FOURPORT   1
+#define ASYNCB_SAK   2
+#define ASYNCB_SPLIT_TERMIOS  3
+#define ASYNCB_SPD_HI   4
+#define ASYNCB_SPD_VHI   5
+#define ASYNCB_SKIP_TEST  6
+#define ASYNCB_AUTO_IRQ   7
+#define ASYNCB_SESSION_LOCKOUT  8
+#define ASYNCB_PGRP_LOCKOUT  9
+#define ASYNCB_CALLOUT_NOHUP 10
+#define ASYNCB_HARDPPS_CD 11
+#define ASYNCB_SPD_SHI  12
+#define ASYNCB_LOW_LATENCY 13
+#define ASYNCB_BUGGY_UART 14
+#define ASYNCB_AUTOPROBE 15
+
+#endif /* _LINUX_SERIAL_H */
diff --git a/src/connectivity/combo_tool/src/stp_dump/eloop.c b/src/connectivity/combo_tool/src/stp_dump/eloop.c
new file mode 100755
index 0000000..586091d
--- /dev/null
+++ b/src/connectivity/combo_tool/src/stp_dump/eloop.c
@@ -0,0 +1,649 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ */
+
+/*
+ * Event loop based on select() loop
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <sys/stat.h>
+#include <grp.h>
+#include <stddef.h>
+//#include <cutils/sockets.h>
+//#include <android/log.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <dirent.h>
+//#include <cutils/properties.h>
+#include <sys/un.h>
+#include <dirent.h>
+#include <linux/limits.h>
+//#include <cutils/sockets.h>
+//#include <cutils/memory.h>
+
+#include "os_linux.h"
+#include "stp_dump.h"
+#include "eloop.h"
+
+struct eloop_sock {
+    int sock;
+    void *eloop_data;
+    void *user_data;
+    eloop_sock_handler handler;
+};
+
+struct eloop_timeout {
+    struct os_time time;
+    void *eloop_data;
+    void *user_data;
+    eloop_timeout_handler handler;
+    struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+    int sig;
+    void *user_data;
+    eloop_signal_handler handler;
+    int signaled;
+};
+
+struct eloop_sock_table {
+    int count;
+    struct eloop_sock *table;
+    int changed;
+};
+
+struct eloop_data {
+    void *user_data;
+
+    int max_sock;
+
+    struct eloop_sock_table readers;
+    struct eloop_sock_table writers;
+    struct eloop_sock_table exceptions;
+
+    struct eloop_timeout *timeout;
+
+    int signal_count;
+    struct eloop_signal *signals;
+    int signaled;
+    int pending_terminate;
+
+    int terminate;
+    int reader_table_changed;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void *user_data)
+{
+    os_memset(&eloop, 0, sizeof(eloop));
+    eloop.user_data = user_data;
+    return 0;
+}
+
+
+static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
+                                     int sock, eloop_sock_handler handler,
+                                     void *eloop_data, void *user_data)
+{
+    struct eloop_sock *tmp;
+
+    if (table == NULL)
+    {
+        ALOGI("table = NULL\n");
+        return -1;
+    }
+    tmp = (struct eloop_sock *)
+        os_realloc(table->table,
+               (table->count + 1) * sizeof(struct eloop_sock));
+    if (tmp == NULL)
+    {
+		ALOGI( "memory allocation for eloop_sock failed\n");
+        return -1;
+    }
+    tmp[table->count].sock = sock;
+    tmp[table->count].eloop_data = eloop_data;
+    tmp[table->count].user_data = user_data;
+    tmp[table->count].handler = handler;
+    table->count++;
+    table->table = tmp;
+    if (sock > eloop.max_sock)
+    {
+        eloop.max_sock = sock;
+		ALOGI("set sock number to %d\n", eloop.max_sock);
+    }
+    table->changed = 1;
+
+    return 0;
+}
+
+
+static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
+                                         int sock)
+{
+    int i;
+
+    if (table == NULL || table->table == NULL || table->count == 0)
+        return;
+
+    for (i = 0; i < table->count; i++) {
+        if (table->table[i].sock == sock)
+            break;
+    }
+    if (i == table->count)
+        return;
+    if (i != table->count - 1) {
+        os_memmove(&table->table[i], &table->table[i + 1],
+               (table->count - i - 1) *
+               sizeof(struct eloop_sock));
+    }
+    table->count--;
+    table->changed = 1;
+}
+
+
+static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
+                     fd_set *fds)
+{
+    int i;
+
+    FD_ZERO(fds);
+
+    if (table->table == NULL)
+        return;
+
+    for (i = 0; i < table->count; i++)
+        FD_SET(table->table[i].sock, fds);
+}
+
+
+static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
+                      fd_set *fds)
+{
+    int i;
+
+    if (table == NULL || table->table == NULL)
+    {
+        /*stp_printf(MSG_ERROR, "table == NULL || table->table == NULL\n");*/
+        return;
+    }
+    table->changed = 0;
+    for (i = 0; i < table->count; i++) {
+        if (FD_ISSET(table->table[i].sock, fds)) {
+            table->table[i].handler(table->table[i].sock,
+                        table->table[i].eloop_data,
+                        table->table[i].user_data);
+            if (table->changed)
+                break;
+        }
+    }
+}
+
+
+static void eloop_sock_table_destroy(struct eloop_sock_table *table)
+{
+    if (table) {
+        int i;
+        for (i = 0; i < table->count && table->table; i++) {
+            printf("ELOOP: remaining socket: sock=%d "
+                   "eloop_data=%p user_data=%p handler=%p\n",
+                   table->table[i].sock,
+                   table->table[i].eloop_data,
+                   table->table[i].user_data,
+                   table->table[i].handler);
+        }
+        os_free(table->table);
+    }
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+                 void *eloop_data, void *user_data)
+{
+    return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
+                   eloop_data, user_data);
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+    eloop_unregister_sock(sock, EVENT_TYPE_READ);
+}
+
+
+static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
+{
+    switch (type) {
+    case EVENT_TYPE_READ:
+        return &eloop.readers;
+    case EVENT_TYPE_WRITE:
+        return &eloop.writers;
+    case EVENT_TYPE_EXCEPTION:
+        return &eloop.exceptions;
+    }
+    ALOGE("tyep (%d) error\n", type);
+    return NULL;
+}
+
+
+int eloop_register_sock(int sock, eloop_event_type type,
+            eloop_sock_handler handler,
+            void *eloop_data, void *user_data)
+{
+    struct eloop_sock_table *table;
+
+    table = eloop_get_sock_table(type);
+    return eloop_sock_table_add_sock(table, sock, handler,
+                     eloop_data, user_data);
+}
+
+
+void eloop_unregister_sock(int sock, eloop_event_type type)
+{
+    struct eloop_sock_table *table;
+
+    table = eloop_get_sock_table(type);
+    eloop_sock_table_remove_sock(table, sock);
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+               eloop_timeout_handler handler,
+               void *eloop_data, void *user_data)
+{
+    struct eloop_timeout *timeout, *tmp, *prev;
+
+    timeout = os_malloc(sizeof(*timeout));
+    if (timeout == NULL)
+        return -1;
+    if (os_get_time(&timeout->time) < 0) {
+        os_free(timeout);
+        return -1;
+    }
+    timeout->time.sec += secs;
+    timeout->time.usec += usecs;
+    while (timeout->time.usec >= 1000000) {
+        timeout->time.sec++;
+        timeout->time.usec -= 1000000;
+    }
+    timeout->eloop_data = eloop_data;
+    timeout->user_data = user_data;
+    timeout->handler = handler;
+    timeout->next = NULL;
+
+    if (eloop.timeout == NULL) {
+        eloop.timeout = timeout;
+        return 0;
+    }
+
+    prev = NULL;
+    tmp = eloop.timeout;
+    while (tmp != NULL) {
+        if (os_time_before(&timeout->time, &tmp->time))
+            break;
+        prev = tmp;
+        tmp = tmp->next;
+    }
+
+    if (prev == NULL) {
+        timeout->next = eloop.timeout;
+        eloop.timeout = timeout;
+    } else {
+        timeout->next = prev->next;
+        prev->next = timeout;
+    }
+
+    return 0;
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+             void *eloop_data, void *user_data)
+{
+    struct eloop_timeout *timeout, *prev, *next;
+    int removed = 0;
+
+    prev = NULL;
+    timeout = eloop.timeout;
+    while (timeout != NULL) {
+        next = timeout->next;
+
+        if (timeout->handler == handler &&
+            (timeout->eloop_data == eloop_data ||
+             eloop_data == ELOOP_ALL_CTX) &&
+            (timeout->user_data == user_data ||
+             user_data == ELOOP_ALL_CTX)) {
+            if (prev == NULL)
+                eloop.timeout = next;
+            else
+                prev->next = next;
+            os_free(timeout);
+            removed++;
+        } else
+            prev = timeout;
+
+        timeout = next;
+    }
+
+    return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+                void *eloop_data, void *user_data)
+{
+    struct eloop_timeout *tmp;
+
+    tmp = eloop.timeout;
+    while (tmp != NULL) {
+        if (tmp->handler == handler &&
+            tmp->eloop_data == eloop_data &&
+            tmp->user_data == user_data)
+            return 1;
+
+        tmp = tmp->next;
+    }
+
+    return 0;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+static void eloop_handle_alarm(int sig)
+{
+    fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
+        "seconds. Looks like there\n"
+        "is a bug that ends up in a busy loop that "
+        "prevents clean shutdown.\n"
+        "Killing program forcefully.\n");
+    exit(1);
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static void eloop_handle_signal(int sig)
+{
+    int i;
+
+#ifndef CONFIG_NATIVE_WINDOWS
+    if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
+        /* Use SIGALRM to break out from potential busy loops that
+         * would not allow the program to be killed. */
+        eloop.pending_terminate = 1;
+        signal(SIGALRM, eloop_handle_alarm);
+        alarm(2);
+    }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+    eloop.signaled++;
+    for (i = 0; i < eloop.signal_count; i++) {
+        if (eloop.signals[i].sig == sig) {
+            eloop.signals[i].signaled++;
+            break;
+        }
+    }
+}
+
+
+static void eloop_process_pending_signals(void)
+{
+    int i;
+
+    if (eloop.signaled == 0)
+        return;
+    eloop.signaled = 0;
+
+    if (eloop.pending_terminate) {
+#ifndef CONFIG_NATIVE_WINDOWS
+        alarm(0);
+#endif /* CONFIG_NATIVE_WINDOWS */
+        eloop.pending_terminate = 0;
+    }
+
+    for (i = 0; i < eloop.signal_count; i++) {
+        if (eloop.signals[i].signaled) {
+            eloop.signals[i].signaled = 0;
+            eloop.signals[i].handler(eloop.signals[i].sig,
+                         eloop.user_data,
+                         eloop.signals[i].user_data);
+        }
+    }
+}
+
+
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+              void *user_data)
+{
+    struct eloop_signal *tmp;
+
+    tmp = (struct eloop_signal *)
+        os_realloc(eloop.signals,
+               (eloop.signal_count + 1) *
+               sizeof(struct eloop_signal));
+    if (tmp == NULL)
+        return -1;
+
+    tmp[eloop.signal_count].sig = sig;
+    tmp[eloop.signal_count].user_data = user_data;
+    tmp[eloop.signal_count].handler = handler;
+    tmp[eloop.signal_count].signaled = 0;
+    eloop.signal_count++;
+    eloop.signals = tmp;
+    signal(sig, eloop_handle_signal);
+
+    return 0;
+}
+
+
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+                    void *user_data)
+{
+    int ret = eloop_register_signal(SIGINT, handler, user_data);
+    if (ret == 0)
+        ret = eloop_register_signal(SIGTERM, handler, user_data);
+    if (ret == 0)
+        ret = eloop_register_signal(SIGSEGV, handler, user_data);
+    return ret;
+}
+
+
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+                   void *user_data)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+    return 0;
+#else /* CONFIG_NATIVE_WINDOWS */
+    return eloop_register_signal(SIGHUP, handler, user_data);
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+void eloop_run(void)
+{
+    fd_set *rfds, *wfds, *efds;
+    int res;
+    struct timeval _tv;
+    struct os_time tv, now;
+
+    rfds = os_malloc(sizeof(*rfds));
+    wfds = os_malloc(sizeof(*wfds));
+    efds = os_malloc(sizeof(*efds));
+    if (rfds == NULL || wfds == NULL || efds == NULL) {
+        ALOGE("eloop_run - malloc failed\n");
+        goto out;
+    }
+
+    while (!eloop.terminate &&
+           (eloop.timeout || eloop.readers.count > 0 ||
+        eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
+        if (eloop.timeout) {
+            os_get_time(&now);
+            if (os_time_before(&now, &eloop.timeout->time))
+                os_time_sub(&eloop.timeout->time, &now, &tv);
+            else
+                tv.sec = tv.usec = 0;
+#if 1
+            printf("next timeout in %lu.%06lu sec\n",
+                   tv.sec, tv.usec);
+#endif
+            _tv.tv_sec = tv.sec;
+            _tv.tv_usec = tv.usec;
+        }
+
+        eloop_sock_table_set_fds(&eloop.readers, rfds);
+        eloop_sock_table_set_fds(&eloop.writers, wfds);
+        eloop_sock_table_set_fds(&eloop.exceptions, efds);
+        res = select(eloop.max_sock + 1, rfds, wfds, efds,
+                 eloop.timeout ? &_tv : NULL);
+        if (res < 0 && errno != EINTR && errno != 0) {
+            perror("select");
+			ALOGE("select on socket failed\n");
+            goto out;
+        }
+        eloop_process_pending_signals();
+
+        /* check if some registered timeouts have occurred */
+        if (eloop.timeout) {
+            struct eloop_timeout *tmp;
+
+            os_get_time(&now);
+            if (!os_time_before(&now, &eloop.timeout->time)) {
+                tmp = eloop.timeout;
+                eloop.timeout = eloop.timeout->next;
+                tmp->handler(tmp->eloop_data,
+                         tmp->user_data);
+                os_free(tmp);
+            }
+
+        }
+
+        if (res <= 0)
+            continue;
+
+        eloop_sock_table_dispatch(&eloop.readers, rfds);
+        eloop_sock_table_dispatch(&eloop.writers, wfds);
+        eloop_sock_table_dispatch(&eloop.exceptions, efds);
+    }
+
+out:
+	ALOGI("eloop_run exit\n");
+    os_free(rfds);
+    os_free(wfds);
+    os_free(efds);
+}
+
+
+void eloop_terminate(void)
+{
+    eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+    struct eloop_timeout *timeout, *prev;
+    struct os_time now;
+
+    timeout = eloop.timeout;
+    if (timeout)
+        os_get_time(&now);
+    while (timeout != NULL) {
+        int sec, usec;
+        prev = timeout;
+        timeout = timeout->next;
+        sec = prev->time.sec - now.sec;
+        usec = prev->time.usec - now.usec;
+        if (prev->time.usec < now.usec) {
+            sec--;
+            usec += 1000000;
+        }
+        printf("ELOOP: remaining timeout: %d.%06d eloop_data=%p "
+               "user_data=%p handler=%p\n",
+               sec, usec, prev->eloop_data, prev->user_data,
+               prev->handler);
+        os_free(prev);
+    }
+    eloop_sock_table_destroy(&eloop.readers);
+    eloop_sock_table_destroy(&eloop.writers);
+    eloop_sock_table_destroy(&eloop.exceptions);
+    os_free(eloop.signals);
+}
+
+
+int eloop_terminated(void)
+{
+    return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+    fd_set rfds;
+
+    if (sock < 0)
+        return;
+
+    FD_ZERO(&rfds);
+    FD_SET(sock, &rfds);
+    select(sock + 1, &rfds, NULL, NULL, NULL);
+}
+
+
+void * eloop_get_user_data(void)
+{
+    return eloop.user_data;
+}
diff --git a/src/connectivity/combo_tool/src/stp_dump/eloop.h b/src/connectivity/combo_tool/src/stp_dump/eloop.h
new file mode 100755
index 0000000..333ee08
--- /dev/null
+++ b/src/connectivity/combo_tool/src/stp_dump/eloop.h
@@ -0,0 +1,375 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ */
+
+/*
+ * Event loop
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file defines an event loop interface that supports processing events
+ * from registered timeouts (i.e., do something after N seconds), sockets
+ * (e.g., a new packet available for reading), and signals. eloop.c is an
+ * implementation of this interface using select() and sockets. This is
+ * suitable for most UNIX/POSIX systems. When porting to other operating
+ * systems, it may be necessary to replace that implementation with OS specific
+ * mechanisms.
+ */
+
+#ifndef ELOOP_H
+#define ELOOP_H
+
+/**
+ * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts
+ */
+#define ELOOP_ALL_CTX (void *) -1
+
+/**
+ * eloop_event_type - eloop socket event type for eloop_register_sock()
+ * @EVENT_TYPE_READ: Socket has data available for reading
+ * @EVENT_TYPE_WRITE: Socket has room for new data to be written
+ * @EVENT_TYPE_EXCEPTION: An exception has been reported
+ */
+typedef enum {
+    EVENT_TYPE_READ = 0,
+    EVENT_TYPE_WRITE,
+    EVENT_TYPE_EXCEPTION
+} eloop_event_type;
+
+
+
+
+
+/**
+ * eloop_sock_handler - eloop socket event callback type
+ * @sock: File descriptor number for the socket
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx);
+
+/**
+ * eloop_event_handler - eloop generic event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_timeout_handler - eloop timeout event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_signal_handler - eloop signal event callback type
+ * @sig: Signal number
+ * @eloop_ctx: Registered callback context data (global user_data from
+ * eloop_init() call)
+ * @signal_ctx: Registered callback context data (user_data from
+ * eloop_register_signal(), eloop_register_signal_terminate(), or
+ * eloop_register_signal_reconfig() call)
+ */
+typedef void (*eloop_signal_handler)(int sig, void *eloop_ctx,
+                     void *signal_ctx);
+
+/**
+ * eloop_init() - Initialize global event loop data
+ * @user_data: Pointer to global data passed as eloop_ctx to signal handlers
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function must be called before any other eloop_* function. user_data
+ * can be used to configure a global (to the process) pointer that will be
+ * passed as eloop_ctx parameter to signal handlers.
+ */
+int eloop_init(void *user_data);
+
+/**
+ * eloop_register_read_sock - Register handler for read events
+ * @sock: File descriptor number for the socket
+ * @handler: Callback function to be called when data is available for reading
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a read socket notifier for the given file descriptor. The handler
+ * function will be called whenever data is available for reading from the
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
+ */
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+                 void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_read_sock - Unregister handler for read events
+ * @sock: File descriptor number for the socket
+ *
+ * Unregister a read socket notifier that was previously registered with
+ * eloop_register_read_sock().
+ */
+void eloop_unregister_read_sock(int sock);
+
+/**
+ * eloop_register_sock - Register handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event to wait for
+ * @handler: Callback function to be called when the event is triggered
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event notifier for the given socket's file descriptor. The
+ * handler function will be called whenever the that event is triggered for the
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
+ */
+int eloop_register_sock(int sock, eloop_event_type type,
+            eloop_sock_handler handler,
+            void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_sock - Unregister handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event for which sock was registered
+ *
+ * Unregister a socket event notifier that was previously registered with
+ * eloop_register_sock().
+ */
+void eloop_unregister_sock(int sock, eloop_event_type type);
+
+/**
+ * eloop_register_event - Register handler for generic events
+ * @event: Event to wait (eloop implementation specific)
+ * @event_size: Size of event data
+ * @handler: Callback function to be called when event is triggered
+ * @eloop_data: Callback context data (eloop_data)
+ * @user_data: Callback context data (user_data)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event handler for the given event. This function is used to
+ * register eloop implementation specific events which are mainly targetted for
+ * operating system specific code (driver interface and l2_packet) since the
+ * portable code will not be able to use such an OS-specific call. The handler
+ * function will be called whenever the event is triggered. The handler
+ * function is responsible for clearing the event after having processed it in
+ * order to avoid eloop from calling the handler again for the same event.
+ *
+ * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE
+ * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable,
+ * and they would call this function with eloop_register_event(h, sizeof(h),
+ * ...).
+ */
+int eloop_register_event(void *event, size_t event_size,
+             eloop_event_handler handler,
+             void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_event - Unregister handler for a generic event
+ * @event: Event to cancel (eloop implementation specific)
+ * @event_size: Size of event data
+ *
+ * Unregister a generic event notifier that was previously registered with
+ * eloop_register_event().
+ */
+void eloop_unregister_event(void *event, size_t event_size);
+
+/**
+ * eloop_register_timeout - Register timeout
+ * @secs: Number of seconds to the timeout
+ * @usecs: Number of microseconds to the timeout
+ * @handler: Callback function to be called when timeout occurs
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a timeout that will cause the handler function to be called after
+ * given time.
+ */
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+               eloop_timeout_handler handler,
+               void *eloop_data, void *user_data);
+
+/**
+ * eloop_cancel_timeout - Cancel timeouts
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all
+ * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all
+ * Returns: Number of cancelled timeouts
+ *
+ * Cancel matching <handler,eloop_data,user_data> timeouts registered with
+ * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for
+ * cancelling all timeouts regardless of eloop_data/user_data.
+ */
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+             void *eloop_data, void *user_data);
+
+/**
+ * eloop_is_timeout_registered - Check if a timeout is already registered
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is registered, 0 if the timeout is not registered
+ *
+ * Determine if a matching <handler,eloop_data,user_data> timeout is registered
+ * with eloop_register_timeout().
+ */
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+                void *eloop_data, void *user_data);
+
+/**
+ * eloop_register_signal - Register handler for signals
+ * @sig: Signal number (e.g., SIGHUP)
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a signal is received.
+ * The callback function is actually called only after the system signal
+ * handler has returned. This means that the normal limits for sighandlers
+ * (i.e., only "safe functions" allowed) do not apply for the registered
+ * callback.
+ *
+ * Signals are 'global' events and there is no local eloop_data pointer like
+ * with other handlers. The global user_data pointer registered with
+ * eloop_init() will be used as eloop_ctx for signal handlers.
+ */
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+              void *user_data);
+
+/**
+ * eloop_register_signal_terminate - Register handler for terminate signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a process termination
+ * signal is received. The callback function is actually called only after the
+ * system signal handler has returned. This means that the normal limits for
+ * sighandlers (i.e., only "safe functions" allowed) do not apply for the
+ * registered callback.
+ *
+ * Signals are 'global' events and there is no local eloop_data pointer like
+ * with other handlers. The global user_data pointer registered with
+ * eloop_init() will be used as eloop_ctx for signal handlers.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers handlers for SIGINT and SIGTERM.
+ */
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+                    void *user_data);
+
+/**
+ * eloop_register_signal_reconfig - Register handler for reconfig signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a reconfiguration /
+ * hangup signal is received. The callback function is actually called only
+ * after the system signal handler has returned. This means that the normal
+ * limits for sighandlers (i.e., only "safe functions" allowed) do not apply
+ * for the registered callback.
+ *
+ * Signals are 'global' events and there is no local eloop_data pointer like
+ * with other handlers. The global user_data pointer registered with
+ * eloop_init() will be used as eloop_ctx for signal handlers.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers a handler for SIGHUP.
+ */
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+                   void *user_data);
+
+/**
+ * eloop_run - Start the event loop
+ *
+ * Start the event loop and continue running as long as there are any
+ * registered event handlers. This function is run after event loop has been
+ * initialized with event_init() and one or more events have been registered.
+ */
+void eloop_run(void);
+
+/**
+ * eloop_terminate - Terminate event loop
+ *
+ * Terminate event loop even if there are registered events. This can be used
+ * to request the program to be terminated cleanly.
+ */
+void eloop_terminate(void);
+
+/**
+ * eloop_destroy - Free any resources allocated for the event loop
+ *
+ * After calling eloop_destroy(), other eloop_* functions must not be called
+ * before re-running eloop_init().
+ */
+void eloop_destroy(void);
+
+/**
+ * eloop_terminated - Check whether event loop has been terminated
+ * Returns: 1 = event loop terminate, 0 = event loop still running
+ *
+ * This function can be used to check whether eloop_terminate() has been called
+ * to request termination of the event loop. This is normally used to abort
+ * operations that may still be queued to be run when eloop_terminate() was
+ * called.
+ */
+int eloop_terminated(void);
+
+/**
+ * eloop_wait_for_read_sock - Wait for a single reader
+ * @sock: File descriptor number for the socket
+ *
+ * Do a blocking wait for a single read socket.
+ */
+void eloop_wait_for_read_sock(int sock);
+
+/**
+ * eloop_get_user_data - Get global user data
+ * Returns: user_data pointer that was registered with eloop_init()
+ */
+void * eloop_get_user_data(void);
+
+#endif /* ELOOP_H */
diff --git a/src/connectivity/combo_tool/src/stp_dump/os_linux.c b/src/connectivity/combo_tool/src/stp_dump/os_linux.c
new file mode 100755
index 0000000..288b7a2
--- /dev/null
+++ b/src/connectivity/combo_tool/src/stp_dump/os_linux.c
@@ -0,0 +1,492 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ * 
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ * 
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <dirent.h>
+//#include <cutils/properties.h>
+#include <sys/un.h>
+#include <dirent.h>
+#include "os_linux.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+    if (sec)
+        sleep(sec);
+    if (usec)
+        usleep(usec);
+}
+
+int os_get_time(struct os_time *t)
+{
+    int res;
+    struct timeval tv;
+    res = gettimeofday(&tv, NULL);
+    t->sec = tv.tv_sec;
+    t->usec = tv.tv_usec;
+    return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+          os_time_t *t)
+{
+    struct tm tm;
+
+    if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+        hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+        sec > 60)
+        return -1;
+
+    os_memset(&tm, 0, sizeof(tm));
+    tm.tm_year = year - 1900;
+    tm.tm_mon = month - 1;
+    tm.tm_mday = day;
+    tm.tm_hour = hour;
+    tm.tm_min = min;
+    tm.tm_sec = sec;
+
+    *t = (os_time_t) mktime(&tm);
+    return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+    if (daemon(0, 0)) {
+        perror("daemon");
+        return -1;
+    }
+
+    if (pid_file) {
+        FILE *f = fopen(pid_file, "w");
+        if (f) {
+            fprintf(f, "%u\n", getpid());
+            fclose(f);
+        }
+    }
+
+    return -0;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+    if (pid_file)
+        unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+    FILE *f;
+    size_t rc;
+
+    f = fopen("/dev/urandom", "rb");
+    if (f == NULL) {
+        printf("Could not open /dev/urandom.\n");
+        return -1;
+    }
+
+    rc = fread(buf, 1, len, f);
+    fclose(f);
+
+    return rc != len ? -1 : 0;
+}
+
+
+unsigned long os_random(void)
+{
+    return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+    char *buf = NULL, *cwd, *ret;
+    size_t len = 128, cwd_len, rel_len, ret_len;
+
+    if (rel_path[0] == '/')
+        return os_strdup(rel_path);
+
+    for (;;) {
+        buf = os_malloc(len);
+        if (buf == NULL)
+            return NULL;
+        cwd = getcwd(buf, len);
+        if (cwd == NULL) {
+            os_free(buf);
+            if (errno != ERANGE) {
+                return NULL;
+            }
+            len *= 2;
+        } else {
+            break;
+        }
+    }
+
+    cwd_len = strlen(cwd);
+    rel_len = strlen(rel_path);
+    ret_len = cwd_len + 1 + rel_len + 1;
+    ret = os_malloc(ret_len);
+    if (ret) {
+        os_memcpy(ret, cwd, cwd_len);
+        ret[cwd_len] = '/';
+        os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
+        ret[ret_len - 1] = '\0';
+    }
+    os_free(buf);
+    return ret;
+}
+
+
+int os_program_init(void)
+{
+    return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+    return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+    return unsetenv(name);
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+    FILE *f;
+    char *buf;
+
+    f = fopen(name, "rb");
+    if (f == NULL)
+        return NULL;
+
+    fseek(f, 0, SEEK_END);
+    *len = ftell(f);
+    fseek(f, 0, SEEK_SET);
+
+    buf = os_malloc(*len);
+    if (buf == NULL) {
+        fclose(f);
+        return NULL;
+    }
+
+    fread(buf, 1, *len, f);
+    fclose(f);
+
+    return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+    void *n = os_malloc(size);
+    if (n)
+        os_memset(n, 0, size);
+    return n;
+}
+
+
+void * os_malloc(size_t size)
+{
+    return malloc(size);
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+    return realloc(ptr, size);
+}
+
+
+void os_free(void *ptr)
+{
+    free(ptr);
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+    char *d = dest;
+    const char *s = src;
+    while (n--)
+        *d++ = *s++;
+    return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+    if (dest < src)
+        os_memcpy(dest, src, n);
+    else {
+        /* overlapping areas */
+        char *d = (char *) dest + n;
+        const char *s = (const char *) src + n;
+        while (n--)
+            *--d = *--s;
+    }
+    return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+    char *p = s;
+    while (n--)
+        *p++ = c;
+    return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+    const unsigned char *p1 = s1, *p2 = s2;
+
+    if (n == 0)
+        return 0;
+
+    while (*p1 == *p2) {
+        p1++;
+        p2++;
+        n--;
+        if (n == 0)
+            return 0;
+    }
+
+    return *p1 - *p2;
+}
+
+
+char * os_strdup(const char *s)
+{
+    char *res;
+    size_t len;
+    if (s == NULL)
+        return NULL;
+    len = os_strlen(s);
+    res = os_malloc(len + 1);
+    if (res)
+        os_memcpy(res, s, len + 1);
+    return res;
+}
+
+
+size_t os_strlen(const char *s)
+{
+    const char *p = s;
+    while (*p)
+        p++;
+    return p - s;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+    /*
+     * Ignoring case is not required for main functionality, so just use
+     * the case sensitive version of the function.
+     */
+    return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+    /*
+     * Ignoring case is not required for main functionality, so just use
+     * the case sensitive version of the function.
+     */
+    return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+    while (*s) {
+        if (*s == c)
+            return (char *) s;
+        s++;
+        //printf("==>s = %p\n", s);
+    }
+    return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+    const char *p = s;
+    while (*p)
+        p++;
+    p--;
+    while (p >= s) {
+        if (*p == c)
+            return (char *) p;
+        p--;
+    }
+    return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+    while (*s1 == *s2) {
+        if (*s1 == '\0')
+            break;
+        s1++;
+        s2++;
+    }
+
+    return *s1 - *s2;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+    if (n == 0)
+        return 0;
+
+    while (*s1 == *s2) {
+        if (*s1 == '\0')
+            break;
+        s1++;
+        s2++;
+        n--;
+        if (n == 0)
+            return 0;
+    }
+
+    return *s1 - *s2;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+    char *d = dest;
+
+    while (n--) {
+        *d = *src;
+        if (*src == '\0')
+            break;
+        d++;
+        src++;
+    }
+
+    return dest;
+}
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+    const char *s = src;
+    size_t left = siz;
+
+    if (left) {
+        /* Copy string up to the maximum size of the dest buffer */
+        while (--left != 0) {
+            if ((*dest++ = *s++) == '\0')
+                break;
+        }
+    }
+
+    if (left == 0) {
+        /* Not enough room for the string; force NUL-termination */
+        if (siz != 0)
+            *dest = '\0';
+        while (*s++)
+            ; /* determine total src string length */
+    }
+
+    return s - src - 1;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+    size_t len = os_strlen(needle);
+    while (*haystack) {
+        if (os_strncmp(haystack, needle, len) == 0)
+            return (char *) haystack;
+        haystack++;
+    }
+
+    return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+    va_list ap;
+    int ret;
+
+    /* See http://www.ijs.si/software/snprintf/ for portable
+     * implementation of snprintf.
+     */
+
+    va_start(ap, format);
+    ret = vsnprintf(str, size, format, ap);
+    va_end(ap);
+    if (size > 0)
+        str[size - 1] = '\0';
+    return ret;
+}
diff --git a/src/connectivity/combo_tool/src/stp_dump/os_linux.h b/src/connectivity/combo_tool/src/stp_dump/os_linux.h
new file mode 100755
index 0000000..44a10c4
--- /dev/null
+++ b/src/connectivity/combo_tool/src/stp_dump/os_linux.h
@@ -0,0 +1,117 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ * 
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ * 
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef OS_LINUX_H
+#define OS_LINUX_H
+
+typedef long os_time_t;
+
+void os_sleep(os_time_t sec, os_time_t usec);
+
+struct os_time {
+    os_time_t sec;
+    os_time_t usec;
+};
+
+
+#define os_time_before(a, b) \
+    ((a)->sec < (b)->sec || \
+     ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+
+#define os_time_sub(a, b, res) do { \
+    (res)->sec = (a)->sec - (b)->sec; \
+    (res)->usec = (a)->usec - (b)->usec; \
+    if ((res)->usec < 0) { \
+        (res)->sec--; \
+        (res)->usec += 1000000; \
+    } \
+} while (0)
+
+int os_get_time(struct os_time *t);
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+          os_time_t *t);
+int os_daemonize(const char *pid_file);
+void os_daemonize_terminate(const char *pid_file);
+int os_get_random(unsigned char *buf, size_t len);
+unsigned long os_random(void);
+char * os_rel2abs_path(const char *rel_path);
+int os_program_init(void);
+void os_program_deinit(void);
+int os_setenv(const char *name, const char *value, int overwrite);
+int os_unsetenv(const char *name);
+char * os_readfile(const char *name, size_t *len);
+void * os_zalloc(size_t size);
+void * os_malloc(size_t size);
+void * os_realloc(void *ptr, size_t size);
+void os_free(void *ptr);
+void * os_memcpy(void *dest, const void *src, size_t n);
+void * os_memmove(void *dest, const void *src, size_t n);
+void * os_memset(void *s, int c, size_t n);
+int os_memcmp(const void *s1, const void *s2, size_t n);
+char * os_strdup(const char *s);
+size_t os_strlen(const char *s);
+int os_strcasecmp(const char *s1, const char *s2);
+int os_strncasecmp(const char *s1, const char *s2, size_t n);
+char * os_strchr(const char *s, int c);
+char * os_strrchr(const char *s, int c);
+int os_strcmp(const char *s1, const char *s2);
+int os_strncmp(const char *s1, const char *s2, size_t n);
+char * os_strncpy(char *dest, const char *src, size_t n);
+size_t os_strlcpy(char *dest, const char *src, size_t siz);
+
+char * os_strstr(const char *haystack, const char *needle);
+int os_snprintf(char *str, size_t size, const char *format, ...);
+void os_sleep(os_time_t sec, os_time_t usec);
+int os_get_time(struct os_time *t);
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+          os_time_t *t);
+#define os_daemon daemon
+int os_daemonize(const char *pid_file);
+void os_daemonize_terminate(const char *pid_file);
+int os_get_random(unsigned char *buf, size_t len);
+unsigned long os_random(void);
+char * os_rel2abs_path(const char *rel_path);
+int os_program_init(void);
+void os_program_deinit(void);
+int os_setenv(const char *name, const char *value, int overwrite);
+int os_unsetenv(const char *name);
+char * os_readfile(const char *name, size_t *len);
+void * os_zalloc(size_t size);
+size_t os_strlcpy(char *dest, const char *src, size_t siz);
+
+#endif
+
diff --git a/src/connectivity/combo_tool/src/stp_dump/stp_dump.c b/src/connectivity/combo_tool/src/stp_dump/stp_dump.c
new file mode 100755
index 0000000..3593240
--- /dev/null
+++ b/src/connectivity/combo_tool/src/stp_dump/stp_dump.c
@@ -0,0 +1,1361 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ * 
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ * 
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#include <sys/stat.h>
+#include <grp.h>
+#include <stddef.h>
+//#include <cutils/sockets.h>
+//#include <android/log.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <dirent.h>
+//#include <cutils/properties.h>
+#include <sys/un.h>
+#include <dirent.h>
+#include <linux/limits.h>
+//#include <cutils/sockets.h>
+//#include <cutils/memory.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+//#include <sys/endian.h>
+#include <linux/serial.h> /* struct serial_struct  */
+#include <unistd.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <termios.h>
+#include <sys/poll.h>
+#include <linux/serial.h> /* struct serial_struct  */
+#include <sched.h>
+#include <netdb.h>
+#include <pthread.h>
+#include "os_linux.h"
+#include "stp_dump.h"
+#include "eloop.h"
+#include <linux/netlink.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#define LOGE printf
+#define LOGD printf
+
+#define GENL_ID_CTRL    NLMSG_MIN_TYPE
+#define GENL_HDRLEN     NLMSG_ALIGN(sizeof(struct genlmsghdr))
+#define COMBO_T32_DIR         "/data/misc/stp_dump/"
+#define COMBO_T32_NAME        "combo_t32"
+#define COMBO_T32_ENAME       ".cmm"
+#define COMBO_T32_NUM_MAX     50
+#define COM_STR_MAX 100
+
+enum {
+    CTRL_CMD_UNSPEC,
+    CTRL_CMD_NEWFAMILY,
+    CTRL_CMD_DELFAMILY,
+    CTRL_CMD_GETFAMILY,
+    CTRL_CMD_NEWOPS,
+    CTRL_CMD_DELOPS,
+    CTRL_CMD_GETOPS,
+    CTRL_CMD_NEWMCAST_GRP,
+    CTRL_CMD_DELMCAST_GRP,
+    CTRL_CMD_GETMCAST_GRP, /* unused */
+    __CTRL_CMD_MAX,
+};
+#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1)
+
+enum {
+    CTRL_ATTR_UNSPEC,
+    CTRL_ATTR_FAMILY_ID,
+    CTRL_ATTR_FAMILY_NAME,
+    CTRL_ATTR_VERSION,
+    CTRL_ATTR_HDRSIZE,
+    CTRL_ATTR_MAXATTR,
+    CTRL_ATTR_OPS,
+    CTRL_ATTR_MCAST_GROUPS,
+    __CTRL_ATTR_MAX,
+};
+
+#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
+
+struct genlmsghdr {
+    __u8    cmd;
+    __u8    version;
+    __u16   reserved;
+};
+
+#define GENLMSG_DATA(glh) ((void *)((long)NLMSG_DATA(glh) + GENL_HDRLEN))
+#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
+#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))
+
+typedef struct _tagGenericNetlinkPacket {
+    struct nlmsghdr n;
+    struct genlmsghdr g;
+    char buf[512*16];
+} GENERIC_NETLINK_PACKET, *P_GENERIC_NETLINK_PACKET;
+
+
+
+////typedef int socklen_t;
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+int stp_debug_level = MSG_MSGDUMP;
+
+struct stp_ctrl_dst {
+    struct stp_ctrl_dst *next;
+    struct sockaddr_un addr;
+    socklen_t addrlen;
+    int debug_level;
+    int errors;
+};
+
+struct ctrl_iface_priv {
+    struct stp_dump *stp_d;
+    int sock;
+    struct stp_ctrl_dst *ctrl_dst;
+};
+
+struct trace_iface_priv {
+    struct stp_dump *stp_d;
+    int sock;
+    struct {
+        FILE *fp_pkt;
+        FILE *fp_drv;
+        FILE *fp_fw;
+        FILE *fp_t32; 
+    } log_f;
+};
+
+struct stp_dump {
+    const char *ctrl_interface;
+    const char *ifname;
+    char *ctrl_interface_group;
+    int wmt_fd;
+    struct ctrl_iface_priv *ctrl_iface;
+    struct trace_iface_priv *trace_iface;
+};
+struct list_head {
+        char file_name[100];
+        struct list_head *next, *prev;
+};
+
+struct list_head list_head;
+int combo_t32_num = 0;
+
+static inline void INIT_LIST_HEAD(struct list_head *list) {
+    list->next = list;
+    list->prev = list;
+}
+
+static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) {
+    next->prev = new;
+    new->next = next;
+    new->prev = prev;
+    prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head) {
+    __list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head) {
+    __list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head * prev, struct list_head * next) {
+    next->prev = prev;
+    prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry) {
+    __list_del(entry->prev, entry->next);
+    entry->next = NULL;
+    entry->prev = NULL;
+}
+
+void bubble_sort(char *a[], int n)
+{
+    int i, j, len1, len2, len3;
+    char temp[COM_STR_MAX];
+    for (j = 0; j < n - 1; j++)
+        for (i = 0; i < n - 1 - j; i++) {
+            if (atoi(&a[i][10]) > atoi(&a[i+1][10])) {
+                len1 = (strlen(a[i]) <= COM_STR_MAX) ? strlen(a[i]) : COM_STR_MAX;
+                strncpy(temp, a[i], len1);
+                temp[len1-1] = '\0';
+                len2 = (strlen(a[i+1]) <= COM_STR_MAX) ? strlen(a[i+1]) : COM_STR_MAX;
+                strncpy(a[i], a[i+1], len2);
+                a[i][len2-1] = '\0';
+                len3 = (strlen(a[i+1]) <= COM_STR_MAX) ? strlen(a[i+1]) : COM_STR_MAX;
+                strncpy(a[i+1], temp, len3);
+                a[i+1][len3-1] = '\0';
+            }
+        }
+}
+/*
+void android_printf(int level, char *format, ...)
+{
+    if (level >= stp_debug_level) {
+        va_list ap;
+        if (level == MSG_ERROR) {
+            level = ANDROID_LOG_ERROR;
+        } else if (level == MSG_WARNING) {
+            level = ANDROID_LOG_WARN;
+        } else if (level == MSG_INFO) {
+            level = ANDROID_LOG_INFO;
+        } else {
+            level = ANDROID_LOG_DEBUG;
+        }
+        va_start(ap, format);
+        __android_log_vprint(level, "stp_dump", format, ap);
+        va_end(ap);
+    }
+}
+*/
+
+
+static void _stp_hexdump(int level, const char *title, const u8 *buf,
+             size_t len, int show)
+{
+    size_t i;
+    if (level < stp_debug_level)
+        return;
+
+    printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+    if (buf == NULL) {
+        printf(" [NULL]");
+    } else if (show) {
+        for (i = 0; i < len; i++)
+            printf(" %02x", buf[i]);
+    } else {
+        printf(" [REMOVED]");
+    }
+    printf("\n");
+}
+
+void stp_hexdump(int level, const char *title, const u8 *buf, size_t len)
+{
+    _stp_hexdump(level, title, buf, len, 1);
+}
+
+static void stp_dump_ctrl_iface_send(struct ctrl_iface_priv *priv,
+                       int level, const char *buf,
+                       size_t len);
+
+
+static int stp_dump_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+                        struct sockaddr_un *from,
+                        socklen_t fromlen)
+{
+    struct stp_ctrl_dst *dst;
+
+    dst = os_zalloc(sizeof(*dst));
+    if (dst == NULL)
+        return -1;
+    os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+    dst->addrlen = fromlen;
+    dst->debug_level = MSG_INFO;
+    dst->next = priv->ctrl_dst;
+    priv->ctrl_dst = dst;
+    stp_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
+            (u8 *) from->sun_path,
+            fromlen - offsetof(struct sockaddr_un, sun_path));
+    return 0;
+}
+
+static int stp_dump_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+                        struct sockaddr_un *from,
+                        socklen_t fromlen)
+{
+    struct stp_ctrl_dst *dst, *prev = NULL;
+
+    dst = priv->ctrl_dst;
+    while (dst) {
+        if (fromlen == dst->addrlen &&
+            os_memcmp(from->sun_path, dst->addr.sun_path,
+                  fromlen - offsetof(struct sockaddr_un, sun_path))
+            == 0) {
+            if (prev == NULL)
+                priv->ctrl_dst = dst->next;
+            else
+                prev->next = dst->next;
+            os_free(dst);
+            stp_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+                    (u8 *) from->sun_path,
+                    fromlen -
+                    offsetof(struct sockaddr_un, sun_path));
+            return 0;
+        }
+        prev = dst;
+        dst = dst->next;
+    }
+    return -1;
+}
+
+static int stp_dump_ctrl_iface_level(struct ctrl_iface_priv *priv,
+                       struct sockaddr_un *from,
+                       socklen_t fromlen,
+                       char *level)
+{
+    struct stp_ctrl_dst *dst;
+
+    ALOGD("CTRL_IFACE LEVEL %s\n", level);
+
+    dst = priv->ctrl_dst;
+    while (dst) {
+        if (fromlen == dst->addrlen &&
+            os_memcmp(from->sun_path, dst->addr.sun_path,
+                  fromlen - offsetof(struct sockaddr_un, sun_path))
+            == 0) {
+            stp_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
+                    "level", (u8 *) from->sun_path,
+                    fromlen -
+                    offsetof(struct sockaddr_un, sun_path));
+            dst->debug_level = atoi(level);
+            return 0;
+        }
+        dst = dst->next;
+    }
+
+    return -1;
+}
+
+static void stp_dump_ctrl_iface_receive(int sock, void *eloop_ctx,
+                          void *sock_ctx)
+{
+    struct stp_dump *stp_d = eloop_ctx;  
+    struct ctrl_iface_priv *priv = sock_ctx;
+    char buf[256];
+    int res;
+    struct sockaddr_un from;
+    socklen_t fromlen = sizeof(from);
+    char *reply = NULL;
+    size_t reply_len = 0;
+    int new_attached = 0;
+
+    res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+               (struct sockaddr *) &from, &fromlen);
+    if (res < 0) {
+        perror("recvfrom(ctrl_iface)");
+        return;
+    }
+    buf[res] = '\0';
+
+    if (os_strcmp(buf, "ATTACH") == 0) {
+        if (stp_dump_ctrl_iface_attach(priv, &from, fromlen))
+            reply_len = 1;
+        else {
+            new_attached = 1;
+            reply_len = 2;
+        }
+    } else if (os_strcmp(buf, "DETACH") == 0) {
+        if (stp_dump_ctrl_iface_detach(priv, &from, fromlen))
+            reply_len = 1;
+        else
+            reply_len = 2;
+    } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+        if (stp_dump_ctrl_iface_level(priv, &from, fromlen,
+                            buf + 6))
+            reply_len = 1;
+        else
+            reply_len = 2;
+    } else {
+        //stp_hexdump(MSG_INFO, "stp_dump_ctrl_iface_process", buf, 4);
+        //reply = stp_dump_ctrl_iface_process(stp_d, buf,
+        //                      &reply_len);
+    }
+#if 0
+    if (reply) {
+       if ( 0 > sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen))
+           perror("send reply error\n");
+        os_free(reply);
+    } else if (reply_len == 1) {
+#else
+    if (reply_len == 1) {
+#endif
+       if (0 > sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, fromlen))
+           perror("send string 'FAIL' to sock error\n");
+    } else if (reply_len == 2) {
+        if ( 0 > sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen))
+            perror("send string 'OK' to sock error\n");
+    }
+}
+
+
+static char * stp_dump_ctrl_iface_path(struct stp_dump *stp_d)
+{
+    char *buf;
+    size_t len;
+    char *pbuf, *dir = NULL, *gid_str = NULL;
+    int res;
+
+    if (stp_d->ctrl_interface == NULL)
+    {
+        ALOGE("stp_d->ctrl_interface = NULL\n");
+        return NULL;    
+    }
+    pbuf = os_strdup(stp_d->ctrl_interface);
+
+    if (pbuf == NULL)
+    {
+        ALOGD("copy string failed\n");
+        return NULL;
+    }
+    if (os_strncmp(pbuf, "DIR=", 4) == 0) {
+        dir = pbuf + 4;
+        gid_str = os_strstr(dir, " GROUP=");
+        if (gid_str) {
+            *gid_str = '\0';
+            gid_str += 7;
+        }
+    } else
+        dir = pbuf;
+    
+    len = os_strlen(dir) + os_strlen(stp_d->ifname) + 2;
+    buf = os_malloc(len);
+    if (buf == NULL) 
+    {
+        ALOGE("memory allocation failed\n");
+        os_free(pbuf);
+        return NULL;
+    }
+
+    res = os_snprintf(buf, len, "%s/%s", dir, stp_d->ifname);
+    if (res < 0 || (size_t) res >= len) 
+    {
+        ALOGE("os_snprintf failed\n");
+        os_free(pbuf);
+        os_free(buf);
+        return NULL;
+    }
+    os_free(pbuf);
+    return buf;
+}
+
+static void stp_dump_ctrl_iface_msg_cb(void *ctx, int level,
+                         const char *txt, size_t len)
+{
+    struct stp_dump *stp_d = ctx;
+    if (stp_d == NULL || stp_d->ctrl_iface == NULL)
+        return;
+    stp_dump_ctrl_iface_send(stp_d->ctrl_iface, level, txt, len);
+}
+
+int stp_dump_ctrl_iface_trace_logger_init(struct trace_iface_priv *tr_priv) {
+    char str[100] = {""};
+    char *file_name[50] = {NULL};
+    int i = 0;
+    struct dirent *pDirent = NULL;
+    DIR *pDir = NULL;
+    struct list_head *node;
+
+    sprintf(str, "%s%s%s", COMBO_T32_DIR, COMBO_T32_NAME, COMBO_T32_ENAME);
+    tr_priv->log_f.fp_t32 = fopen(str, "a+");
+    if (tr_priv->log_f.fp_t32 == NULL) {
+        ALOGE("create combo_fw.log fails, exit errno:%d\n", errno);
+        exit(EXIT_FAILURE);
+    }
+    if (0 != remove(str))
+        perror("remove combo_fw fails\n");
+
+    pDir = opendir(COMBO_T32_DIR);
+    if (NULL == pDir) {
+        ALOGE("coredump patch cannot be opened\n");
+        exit(EXIT_FAILURE);
+    }
+    /* stp_printf(MSG_ERROR, "coredump patch opened\n"); */
+
+    while (NULL != (pDirent = readdir(pDir))) {
+        if (0 == strncmp(pDirent->d_name, COMBO_T32_NAME, sizeof(COMBO_T32_NAME)-1)) {
+            if (combo_t32_num < COMBO_T32_NUM_MAX) {
+                file_name[combo_t32_num] = malloc(100);
+                strcpy(file_name[combo_t32_num], pDirent->d_name);
+                /* stp_printf(MSG_ERROR, "file name:%s\n", file_name[combo_t32_num]); */
+                combo_t32_num++;
+                /* stp_printf(MSG_ERROR, "combo_t32_num:%d\n", combo_t32_num); */
+            } else {
+                /* stp_printf(MSG_ERROR, "file num more than the max\n"); */
+                break;
+            }
+            }
+        }
+    closedir(pDir);
+    bubble_sort(file_name, combo_t32_num);
+
+    INIT_LIST_HEAD(&list_head);
+    for (i = 0; i < combo_t32_num; i++) {
+        node = malloc(sizeof(struct list_head));
+        sprintf(node->file_name, "%s%s", COMBO_T32_DIR, file_name[i]);
+        list_add_tail(node, &list_head);
+        /* stp_printf(MSG_ERROR, "file name:%s\n", node->file_name); */
+        free(file_name[i]);
+    }
+    fclose(tr_priv->log_f.fp_t32);
+    ALOGI("close file combo_t32\n");
+    return 0;
+}
+
+int stp_dump_ctrl_iface_trace_logger_decode(int sock, void *eloop_ctx,
+                          void *sock_ctx)
+{
+    struct nlattr *na;
+    char *stpmsghdr = NULL;
+    char *packet_raw = NULL;      
+    int size;
+    struct trace_iface_priv *tr_priv = sock_ctx;
+    GENERIC_NETLINK_PACKET mBuffer;
+    GENERIC_NETLINK_PACKET *prBuffer;
+    int i;
+    int len;
+    
+    if ((size = recv(sock, &mBuffer, sizeof(mBuffer), 0)) < 0) 
+    {
+        LOGE("recv failed (%s)\n", strerror(errno));
+        return -1;
+    }
+    
+    prBuffer = &mBuffer;
+
+    /* Validate response message */
+    if (!NLMSG_OK(&(prBuffer->n), (unsigned int)size))
+    {
+        LOGE("invalid reply message\n");
+        return -1;
+    }
+    else if (prBuffer->n.nlmsg_type == NLMSG_ERROR) 
+    { /* error */
+        LOGE("received error\n");
+        return -1;
+    }
+    else if (!NLMSG_OK((&prBuffer->n), (unsigned int)size)) 
+    {
+        LOGE("invalid reply message received via Netlink\n");
+        return -1;
+    }
+
+    size = GENLMSG_PAYLOAD(&prBuffer->n);
+    na = (struct nlattr *) GENLMSG_DATA(prBuffer);
+    
+    stpmsghdr = (char *)NLA_DATA(na);
+    if ((stpmsghdr[0] == '[') &&
+        (stpmsghdr[1] == 'M') &&
+        (stpmsghdr[2] == ']')) {
+        static char start_dump = 1;
+
+        /* TODO: parsing message to know the action to start dump */
+        if (start_dump) {
+            char combo_t32[100] = {""};
+            char date[64];
+            time_t t = time(0);
+            struct list_head *node;
+
+            strftime(date, sizeof(date), "%Y%m%d%H%M%S", localtime(&t));
+            sprintf(combo_t32, "%s%s_%s%s", COMBO_T32_DIR, COMBO_T32_NAME, date, COMBO_T32_ENAME);
+            /*fclose(tr_priv->log_f.fp_t32);*/
+            tr_priv->log_f.fp_t32 = 0;
+            tr_priv->log_f.fp_t32 = fopen(combo_t32, "w");
+            if (0 != chmod(combo_t32, 00664)) {
+                perror("chmod combo_t32 error\n");
+                return -1;
+            }
+            /* stp_printf(MSG_DEBUG, "create a new file %s\n", combo_t32); */
+            combo_t32_num++;
+
+            if (combo_t32_num < COMBO_T32_NUM_MAX) {
+                node = malloc(sizeof(struct list_head));
+                /* stp_printf(MSG_ERROR, "create a new node\n"); */
+            } else {
+                    node = list_head.next;
+                    list_del(list_head.next);
+                   if (0 != remove(node->file_name)) {
+                       perror("remove node->file error\n");
+                   }
+                    /* stp_printf(MSG_ERROR, "combo_t32_num more than max:%d\n", combo_t32_num); */
+                    /* stp_printf(MSG_ERROR, "remove file:%s\n", node->file_name); */
+            }
+            strcpy(node->file_name, combo_t32);
+            list_add_tail(node, &list_head);
+
+            len = stpmsghdr[4];
+            len <<= 8;
+            len += stpmsghdr[3];
+            for (i = 0; i < len; i++)
+                fprintf(tr_priv->log_f.fp_t32, "%c",  stpmsghdr[5+i]);
+            fflush(tr_priv->log_f.fp_t32);
+            ioctl(tr_priv->stp_d->wmt_fd, 10, &stpmsghdr[5]);
+            start_dump = 0;
+            /* stp_printf(MSG_DEBUG, "rev coredump len:%d\n", len); */
+            /* stp_printf(MSG_DEBUG, "rev coredump date:%s\n", &stpmsghdr[5]); */
+        } else {
+            len = stpmsghdr[4];
+            len <<= 8;
+            len += stpmsghdr[3];
+            for (i = 0; i < len; i++)
+                fprintf(tr_priv->log_f.fp_t32, "%c",  stpmsghdr[5+i]);
+            fflush(tr_priv->log_f.fp_t32);
+            /* stp_printf(MSG_DEBUG, "rev coredump len:%d\n", len); */
+            /* stp_printf(MSG_DEBUG, "rev coredump date:%s\n", &stpmsghdr[5]); */
+        }
+        if (len < 1024) {
+            i = 0;
+            do {
+                i++;
+            }while(('c' != stpmsghdr[len - i]) && (i < 50));
+        }
+        if (strstr(&stpmsghdr[5], "coredump end") || strstr(&stpmsghdr[len - i], "coredump end")) {
+            /* inform user to dump action is done */
+            ioctl(tr_priv->stp_d->wmt_fd, 11, 0);
+            start_dump = 1;
+            ALOGD("coredump end\n");
+        }
+    } else
+    {
+        LOGE("invalid dump data\n");
+    }
+    
+    return 0;
+}
+
+int stp_dump_ctrl_iface_trace_logger_sendto_fd(int s, const char *buf, int bufLen)
+{
+    struct sockaddr_nl nladdr;
+    int r;
+
+    memset(&nladdr, 0, sizeof(nladdr));
+    nladdr.nl_family = AF_NETLINK;
+
+    while ((r = sendto(s, buf, bufLen, 0, (struct sockaddr *) &nladdr,
+                    sizeof(nladdr))) < bufLen) 
+    {
+        if (r > 0) 
+        {
+            buf += r;
+            bufLen -= r;
+        } 
+        else if (errno != EAGAIN)
+        {
+            ALOGE("%s failed\n", __func__);
+            return -1;
+        }
+    }
+	ALOGI("%s succeed\n", __func__);
+    return 0;
+}
+
+/*
+ * Probe the controller in genetlink to find the family id
+ */
+int stp_dump_ctrl_iface_trace_logger_get_family_id(int sk, const char *family_name)
+{
+    struct nlattr *na;
+    int rep_len;
+    int id = -1;
+    GENERIC_NETLINK_PACKET family_req, ans;
+
+    /* Get family name */
+    family_req.n.nlmsg_type = GENL_ID_CTRL;
+    family_req.n.nlmsg_flags = NLM_F_REQUEST;
+    family_req.n.nlmsg_seq = 0;
+    family_req.n.nlmsg_pid = getpid();
+    family_req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+    family_req.g.cmd = CTRL_CMD_GETFAMILY;
+    family_req.g.version = 0x1;
+
+    na = (struct nlattr *) GENLMSG_DATA(&family_req);
+    na->nla_type = CTRL_ATTR_FAMILY_NAME;
+    na->nla_len = strlen(family_name) + 1 + NLA_HDRLEN;
+    strcpy((char *)NLA_DATA(na), family_name);
+ 
+    family_req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
+
+    if (stp_dump_ctrl_iface_trace_logger_sendto_fd(sk, (char *) &family_req, family_req.n.nlmsg_len) < 0) 
+    {
+        ALOGE("%s failed\n", __func__);
+        return -1;
+    }
+
+    rep_len = recv(sk, &ans, sizeof(ans), 0);
+    if (rep_len < 0)
+    {
+        ALOGE("no response\n");
+        return -1;
+    }
+    /* Validate response message */
+    else if (!NLMSG_OK((&ans.n), (unsigned int)rep_len))
+    {
+        ALOGE("invalid reply message\n");
+        return -1;
+    }
+    else if (ans.n.nlmsg_type == NLMSG_ERROR) 
+    { /* error */
+        ALOGE("received error\n");
+        return -1;
+    }
+
+    na = (struct nlattr *) GENLMSG_DATA(&ans);
+    na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
+    if (na->nla_type == CTRL_ATTR_FAMILY_ID) 
+    {
+        id = *(__u16 *) NLA_DATA(na);
+    }
+
+    return id;
+}
+
+int stp_dump_ctrl_iface_trace_logger_start(struct trace_iface_priv *tr_priv){
+    
+    struct sockaddr_nl nladdr;
+    int sz = 64 * 1024;
+    GENERIC_NETLINK_PACKET ans, req;
+    struct nlattr *na;
+    int id;
+    int mlength = 14;
+    const char *message = "HELLO"; //message
+    int rc;
+    int count = 100;
+      
+    stp_dump_ctrl_iface_trace_logger_init(tr_priv);
+
+    memset(&nladdr, 0, sizeof(nladdr));
+    nladdr.nl_family = AF_NETLINK;
+    nladdr.nl_pid = getpid();
+    //nladdr.nl_groups = 0xffffffff;
+
+    if ((tr_priv->sock= socket(AF_NETLINK,
+                        SOCK_RAW,NETLINK_GENERIC)) < 0) 
+    {
+        ALOGE("Unable to create uevent socket: %s", strerror(errno));
+        return -1;
+    }
+
+    if (setsockopt(tr_priv->sock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) 
+    {
+        ALOGE("Unable to set uevent socket options: %s", strerror(errno));
+        return -1;
+    }
+
+    if (bind(tr_priv->sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) 
+    {
+        ALOGD("Unable to bind uevent socket: %d:%s\n", errno, strerror(errno));
+        return -1;
+    }
+
+    while(count--) 
+    {
+        id = stp_dump_ctrl_iface_trace_logger_get_family_id(tr_priv->sock, "STP_DBG");
+        if (-1 == id) 
+        {
+            ALOGD("Unable to get family id, Retry");
+            sleep(3);
+        } 
+        else 
+        {
+            ALOGD("[STP_DBG] family id = %d\n", id);
+            printf("[STP_DBG] family id = %d\n", id);
+            break;
+        }
+    }
+    
+    req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+    req.n.nlmsg_type = id;
+    req.n.nlmsg_flags = NLM_F_REQUEST;
+    req.n.nlmsg_seq = 60;
+    req.n.nlmsg_pid = getpid();
+    req.g.cmd = 1; 
+    
+    na = (struct nlattr *) GENLMSG_DATA(&req);
+    na->nla_type = 1; //MTK_WIFI_ATTR_MSG
+    na->nla_len = mlength + NLA_HDRLEN; //message length
+    memcpy(NLA_DATA(na), message, strlen(message));
+    req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
+
+    ALOGI( "sending dummy command\n");
+    
+    memset(&nladdr, 0, sizeof(nladdr));
+    nladdr.nl_family = AF_NETLINK;
+
+    rc = sendto(tr_priv->sock, (char *)&req, req.n.nlmsg_len, 0,
+            (struct sockaddr *) &nladdr, sizeof(nladdr));
+#if 0
+    if (rc > 0) 
+    {
+        stp_printf(MSG_INFO, "sending dummy command okay\n");
+    }
+    else if (errno != EAGAIN)
+    {
+        stp_printf(MSG_ERROR, "%s failed\n", __func__); 
+        return -1;
+    }    
+#endif
+    eloop_register_read_sock(tr_priv->sock, stp_dump_ctrl_iface_trace_logger_decode,
+                 tr_priv->stp_d, tr_priv);    
+    return 0;
+}
+
+struct ctrl_iface_priv *
+stp_dump_ctrl_iface_init(struct stp_dump *stp_d)
+{
+    struct ctrl_iface_priv *priv;
+    struct trace_iface_priv *tr_priv;
+    struct sockaddr_un addr;
+    char *fname = NULL;
+    gid_t gid = 0;
+    int gid_set = 0;
+    char *buf, *dir = NULL, *gid_str = NULL;
+    struct group *grp;
+    char *endp;
+
+    priv = os_zalloc(sizeof(*priv));
+    if (priv == NULL)
+    {   
+        ALOGE("memory allocation for priv failed\n");
+        return NULL;
+    }
+
+    tr_priv = os_zalloc(sizeof(*tr_priv));
+    if(tr_priv == NULL)
+    {
+        ALOGE("memory allocation for tr_priv failed\n");
+        os_free(priv);
+        priv = NULL;
+        return NULL;
+    }
+
+    priv->stp_d = stp_d;
+    priv->sock = -1;
+
+    tr_priv->stp_d = stp_d;
+    tr_priv->sock = -1;
+
+    if (stp_d->ctrl_interface == NULL)
+    {   
+        ALOGE("stp_d->ctrl_interface = NULL\n");
+        os_free(tr_priv);
+        tr_priv = NULL;
+        return priv;
+    }
+
+    buf = os_strdup(stp_d->ctrl_interface);
+    if (buf == NULL)
+    {
+        ALOGE("os_strdup\n");
+        goto fail;
+    }
+
+    os_snprintf(addr.sun_path, sizeof(addr.sun_path), "stp_%s",
+            stp_d->ctrl_interface);
+    ALOGI("addr.sun_path:%s\n", addr.sun_path);
+    /*priv->sock = android_get_control_socket(addr.sun_path);
+    if (priv->sock >= 0)
+    {
+        ALOGI("priv->sock already exist\n");
+        goto havesock;
+    }*/
+
+    if (os_strncmp(buf, "DIR=", 4) == 0) {
+        dir = buf + 4;
+        gid_str = os_strstr(dir, " GROUP=");
+        if (gid_str) {
+            *gid_str = '\0';
+            gid_str += 7;
+        }
+    } else {
+        dir = buf;
+        gid_str = stp_d->ctrl_interface_group;
+    }
+
+    if (mkdir(dir, 00777) < 0)
+    {
+        if (errno == EEXIST)
+        {
+            ALOGI("Using existing control "
+                   "interface directory.\n");
+        }
+        else
+        {
+            ALOGE("mkdir (%s) failed\n", dir);
+            perror("mkdir[ctrl_interface]");
+            goto fail;
+        }
+    }
+    ALOGE("mkdir (%s) succeed\n", dir);
+    if (gid_str)
+    {
+        grp = getgrnam("sys");
+        if (grp)
+        {
+            gid = grp->gr_gid;
+            gid_set = 1;
+            ALOGI("ctrl_interface_group=%d"
+                   " (from group name '%s')\n",
+                   (int) gid, gid_str);
+        }
+        else
+        {
+            // Group name not found - try to parse this as gid
+            gid = strtol(gid_str, &endp, 10);
+            if (*gid_str == '\0' || *endp != '\0') {
+                ALOGE("CTRL: Invalid group "
+                       "'%s'\n", gid_str);
+                goto fail;
+            }
+            gid_set = 1;
+            ALOGI("ctrl_interface_group=%d\n",
+                   (int) gid);
+        }
+    }
+
+    if (gid_set && chown(dir,  getuid(), gid) < 0)
+    {
+        perror("chown[ctrl_interface]");
+		ALOGE("chown (%s) failed\n", dir);
+        goto fail;
+    }
+    ALOGI("chown (%s) succeed\n", dir);
+	
+    // Make sure the group can enter and read the directory
+    if (gid_set &&
+    chmod(dir, 00775) < 0)
+    {
+        ALOGE("CTRL: chmod[%s]: %s\n", dir, strerror(errno));
+        goto fail;
+    }
+    ALOGI("CTRL: chmod[%s] succeed\n", dir);
+    if (os_strlen(dir) + 1 + os_strlen(stp_d->ifname) >=
+        sizeof(addr.sun_path)) 
+    {
+        ALOGE("ctrl_iface path limit exceeded\n");
+        goto fail;
+    }
+
+    stp_dump_ctrl_iface_trace_logger_start(tr_priv);
+    priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+    if (priv->sock < 0) 
+    {
+        perror("socket(PF_UNIX)");
+		ALOGE("create socket failed\n");
+        goto fail;
+    }
+
+    os_memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+
+    fname = stp_dump_ctrl_iface_path(stp_d);
+
+    if (fname == NULL)
+    {
+        ALOGE("stp_dump_ctrl_iface_path failed\n");
+        goto fail;
+    }
+    os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+    if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        ALOGE("ctrl_iface bind(PF_UNIX) failed: %s\n",
+               strerror(errno));
+        if (connect(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+            ALOGE("ctrl_iface exists, but does not"
+                   " allow connections - assuming it was left"
+                   "over from forced program termination\n");
+            if (unlink(fname) < 0) {
+                perror("unlink[ctrl_iface]");
+                ALOGE("Could not unlink "
+                       "existing ctrl_iface socket '%s'\n",
+                       fname);
+                goto fail;
+            }
+            if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+                perror("bind(PF_UNIX)");
+                goto fail;
+            }
+            ALOGE("Successfully replaced leftover " "ctrl_iface socket '%s'\n", fname);
+        } else {
+            ALOGI("ctrl_iface exists and seems to " "be in use - cannot override it\n");
+            ALOGI("Delete '%s' manually if it is "
+                   "not used anymore\n", fname);
+            os_free(fname);
+            fname = NULL;
+            goto fail;
+        }
+    }
+    if (gid_set && chown(fname, -1, gid) < 0) {
+        perror("chown[ctrl_interface/ifname]");
+		ALOGE("chown(%s) failed, ", fname);
+        goto fail;
+    }
+
+    if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+        perror("chmod[ctrl_interface/ifname]");
+		ALOGE("chmod(%s) failed, ", fname);
+        goto fail;
+    }
+    os_free(fname);
+    fname = NULL;
+    /* open wmt dev */
+    stp_d->wmt_fd = open("/dev/stpwmt", O_RDWR | O_NOCTTY);
+    if (stp_d->wmt_fd < 0) {
+        ALOGE("[%s] Can't open stpwmt \n", __FUNCTION__);
+        goto fail;
+    }
+
+havesock:
+    eloop_register_read_sock(priv->sock, stp_dump_ctrl_iface_receive,
+                 stp_d, priv);
+
+    os_free(buf);
+    buf = NULL;
+    return priv;
+
+fail:
+    if (priv->sock >= 0)
+        close(priv->sock);
+    os_free(priv);
+    if (fname) {
+        unlink(fname);
+        os_free(fname);
+        fname = NULL;
+    }
+    os_free(buf);
+    buf = NULL;
+    return NULL;
+}
+
+
+void stp_dump_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+#if 0
+    struct wpa_ctrl_dst *dst, *prev;
+#endif
+    struct stp_ctrl_dst *dst, *prev;
+    ALOGI("%s\n", __func__);
+    os_sleep(1, 0);
+    /* close wmt dev */
+    if (priv->stp_d->wmt_fd >= 0) {
+        close(priv->stp_d->wmt_fd);
+    }
+    if (priv->sock > -1) {
+        char *fname;
+        char *buf, *dir = NULL, *gid_str = NULL;
+        eloop_unregister_read_sock(priv->sock);
+        if (priv->ctrl_dst) {
+            /*
+             * Wait a second before closing the control socket if
+             * there are any attached monitors in order to allow
+             * them to receive any pending messages.
+             */
+            ALOGD("CTRL_IFACE wait for attached "
+                   "monitors to receive messages\n");
+            os_sleep(1, 0);
+        }
+        close(priv->sock);
+        priv->sock = -1;
+#if 0        
+        fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s);
+#endif
+        fname = stp_dump_ctrl_iface_path(priv->stp_d);
+        if (fname) {
+            unlink(fname);
+            os_free(fname);
+            fname = NULL;
+        }
+#if 0
+        buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
+#endif  
+        buf = os_strdup(priv->stp_d->ctrl_interface);
+        if (buf == NULL)
+            goto free_dst;
+        if (os_strncmp(buf, "DIR=", 4) == 0) {
+            dir = buf + 4;
+            gid_str = os_strstr(dir, " GROUP=");
+            if (gid_str) {
+                *gid_str = '\0';
+                gid_str += 7;
+            }
+        } else
+            dir = buf;
+
+        if (rmdir(dir) < 0) {
+            if (errno == ENOTEMPTY) {
+                ALOGE("Control interface "
+                       "directory not empty - leaving it "
+                       "behind\n");
+            } else {
+                perror("rmdir[ctrl_interface]");
+            }
+        }
+        os_free(buf);
+    }
+
+free_dst:
+    dst = priv->ctrl_dst;
+    while (dst) {
+        prev = dst;
+        dst = dst->next;
+        os_free(prev);
+    }
+    os_free(priv);
+}
+
+
+/**
+ * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
+ * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ * @level: Priority level of the message
+ * @buf: Message data
+ * @len: Message length
+ *
+ * Send a packet to all monitor programs attached to the control interface.
+ */
+static void stp_dump_ctrl_iface_send(struct ctrl_iface_priv *priv,
+                       int level, const char *buf,
+                       size_t len)
+{
+    struct stp_ctrl_dst *dst, *next;
+    char levelstr[10];
+    int idx, res;
+    struct msghdr msg;
+    struct iovec io[2];
+
+    dst = priv->ctrl_dst;
+    if (priv->sock < 0 || dst == NULL)
+        return;
+
+    res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+    if (res < 0 || (size_t) res >= sizeof(levelstr))
+        return;
+    io[0].iov_base = levelstr;
+    io[0].iov_len = os_strlen(levelstr);
+    io[1].iov_base = (char *) buf;
+    io[1].iov_len = len;
+    os_memset(&msg, 0, sizeof(msg));
+    msg.msg_iov = io;
+    msg.msg_iovlen = 2;
+
+    idx = 0;
+    while (dst) {
+        next = dst->next;
+        if (level >= dst->debug_level) {
+            stp_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+                    (u8 *) dst->addr.sun_path, dst->addrlen -
+                    offsetof(struct sockaddr_un, sun_path));
+            msg.msg_name = (void *) &dst->addr;
+            msg.msg_namelen = dst->addrlen;
+            if (sendmsg(priv->sock, &msg, 0) < 0) {
+                int _errno = errno;
+                ALOGI("CTRL_IFACE monitor[%d]: "
+                       "%d - %s\n",
+                       idx, errno, strerror(errno));
+                dst->errors++;
+                if (dst->errors > 10 || _errno == ENOENT) {
+                    stp_dump_ctrl_iface_detach(
+                        priv, &dst->addr,
+                        dst->addrlen);
+                }
+            } else
+                dst->errors = 0;
+        }
+        idx++;
+        dst = next;
+    }
+}
+
+
+void stp_dump_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+    char buf[256];
+    int res;
+    struct sockaddr_un from;
+    socklen_t fromlen = sizeof(from);
+
+    for (;;) {
+        ALOGD("CTRL_IFACE - %s - wait for monitor to "
+               "attach\n", priv->stp_d->ifname);
+        eloop_wait_for_read_sock(priv->sock);
+
+        res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
+                   (struct sockaddr *) &from, &fromlen);
+        if (res < 0) {
+            perror("recvfrom(ctrl_iface)");
+            continue;
+        }
+        buf[res] = '\0';
+
+        if (os_strcmp(buf, "ATTACH") == 0) {
+            /* handle ATTACH signal of first monitor interface */
+            if (!stp_dump_ctrl_iface_attach(priv, &from,
+                                  fromlen)) {
+               if (0 > sendto(priv->sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen))
+                   perror("send string 'OK' to sock error\n");
+                /* OK to continue */
+                return;
+            } else {
+                if (0 > sendto(priv->sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, fromlen))
+                    perror("send string 'FAIL' to sock error\n");
+            }
+        } else {
+            /* return FAIL for all other signals */
+           if (0 > sendto(priv->sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, fromlen))
+                perror("send string 'FAIL' to sock error\n");
+        }
+    }
+}
+
+static void stp_dump_terminate(int sig, void *eloop_ctx,
+                     void *signal_ctx)
+{
+    eloop_terminate();
+}
+
+int stp_dump_run(void)
+{
+    eloop_register_signal_terminate(stp_dump_terminate, NULL);
+    eloop_run();
+    return 0;
+}
+
+void set_sched_prio(void)
+{
+    struct sched_param sched, test_sched;
+    int policy = 0xff;
+    int err=0xff;
+
+    policy = sched_getscheduler(0);
+    sched_getparam(0, &test_sched);
+    printf("Before %s policy = %d, priority = %d\n", "main" , policy, test_sched.sched_priority);
+
+    sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
+    err = sched_setscheduler(0, SCHED_FIFO, &sched);
+    if(err == 0){
+         printf("pthread_setschedparam SUCCESS \n");
+         policy = sched_getscheduler(0);
+         sched_getparam(0, &test_sched);
+         printf("After %s policy = %d, priority = %d\n", "main" ,policy , test_sched.sched_priority);
+    }
+    else{
+         if(err == EINVAL) printf("policy is not one of SCHED_OTHER, SCHED_RR, SCHED_FIFO\n");
+         if(err == EINVAL) printf("the  priority  value  specified by param is not valid for the specified policy\n");
+         if(err == EPERM) printf("the calling process does not have superuser permissions\n");
+         if(err == ESRCH) printf("the target_thread is invalid or has already terminated\n");
+         if(err == EFAULT)  printf("param points outside the process memory space\n");
+         printf("pthread_setschedparam FAIL \n");
+    }
+}
+
+int main(int argc, char *argv[]){
+
+    struct stp_dump *stp_d = NULL;
+    const char *conf ="DIR=/data/misc/stp_dump GROUP=stp";
+    const char *ifname = "stpd";
+    char value[PROPERTY_VALUE_MAX];
+
+    ALOGI("==>%s \n", __func__ );
+/*
+    property_get("ro.crypto.state", value, "");
+    if (!strcmp(value, "")) {
+            do {
+                    stp_printf(MSG_INFO, "ro.crypto.state is NULL, Retry");
+                    sleep(1);
+                    property_get("ro.crypto.state", value, "");
+                    stp_printf(MSG_INFO, "ro.crypto.state: %s!", value);
+            }while(!strcmp(value, ""));
+    }
+    stp_printf(MSG_INFO, "ro.crypto.state: %s!", value);
+    if (0 == strcmp(value, "encrypted")) {
+            property_get("vold.decrypt", value, "");
+            if (strcmp(value, "trigger_restart_framework")) {
+                    do {
+                            stp_printf(MSG_INFO, "Waiting for decrypt done");
+                            sleep(1);
+                            property_get("vold.decrypt", value, "");
+                            stp_printf(MSG_INFO, "vold.decrypt: %s!", value);
+                    }while(strcmp(value, "trigger_restart_framework"));
+            }
+            stp_printf(MSG_INFO, "vold.decrypt: %s!", value);
+            stp_printf(MSG_INFO, "Decrypt done!");
+    } else
+            stp_printf(MSG_INFO, "Device is unencrypted!");
+*/
+    stp_d = os_zalloc(sizeof(struct stp_dump));
+    if (stp_d == NULL)
+    {   
+        ALOGE("memory allocation for stp_dump failed\n");
+        return -1;
+    }
+    stp_d->ctrl_interface = conf;
+    stp_d->ifname = ifname;
+    stp_d->ctrl_iface = stp_dump_ctrl_iface_init(stp_d);
+    if (stp_d->ctrl_iface == NULL) 
+    {
+        ALOGE("Failed to initialize control interface '%s'.\n"
+               "You may have another stp_dump process "
+               "already running or the file was\n"
+               "left by an unclean termination of stp_dump "
+               "in which case you will need\n"
+               "to manually remove this file before starting "
+               "wpa_supplicant again.\n",
+               "used by stp_dump\n");
+        return -1;
+    } 
+    else 
+    {
+        ALOGI("stp_dump_ctrl_iface_init succeed.\n");
+    }
+    ALOGI("==>%s222 \n", __func__ );
+
+    //set_sched_prio();
+   
+    stp_dump_run();
+
+    stp_dump_ctrl_iface_deinit(stp_d->ctrl_iface);
+    os_free(stp_d);
+
+    return 0;
+}
diff --git a/src/connectivity/combo_tool/src/stp_dump/stp_dump.h b/src/connectivity/combo_tool/src/stp_dump/stp_dump.h
new file mode 100755
index 0000000..c3fca88
--- /dev/null
+++ b/src/connectivity/combo_tool/src/stp_dump/stp_dump.h
@@ -0,0 +1,68 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ * 
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ * 
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef STP_DUMP_H
+#define STP_DUMP_H
+extern int stp_debug_level;
+
+#ifndef ALOGI
+#define ALOGI printf
+#endif
+#ifndef ALOGE
+#define ALOGE printf
+#endif
+#ifndef ALOGD
+#define ALOGD printf
+#endif
+
+#ifndef PROPERTY_VALUE_MAX
+#define PROPERTY_VALUE_MAX (128)
+#endif
+
+
+enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
+extern void android_printf(int level, char *format, ...);
+#define stp_printf(level, ...) \
+        do {                                            \
+            if ((level) >= MSG_MSGDUMP) {                  \
+                android_printf((level), __VA_ARGS__);   \
+            }                                           \
+            printf(__VA_ARGS__);  \
+        } while (0)
+
+#endif
+
diff --git a/src/connectivity/combo_tool/src/stp_uart_launcher.c b/src/connectivity/combo_tool/src/stp_uart_launcher.c
new file mode 100755
index 0000000..237bc26
--- /dev/null
+++ b/src/connectivity/combo_tool/src/stp_uart_launcher.c
@@ -0,0 +1,1927 @@
+
+/******************************************************************************
+*                         C O M P I L E R   F L A G S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                    E X T E R N A L   R E F E R E N C E S
+*******************************************************************************
+*/
+#include "wmt_ioctl.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <pthread.h>
+/*#include <syslog.h>*/
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/endian.h>
+#include <sys/uio.h>
+#include <linux/serial.h> /* struct serial_struct  */
+#include <utils/Log.h>
+
+//For directory operation
+#include <dirent.h>
+#include <cutils/properties.h>
+
+
+/******************************************************************************
+*                              C O N S T A N T S
+*******************************************************************************
+*/
+
+#define  WCN_COMBO_CHIP_ID_PROP     "persist.mtk.wcn.combo.chipid"
+#define  WCN_DRIVER_READY_PROP      "service.wcn.driver.ready"
+#define  WCN_COMBO_COREDUMP_PROP    "service.wcn.coredump.mode"
+#define  WCN_FW_DBG_LOG_PROP        "persist.mtk.wcn.fwlog.status"
+#define  WCN_DYNAMIC_DUMP_PROP      "persist.mtk.wcn.dynamic.dump"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "6620_launcher"
+//#include "cust_mt6620_test.h" /* project custom header file */
+
+#ifndef N_MTKSTP
+#define N_MTKSTP    (15 + 1)  /* MediaTek WCN Serial Transport Protocol */
+#endif
+
+#define HCIUARTSETPROTO        _IOW('U', 200, int)
+
+#define CUST_COMBO_WMT_DEV "/dev/stpwmt"
+#define CUST_COMBO_STP_DEV "/dev/ttyMT2" //-- for ALPS
+#define CUST_COMBO_PATCH_PATH "/etc/firmware" //-- for ALPS
+
+
+#define CUST_BAUDRATE_DFT (115200)
+
+#define CUST_MULTI_PATCH (1)
+#define MTK_WCN_ENABLE_COREDUMP_BY_PROPERTY 0
+
+typedef enum {
+    STP_MIN = 0x0,
+    STP_UART_FULL = 0x1,
+    STP_UART_MAND = 0x2,
+    STP_BTIF_FULL = 0x3,
+    STP_SDIO = 0x4,
+    STP_MAX = 0x5,
+}STP_MODE;
+
+#define MAX_CMD_LEN (NAME_MAX+1)
+
+typedef enum {
+    UART_DISABLE_FC = 0, /*NO flow control*/
+    UART_MTK_SW_FC = 1,  /*MTK SW Flow Control, differs from Linux Flow Control*/
+    UART_LINUX_FC = 2,   /*Linux SW Flow Control*/
+    UART_HW_FC = 3,      /*HW Flow Control*/
+} STP_UART_FC;
+
+typedef struct 
+{
+    const char *key;
+    const char *defValue;
+    char value[PROPERTY_VALUE_MAX];
+    
+}SYS_PROPERTY;
+
+
+typedef struct {
+    STP_UART_FC fc;
+    int parity;
+    int stop_bit;
+} STP_UART_CONFIG;
+
+typedef struct {
+    STP_MODE eStpMode;
+    char *pPatchPath;
+    char *pPatchName;
+    char *gStpDev;
+    int iBaudrate;
+    STP_UART_CONFIG sUartConfig;
+}STP_PARAMS_CONFIG, *P_STP_PARAMS_CONFIG;
+
+
+#if CUST_MULTI_PATCH
+typedef struct {
+    int dowloadSeq;
+    char addRess[4];
+    char patchName[256];
+}STP_PATCH_INFO,*P_STP_PATCH_INFO;
+#endif
+
+typedef struct {
+    const char *pCfgItem;
+    char cfgItemValue[NAME_MAX + 1];
+}CHIP_ANT_MODE_INFO, *P_CHIP_ANT_MODE_INFO;
+
+
+typedef struct {
+    int chipId; 
+    STP_MODE stpMode;
+    CHIP_ANT_MODE_INFO antMode;
+}CHIP_MODE_INFO, *P_CHIP_MODE_INFO;
+#ifndef WMT_PLAT_APEX
+CHIP_MODE_INFO gChipModeInfo[] = {
+    {0x6620, STP_UART_FULL, {"mt6620.defAnt", "mt6620_ant_m3.cfg"}},
+    {0x6628, STP_UART_FULL, {"mt6628.defAnt", "mt6628_ant_m1.cfg"}},
+    {0x6630, STP_UART_FULL, {"mt6630.defAnt", "mt6630_ant_m1.cfg"}},
+};
+#else
+CHIP_MODE_INFO gChipModeInfo[] = {
+    {0x6620, STP_UART_FULL, {"mt6620.defAnt", "WMT.cfg"}},
+    {0x6628, STP_UART_FULL, {"mt6628.defAnt", "WMT.cfg"}},
+    {0x6630, STP_UART_FULL, {"mt6630.defAnt", "WMT.cfg"}},
+};
+#endif
+/******************************************************************************
+*                             D A T A   T Y P E S
+*******************************************************************************
+*/
+struct cmd_hdr{
+    char *pCmd;
+    int (*hdr_func)(P_STP_PARAMS_CONFIG pStpParamsConfig);
+};
+
+struct speed_map {
+    unsigned int baud;
+    speed_t      speed;
+};
+
+/******************************************************************************
+*                                 M A C R O S
+*******************************************************************************
+*/
+#define INIT_CMD(c, e, s) {.cmd= c, .cmd_sz=sizeof(c), .evt=e, .evt_sz=sizeof(e), .str=s}
+
+/******************************************************************************
+*                   F U N C T I O N   D E C L A R A T I O N S
+*******************************************************************************
+*/
+static int set_speed(int fd, struct termios *ti, int speed);
+int setup_uart_param (int hComPort, int iBaudrate, STP_UART_CONFIG *stp_uart);
+
+int cmd_hdr_baud_115k (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_921k (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_2_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_3kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_3_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_3_25kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_3_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_4kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_stp_open (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_stp_close (P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_stp_rst(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_sch_patch (P_STP_PARAMS_CONFIG pStpParamsConfig);
+static int check_chip_id(void);
+static int setHifInfo(int chipId, char *cfgFilePath);
+static int wmt_cfg_item_parser(char *pItem);
+static int get_wmt_cfg (int chipId);
+static speed_t get_speed (int baudrate);
+
+
+/******************************************************************************
+*                            P U B L I C   D A T A
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                           P R I V A T E   D A T A
+*******************************************************************************
+*/
+static struct speed_map speeds[] = {
+    {115200,    B115200},
+    {921600,    B921600},
+    {1000000,    B1000000},
+    {1152000,    B1152000},
+    {2000000,    B2000000},
+    {2500000,    B2500000},
+    {3000000,    B3000000},
+    {3500000,    B3500000},
+    {4000000,    B4000000},
+};
+
+static STP_UART_CONFIG g_stp_uart_config;
+
+struct cmd_hdr cmd_hdr_table[] = {
+    { "baud_115200_0", cmd_hdr_baud_115k},
+    { "baud_921600_0", cmd_hdr_baud_921k},    
+    { "baud_2000000_0", cmd_hdr_baud_2kk},
+    { "baud_2500000_0", cmd_hdr_baud_2_5kk},    
+    { "baud_3000000_0", cmd_hdr_baud_3kk},
+    //{ "baud_3200000_0", cmd_hdr_baud_3_2kk},
+    //{ "baud_3250000_0", cmd_hdr_baud_3_25kk},   
+    { "baud_3500000_0", cmd_hdr_baud_3_5kk},
+    { "baud_4000000_0", cmd_hdr_baud_4kk},
+    { "open_stp", cmd_hdr_stp_open},
+    { "close_stp", cmd_hdr_stp_close},
+    { "rst_stp", cmd_hdr_stp_rst},
+    { "srh_patch", cmd_hdr_sch_patch},
+};
+
+static volatile sig_atomic_t __io_canceled = 0;
+static char gPatchName[NAME_MAX+1]= {0};
+static char gPatchFolder[NAME_MAX+1]= {0};
+static char gStpDev[NAME_MAX+1]= {0};
+static int gStpMode = -1;
+static char gWmtCfgName[NAME_MAX+1] = {0};
+static int gWmtFd = -1;
+static int gTtyFd = -1;
+static char gCmdStr[MAX_CMD_LEN]= {0};
+static char gRespStr[MAX_CMD_LEN]= {0};
+static int gFmMode = 2; /* 1: i2c, 2: comm I/F */
+static const char *gUartName = NULL;
+
+#if CUST_MULTI_PATCH
+static unsigned int gPatchNum = 0;
+static unsigned int gDwonSeq = 0; 
+static P_STP_PATCH_INFO pStpPatchInfo = NULL;
+static STP_PATCH_INFO gStpPatchInfo;
+#endif
+
+pthread_t thread_handle = -1;
+/******************************************************************************
+*                              F U N C T I O N S
+*******************************************************************************
+*/
+
+/* Used as host uart param setup callback */
+int setup_uart_param (
+    int hComPort,
+    int iBaudrate,
+    STP_UART_CONFIG *stpUartConfig)
+{
+    struct termios ti;
+    int  fd;
+
+    if(!stpUartConfig){
+        ALOGE("Invalid stpUartConfig");
+        return -2;
+    }
+    
+    ALOGI("setup_uart_param %d %d\n", iBaudrate, stpUartConfig->fc);
+
+    fd = hComPort;
+    if (fd < 0) {
+        ALOGE("Invalid serial port");
+        return -2;
+    }
+
+    tcflush(fd, TCIOFLUSH);
+
+    if (tcgetattr(fd, &ti) < 0) {
+        ALOGE("Can't get port settings");
+        return -3;
+    }
+
+    cfmakeraw(&ti);
+
+    ALOGI("ti.c_cflag = 0x%08x\n", ti.c_cflag);
+    ti.c_cflag |= CLOCAL;
+    ALOGI("CLOCAL = 0x%x\n", CLOCAL);
+    ALOGI("(ori)ti.c_iflag = 0x%08x\n", ti.c_iflag);
+    ALOGI("(ori)ti.c_cflag = 0x%08x\n", ti.c_cflag);
+    ALOGI("stpUartConfig->fc= %d (0:none,sw,hw,linux)\n", stpUartConfig->fc);
+     
+    if(stpUartConfig->fc == UART_DISABLE_FC){
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    } else if(stpUartConfig->fc == UART_MTK_SW_FC){
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag |= 0x80000000; /*MTK Software FC*/
+    } else if(stpUartConfig->fc == UART_HW_FC){ 
+        ti.c_cflag |= CRTSCTS;      /*RTS, CTS Enable*/
+        ti.c_iflag &= ~(0x80000000);
+    } else if(stpUartConfig->fc == UART_LINUX_FC){
+        ti.c_iflag |= (IXON | IXOFF | IXANY); /*Linux Software FC*/
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    }else {
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    }
+    
+    ALOGI("c_c CRTSCTS = 0x%16x\n", CRTSCTS);
+    ALOGI("c_i IXON = 0x%08x\n", IXON);
+    ALOGI("c_i IXOFF = 0x%08x\n", IXOFF);
+    ALOGI("c_i IXANY = 0x%08x\n", IXANY);
+    ALOGI("(aft)ti.c_iflag = 0x%08x\n", ti.c_iflag);
+    ALOGI("(aft)ti.c_cflag = 0x%08x\n\n", ti.c_cflag);
+
+    if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+        ALOGE("Can't set port settings");
+        return -4;
+    }
+
+    /* Set baudrate */
+    if (set_speed(fd, &ti, iBaudrate) < 0) {
+        ALOGE("Can't set initial baud rate");
+        return -5;
+    }
+
+    tcflush(fd, TCIOFLUSH);
+
+    return 0;
+}
+
+static void sig_hup(int sig)
+{
+    fprintf(stderr, "sig_hup...\n");
+}
+
+static void sig_term(int sig)
+{
+    fprintf(stderr, "sig_term...\n");
+    __io_canceled = 1;
+    ioctl(gWmtFd, WMT_IOCTL_SET_LAUNCHER_KILL, 1);
+}
+
+
+static speed_t get_speed (int baudrate)
+{
+    unsigned int idx;
+    for (idx = 0; idx < sizeof(speeds)/sizeof(speeds[0]); idx++) {
+        if (baudrate == (int)speeds[idx].baud) {
+            return speeds[idx].speed;
+        }
+    }
+    return CBAUDEX;
+}
+
+int set_speed(int fd, struct termios *ti, int speed)
+{
+    struct serial_struct ss;
+    int baudenum = get_speed(speed);
+
+    if (speed != CBAUDEX) {
+        //printf("%s: standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum);
+        if ((ioctl(fd, TIOCGSERIAL, &ss)) < 0) {
+            ALOGI("%s: BAUD: error to get the serial_struct info:%s\n", __FUNCTION__, strerror(errno));
+            return -1;
+        }
+        ss.flags &= ~ASYNC_SPD_CUST;
+#if defined(SERIAL_STRUCT_EXT) /*modified in serial_struct.h*/
+        memset(ss.reserved, 0x00, sizeof(ss.reserved));
+#endif
+        ss.flags |= (1 << 13);    /*set UPFLOWLATENCY flat to tty, or serial_core will reset tty->low_latency to 0*/
+        /*set standard buadrate setting*/
+        if ((ioctl(fd, TIOCSSERIAL, &ss)) < 0) {
+            ALOGI("%s: BAUD: error to set serial_struct:%s\n", __FUNCTION__, strerror(errno));
+            return -2;
+        }
+        cfsetospeed(ti, baudenum);
+        cfsetispeed(ti, baudenum);
+        return tcsetattr(fd, TCSANOW, ti);
+    }
+    else {
+        ALOGI("%s: unsupported non-standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum);
+        return -3;
+    }
+}
+
+
+int cmd_hdr_baud_115k (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 115200, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_921k (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 921600, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 2000000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_2_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 2500000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_3kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3000000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_3_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3200000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_3_25kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3250000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_3_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3500000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_4kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 4000000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_stp_open (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    int ld;
+    if ((STP_UART_FULL == gStpMode) && (-1 == gTtyFd)) {
+        gTtyFd = open(gStpDev, O_RDWR | O_NOCTTY);
+        if (gTtyFd < 0) {
+            fprintf(stderr, "Can't open serial port %s\n", gStpDev);
+            return -2;
+        }
+        ALOGI("real_tty(%s) opened(%d)\n", gStpDev, gTtyFd);
+
+        /* Set TTY to N_MTKSTP line discipline */
+        ld = N_MTKSTP;
+        if (ioctl(gTtyFd, TIOCSETD, &ld) < 0) {
+            fprintf(stderr, "Can't set ldisc to N_MTKSTP\n");
+            return -3;
+        }
+
+         //printf("Set tty->low_latency\n");
+         if (ioctl(gTtyFd, HCIUARTSETPROTO, 0) < 0) {
+                ALOGE("Can't set HCIUARTSETPROTO\n");
+                return -4;
+        }
+        return 0;
+    }
+    else {
+        fprintf(stderr, "stp_open fail: stp_mode(%d) real_tty_fd(%d) \n", gStpMode, gTtyFd);
+        return -1;
+    }
+}
+
+int cmd_hdr_stp_close (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    int ld;
+
+    if ((STP_UART_FULL == gStpMode) && (0 <= gTtyFd)) {
+        /* Restore TTY line discipline */
+        ld = N_TTY;
+        if (ioctl(gTtyFd, TIOCSETD, &ld) < 0) {
+            ALOGE("Can't restore line discipline");
+            return -2;
+        }
+
+        close(gTtyFd);
+        gTtyFd = -1;
+        return 0;
+    } else if (gTtyFd == -1) {
+        return 0;
+    } else {
+        fprintf(stderr, "stp_close fail: stp_mode(%d) real_tty_fd(%d) \n", gStpMode, gTtyFd);
+        return -1;
+    }
+}
+
+int cmd_hdr_stp_rst (P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    int ret = 0;
+    /*this step fail?*/
+    ret = cmd_hdr_stp_close(pStpParamsConfig);
+    /*here, launcher is close state*/
+    ret = cmd_hdr_stp_open(pStpParamsConfig);
+    return ret;
+}
+
+#if CUST_MULTI_PATCH
+int cmd_hdr_sch_patch (P_STP_PARAMS_CONFIG pStpParamsConfig)
+{
+    //#define PATCH_PATH "/system/etc/firmware"
+    int chipId = 0;
+    int hwVersion = 0;
+    int fwVersion = 0;
+    char chipName[16] = {0};
+    char patchFullName[256] = {0};
+    unsigned int patchVer = 0;
+    DIR *pDir = NULL;
+    int patchFd = -1;
+    int iRet = 0;
+    int bytes;
+    unsigned int patchNum = 0;
+    char patchInfo[8] = {0};
+    unsigned int isFirst = 1;
+    P_STP_PATCH_INFO pstPaInfo = NULL;
+    struct dirent* pDirent = NULL;
+    
+    if (gWmtFd > 0)
+    {
+        /*1. ioctl to get CHIP ID*/
+        chipId = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 0);
+		if((0x0321 == chipId) || (0x0335 == chipId) || (0x0337 == chipId))
+		{
+			chipId = 0x6735;
+			ALOGI("for denali chipid convert\n");
+		}
+        if (0x0326 == chipId) {
+          chipId = 0x6755;
+          ALOGI("for jade chipid convert\n");
+        }
+        if (0x0279 == chipId) {
+          chipId = 0x6797;
+          ALOGI("for everest chipid convert\n");
+        }
+        strncpy(chipName, "mt",strlen("mt"));
+        sprintf(chipName + strlen("mt"), "%04x", chipId);
+
+#if 0
+		/* single patch 6630 */
+        if(!strcmp(chipName,"mt6630"))//apply to MT6630
+        {
+            strcat (chipName, "_patch");
+            ALOGI ("6630 patch name pre-fix:%s\n", chipName);
+
+            /*2. ioctl to get FIRMWARE VERSION*/
+            fwVersion = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 2);
+            ALOGI ("fwVersion:0x%04x\n", fwVersion);
+
+            /*3. open directory patch located*/
+            if (NULL == pStpParamsConfig->pPatchPath)
+            {
+                pStpParamsConfig->pPatchPath = CUST_COMBO_PATCH_PATH;
+            }
+			pDir = opendir(pStpParamsConfig->pPatchPath);
+			if (NULL == pDir)
+			{
+				ALOGE("patch path cannot be opened");
+				iRet = -1;
+				return iRet;
+			}
+			while (NULL != (pDirent = readdir(pDir)))
+			{
+				patchVer = 0;
+				
+				if (0 == (strncmp(pDirent->d_name, chipName, strlen(chipName))))
+				{    /*4.1. search patch name begined with chipName*/
+					strcpy (patchFullName, pStpParamsConfig->pPatchPath);
+					strcat (patchFullName, "/"); // robust, if input patch is /etc/firmwre/ no issue should be happened.
+					strcat (patchFullName, pDirent->d_name);
+					
+					ALOGI ("%s\n", patchFullName);
+					/*4.1. search patch name mt[CHIP ID]xxx.bin*/
+					if (0 < (patchFd = (open(patchFullName, O_RDONLY ))))
+					{
+						/*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */
+						if (-1 != lseek (patchFd, 22, SEEK_SET))
+						{
+							read(patchFd, ((char *)&patchVer) + 1, 1);
+							read(patchFd, ((char *)&patchVer), 1);
+							/*print hardware version information in patch*/
+							ALOGI ("fw Ver in patch: 0x%04x\n", patchVer);
+							if (0 == ((patchVer ^ fwVersion) & 0x00ff))
+							{
+								ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, patchFullName);
+								ALOGI ("fw Ver in patch matches with firmware version\n");
+								close (patchFd);
+								break;
+							}
+						}
+						else
+						{
+							ALOGE("seek failed\n");
+						}
+						close (patchFd);
+						patchFd = -1;
+					}
+					else
+					{
+						ALOGI("open patch file(%s) failed\n", patchFullName);
+						//ALOGE(patchFullName);
+					}
+				}
+			}
+			/*5. return value*/
+			closedir(pDir);
+			pDir = NULL;
+        }
+#endif
+
+        if ((!strcmp(chipName, "mt6620")) || (!strcmp(chipName, "mt6628")) || (!strcmp(chipName, "mt6630")) ||
+            (!strcmp(chipName, "mt6572")) || (!strcmp(chipName, "mt6582")) || (!strcmp(chipName, "mt6592")) ||
+            (!strcmp(chipName, "mt8127"))|| (!strcmp(chipName, "mt7623"))  || (!strcmp(chipName, "mt6571")) || (!strcmp(chipName, "mt6752")) ||
+            (!strcmp(chipName, "mt8163")) || (!strcmp(chipName, "mt6580")) ||
+            (!strcmp(chipName, "mt6735")) || (!strcmp(chipName, "mt6755")) || (!strcmp(chipName, "mt6797")))
+        {
+            if ((!strcmp(chipName, "mt6572")) || (!strcmp(chipName, "mt6582")) || (!strcmp(chipName, "mt6592")))
+        	{
+                strncpy(chipName, "ROMv1", strlen("ROMv1"));
+        		chipName[5] = '\0';
+        	}else if(!strcmp(chipName,"mt8127") || !strcmp(chipName,"mt6571")){
+				strncpy(chipName,"ROMv2",strlen("ROMv2"));
+				chipName[5] = '\0';
+            } else if (!strcmp(chipName, "mt6755") ||!strcmp(chipName, "mt6752") || !strcmp(chipName, "mt6735")
+                        || !strcmp(chipName, "mt8163") || !strcmp(chipName, "mt6580") || !strcmp(chipName, "mt7623")) {
+                        strncpy(chipName, "ROMv2_lm", strlen("ROMv2_lm"));
+            } else if (!strcmp(chipName, "mt6797")) {
+                strncpy(chipName, "ROMv3", strlen("ROMv3"));
+                chipName[5] = '\0';
+            }
+        	strcat (chipName, "_patch");
+            ALOGI ("patch name pre-fix:%s\n", chipName);
+            /*2. ioctl to get FIRMWARE VERSION*/
+            fwVersion = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 2);
+            ALOGI ("fwVersion:0x%04x\n", fwVersion);
+            /*3. open directory patch located*/
+            if (NULL == pStpParamsConfig->pPatchPath)
+            {
+                pStpParamsConfig->pPatchPath = CUST_COMBO_PATCH_PATH;
+            }
+
+            {
+                pDir = opendir(pStpParamsConfig->pPatchPath);
+                if (NULL == pDir)
+                {
+                    ALOGE("patch path cannot be opened");
+                    iRet = -1;
+                    return iRet;
+                }
+                while (NULL != (pDirent = readdir(pDir)))
+                {
+                    patchVer = 0;
+                    
+                    if (0 == (strncmp(pDirent->d_name, chipName, strlen(chipName))))
+                    {    /*4.1. search patch name begined with chipName*/
+                        strcpy (patchFullName, pStpParamsConfig->pPatchPath);
+                        strcat (patchFullName, "/"); // robust, if input patch is /etc/firmwre/ no issue should be happened.
+                        strcat (patchFullName, pDirent->d_name);
+                        
+                        ALOGI ("%s\n", patchFullName);
+                        /*4.1. search patch name mt[CHIP ID]xxx.bin*/
+                        if (0 <= (patchFd = (open(patchFullName, O_RDONLY ))))
+                        {
+                          /*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */
+                            if (-1 != lseek (patchFd, 22, SEEK_SET))
+                            {
+                                memset(&gStpPatchInfo,0,sizeof(gStpPatchInfo));
+                                memset(patchInfo,0,sizeof(patchInfo));
+                                
+                                bytes = read(patchFd, ((char *)&patchVer) + 1, 1);
+                                if (-1 == bytes) {
+                                    ALOGI ("read patchVer1 failed!\n");
+                                    goto readfailed;
+                                }
+                                bytes = read(patchFd, ((char *)&patchVer), 1);
+                                if (-1 == bytes) {
+                                    ALOGI ("read patchVer failed!\n");
+                                    goto readfailed;
+                                }
+                                  /*print hardware version information in patch*/
+                                ALOGI ("fw Ver in patch: 0x%04x\n", patchVer);
+                                if (0 == ((patchVer ^ fwVersion) & 0x00ff)) {
+                                    bytes = read(patchFd, patchInfo, 4);
+                                    if (-1 == bytes) {
+                                        ALOGI ("read patchInfo failed!\n");
+                                        goto readfailed;
+                                     }
+                                    patchInfo[4] = '\0';
+                                    ALOGI("read patch info:0x%02x,0x%02x,0x%02x,0x%02x\n",patchInfo[0],patchInfo[1],patchInfo[2],patchInfo[3]);
+                                    if (1 == isFirst) {
+                                        gPatchNum = (patchInfo[0] & 0xF0) >> 4;
+                                        ALOGI("gpatchnum = [%d]\n",gPatchNum);
+                                        ioctl(gWmtFd,WMT_IOCTL_SET_PATCH_NUM,gPatchNum);
+
+                                        gDwonSeq = (patchInfo[0] & 0x0F);
+                                        ALOGI("gdwonseq = [%d]\n",gDwonSeq);
+                                        gStpPatchInfo.dowloadSeq = gDwonSeq;
+                                        memcpy(gStpPatchInfo.addRess,patchInfo,sizeof(gStpPatchInfo.addRess));
+                                        gStpPatchInfo.addRess[0] = 0x00;
+                                        strncpy(gStpPatchInfo.patchName, patchFullName, sizeof(gStpPatchInfo.patchName) - 1);
+                                        gStpPatchInfo.patchName[sizeof(gStpPatchInfo.patchName) - 1] = '\0';
+                                        //printf("gStpPatchInfo address info:0x%02x,0x%02x,0x%02x,0x%02x\n",gStpPatchInfo.addRess[0],gStpPatchInfo.addRess[1],gStpPatchInfo.addRess[2],gStpPatchInfo.addRess[3]);
+                                        ioctl(gWmtFd,WMT_IOCTL_SET_PATCH_INFO,&gStpPatchInfo);
+										isFirst ++;
+                                     } else {
+                                        gDwonSeq = (patchInfo[0] & 0x0F);
+                                        ALOGI("gdwonseq = [%d]\n",gDwonSeq);
+                                        gStpPatchInfo.dowloadSeq = gDwonSeq;
+                                        memcpy(gStpPatchInfo.addRess,patchInfo,sizeof(gStpPatchInfo.addRess));
+                                        gStpPatchInfo.addRess[0] = 0x00;
+                                        strncpy(gStpPatchInfo.patchName, patchFullName, sizeof(gStpPatchInfo.patchName) - 1);
+                                        gStpPatchInfo.patchName[sizeof(gStpPatchInfo.patchName) - 1] = '\0';
+                                        //printf("gStpPatchInfo address info:0x%02x,0x%02x,0x%02x,0x%02x\n",gStpPatchInfo.addRess[0],gStpPatchInfo.addRess[1],gStpPatchInfo.addRess[2],gStpPatchInfo.addRess[3]);
+                                        ioctl(gWmtFd,WMT_IOCTL_SET_PATCH_INFO,&gStpPatchInfo);
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                ALOGE("seek failed\n");
+                            }
+readfailed:
+                            close (patchFd);
+                            patchFd = -1;
+                        }
+                        else
+                        {
+                            ALOGI("open patch file(%s) failed\n", patchFullName);
+                            //ALOGE(patchFullName);
+                        }
+					}
+                }
+                /*5. return value*/
+                closedir(pDir);
+                pDir = NULL;
+            }
+        }
+    }
+    else
+    {
+        ALOGE("file descriptor is not valid\n");
+        iRet = -2;
+    }
+    return iRet;
+}
+#else
+int cmd_hdr_sch_patch (P_STP_PARAMS_CONFIG pStpParamsConfig)
+{
+    //#define PATCH_PATH "/system/etc/firmware"
+    int chipId = 0;
+    int hwVersion = 0;
+    int fwVersion = 0;
+    char chipName[16] = {0};
+    char patchFullName[256] = {0};
+    unsigned int patchVer = 0;
+    DIR *pDir = NULL;
+    int patchFd = -1;
+    struct dirent* pDirent = NULL;
+    int iRet = -1;
+	
+    if (gWmtFd > 0)
+    {
+    /*1. ioctl to get CHIP ID*/
+        chipId = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 0);
+        strcpy(chipName, "mt");
+        sprintf (chipName + strlen(chipName), "%04x", chipId);
+        strcat (chipName, "_patch");
+        ALOGI ("patch name pre-fix:%s\n", chipName);
+#if 0        
+    /*2. ioctl to get HARDWARE VERSION*/
+        hwVersion = ioctl(gWmtFd, 12, 1);
+        ALOGI ("hwVersion:0x%04x\n", hwVersion);
+#else
+    /*2. ioctl to get FIRMWARE VERSION*/
+        fwVersion = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 2);
+        ALOGI ("fwVersion:0x%04x\n", fwVersion);
+#endif
+    /*3. open directory patch located*/
+        if (NULL == pStpParamsConfig->pPatchPath)
+        {
+            pStpParamsConfig->pPatchPath = CUST_COMBO_PATCH_PATH;
+        }
+        pDir = opendir(pStpParamsConfig->pPatchPath);
+        if (NULL == pDir)
+        {
+            ALOGE("patch path cannot be opened");
+            iRet = -2;
+            return iRet;
+        }
+        while (NULL != (pDirent = readdir(pDir)))
+        {
+            patchVer = 0;
+            
+            if (0 == (strncmp(pDirent->d_name, chipName, strlen(chipName))))
+            {    /*4.1. search patch name begined with chipName*/
+                strcpy (patchFullName, pStpParamsConfig->pPatchPath);
+                strcat (patchFullName, "/"); // robust, if input patch is /etc/firmwre/ no issue should be happened.
+                strcat (patchFullName, pDirent->d_name);
+                
+                ALOGI ("%s\n", patchFullName);
+                /*4.1. search patch name mt[CHIP ID]xxx.bin*/
+                if (0 < (patchFd = (open(patchFullName, O_RDONLY ))))
+                {
+
+                  /*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */
+                    if (-1 != lseek (patchFd, 22, SEEK_SET))
+                    {
+                        
+                        read(patchFd, ((char *)&patchVer) + 1, 1);
+                        read(patchFd, ((char *)&patchVer), 1);
+                        /*print firmware version information in patch*/
+                          ALOGI ("fw Ver in patch: 0x%04x\n", patchVer);
+                          if (0 == ((patchVer ^ fwVersion) & 0x00ff)) 
+                            {
+                                ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, patchFullName);
+                                ALOGI ("fw Ver in patch matches with firmware version\n");
+                                iRet = 0;
+                                close (patchFd);
+                                break;
+                            }
+                    }
+                    else
+                    {
+                        ALOGE("seek failed\n");
+                    }
+                    close (patchFd);
+                    patchFd = -1;
+                }
+                else
+                {
+                    //printf("open patch file(%s) failed\n", patchFullName);
+                    ALOGE(patchFullName);
+                }
+          }
+            
+        }
+        
+        /*5. return value*/
+        closedir(pDir);
+        pDir = NULL;
+    }
+    else
+    {
+        ALOGE("file descriptor is not valid\n");
+        iRet = -1;
+    }
+    return iRet;
+}
+#endif
+/*
+ret 0: success
+ret 1: cmd not found
+ret -x: handler return value
+*/
+int handle_cmd (P_STP_PARAMS_CONFIG pStpParamsConfig, char *cmd, int len) {
+    int ret = 1;
+    int i;
+    int cmd_len;
+    
+    for (i = 0; i < (int)(sizeof(cmd_hdr_table)/sizeof(cmd_hdr_table[0])); ++i) {
+        cmd_len = (int)strlen(cmd_hdr_table[i].pCmd);
+        if (!strncmp(cmd_hdr_table[i].pCmd, cmd, (len < cmd_len) ? len : cmd_len)) {
+            ret = (*cmd_hdr_table[i].hdr_func)(pStpParamsConfig);
+        }
+    }
+
+    return ret;
+}
+
+void display_usage(int chipid)
+{
+    unsigned int index = 0;
+    char * usage1[] = {
+        "MTK WCN combo tool set, version 1.0-release",
+        "Usage: consys_launcher -m mode -p patchfolderpath",
+        "    -m (BT/GPS/FM common interface mode selection)",
+        "        -1: UART mode (common interface: UART)",
+        "        -3: BTIF mode (common interface: BTIF)",
+        "        -4: SDIO mode (common interface: SDIO)",
+        "    -p (MTK WCN soc conssy chip firmware patch location)",
+        "        -e.g. /etc/firmware",
+        "e.g. consys_launcher -m 3 -p /etc/firmware/",
+    };
+	char * usage2[] = {
+        "MTK WCN combo tool set, version 1.0-release",
+        "Usage: 6620_launcher -m mode -p patchfolderpath [-d uartdevicenode] [-b baudrate] [-c uartflowcontrol]",
+//        "    -m (BT/GPS/FM common interface mode selection)",
+//        "        -1: UART mode (common interface: UART)",
+//        "        -1: UART full mode (common interface UART)",
+//        "        -2: UART mandetary mode (common interface UART)",
+        "        -4: UART mode (common interface SDIO)",
+        "    -p (MTK WCN Combo chip firmware patch location)",
+        "        -e.g. /etc/firmware",
+        "    -b (Baudrate set when BT/GPS/FM runs under UART mode, no needed under SDIO mode)",
+        "        -115200/921600/2000000/2500000/3000000/3500000/4000000",
+        "    -d (UART device node, when under UART mode, no needed under SDIO mode)",
+        "        -e.g. /dev/ttyMT1, /dev/ttyMT2, /dev/ttyHS2, etc.",
+        "    -c (UART flowcontrol set)",
+        "        -0, no flowcontrol default value, please donot modify this parameter",
+        "e.g. 6620_launcher 4 /etc/firmware/mt6628_patch_hdr.bin",
+        "e.g. 6620_launcher -m 1 -p /etc/firmware/",
+        "e.g. 6620_launcher -m 1 -n /etc/firmware/mt6628_patch_hdr.bin",
+        "e.g. 6620_launcher -m 4 -d /dev/ttyMT2 -b 4000000 -n /etc/firmware/mt6628_patch_hdr.bin",
+    };
+	if(0x6582 == chipid || 0x8127 == chipid)
+	{
+	    for (index = 0; index < sizeof (usage1)/sizeof (usage1[0]); index++ )
+	    {
+	       ALOGI("%s\n", usage1[index]); 
+	    }
+    }else
+	{
+		for (index = 0; index < sizeof (usage2)/sizeof (usage2[0]); index++ )
+	    {
+	       ALOGI("%s\n", usage2[index]); 
+	    }
+	}
+    exit(EXIT_FAILURE);
+}
+
+
+int para_valid_check (P_STP_PARAMS_CONFIG pStpParamConfig)
+{
+    if ((NULL != pStpParamConfig->pPatchPath) || (NULL != pStpParamConfig->pPatchName))
+    {
+        if (NULL != pStpParamConfig->pPatchPath){
+            ALOGI ("MCU patch folder path: %s\n", pStpParamConfig->pPatchPath);
+        }
+        if (NULL != pStpParamConfig->pPatchName){
+            ALOGI ("MCU patch full path: %s\n", pStpParamConfig->pPatchName);
+        }
+    }
+    else
+    {
+        puts ("MCU patch name or patch not found, exit.");
+        return -1;
+    }
+    if(pStpParamConfig->eStpMode != STP_SDIO && pStpParamConfig->eStpMode != STP_UART_MAND && pStpParamConfig->eStpMode != STP_UART_FULL)
+    {
+        puts("Stp Mode is not set, common interface use default: SDIO Mode");
+        pStpParamConfig->eStpMode = STP_SDIO;
+        return 0;
+    }
+    //SDIO mode: eStpMode = STP_SDIO && (pPachName != NULL || pPatchPath != NULL)
+    if (pStpParamConfig->eStpMode == STP_SDIO)
+    {
+        ALOGI ("Common Interface: SDIO mode\n");
+    }
+    else if (pStpParamConfig->eStpMode == STP_UART_MAND || pStpParamConfig->eStpMode == STP_UART_FULL)
+    {
+        //UART mode: (eStpMode = STP_MAND_MODE || STP_FULL_MODE) && (pPachName != NULL || pPatchPath != NULL) && (iBaudrate > 0) 
+        ALOGI ("Common Interface: UART mode\n");
+        if (NULL == pStpParamConfig->gStpDev){
+            pStpParamConfig->gStpDev = CUST_COMBO_STP_DEV;
+            ALOGI ("no uart device input, use default: %s\n", pStpParamConfig->gStpDev);    
+        }
+        if (pStpParamConfig->iBaudrate < 0)
+        {
+            //FixMe:Chaozhong, add baudrate validation check
+            pStpParamConfig->iBaudrate = 4000000;
+            ALOGI ("no baudrate input, use default: %d\n", pStpParamConfig->iBaudrate);  
+        }
+        
+    }  
+    return 0; 
+}
+
+static int wmt_cfg_item_parser(char *pItem)
+{
+    int maxIndex  = sizeof (gChipModeInfo) / sizeof (gChipModeInfo[0]);
+    int index = 0;
+    int length = 0;
+    char *str = NULL;
+    char *keyStr = NULL;
+    char *valueStr = NULL;
+    if (NULL == pItem)
+    {
+        ALOGI("Warning:pItem is NULL\n");
+        return -1;
+    }
+    /*all item must be start with mt66xx*/
+    str = strstr(pItem, "m");
+    if (NULL == str)
+    {
+        ALOGI("Warning:no string start with 'm' found in %s\n", pItem);
+        return -2;
+    }
+        
+    for (index = 0; index < maxIndex; index++)
+    {
+        keyStr = (char*)gChipModeInfo[index].antMode.pCfgItem;
+        
+        if (0 == strncasecmp(str, keyStr, strlen (keyStr)))
+        {
+            str = strstr(str, "=");
+            if (NULL == str)
+            {
+                ALOGI("Warning:no '=' found in %s\n", str);
+                return -3;
+            }
+            str = strstr(str, "m");
+            if (NULL == str)
+            {
+                ALOGI("Warning:no 'm' found in %s\n", str);
+                return -4;
+            }
+            
+            
+            while (((*str)==' ') || ((*str)=='\t') || ((*str)=='\n'))
+            {
+                if (str >= pItem + strlen(pItem))
+                {
+                    break;
+                }
+                str++;
+            }
+            valueStr = str;
+            
+            while (((*str)!=' ') && ((*str)!='\t') && ((*str)!='\0') && ((*str)!='\n') && ((*str)!='\r'))
+            {
+                if (str >= pItem + strlen(pItem))
+                {
+                    ALOGI("break\n");
+                    break;
+                }
+                str++;
+                
+            }
+            *str = '\0';
+            length = sizeof(gChipModeInfo[index].antMode.cfgItemValue);
+            strncpy(gChipModeInfo[index].antMode.cfgItemValue, valueStr, length - 1);
+            gChipModeInfo[index].antMode.cfgItemValue[length - 1] = '\0';
+            ALOGI("Info:key:%s value:%s\n", keyStr, gChipModeInfo[index].antMode.cfgItemValue);
+            break;
+        }
+    }
+    
+    return 0;
+}
+
+static void set_coredump_flag(void)
+{
+#define  ANDROID_BUILD_TYPE    "ro.build.type"
+#define COREDUMP_CTRL_FILE "/data/coredump"
+    SYS_PROPERTY buildTypeProp;
+    buildTypeProp.key = ANDROID_BUILD_TYPE;
+    buildTypeProp.defValue = NULL;
+    SYS_PROPERTY coredump_mode;
+    coredump_mode.key = WCN_COMBO_COREDUMP_PROP;
+    coredump_mode.defValue = NULL;
+    int coredumpEnableFlag = 0;
+    int iRet = -1;
+    int coredumpFd = -1;
+    if (gWmtFd < 0) {
+        ALOGI("%s:invalid wmt fd\n", __func__);
+        return;
+    }
+#if MTK_WCN_ENABLE_COREDUMP_BY_PROPERTY
+    iRet = property_get(coredump_mode.key, coredump_mode.value, NULL);
+    if (0 != iRet) {
+             ALOGI("key:(%s)-value:(%s)\n", coredump_mode.key, coredump_mode.value);
+    } else {
+            ALOGI("get coredump_mode property(%s) failed\n", coredump_mode.key);
+            iRet = property_set(coredump_mode.key, "0");
+            if (0 != iRet)
+                    ALOGI("set property(%s) to %s failed,iRet:%d, errno:%d\n", coredump_mode.key, "0", iRet, errno);
+            else
+                    ALOGI("set property(%s) default value is %s succeed.\n", coredump_mode.key, "0");
+    }
+    if (0 == strcmp(coredump_mode.value, "1")) {
+            coredumpEnableFlag = 1;
+            ALOGI("Connectivity coredump set aee mode: %d\n", coredumpEnableFlag);
+    } else if (0 == strcmp(coredump_mode.value, "2")) {
+            coredumpEnableFlag = 2;
+            ALOGI("Connectivity coredump set stp_dump mode: %d\n", coredumpEnableFlag);
+    } else {
+            coredumpEnableFlag = 0;
+            ALOGI("Connectivity coredump is disabled!\n");
+    }
+
+#else
+    //read from system property
+    iRet = property_get(buildTypeProp.key, buildTypeProp.value, buildTypeProp.defValue);
+    if (0 != iRet)
+    {
+        ALOGI("key:(%s)-value:(%s)\n", buildTypeProp.key, buildTypeProp.value);
+        if (0 == strcmp(buildTypeProp.value, "eng")) {
+            coredumpEnableFlag = 1;
+            ALOGI("Connectivity coredump set default aee mode: %d\n", coredumpEnableFlag);
+        } else if (0 == strcmp(buildTypeProp.value, "userdebug")) {
+            iRet = property_get(coredump_mode.key, coredump_mode.value, NULL);
+            if (0 != iRet) {
+                ALOGI("key:(%s)-value:(%s)\n", coredump_mode.key, coredump_mode.value);
+                    if (0 == strcmp(coredump_mode.value, "1")) {
+                        coredumpEnableFlag = 1;
+                        ALOGI("Connectivity coredump set aee mode: %d\n", coredumpEnableFlag);
+                    } else if (0 == strcmp(coredump_mode.value, "2")) {
+                        coredumpEnableFlag = 2;
+                        ALOGI("Connectivity coredump set stp_dump mode: %d\n", coredumpEnableFlag);
+                    } else {
+                        coredumpEnableFlag = 0;
+                        ALOGI("Connectivity coredump is disabled!\n");
+                    }
+            } else {
+                ALOGI("get coredump_mode property(%s) failed\n", coredump_mode.key);
+                coredumpEnableFlag = 0;
+                ALOGI("Connectivity coredump is disabled!\n");
+            }
+        } else {
+            coredumpEnableFlag = 0;
+            iRet = property_set(coredump_mode.key, "0");
+            if (0 != iRet)
+                ALOGI("set property(%s) to %s failed,iRet:%d, errno:%d\n", coredump_mode.key, "0", iRet, errno);
+            else
+                ALOGI("set property(%s) to %s succeed.\n", coredump_mode.key, "0");
+        }
+    }
+    else
+    {
+        ALOGI("get system build type(%s) failed\n", buildTypeProp.key);
+    }
+#endif
+#if 0
+    coredumpFd = open(COREDUMP_CTRL_FILE, O_RDWR | O_NOCTTY);
+    if (coredumpFd >= 0)
+    {
+        ALOGI("coredump control file: %s found.\n", COREDUMP_CTRL_FILE);
+        coredumpEnableFlag = 1;
+        if (0 == close(coredumpFd))
+        {
+            ALOGI("close %s succeed\n", COREDUMP_CTRL_FILE);
+        }
+        else
+        {
+            ALOGE("close %s failed, errno:%d\n", COREDUMP_CTRL_FILE, errno);
+        }
+        coredumpFd = -1;
+    } else
+    {
+        ALOGI("coredump control file: %s not found, errno:%d.\n", COREDUMP_CTRL_FILE, errno);
+    }
+	if (coredumpEnableFlag)
+#endif
+        /*set coredump mode to kernel driver*/
+        ioctl(gWmtFd, WMT_IOCTL_WMT_COREDUMP_CTRL, coredumpEnableFlag);
+        return;
+}
+
+
+static int get_wmt_cfg (int chipId)
+{
+#define WMTCFGFILEPATH "/system/etc/firmware/WMT.cfg"
+#define OPENMODE "r"
+#define MAXLINELEN 512
+    FILE * file = NULL;
+    int iRet = -1;
+    char *pStr = NULL;
+    char line[MAXLINELEN];
+    
+    file = fopen(WMTCFGFILEPATH, OPENMODE);
+    if (NULL == file)
+    {
+        ALOGI("%s cannot be opened, errno:%d\n", WMTCFGFILEPATH, errno);
+        return -2;
+    }
+    iRet = 0;
+    do {
+        pStr = fgets(line, MAXLINELEN, file);
+        if (NULL == pStr)
+        {
+            ALOGI("NULL is returned, eighter EOF or error maybe found\n");
+            break;
+        }
+
+        wmt_cfg_item_parser(line);
+        
+        memset(line, 0, MAXLINELEN);
+        
+    }while (pStr != NULL);
+
+    if (NULL != file)
+    {
+        
+        if (0 == fclose(file))
+        {
+            ALOGI("close %s succeed\n", WMTCFGFILEPATH);
+        }
+        else
+        {
+            ALOGI("close %s failed, errno:%d\n", WMTCFGFILEPATH, errno);
+        }
+    }
+    return iRet;
+}
+
+
+static int get_chip_info_index (int chipId)
+{
+    
+    int i = 0;
+    int index = -1;
+    
+    int left = 0;
+    int middle = 0;
+    int right = sizeof (gChipModeInfo) / sizeof (gChipModeInfo[0]) - 1;
+    
+    if ((chipId < gChipModeInfo[left].chipId) || (chipId > gChipModeInfo[right].chipId))
+        return index;
+    
+    middle = (left + right) / 2;
+    
+    while (left <= right)
+    {
+        if (chipId > gChipModeInfo[middle].chipId)
+        {
+            left = middle + 1;
+        }
+        else if (chipId < gChipModeInfo[middle].chipId)
+        {
+            right = middle - 1;
+        }
+        else
+        {
+            index = middle;
+            break;
+        }
+        middle = (left + right) / 2;
+    }
+    
+    if (0 > index)
+        ALOGI("no supported chipid found\n");
+    else
+        ALOGI("index:%d, chipId:0x%x\n", index, gChipModeInfo[index].chipId);
+
+    return index;
+}
+
+static int query_chip_id(void)
+{
+
+    int chipId = -1;
+    int iRet = -1;
+    SYS_PROPERTY chipIdProp;
+    chipIdProp.key = WCN_COMBO_CHIP_ID_PROP;
+    chipIdProp.defValue = NULL;
+
+    //read from system property
+    iRet = property_get(chipIdProp.key, chipIdProp.value, chipIdProp.defValue);
+    if (0 != iRet)
+    {
+        chipId = strtoul(chipIdProp.value, NULL, 16);
+        ALOGI("key:(%s)-value:(%s),chipId:0x%04x\n", chipIdProp.key, chipIdProp.value, chipId);
+    }
+    else
+    {
+        ALOGI("get chipId property(%s) failed\n", chipIdProp.key);
+        // we do not return here, use another way to get chip id
+    }
+#if 1
+    //read from config file
+    if (0 > get_chip_info_index(chipId))
+    {
+        //no wcn.combo.chipid property information found
+        //get chip id
+        chipId = ioctl(gWmtFd, WMT_IOCTL_WMT_QUERY_CHIPID, NULL);
+		if(chipId > 0)
+		{
+	        ALOGI ("chip id is 0x%x\n", chipId);
+	        ALOGI("chiId:0x%x, setting to property(%s)\n", chipId, chipIdProp.key);
+	        sprintf (chipIdProp.value, "0x%04x", chipId);
+	        iRet = property_set(chipIdProp.key, chipIdProp.value);
+	        if (0 != iRet)
+	        {
+	            ALOGI("set property(%s) to %s failed,iRet:%d, errno:%d\n", chipIdProp.key, chipIdProp.value, iRet, errno);
+	        }
+	        else
+	        {
+	            ALOGI("set property(%s) to %s succeed.\n", chipIdProp.key, chipIdProp.value);
+	        }
+	        
+	        // read again
+	        if (0 != property_get(chipIdProp.key, chipIdProp.value, chipIdProp.defValue))
+	        {
+	            ALOGI("chipIdProp:key(%s)value(%s)\n", chipIdProp.key, chipIdProp.value);
+	        }
+	        else
+	        {
+	            ALOGI("get chipId property failed, errno:%d\n", errno);
+	            chipId = -1;
+	        }
+		}
+    }
+#endif
+    return chipId;
+}
+
+
+static int check_chip_id(void)
+{
+
+#define COMBO_IOC_MAGIC        'h'
+#define COMBO_IOCTL_GET_CHIP_ID  _IOR(COMBO_IOC_MAGIC, 0, int)
+#define COMBO_IOCTL_SET_CHIP_ID  _IOW(COMBO_IOC_MAGIC, 1, int)
+
+    int chipId = -1;
+    SYS_PROPERTY chipIdProp;
+    chipIdProp.key = WCN_COMBO_CHIP_ID_PROP;
+    chipIdProp.defValue = NULL;
+    int fdHifsdio = -1;
+    
+#if 1
+    //read from system property
+    if (0 != property_get(chipIdProp.key, chipIdProp.value, chipIdProp.defValue))
+    {
+        chipId = strtoul(chipIdProp.value, NULL, 16);
+        ALOGI("key:(%s)-value:(%s),chipId:0x%04x\n", chipIdProp.key, chipIdProp.value, chipId);
+    }
+    else
+    {
+        ALOGI("get chipId property(%s) failed\n", chipIdProp.key);
+        // we do not return here, use another way to get chip id
+    }
+#else
+    /*read from config file*/
+    
+#endif
+    //open HIF-SDIO
+    fdHifsdio = open("/dev/hifsdiod", O_RDWR | O_NOCTTY);
+    if (fdHifsdio < 0)
+    {
+        ALOGI ("open hifsdiod fail\n");
+        return -1;
+    }
+
+    //read from config file
+    if (0 > get_chip_info_index(chipId))
+    {
+        //no wcn.combo.chipid property information found
+        //get chip id
+        chipId = ioctl(fdHifsdio, COMBO_IOCTL_GET_CHIP_ID, NULL);
+        ALOGI ("chip id is 0x%x\n", chipId);
+        //assume we get 0x6628 here
+        ALOGI("chiId:0x%x, setting to property(%s)\n", chipId, chipIdProp.key);
+        sprintf (chipIdProp.value, "0x%04x", chipId);
+        property_set(chipIdProp.key, chipIdProp.value);
+        ALOGI("set property(%s) to %s done.\n", chipIdProp.key, chipIdProp.value);
+        // read again
+        if (0 != property_get(chipIdProp.key, chipIdProp.value, chipIdProp.defValue))
+        {
+            ALOGI("chipIdProp:key(%s)value(%s)\n", chipIdProp.key, chipIdProp.value);
+        }
+        else
+        {
+            ALOGI("get chipId property failed, errno:%d\n", errno);
+            chipId = -1;
+        }
+    }
+    else
+    {
+        ioctl(fdHifsdio, COMBO_IOCTL_SET_CHIP_ID, chipId);
+        ALOGI("set chipId(0x%x) to HIF-SDIO module\n", chipId);
+    }
+    
+    //close HIF-SDIO
+    close (fdHifsdio);
+    fdHifsdio = -1;
+
+    return chipId;
+}
+
+static int setHifInfo(int chipId, char *cfgFilePath)
+{
+    int index = -1;
+    index = get_chip_info_index(chipId);
+    if ((gStpMode <= STP_MIN) || (STP_SDIO < gStpMode))
+    {
+        ALOGI ("STP Mode is not set, fetching default mode...\n");
+        
+        if (0 <= index)
+        {
+            gStpMode = gChipModeInfo[index].stpMode;
+        }
+        else
+        {
+            //gStpMode = STP_UART_FULL;
+            gStpMode = -1;
+        }
+        
+    }
+
+    if ((0 <= index) && (NULL != cfgFilePath))
+    {
+        memset(gWmtCfgName, 0, sizeof(gWmtCfgName));
+        strncpy (gWmtCfgName, cfgFilePath, sizeof(gWmtCfgName) - 1);
+        gWmtCfgName[sizeof(gWmtCfgName) - 1] = '\0';
+        strcat (gWmtCfgName, "/");
+        strcat (gWmtCfgName, gChipModeInfo[index].antMode.cfgItemValue);
+        gWmtCfgName[strlen(cfgFilePath) + strlen("/") + strlen(gChipModeInfo[index].antMode.cfgItemValue)] = '\0'; 
+		#if 0
+        ALOGI ("strlen(cfgFilePath):%d, strlen('/'):%d, strlen(gChipModeInfo[index].antMode.cfgItemValue):%d\n", strlen(cfgFilePath),\
+            strlen("/"), \
+            strlen(gChipModeInfo[index].antMode.cfgItemValue)\
+            );
+	    #endif
+    }
+    else
+    {
+        memset(gWmtCfgName, 0, sizeof(gWmtCfgName));
+    }
+    ALOGI ("chipId(0x%04x), default Mode(%d), strlen(gWmtCfgName)(%u), wmtCfgFile(%s)\n", chipId, gStpMode, strlen(gWmtCfgName), gWmtCfgName);
+    return gStpMode;
+}
+
+static void* launcher_pwr_on_chip(void * arg)
+{
+	int retryCounter = 0;
+	int i_ret = -1;
+	int chipid = *(int*) arg;
+	char readyStr[PROPERTY_VALUE_MAX] = {0};
+	int iRet = -1;
+
+	pthread_setname_np(pthread_self(), "pwr_on_conn");
+
+	ALOGI("enter power on connsys flow");
+	do {
+		i_ret = ioctl(gWmtFd, WMT_IOCTL_LPBK_POWER_CTRL, 1);
+		if (0 == i_ret){
+			break;
+        } else {
+			ioctl(gWmtFd, WMT_IOCTL_LPBK_POWER_CTRL, 0);
+			ALOGI("power on %x failed, retrying, retry counter:%d\n", chipid, retryCounter);
+			usleep(1000000);
+		}
+		retryCounter++;
+	}while (retryCounter < 20);
+
+	pthread_detach(thread_handle);
+	thread_handle = -1;
+
+	return NULL;
+}
+static void* launcher_set_fwdbg_flag(void * arg)
+{
+    int i_ret = -1;
+    int flag = *(int*) arg;
+
+    pthread_setname_np(pthread_self(), "dump_fwemi_log");
+    ALOGI("dump firmware dbg log from emi buffer ");
+    i_ret = ioctl(gWmtFd, WMT_IOCTL_FW_DBGLOG_CTRL, flag);
+    if (i_ret < 0) {
+        ALOGI("ioctl error: err msg: %s\n", strerror(errno));
+        pthread_detach(thread_handle);
+        thread_handle = -1;
+    }
+    return NULL;
+}
+
+/*
+ * -m: mode (SDIO/UART)
+ * -d: uart device node
+ * -b: baudrate
+ * -c: enable SW FC or not
+ * -p: patch folder path
+ * -n: patch file name (fullpath) 
+ *
+ */
+int main(int argc, char *argv[])
+{
+    static const char *opString = "m:d:b:c:p:n:?";
+    struct uart_t *u = NULL;
+    int opt, ld, err;
+    int baud = 0;
+    struct sigaction sa;
+    struct pollfd fds[2];
+    int fd_num = 0;
+    int len = 0;
+    int uartFcCtrl = 0;
+    int argCount = 0;
+    int chipId = -1;
+    int i_ret = 1;
+    int retry = 0;
+    int polling_flag = 0;
+    int dynamicdump_flag = 0;
+    int dump_retry = 0;
+    int fwdbgEnableFlag = 0;
+    char readyStr[PROPERTY_VALUE_MAX] = {0};
+    STP_PARAMS_CONFIG sStpParaConfig;
+    char fwStateStr0[PROPERTY_VALUE_MAX] = {0};
+    char fwStateStr[PROPERTY_VALUE_MAX] = {0};
+    char dynamicDump0[PROPERTY_VALUE_MAX] = {0};
+    char dynamicDump[PROPERTY_VALUE_MAX] = {0};
+
+    do {
+        i_ret = property_get(WCN_DRIVER_READY_PROP, readyStr, NULL);
+        if (0 >= i_ret) {
+            ALOGI("get property(%s) failed i_ret:%d\n", WCN_DRIVER_READY_PROP, i_ret);
+        } else {
+            ALOGI("get property(%s) is %s\n", WCN_DRIVER_READY_PROP, readyStr);
+            if (!strcmp(readyStr, "yes"))
+                break;
+        }
+        usleep(300000);
+    } while (1);
+
+    do {
+		gWmtFd = open(CUST_COMBO_WMT_DEV, O_RDWR | O_NOCTTY);
+	    if (gWmtFd < 0) {
+	        ALOGI("Can't open device node(%s) error:%d \n", CUST_COMBO_WMT_DEV,gWmtFd);
+	        usleep(300000);
+	    }
+		else
+			break;
+	}while(1);
+    ALOGE("open device node succeed.(Node:%s, fd:%d) \n", CUST_COMBO_WMT_DEV, gWmtFd);
+
+	do{
+		chipId = query_chip_id(); 
+		if(0 > chipId)
+		{
+			usleep(300000);
+			chipId = ioctl(gWmtFd,WMT_IOCTL_WMT_QUERY_CHIPID,NULL);	
+			ALOGI("chiId from kernel by ioctl:0x%04x\n", chipId);
+			if(-1 != chipId)
+				break;
+		}else
+			break;
+	}while(1);
+	ALOGI("chiId:0x%04x\n", chipId);
+
+	if((0x0321 == chipId) || (0x0335 == chipId) || (0x0337 == chipId))
+	{
+		chipId = 0x6735;
+		ALOGI("for denali chipid convert\n");
+	}
+    if (0x0326 == chipId)
+	{
+            chipId = 0x6755;
+            ALOGI("for jade chipid convert\n");
+    }
+        if ((0x6735 == chipId) || (0x6752 == chipId) || (0x6582 == chipId) || (0x6592 == chipId)
+              || (0x6572 == chipId) || (0x6571 == chipId) || (0x8127 == chipId)
+              || (0x8163 == chipId) || (0x6580 == chipId) || (0x6755 == chipId) || (0x6797 == chipId) || (0x7623 == chipId) ) {
+		ALOGI("run SOC chip flow\n");
+		gStpMode = STP_BTIF_FULL;
+		memset(gPatchFolder, 0, sizeof(gPatchFolder));
+
+		opt = getopt(argc, argv, opString);
+	    while (opt != -1)
+	    {
+	    	switch (opt)
+	    	{
+	    		case 'm':
+	    			gStpMode = atoi(optarg);
+	    			sStpParaConfig.eStpMode  = gStpMode;
+					ALOGI("stpmode[%d]\n",gStpMode);
+	    			break;
+	    		case 'p':
+	    			//gPatchFolder = optarg;
+	    			strcpy(gPatchFolder, optarg);
+	    			sStpParaConfig.pPatchPath = gPatchFolder;
+	    			break;
+	    		case '?':
+	    		default:
+	    			display_usage(chipId);
+	    			break;
+	    	}
+	    	opt = getopt(argc, argv, opString);
+	    }
+		/* send default patch file name path to driver */
+    	ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, gPatchName);
+		/* set fm mode & stp mode*/
+		ioctl(gWmtFd, WMT_IOCTL_SET_STP_MODE, ((gFmMode & 0x0F) << 4)  |(gStpMode & 0x0F));
+#ifndef WMT_PLAT_APEX
+       set_coredump_flag();
+#endif
+	}else
+	{
+		ALOGI("run combo chip flow\n");
+	    sStpParaConfig.pPatchPath = NULL;
+	    sStpParaConfig.pPatchName = NULL;
+	    sStpParaConfig.gStpDev = NULL;
+	    sStpParaConfig.eStpMode  = -1;
+	    sStpParaConfig.iBaudrate  = -1;
+	    sStpParaConfig.sUartConfig.fc = UART_DISABLE_FC;
+	    sStpParaConfig.sUartConfig.parity = 0;
+	    sStpParaConfig.sUartConfig.stop_bit = 0;
+	    
+	    /*Default parameters starts*/
+	    baud = 4000000;
+	    gStpMode = -1;
+	    uartFcCtrl = UART_DISABLE_FC;
+        strncpy(gStpDev, CUST_COMBO_STP_DEV, sizeof(gStpDev) - 1);
+        gStpDev[sizeof(gStpDev) - 1] = '\0';
+        memset(gPatchFolder, 0, sizeof(gPatchFolder));
+	    memset(gPatchName, 0, sizeof(gPatchName));
+	    /*Default parameters ends*/
+	    
+	    opt = getopt(argc, argv, opString);
+	    while (opt != -1)
+	    {
+	        switch (opt)
+	        {
+	            case 'm':
+	                gStpMode = atoi(optarg);
+	                sStpParaConfig.eStpMode  = gStpMode;
+	                break;
+	          case 'd':
+                    strncpy(gStpDev, optarg, sizeof(gStpDev) - 1);
+                    gStpDev[sizeof(gStpDev) - 1] = '\0';
+	                sStpParaConfig.gStpDev = gStpDev;
+	                break;
+	            case 'b':
+	                baud = atoi(optarg);
+	                sStpParaConfig.iBaudrate = baud;
+	                break;
+	            case 'c':
+	                uartFcCtrl = atoi(optarg);
+	                sStpParaConfig.sUartConfig.fc = uartFcCtrl;
+	                ALOGI("c found\n");    
+	                break;
+	            case 'p':
+	                //gPatchFolder = optarg;
+	                strcpy(gPatchFolder, optarg);
+	                sStpParaConfig.pPatchPath = gPatchFolder;
+	                break;
+	            case 'n':
+	                //gPatchName = optarg;
+	                strcpy(gPatchName, optarg);
+	                sStpParaConfig.pPatchName = gPatchName;
+	                break;
+	            case '?':
+	            default:
+	                display_usage(chipId);
+	                break;
+	        }
+	        opt = getopt(argc, argv, opString);
+	    }
+#if 0
+	    ALOGI ("argc = %d, optind= %d\n", argc, optind);
+	    {
+	        int i = 0;
+	        for (i = 0; i < argc; i++)
+	        {
+	            ALOGI("arg[%d] = %s\n", i, argv[i]);    
+	        }
+	    }
+#endif
+
+	     
+	    if (0 > get_chip_info_index(chipId))
+	    {
+	          ALOGI("invalid chip, check again\n");
+	          chipId = query_chip_id();
+	    	  ALOGI("chiId:0x%04x\n", chipId);
+	    }
+
+		ioctl(gWmtFd, WMT_IOCTL_WMT_TELL_CHIPID, chipId);
+    	ALOGI("set chipId(0x%x) to HIF-SDIO module\n", chipId);
+
+		get_wmt_cfg(chipId);
+
+        setHifInfo(chipId, sStpParaConfig.pPatchPath);
+        ALOGI("HifConfig:0x%04x, wmtCfgFile:%s\n", sStpParaConfig.eStpMode, gWmtCfgName);
+#ifndef WMT_PLAT_APEX
+        set_coredump_flag();
+#endif		
+        if (0 != para_valid_check(&sStpParaConfig))
+        {
+            //Try to use custom method to check parameters
+            if (argc > optind)//argv[optind]
+	        {
+	        // For this competible usage , we only left STP mode set and firmware patch input, omit flowcontrol set
+	        //First baud for STP UART mode, otherwise, SDIO mode
+	            baud = atoi(argv[optind]);
+	                if (baud >=  CUST_BAUDRATE_DFT) {
+	                ALOGI("get baud rate(%d) for UART mode\n", baud);
+	                gStpMode = STP_UART_FULL;
+	                sStpParaConfig.iBaudrate = baud;
+	            }
+	            else if (baud == 1){
+	                ALOGI("Definitively use SDIO mode\n");
+	                gStpMode = STP_SDIO;
+	            }
+	            else {
+	                ALOGI("invalid baud rate(%d) for UART, use SDIO mode\n", baud);
+	                gStpMode = STP_SDIO;
+	            }
+	            sStpParaConfig.eStpMode  = gStpMode;
+	            
+	            //Firmare patch analysis
+	            optind++;    
+	            memset(gPatchName, 0, sizeof(gPatchName));
+	            if (argc > optind)
+	            {
+	               strncat(gPatchName, argv[optind], sizeof(gPatchName)-1); 
+	               sStpParaConfig.pPatchName = gPatchName;
+	               ALOGI("PatchFile:%s\n", sStpParaConfig.pPatchName);
+	            }
+	            else
+	            {
+	                sStpParaConfig.pPatchName = NULL;
+	                ALOGI("no patch file \n");
+	            }
+	            //Flow Control analysis
+	            optind++;
+	            if (argc > optind)
+	            {
+	                uartFcCtrl = atoi(argv[optind]);
+	                sStpParaConfig.sUartConfig.fc = uartFcCtrl;
+	                ALOGI("flowcontrol flag: %d\n", sStpParaConfig.sUartConfig.fc);    
+	            }
+	            else
+	            {
+	                ALOGI("no flow control flat set\n");    
+	            }
+	                
+	        }
+	    }
+	    if (0 != para_valid_check(&sStpParaConfig))
+	    {
+	        display_usage(chipId);
+	    }
+		
+		/* send default patch file name path to driver */
+    	ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, gPatchName);
+		    /* send uart name to driver*/
+    	if (sStpParaConfig.gStpDev) {
+        	gUartName = strstr(sStpParaConfig.gStpDev, "tty");
+        	if (!gUartName) {
+            	ALOGI("no uart name found in %s\n", sStpParaConfig.gStpDev);
+        	} else {
+            	ALOGI("uart name %s\n", gUartName);
+        	}
+    	}
+    
+    	if (!gUartName) {
+        	gUartName = "ttyMT2";
+        	ALOGI("use default uart %s\n", gUartName);
+    	}
+    
+    	ioctl(gWmtFd, WMT_IOCTL_PORT_NAME, gUartName);
+    
+    	/* send hardware interface configuration to driver */
+    	ioctl(gWmtFd, WMT_IOCTL_SET_STP_MODE, ((baud & 0xFFFFFF) << 8) | ((gFmMode & 0x0F) << 4)  |(gStpMode & 0x0F));
+    
+    	/* send WMT config name configuration to driver */
+    	ioctl(gWmtFd, WMT_IOCTL_WMT_CFG_NAME, gWmtCfgName);
+    }
+
+    ioctl(gWmtFd, WMT_IOCTL_SET_LAUNCHER_KILL, 0);
+
+    i_ret = ioctl(gWmtFd, WMT_IOCTL_GET_APO_FLAG, NULL);
+    if (i_ret != 0) {
+        if (pthread_create(&thread_handle, NULL, launcher_pwr_on_chip, &chipId)) {
+            ALOGE("create pwr on thread fail\n");
+        } else {
+            ALOGI("create pwr on thread ok\n");
+        }
+    } else {
+        ALOGI("no supported always power on\n");
+    }
+    /*set signal handler*/
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_flags   = SA_NOCLDSTOP;
+    sa.sa_handler = SIG_IGN;
+    sigaction(SIGCHLD, &sa, NULL);
+    sigaction(SIGPIPE, &sa, NULL);
+
+    sa.sa_handler = sig_term;
+    sigaction(SIGTERM, &sa, NULL);
+    sigaction(SIGINT,  &sa, NULL);
+
+    sa.sa_handler = sig_hup;
+    sigaction(SIGHUP, &sa, NULL);
+    
+
+    fds[0].fd = gWmtFd; /* stp_wmt fd */
+    fds[0].events = POLLIN | POLLRDNORM; /* wait read events */
+    ++fd_num;
+    i_ret = property_get(WCN_FW_DBG_LOG_PROP, fwStateStr0, NULL);
+    if (0 >= i_ret) {
+        ALOGI("get property(%s) failed ret:%d\n", WCN_FW_DBG_LOG_PROP, i_ret);
+    } else
+        ALOGI("get property fwStateStr0 (%s) is %s\n", WCN_FW_DBG_LOG_PROP, fwStateStr0);
+     i_ret = property_get(WCN_DYNAMIC_DUMP_PROP, dynamicDump0, NULL);
+    if (0 >= i_ret) {
+        ALOGI("get property(%s) failed ret:%d\n", WCN_DYNAMIC_DUMP_PROP, i_ret);
+    } else
+        ALOGI("get property dynamicDump0 (%s) is %s\n", WCN_DYNAMIC_DUMP_PROP, dynamicDump0);
+#if 0 //does this part needed?, no uart device is opened at this time.    
+    if (gStpMode == STP_UART_FULL) {
+        fds[1].fd = gTtyFd;          /* real tty fd */
+        fds[1].events = POLLERR | POLLHUP;  /* POLLERR | POLLHUP is unnecessary? */
+        ++fd_num;
+    }
+#endif
+    
+    while (!__io_canceled) {
+        fds[0].revents = 0;
+#if 0 //does this part needed?, do we need to poll on uart?        
+        if (gStpMode == STP_UART_FULL) {        
+            fds[1].revents = 0;
+        }
+#endif     
+        err = poll(fds, fd_num, 2000);  // 5 seconds
+        if (err < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+            else {
+                ALOGI("poll error:%d errno:%d, %s\n", err, errno, strerror(errno));
+                break;
+            }
+        }
+        else if (!err) {
+            continue;
+        }
+#if 0 //does this part needed?, do we need to poll on uart? 
+        if (gStpMode == STP_UART_FULL) {
+            if (fds[1].revents & (POLLERR | POLLHUP)) {
+                ALOGI("poll result: pa[1].revents:0x%x\n", fds[1].revents);
+                break;
+            }
+        }
+#endif        
+        if (fds[0].revents & POLLIN) {
+            memset(gCmdStr, 0, sizeof(gCmdStr));
+            len = read(gWmtFd, gCmdStr, sizeof(gCmdStr)-1);
+            if (len > 0 && len < (int)sizeof(gCmdStr)) {
+                //printf ("POLLIN(%d) and read(%d)\n", gWmtFd, len);
+            }
+            else {
+                ALOGI("POLLIN(%d) but read fail:%d\n", gWmtFd, len);
+                continue;
+            }
+            gCmdStr[len] = '\0';
+            //ALOGI("rx_cmd_str:%s\n", gCmdStr);
+            err = handle_cmd(&sStpParaConfig, gCmdStr, len);
+            if (!err) {
+                //ALOGI("handle_cmd(%s), respond ok \n", gCmdStr);
+                snprintf(gRespStr, sizeof(gRespStr), "ok");
+            }
+            else {
+                if (err == 1) {
+                    snprintf(gRespStr, sizeof(gRespStr), "cmd not found");
+                }
+                else {
+                    snprintf(gRespStr, sizeof(gRespStr), "resp_%d", err);
+                }
+            }
+            ALOGI("cmd(%s) resp(%s)\n", gCmdStr, gRespStr);
+            len = write(gWmtFd, gRespStr, strlen(gRespStr));
+            if (len != (int)strlen(gRespStr)) {
+                fprintf(stderr, "write resp(%d) fail: len(%d), errno(%d, %s)\n", gWmtFd, len, errno, (len == -1) ? strerror(errno) : "");
+            }
+        }
+            if (polling_flag == 0) {
+                if (retry++ <= 5) {
+                    i_ret = property_get(WCN_FW_DBG_LOG_PROP, fwStateStr, NULL);
+                    if (0 >= i_ret) {
+                        ALOGI("get property(%s) failed ret:%d\n", WCN_FW_DBG_LOG_PROP, i_ret);
+                    } else {
+                        ALOGI("get property(%s) is %s\n", WCN_FW_DBG_LOG_PROP, fwStateStr);
+                        if (strcmp(fwStateStr, fwStateStr0))
+                            polling_flag = 1;
+                    }
+                }
+            }
+            if (polling_flag == 1 || retry == 6) {
+                ALOGI("polling_flag:%d, retry: %d\n", polling_flag, retry);
+                if (!strcmp(fwStateStr, "yes")) {
+                    fwdbgEnableFlag = 1;
+                    i_ret = pthread_create(&thread_handle, NULL, launcher_set_fwdbg_flag, &fwdbgEnableFlag);
+                    if (i_ret) {
+                        ALOGE("create enable firmware dbglog thread fail\n");
+                    } else
+                        ALOGI("create enable firmware dbglog thread ok\n");
+                } else {
+                    i_ret = ioctl(gWmtFd, WMT_IOCTL_FW_DBGLOG_CTRL, fwdbgEnableFlag);
+                    if (i_ret < 0)
+                    ALOGI("ioctl error: err msg: %s\n", strerror(errno));
+                }
+            }
+
+            if (dynamicdump_flag == 0) {
+                if (dump_retry++ <= 5) {
+                    i_ret = property_get(WCN_DYNAMIC_DUMP_PROP, dynamicDump, NULL);
+                    if (0 >= i_ret) {
+                        ALOGI("get property(%s) failed ret:%d\n", WCN_DYNAMIC_DUMP_PROP, i_ret);
+                    } else {
+                        ALOGI("get property(%s) is %s\n", WCN_DYNAMIC_DUMP_PROP, dynamicDump);
+                        if (strcmp(dynamicDump, dynamicDump0))
+                            dynamicdump_flag = 1;
+                    }
+                }
+            }
+            if (dynamicdump_flag == 1) {
+                ALOGI("dynamicdump_flag:%d, dump_retry: %d\n", dynamicdump_flag, dump_retry);
+                ALOGI("get property(%s) is %s\n", WCN_DYNAMIC_DUMP_PROP, dynamicDump);
+                i_ret = ioctl(gWmtFd, WMT_IOCTL_DYNAMIC_DUMP_CTRL, dynamicDump);
+                if (i_ret < 0)
+                ALOGI("ioctl error: err msg: %s\n", strerror(errno));
+            }
+    }
+
+clean_up:
+
+    if (gWmtFd >= 0) {
+        close(gWmtFd);
+        gWmtFd = -1;
+    }
+
+    if (gStpMode == STP_UART_FULL && gTtyFd >= 0) {
+        /* Restore TTY line discipline */
+        ld = N_TTY;
+        if (ioctl(gTtyFd, TIOCSETD, &ld) < 0) {
+            ALOGE("Can't restore line discipline");
+            exit(1);
+        }
+
+        close(gTtyFd);
+        gTtyFd = -1;
+    }
+
+    return 0;
+}
+
diff --git a/src/connectivity/combo_tool/src/wmt_concurrency.c b/src/connectivity/combo_tool/src/wmt_concurrency.c
new file mode 100755
index 0000000..1163eb6
--- /dev/null
+++ b/src/connectivity/combo_tool/src/wmt_concurrency.c
@@ -0,0 +1,383 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ * 
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ * 
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#define _GNU_SOURCE
+#include "wmt_ioctl.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/endian.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <linux/serial.h> /* struct serial_struct  */
+#include <pthread.h>
+#include <sched.h>
+#define FIBER_STACK 8192
+
+pthread_mutex_t mutex;
+
+typedef enum DRV_INDEX
+{
+  DRV_BT = 0,
+  DRV_FM,  
+  DRV_GPS,
+  DRV_WIFI,
+  DRV_MAX,
+}ENUM_DRV_INDEX;
+
+typedef enum ARG_DRV_INDEX
+{
+  ARG_DRV_BT = 1 << DRV_BT,
+  ARG_DRV_FM = 1 << DRV_FM,  
+  ARG_DRV_GPS = 1 << DRV_GPS,
+  ARG_DRV_WIFI = 1 << DRV_WIFI,
+  ARG_DRV_ALL = ARG_DRV_BT + ARG_DRV_FM + ARG_DRV_GPS + ARG_DRV_WIFI,
+}ENUM_ARG_DRV_INDEX;
+
+#define is_bt_mask_on(a) ((a) & ARG_DRV_BT)
+#define is_fm_mask_on(a) ((a) & ARG_DRV_FM)
+#define is_gps_mask_on(a) ((a) & ARG_DRV_GPS)
+#define is_wifi_mask_on(a) ((a) & ARG_DRV_WIFI)
+
+#define QUICK_FUNC_ON_OFF_SUPPORT
+#ifdef QUICK_FUNC_ON_OFF_SUPPORT
+	#define MIN_INTERVAL 1
+#else 
+	#define MIN_FUNC_ON_TIME 4
+	#define MIN_FUNC_OFF_TIME 1
+	#define MIN_INTERVAL  MIN_FUNC_ON_TIME + MIN_FUNC_OFF_TIME
+#endif
+
+#define MAX_FUNC_ON_TIME 9
+#define MAX_FUNC_OFF_TIME 3
+#define MAX_INTERVAL  MAX_FUNC_ON_TIME + MAX_FUNC_OFF_TIME
+//enum bool {false = 0, true = !false};
+
+char *src_name[]={
+	"BT",  
+	"FM", 
+	"GPS", 
+	"WIFI",
+	"UNKNOWN DEVICE",
+	};
+
+static int g_wmt_fd = -1;
+static int g_reference = 0;
+static int g_count = 2;
+int g_on2off_interval = MAX_INTERVAL;
+int g_off2on_interval = MAX_INTERVAL;
+volatile int g_state[5] = {0};
+
+void dump_state(void)
+{
+	//printf("%s:++, pid =%d\n",  __FUNCTION__, getpid());
+	printf("%d: %s:g_state:[BT]%d, [FM]:%d, [GPS]:%d, [WIFI]:%d\n", getpid(),  __FUNCTION__, g_state[0], g_state[1], g_state[2], g_state[3]);
+	//printf("%s:--, pid =%d\n",  __FUNCTION__, getpid());
+}
+
+int read_reference(ENUM_DRV_INDEX index)
+{
+	int ref = 0;
+	volatile int flag = 0;
+	pthread_mutex_lock(&mutex);
+	if(index >= 4)
+	{
+		if(g_state[0] || g_state[1] || g_state[2] || g_state[3])
+		{
+			flag = 1;
+		}
+		else
+		{
+			flag = 0;
+		}
+	}
+	else
+	{
+		flag = g_state[index];
+	}
+	pthread_mutex_unlock(&mutex);
+	return flag;
+}
+
+void get_reference(ENUM_DRV_INDEX index)
+{
+	pthread_mutex_lock(&mutex);
+	g_reference++;
+	g_state[index] = 1;
+	dump_state();
+	pthread_mutex_unlock(&mutex);
+}
+
+
+void put_reference(ENUM_DRV_INDEX index)
+{
+	pthread_mutex_lock(&mutex);
+	g_reference--;
+	g_state[index] = 0;
+	dump_state();
+	pthread_mutex_unlock(&mutex);
+}
+
+void func_on_off(ENUM_DRV_INDEX index)
+{
+  pid_t pid = -1;
+  int count = g_count;
+//  printf("%s:++, index =%d\n",  __FUNCTION__, index);
+  if(DRV_MAX > index && g_wmt_fd > 0)
+  {
+    while(count--)
+    {
+    	//turn on  src_name[index] function
+    	if (0 == ioctl(g_wmt_fd, WMT_IOCTL_FUNC_ONOFF_CTRL, 0x80000000 | index))
+    	{
+    		printf("pid:%d, turn on %s success.\n",   getpid(), src_name[index]);
+			//exit(0);
+    	}
+    	else
+    	{
+    		printf("pid:%d, turn on %s fail.\n",   getpid(), src_name[index]);
+    		exit(-1);
+    	}
+    	
+    	//printf("%s:-- pid: %d, finish turn on %s\n",  __FUNCTION__, getpid(), src_name[index]);
+    	/*
+    	//turn off  src_name[index] function
+    	*/
+    	sleep(g_on2off_interval);
+    	if ( 0 == ioctl(g_wmt_fd, WMT_IOCTL_FUNC_ONOFF_CTRL, 0x00000000 | index))
+    	{
+    		printf("pid:%d, turn off %s success.\n",   getpid(), src_name[index]);
+    		//exit(0);
+    	}
+    	else
+    	{
+    		printf("pid:%d, turn off %s fail.\n",   getpid(), src_name[index]);
+    		exit(-1);
+    	}
+    	printf("%d:%s test:left count = %d.\n",  getpid(), src_name[index], count);
+    	sleep(g_off2on_interval);
+    	
+    }
+  }
+  else
+  {
+  	printf("pid:%d, undnown device with index:%d.\n",  getpid(), index);
+  }
+ // printf("%s:--, index =%d\n",  __FUNCTION__, index);
+ //exit(-2);
+ //return;
+  exit(0);
+}
+
+
+static void sig_child_term(int sig)
+{
+    printf("%s ++.\n", __FUNCTION__);
+    int pid = -1;
+    int stat;
+    while((pid = waitpid(0, &stat, WNOHANG)) != 0)
+    {
+    	printf("%s:pid = %d, exit event.\n", __FUNCTION__, pid);
+    }
+    printf("%s:pid = %d.\n", __FUNCTION__, pid);
+    printf("%s --.\n", __FUNCTION__);
+}
+
+int main(int argc, char *argv[])
+{
+	
+	int bitmask = ARG_DRV_ALL;
+	
+	int i = 0;
+	int status;
+	void *stack[8];
+	struct sigaction sa;
+	if(argc != 5)
+	{
+		printf("wmt_concurrency usage:\n\
+		wmt_concurrency looptimes  bitmask  on2offtime off2ontime\n\
+		  -looptimes	on<->off switch times (<1000000)\n\
+		  -bitmask\n\
+		    -1:BT on<->off test\n\
+		    -2:FM on<->off test\n\
+		    -4:GPS on<->off test\n\
+		    -8:WIFI on<->off test\n\
+		    -x: can be combination of the upper 4 bitmasks\n\
+		  -on2offtime	(0~12s)\n\
+		    -function on hold time before turn off\n\
+		  -off2ontime	(0~12s)\n\
+		    -function off hold time before turn on\n\
+		");
+		return -1;
+	}
+	if ((argc > 1) && (argv[1] != NULL)) {
+        
+        g_count = atoi(argv[1]);
+        printf("%s:argv[1] g_count param = %d\n",  __FUNCTION__, g_count);
+        if(g_count < 0)
+	    {
+	    	g_count = 2;
+	    }
+	   	g_count = g_count > 1000000 ? 1000000 : g_count;
+	    printf("%s:g_count = %d\n",  __FUNCTION__, g_count);
+    }
+    if ((argc > 2) && (argv[2] != NULL)) {
+        
+        bitmask = atoi(argv[2]);
+        printf("%s:argv[2] bitmask param = %d\n",  __FUNCTION__, bitmask);
+        if(bitmask <= 0 || bitmask > ARG_DRV_ALL)
+    	{
+    		bitmask = ARG_DRV_ALL;
+    	}
+    	printf("%s:bitmask = %d\n",  __FUNCTION__, bitmask);
+    }
+    
+    if ((argc > 3) && (argv[3] != NULL)) {
+        
+        g_on2off_interval = atoi(argv[3]);
+        printf("%s:argv[3] g_on2off_interval param = %d\n",  __FUNCTION__, g_on2off_interval);
+        if(g_on2off_interval < MIN_INTERVAL)
+    	{
+    		g_on2off_interval = MIN_INTERVAL;
+    	}
+    	if(g_on2off_interval > MAX_INTERVAL)
+    	{
+    		g_on2off_interval = MAX_INTERVAL;
+    	}
+		printf("%s:g_on2off_interval = %d\n",  __FUNCTION__, g_on2off_interval);
+    }
+    if ((argc > 4) && (argv[4] != NULL)) {
+        
+        g_off2on_interval = atoi(argv[4]);
+        printf("%s:argv[4] g_off2on_interval param = %d\n",  __FUNCTION__, g_off2on_interval);
+        if(g_off2on_interval < MIN_INTERVAL)
+    	{
+    		g_off2on_interval = MIN_INTERVAL;
+    	}
+    	if(g_off2on_interval > MAX_INTERVAL)
+    	{
+    		g_off2on_interval = MAX_INTERVAL;
+    	}
+		printf("%s:g_off2on_interval = %d\n",  __FUNCTION__, g_off2on_interval);
+    }
+    
+	for (i = sizeof(g_state)/sizeof(g_state[0]); i > 0; )
+	{
+		g_state[--i] = 0;
+	}
+
+	printf("pid = %d\n", getpid());
+	for(i = sizeof(stack)/sizeof(void *); i > 0; )
+	{
+		stack[--i] = malloc(FIBER_STACK);
+		if(stack[i] == NULL)
+		{
+			printf("pid = %d, malloc error\n", getpid());
+			goto out;
+		}
+	}
+
+    g_wmt_fd = open("/dev/stpwmt", O_RDWR | O_NOCTTY);	
+    printf("%s:argc = %d\n", __FUNCTION__,  argc);
+    
+    if(pthread_mutex_init(&mutex, NULL) != 0)
+    {
+    	printf("%s:pthread_mutex_init fail\n",  __FUNCTION__);
+    	goto out;	
+    }
+    if(g_wmt_fd > 0)
+    {
+    	memset(&sa, 0, sizeof(sa));
+    	//signal(SIGCHLD, sig_child_term);
+		sa.sa_handler = sig_child_term;
+		sa.sa_flags = SA_NOCLDSTOP;
+		sigaction(SIGCHLD, &sa, 0);
+    	int sleepCOunter = g_count;
+    	    	
+    		if(is_bt_mask_on(bitmask) && read_reference(DRV_BT) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[0] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_BT);
+    			//clone(&func_off, (char *)stack[4] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_BT);
+    		}
+    		
+    		if(is_wifi_mask_on(bitmask) && read_reference(DRV_WIFI) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[1] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_WIFI);
+    			//clone(&func_off, (char *)stack[5] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_WIFI);
+    		}	
+    		if(is_fm_mask_on(bitmask) && read_reference(DRV_FM) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[2] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_FM);
+    			//clone(&func_off, (char *)stack[6] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_FM);
+    		}
+    		if(is_gps_mask_on(bitmask) && read_reference(DRV_GPS) == 0)
+    		{
+    			clone(&func_on_off, (char *)stack[3] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_GPS);
+  				//clone(&func_off, (char *)stack[7] + FIBER_STACK, CLONE_VM | CLONE_FS | CLONE_FILES /*| CLONE_SIGHAND*/, (void *)DRV_GPS);
+  			}
+    		//printf("%s:left g_count = %d.\n",  __FUNCTION__, g_count);
+    		sleep(sleepCOunter * (g_on2off_interval + g_off2on_interval));
+    }
+out:
+	
+	for(i = sizeof(stack)/sizeof(void *); i > 0; )
+	{
+		printf("%s:pid = %d, free stack information.\n",  __FUNCTION__, getpid());
+		if (NULL != stack[--i])
+		{
+			free(stack[i]);
+		}
+		stack[i] = NULL;
+	}
+    if(g_wmt_fd > 0)
+    {
+    	close(g_wmt_fd);
+    	g_wmt_fd  = -1;
+    }
+    printf("%s:pid = %d, exit.\n",  __FUNCTION__, getpid());
+    return 0;
+}
diff --git a/src/connectivity/combo_tool/src/wmt_ioctl.h b/src/connectivity/combo_tool/src/wmt_ioctl.h
new file mode 100755
index 0000000..78d7f25
--- /dev/null
+++ b/src/connectivity/combo_tool/src/wmt_ioctl.h
@@ -0,0 +1,27 @@
+#ifndef _WMT_IOCTL_H_
+#define _WMT_IOCTL_H_
+
+#include <sys/ioctl.h>
+
+#define WMT_IOC_MAGIC 0xa0
+#define WMT_IOCTL_SET_PATCH_NAME	 	_IOW(WMT_IOC_MAGIC,4,char*)
+#define WMT_IOCTL_SET_STP_MODE		 	_IOW(WMT_IOC_MAGIC,5,int)
+#define WMT_IOCTL_FUNC_ONOFF_CTRL		_IOW(WMT_IOC_MAGIC,6,int)
+#define WMT_IOCTL_LPBK_POWER_CTRL		_IOW(WMT_IOC_MAGIC,7,int)
+#define WMT_IOCTL_LPBK_TEST				_IOWR(WMT_IOC_MAGIC,8,char*)
+#define WMT_IOCTL_GET_CHIP_INFO			_IOR(WMT_IOC_MAGIC,12,int)
+#define WMT_IOCTL_SET_LAUNCHER_KILL		_IOW(WMT_IOC_MAGIC,13,int)
+#define WMT_IOCTL_SET_PATCH_NUM			_IOW(WMT_IOC_MAGIC,14,int)
+#define WMT_IOCTL_SET_PATCH_INFO		_IOW(WMT_IOC_MAGIC,15,char*)
+#define WMT_IOCTL_PORT_NAME          	_IOWR(WMT_IOC_MAGIC, 20, char*)
+#define WMT_IOCTL_WMT_CFG_NAME       	_IOWR(WMT_IOC_MAGIC, 21, char*)
+#define WMT_IOCTL_WMT_QUERY_CHIPID   	_IOR(WMT_IOC_MAGIC,  22, int)
+#define WMT_IOCTL_WMT_TELL_CHIPID    	_IOW(WMT_IOC_MAGIC,  23, int)
+#define WMT_IOCTL_WMT_COREDUMP_CTRL  	_IOW(WMT_IOC_MAGIC, 24, int)
+#define WMT_IOCTL_SEND_BGW_DS_CMD		_IOW(WMT_IOC_MAGIC,25,char*)
+#define WMT_IOCTL_ADIE_LPBK_TEST		_IOWR(WMT_IOC_MAGIC,26,char*)
+#define WMT_IOCTL_GET_APO_FLAG          _IOR(WMT_IOC_MAGIC, 28, int)
+#define WMT_IOCTL_FW_DBGLOG_CTRL        _IOR(WMT_IOC_MAGIC, 29, int)
+#define WMT_IOCTL_DYNAMIC_DUMP_CTRL     _IOR(WMT_IOC_MAGIC, 30, char*)
+
+#endif
diff --git a/src/connectivity/combo_tool/src/wmt_loopback.c b/src/connectivity/combo_tool/src/wmt_loopback.c
new file mode 100755
index 0000000..ea0065e
--- /dev/null
+++ b/src/connectivity/combo_tool/src/wmt_loopback.c
@@ -0,0 +1,321 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+#include "wmt_ioctl.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <endian.h>
+#include <linux/serial.h> /* struct serial_struct  */
+
+#define LEN_MAX 1024
+
+typedef enum {
+    LEN_FIXED = 0,
+    LEN_INC   = 1,
+    LEN_DEC   = 2,
+    LEN_RAND  = 3,
+    COMBO_POWER_ON  = 4, 
+    COMBO_POWER_OFF = 5,
+    ADIE_LPK = 6,
+    LPBK_OP_MAX
+} LPBK_OP_ENUM;
+
+unsigned char WMT_TEST_LPBK_CMD[] = {0x1, 0x2, 0x0, 0x0, 0x7};
+unsigned char WMT_TEST_LPBK_EVT[] = {0x2, 0x2, 0x0, 0x0, 0x0};
+/*
+unsigned char out_buf[2048] = {0};
+unsigned char in_buf[2048] = {0};
+*/
+struct lpbk_package{
+	long payload_length;
+	unsigned char out_payload[2048];
+	unsigned char in_payload[2048];
+};
+
+static int wmt_loopback(int type, int count, int max, int delay) {
+    ssize_t s_result = 0;
+    int wmt_fd;
+    int ret = -1;
+    int loop = 0;
+    int offset;
+    unsigned short buf_length = 0;
+    unsigned short len_in_cmd;
+	struct lpbk_package lpbk_buffer;
+    printf("*type(%d) count(%d) max(%d) \n", type, count, max);
+
+    if(type >= LPBK_OP_MAX){
+        printf("[%s] cannot support %d opeartion\n", __FUNCTION__, type);
+    	return -1;
+    }
+    
+    /* open wmt dev */
+    wmt_fd = open("/dev/stpwmt", O_RDWR | O_NOCTTY);
+    if (wmt_fd < 0) {
+        printf("[%s] Can't open stpwmt \n", __FUNCTION__);
+    	return -1;
+    }
+
+    if(type == COMBO_POWER_ON){
+        printf("[power on combo chip]\n");
+        if(ioctl(wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 1) != 0)
+        {
+            printf("[%s] power on combo chip failed\n", __FUNCTION__);
+            close(wmt_fd);
+            wmt_fd = -1;
+            return -1;
+        } else {
+            close(wmt_fd);
+            printf("[power on combo chip ok!]\n");
+        }       
+        return 0;
+    }
+
+    if(type == COMBO_POWER_OFF){
+        printf("[power off combo chip]\n");
+        if(ioctl(wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 0) != 0)
+        {
+            printf("[%s] power off combo chip failed\n", __FUNCTION__);
+            close(wmt_fd);
+            ret = -1;
+        } else {
+            close(wmt_fd);
+            printf("[power off combo chip ok!]\n");
+        }
+        return 0;
+    }
+    
+    /*turn LPBK function on*/
+    printf("[power on combo chip]\n");
+    if(ioctl(wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 1) != 0)
+    {
+        printf("[%s] Can't power on combo chip ok! failed\n", __FUNCTION__);
+        close(wmt_fd);
+        wmt_fd = -1;
+        return -1;
+    } else {
+        printf("[power on combo chip ok!]\n");
+    }     
+		
+    /* init length */
+    switch (type) {
+        case LEN_FIXED:
+            buf_length = (unsigned short)max;
+            break;
+        case LEN_INC:
+            buf_length = 1;
+            break;
+        case LEN_DEC:
+            buf_length = max;
+            break;
+        default:
+            /* random */
+            break;
+    }
+
+    if( (type >= LEN_FIXED) && (type <= LEN_RAND) )
+    {
+        for (loop = 0; loop < count; loop++) {
+            //<1> init buffer
+            memset((void *)&lpbk_buffer, 0, sizeof(struct lpbk_package));
+            lpbk_buffer.payload_length = buf_length;
+            for (offset = 0; offset < buf_length; offset++) {
+                lpbk_buffer.out_payload[offset] = (offset + 1)/*for test use: begin from 1*/  & 0xFF;
+            }
+            
+            /*<2> do LPBK*/
+            usleep(delay * 1000);   
+
+            if(( ret = ioctl(wmt_fd, WMT_IOCTL_LPBK_TEST, &lpbk_buffer)) != lpbk_buffer.payload_length){
+                printf("[%s] LPBK operation failed, return length = %d\n", __FUNCTION__, ret);
+                break;
+            }
+            
+            /*<3> compare result*/
+            if (memcmp(lpbk_buffer.in_payload, lpbk_buffer.out_payload, lpbk_buffer.payload_length)) {
+                printf("[%s] WMT_TEST_LPBK_CMD payload compare error\n", __FUNCTION__);
+                break;
+            }
+            printf("[%s] exec WMT_TEST_LPBK_CMD succeed(loop = %d, size = %ld) \n", __FUNCTION__, loop, lpbk_buffer.payload_length);
+
+            /*<4> update buffer length */
+            switch (type) {
+            case LEN_INC:
+                buf_length = (buf_length == max) ? 1 : buf_length + 1;
+                break;
+            case LEN_DEC:
+                buf_length = (buf_length == 1) ? max : buf_length - 1;
+                break;
+            case LEN_RAND:
+                buf_length = rand() % max + 1;
+                break;
+            default:
+                /* no change */
+                break;
+            }
+        }
+    }
+    else if( type == ADIE_LPK )
+    {
+        int adie_chipID = 0;
+        for (loop = 0; loop < count; loop++) {
+            //<1> init buffer
+            memset((void *)&lpbk_buffer, 0, sizeof(struct lpbk_package));
+            adie_chipID = 0;
+            
+            /*<2> do LPBK*/
+            usleep(delay * 1000);   
+
+            if(( ret = ioctl(wmt_fd, WMT_IOCTL_ADIE_LPBK_TEST, &lpbk_buffer)) != 2){
+                printf("[%s] ADIE_LPK operation failed, return length = %d\n", __FUNCTION__, ret);
+                break;
+            }
+            adie_chipID = ((lpbk_buffer.out_payload[1] >> 4) & 0xf)*1000 + 
+                          (lpbk_buffer.out_payload[1] & 0xf)*100 + 
+                          ((lpbk_buffer.out_payload[0] >> 4) & 0xf)*10 + 
+                          (lpbk_buffer.out_payload[0] & 0xf);
+            
+            /*<3> compare result*/
+            if ( adie_chipID != max ) {
+                printf("[%s] ADIE_LPK payload compare error\n", __FUNCTION__);
+                break;
+            }
+            printf("[%s] exec ADIE_LPK succeed(loop = %d, ChipID = %d) \n", __FUNCTION__, 
+                loop, adie_chipID);
+        }
+    }
+    
+    /*Not to power off chip on default, please manually to do this*/
+#if 0    
+	/*turn off LPBK function*/
+    if(ioctl(wmt_fd, 7, 0) != 0)
+    {
+    	printf("[%s] turn lpbk function off failed\n", __FUNCTION__);
+		ret = -1;
+    }
+    else
+    {
+    	ret = 0;
+    }
+#endif 
+    ret = 0;
+
+end:
+    if (loop != count) {
+        printf("fail at loop(%d) buf_length(%d)\n", loop, buf_length);
+    }
+
+    /* close wmt dev */
+    if (wmt_fd >= 0) {
+        close(wmt_fd);
+    }
+
+    return ret;
+}
+static void print_usage(void)
+{
+	unsigned int usage_lines = 0;
+	static char *(usage[]) = {
+		"6620_wmt_lpbk type count length delay",	
+		"	--type: essential",
+		"		-0: loopback test  with fixed packet length",
+		"		-1: loopback test with packet length increase 1 per packet based on 1",
+		"		-2: loopback test packet length decrease 1 per packet based on 1024",
+		"		-3: loopback test with random packet length",
+		"		-4: only turn loopback function on without test",
+		"		-5: only turn loopback function off without test",
+		"		-6: loopback test spi bus by get Adie chpid in SOC chip",
+		"	--count: optional, total packet count, 1000 by default",
+		"	--length: optional, 1 ~ 1024, 1024 by default",	
+		"	--delay: optional, interval between packets (ms), 0 by default",
+
+	};
+	for (usage_lines = 0 ; usage_lines < sizeof (usage)/sizeof(usage[0]); usage_lines++)
+	{
+		printf("%s\n", usage[usage_lines]);
+	}
+	
+}
+
+int main(int argc, char *argv[])
+{
+    int type = LEN_FIXED;
+    int count = 1000;
+    int length = 1024;
+    int delay = 0;
+	if(argc <= 1)
+	{
+		printf ("Error lack of arguments\n");
+		print_usage();
+		return -1;
+	}
+	
+    if ((argc > 1) && (argv[1] != NULL)) {
+        printf("type: argv[1] %s %d\n", argv[1], atoi(argv[1]));
+        type = atoi(argv[1]);
+    }
+
+    if ((argc > 2) && (argv[2] != NULL)) {
+        printf("count: argv[2] %s %d\n", argv[2], atoi(argv[2]));
+        count = atoi(argv[2]);
+    }
+
+    if ((argc > 3) && (argv[3] != NULL)) {
+        printf("count: argv[3] %s %d\n", argv[3], atoi(argv[3]));
+        length = atoi(argv[3]);
+        if (0 == length) {
+            printf("length is zero, reset default value 1024\n");
+            length = 1024;
+        }
+    }
+
+    if ((argc > 4) && (argv[4] != NULL)) {
+        printf("count: argv[4] %s %d\n", argv[4], atoi(argv[4]));
+        delay = atoi(argv[4]);
+    }
+    return wmt_loopback(type, count, length, delay);
+}
+
diff --git a/src/connectivity/combo_tool/src/yocto_stp_uart_launcher.c b/src/connectivity/combo_tool/src/yocto_stp_uart_launcher.c
new file mode 100755
index 0000000..1166cf5
--- /dev/null
+++ b/src/connectivity/combo_tool/src/yocto_stp_uart_launcher.c
@@ -0,0 +1,1549 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/******************************************************************************
+*                         C O M P I L E R   F L A G S
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                    E X T E R N A L   R E F E R E N C E S
+*******************************************************************************
+*/
+#include "wmt_ioctl.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <pthread.h>
+/*#include <syslog.h>*/
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+// For directory operation
+#include <dirent.h>
+#include <sys/uio.h>
+#include <linux/serial.h> /* struct serial_struct  */
+
+/******************************************************************************
+*                              C O N S T A N T S
+*******************************************************************************
+*/
+/* !defined(ANDROID) */
+#ifndef ALOGI
+#define ALOGI printf
+#endif
+#ifndef ALOGE
+#define ALOGE printf
+#endif
+#ifndef ALOGD
+#define ALOGD printf
+#endif
+#ifndef PROPERTY_VALUE_MAX
+#define PROPERTY_VALUE_MAX (128)
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "6620_launcher"
+
+#ifndef N_MTKSTP
+#define N_MTKSTP    (15 + 1)  /* MediaTek WCN Serial Transport Protocol */
+#endif
+
+#define HCIUARTSETPROTO        _IOW('U', 200, int)
+
+#define CUST_COMBO_WMT_DEV "/dev/stpwmt"
+#define CUST_COMBO_STP_DEV "/dev/ttyMT2"  //-- for ALPS
+#define CUST_COMBO_PATCH_PATH "/etc/firmware"  //-- for ALPS
+
+#define CUST_BAUDRATE_DFT (115200)
+
+#define CUST_MULTI_PATCH (1)
+#define MTK_WCN_ENABLE_COREDUMP_BY_PROPERTY 0
+
+typedef enum {
+    STP_MIN = 0x0,
+    STP_UART_FULL = 0x1,
+    STP_UART_MAND = 0x2,
+    STP_BTIF_FULL = 0x3,
+    STP_SDIO = 0x4,
+    STP_MAX = 0x5,
+}STP_MODE;
+
+#define MAX_CMD_LEN (NAME_MAX+1)
+
+typedef enum {
+    UART_DISABLE_FC = 0, /*NO flow control*/
+    UART_MTK_SW_FC = 1,  /*MTK SW Flow Control, differs from Linux Flow Control*/
+    UART_LINUX_FC = 2,   /*Linux SW Flow Control*/
+    UART_HW_FC = 3,      /*HW Flow Control*/
+} STP_UART_FC;
+
+typedef struct {
+    const char *key;
+    const char *defValue;
+    char value[PROPERTY_VALUE_MAX];
+} SYS_PROPERTY;
+
+typedef struct {
+    STP_UART_FC fc;
+    int parity;
+    int stop_bit;
+} STP_UART_CONFIG;
+
+typedef struct {
+    STP_MODE eStpMode;
+    char *pPatchPath;
+    char *pPatchName;
+    char *gStpDev;
+    int iBaudrate;
+    STP_UART_CONFIG sUartConfig;
+}STP_PARAMS_CONFIG, *P_STP_PARAMS_CONFIG;
+
+
+#if CUST_MULTI_PATCH
+typedef struct {
+    int dowloadSeq;
+    char addRess[4];
+    char patchName[256];
+} STP_PATCH_INFO, *P_STP_PATCH_INFO;
+#endif
+
+typedef struct {
+    const char *pCfgItem;
+    char cfgItemValue[NAME_MAX + 1];
+} CHIP_ANT_MODE_INFO, *P_CHIP_ANT_MODE_INFO;
+
+
+typedef struct {
+    int chipId;
+    STP_MODE stpMode;
+    CHIP_ANT_MODE_INFO antMode;
+}CHIP_MODE_INFO, *P_CHIP_MODE_INFO;
+#ifndef WMT_PLAT_APEX
+CHIP_MODE_INFO gChipModeInfo[] = {
+    {0x6620, STP_UART_FULL, {"mt6620.defAnt", "mt6620_ant_m3.cfg"}},
+    {0x6628, STP_UART_FULL, {"mt6628.defAnt", "mt6628_ant_m1.cfg"}},
+    {0x6630, STP_UART_FULL, {"mt6630.defAnt", "mt6630_ant_m1.cfg"}},
+};
+#else
+CHIP_MODE_INFO gChipModeInfo[] = {
+    {0x6620, STP_UART_FULL, {"mt6620.defAnt", "WMT.cfg"}},
+    {0x6628, STP_UART_FULL, {"mt6628.defAnt", "WMT.cfg"}},
+    {0x6630, STP_UART_FULL, {"mt6630.defAnt", "WMT.cfg"}},
+};
+#endif
+/******************************************************************************
+*                             D A T A   T Y P E S
+*******************************************************************************
+*/
+struct cmd_hdr{
+    char *pCmd;
+    int (*hdr_func)(P_STP_PARAMS_CONFIG pStpParamsConfig);
+};
+
+struct speed_map {
+    unsigned int baud;
+    speed_t      speed;
+};
+
+/******************************************************************************
+*                                 M A C R O S
+*******************************************************************************
+*/
+#define INIT_CMD(c, e, s) {.cmd = c, .cmd_sz = sizeof(c), .evt = e, .evt_sz = sizeof(e), .str = s}
+
+/******************************************************************************
+*                   F U N C T I O N   D E C L A R A T I O N S
+*******************************************************************************
+*/
+static int set_speed(int fd, struct termios *ti, int speed);
+int setup_uart_param(int hComPort, int iBaudrate, STP_UART_CONFIG *stp_uart);
+
+int cmd_hdr_baud_115k(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_921k(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_2kk(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_2_5kk(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_3kk(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_3_2kk(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_3_25kk(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_3_5kk(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_baud_4kk(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_stp_open(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_stp_close(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_stp_rst(P_STP_PARAMS_CONFIG pStpParamsConfig);
+int cmd_hdr_sch_patch(P_STP_PARAMS_CONFIG pStpParamsConfig);
+static int check_chip_id(void);
+static int setHifInfo(int chipId, char *cfgFilePath);
+static int wmt_cfg_item_parser(char *pItem);
+static int get_wmt_cfg(int chipId);
+static speed_t get_speed(int baudrate);
+
+
+/******************************************************************************
+*                            P U B L I C   D A T A
+*******************************************************************************
+*/
+
+/******************************************************************************
+*                           P R I V A T E   D A T A
+*******************************************************************************
+*/
+static struct speed_map speeds[] = {
+    {115200,    B115200},
+    {921600,    B921600},
+    {1000000,    B1000000},
+    {1152000,    B1152000},
+    {2000000,    B2000000},
+    {2500000,    B2500000},
+    {3000000,    B3000000},
+    {3500000,    B3500000},
+    {4000000,    B4000000},
+};
+
+static STP_UART_CONFIG g_stp_uart_config;
+
+struct cmd_hdr cmd_hdr_table[] = {
+    { "baud_115200_0", cmd_hdr_baud_115k},
+    { "baud_921600_0", cmd_hdr_baud_921k},
+    { "baud_2000000_0", cmd_hdr_baud_2kk},
+    { "baud_2500000_0", cmd_hdr_baud_2_5kk},
+    { "baud_3000000_0", cmd_hdr_baud_3kk},
+    //{ "baud_3200000_0", cmd_hdr_baud_3_2kk},
+    //{ "baud_3250000_0", cmd_hdr_baud_3_25kk},
+    { "baud_3500000_0", cmd_hdr_baud_3_5kk},
+    { "baud_4000000_0", cmd_hdr_baud_4kk},
+    { "open_stp", cmd_hdr_stp_open},
+    { "close_stp", cmd_hdr_stp_close},
+    { "rst_stp", cmd_hdr_stp_rst},
+    { "srh_patch", cmd_hdr_sch_patch},
+};
+
+static volatile sig_atomic_t __io_canceled = 0;
+static char gPatchName[NAME_MAX+1]= {0};
+static char gPatchFolder[NAME_MAX+1]= {0};
+static char gStpDev[NAME_MAX+1]= {0};
+static int gStpMode = -1;
+static char gWmtCfgName[NAME_MAX+1] = {0};
+static int gWmtFd = -1;
+static int gTtyFd = -1;
+static char gCmdStr[MAX_CMD_LEN]= {0};
+static char gRespStr[MAX_CMD_LEN]= {0};
+static int gFmMode = 2; /* 1: i2c, 2: comm I/F */
+static const char *gUartName = NULL;
+
+#if CUST_MULTI_PATCH
+static unsigned int gPatchNum = 0;
+static unsigned int gDwonSeq = 0;
+static P_STP_PATCH_INFO pStpPatchInfo = NULL;
+static STP_PATCH_INFO gStpPatchInfo;
+#endif
+
+pthread_t thread_handle = -1;
+/******************************************************************************
+*                              F U N C T I O N S
+*******************************************************************************
+*/
+
+/* Used as host uart param setup callback */
+int setup_uart_param(
+    int hComPort,
+    int iBaudrate,
+    STP_UART_CONFIG *stpUartConfig) {
+    struct termios ti;
+    int  fd;
+
+    if (!stpUartConfig) {
+        ALOGE("Invalid stpUartConfig");
+        return -2;
+    }
+
+    ALOGI("setup_uart_param %d %d\n", iBaudrate, stpUartConfig->fc);
+
+    fd = hComPort;
+    if (fd < 0) {
+        ALOGE("Invalid serial port");
+        return -2;
+    }
+
+    tcflush(fd, TCIOFLUSH);
+
+    if (tcgetattr(fd, &ti) < 0) {
+        ALOGE("Can't get port settings");
+        return -3;
+    }
+
+    cfmakeraw(&ti);
+
+    ALOGI("ti.c_cflag = 0x%08x\n", ti.c_cflag);
+    ti.c_cflag |= CLOCAL;
+    ALOGI("CLOCAL = 0x%x\n", CLOCAL);
+    ALOGI("(ori)ti.c_iflag = 0x%08x\n", ti.c_iflag);
+    ALOGI("(ori)ti.c_cflag = 0x%08x\n", ti.c_cflag);
+    ALOGI("stpUartConfig->fc= %d (0:none,sw,hw,linux)\n", stpUartConfig->fc);
+
+    if (stpUartConfig->fc == UART_DISABLE_FC) {
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    } else if (stpUartConfig->fc == UART_MTK_SW_FC) {
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag |= 0x80000000; /*MTK Software FC*/
+    } else if (stpUartConfig->fc == UART_HW_FC) {
+        ti.c_cflag |= CRTSCTS;      /*RTS, CTS Enable*/
+        ti.c_iflag &= ~(0x80000000);
+    } else if (stpUartConfig->fc == UART_LINUX_FC) {
+        ti.c_iflag |= (IXON | IXOFF | IXANY); /*Linux Software FC*/
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    } else {
+        ti.c_cflag &= ~CRTSCTS;
+        ti.c_iflag &= ~(0x80000000);
+    }
+
+    ALOGI("c_c CRTSCTS = 0x%16x\n", CRTSCTS);
+    ALOGI("c_i IXON = 0x%08x\n", IXON);
+    ALOGI("c_i IXOFF = 0x%08x\n", IXOFF);
+    ALOGI("c_i IXANY = 0x%08x\n", IXANY);
+    ALOGI("(aft)ti.c_iflag = 0x%08x\n", ti.c_iflag);
+    ALOGI("(aft)ti.c_cflag = 0x%08x\n\n", ti.c_cflag);
+
+    if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+        ALOGE("Can't set port settings");
+        return -4;
+    }
+
+    /* Set baudrate */
+    if (set_speed(fd, &ti, iBaudrate) < 0) {
+        ALOGE("Can't set initial baud rate");
+        return -5;
+    }
+
+    tcflush(fd, TCIOFLUSH);
+
+    return 0;
+}
+
+static void sig_hup(int sig) {
+    fprintf(stderr, "sig_hup...\n");
+}
+
+static void sig_term(int sig) {
+    fprintf(stderr, "sig_term...\n");
+    __io_canceled = 1;
+    ioctl(gWmtFd, WMT_IOCTL_SET_LAUNCHER_KILL, 1);
+}
+
+
+static speed_t get_speed(int baudrate) {
+    unsigned int idx;
+    for (idx = 0; idx < sizeof(speeds)/sizeof(speeds[0]); idx++) {
+        if (baudrate == (int)speeds[idx].baud) {
+            return speeds[idx].speed;
+        }
+    }
+    return CBAUDEX;
+}
+
+int set_speed(int fd, struct termios *ti, int speed) {
+    struct serial_struct ss;
+    int baudenum = get_speed(speed);
+
+    if (speed != CBAUDEX) {
+        // printf("%s: standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum);
+        if ((ioctl(fd, TIOCGSERIAL, &ss)) < 0) {
+            ALOGI("%s: BAUD: error to get the serial_struct info:%s\n", __FUNCTION__, strerror(errno));
+            return -1;
+        }
+        ss.flags &= ~ASYNC_SPD_CUST;
+#if defined(SERIAL_STRUCT_EXT) /*modified in serial_struct.h*/
+        memset(ss.reserved, 0x00, sizeof(ss.reserved));
+#endif
+        ss.flags |= (1 << 13);    /*set UPFLOWLATENCY flat to tty, or serial_core will reset tty->low_latency to 0*/
+        /*set standard buadrate setting*/
+        if ((ioctl(fd, TIOCSSERIAL, &ss)) < 0) {
+            ALOGI("%s: BAUD: error to set serial_struct:%s\n", __FUNCTION__, strerror(errno));
+            return -2;
+        }
+        cfsetospeed(ti, baudenum);
+        cfsetispeed(ti, baudenum);
+        return tcsetattr(fd, TCSANOW, ti);
+    }
+    else {
+        ALOGI("%s: unsupported non-standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum);
+        return -3;
+    }
+}
+
+int cmd_hdr_baud_115k(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 115200, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_921k(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 921600, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_2kk(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 2000000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_2_5kk(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 2500000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_3kk(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3000000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_3_2kk(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3200000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_3_25kk(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3250000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_3_5kk(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3500000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_baud_4kk(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
+    return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 4000000, gStpUartConfig) : -1;
+}
+
+int cmd_hdr_stp_open(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    int ld;
+    if ((STP_UART_FULL == gStpMode) && (-1 == gTtyFd)) {
+        gTtyFd = open(gStpDev, O_RDWR | O_NOCTTY);
+        if (gTtyFd < 0) {
+            fprintf(stderr, "Can't open serial port %s\n", gStpDev);
+            return -2;
+        }
+        ALOGI("real_tty(%s) opened(%d)\n", gStpDev, gTtyFd);
+
+        /* Set TTY to N_MTKSTP line discipline */
+        ld = N_MTKSTP;
+        if (ioctl(gTtyFd, TIOCSETD, &ld) < 0) {
+            fprintf(stderr, "Can't set ldisc to N_MTKSTP\n");
+            return -3;
+        }
+
+         // printf("Set tty->low_latency\n");
+         if (ioctl(gTtyFd, HCIUARTSETPROTO, 0) < 0) {
+                ALOGE("Can't set HCIUARTSETPROTO\n");
+                return -4;
+        }
+        return 0;
+    }
+    else {
+        fprintf(stderr, "stp_open fail: stp_mode(%d) real_tty_fd(%d) \n", gStpMode, gTtyFd);
+        return -1;
+    }
+}
+
+int cmd_hdr_stp_close(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    int ld;
+
+    if ((STP_UART_FULL == gStpMode) && (0 <= gTtyFd)) {
+        /* Restore TTY line discipline */
+        ld = N_TTY;
+        if (ioctl(gTtyFd, TIOCSETD, &ld) < 0) {
+            ALOGE("Can't restore line discipline");
+            return -2;
+        }
+
+        close(gTtyFd);
+        gTtyFd = -1;
+        return 0;
+    } else if (gTtyFd == -1) {
+        return 0;
+    } else {
+        fprintf(stderr, "stp_close fail: stp_mode(%d) real_tty_fd(%d) \n", gStpMode, gTtyFd);
+        return -1;
+    }
+}
+
+int cmd_hdr_stp_rst(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    int ret = 0;
+    /*this step fail?*/
+    ret = cmd_hdr_stp_close(pStpParamsConfig);
+    /*here, launcher is close state*/
+    ret = cmd_hdr_stp_open(pStpParamsConfig);
+    return ret;
+}
+
+#if CUST_MULTI_PATCH
+int cmd_hdr_sch_patch(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    // #define PATCH_PATH "/system/etc/firmware"
+    int chipId = 0;
+    int hwVersion = 0;
+    int fwVersion = 0;
+    char chipName[16] = {0};
+    char patchFullName[256] = {0};
+#if (MTK_COMBO_USING_PATCH_NAME==1)
+    char patchName[128] = {0};
+#endif /* MTK_COMBO_USING_PATCH_NAME */
+    unsigned int patchVer = 0;
+    DIR *pDir = NULL;
+    int patchFd = -1;
+    int iRet = 0;
+    int bytes;
+    unsigned int patchNum = 0;
+    char patchInfo[8] = {0};
+    unsigned int isFirst = 1;
+    P_STP_PATCH_INFO pstPaInfo = NULL;
+    struct dirent* pDirent = NULL;
+
+    if (gWmtFd > 0) {
+        /*1. ioctl to get CHIP ID*/
+        chipId = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 0);
+        if ((0x0321 == chipId) || (0x0335 == chipId) || (0x0337 == chipId)) {
+                chipId = 0x6735;
+                ALOGI("for denali chipid convert\n");
+        }
+        if (0x0326 == chipId) {
+          chipId = 0x6755;
+          ALOGI("for jade chipid convert\n");
+        }
+        if (0x0279 == chipId) {
+          chipId = 0x6797;
+          ALOGI("for everest chipid convert\n");
+        }
+        strncpy(chipName, "mt", strlen("mt"));
+        sprintf(chipName + strlen("mt"), "%04x", chipId);
+
+        if ((!strcmp(chipName, "mt6620")) || (!strcmp(chipName, "mt6628")) || (!strcmp(chipName, "mt6630")) ||
+            (!strcmp(chipName, "mt6572")) || (!strcmp(chipName, "mt6582")) || (!strcmp(chipName, "mt6592")) ||
+            (!strcmp(chipName, "mt8127"))|| (!strcmp(chipName, "mt7623"))  || (!strcmp(chipName, "mt6571")) ||
+            (!strcmp(chipName, "mt6752")) ||
+            (!strcmp(chipName, "mt8163")) || (!strcmp(chipName, "mt6580")) ||
+            (!strcmp(chipName, "mt6735")) || (!strcmp(chipName, "mt6755")) || (!strcmp(chipName, "mt6797")) ||
+			(!strcmp(chipName, "mt8167"))) {
+            if ((!strcmp(chipName, "mt6572")) || (!strcmp(chipName, "mt6582")) || (!strcmp(chipName, "mt6592"))) {
+                strncpy(chipName, "ROMv1", strlen("ROMv1"));
+                chipName[5] = '\0';
+            } else if (!strcmp(chipName, "mt8127") || !strcmp(chipName, "mt6571")) {
+                                strncpy(chipName, "ROMv2", strlen("ROMv2"));
+                                chipName[5] = '\0';
+            } else if (!strcmp(chipName, "mt6755") ||!strcmp(chipName, "mt6752") || !strcmp(chipName, "mt6735")
+                        || !strcmp(chipName, "mt8163") || !strcmp(chipName, "mt6580") || !strcmp(chipName, "mt7623")
+                        || !strcmp(chipName, "mt8167")) {
+                        strncpy(chipName, "ROMv2_lm", strlen("ROMv2_lm"));
+            } else if (!strcmp(chipName, "mt6797")) {
+                strncpy(chipName, "ROMv3", strlen("ROMv3"));
+                chipName[5] = '\0';
+            }
+            strcat(chipName, "_patch");
+            ALOGI("patch name pre-fix:%s\n", chipName);
+            /*2. ioctl to get FIRMWARE VERSION*/
+            fwVersion = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 2);
+            ALOGI("fwVersion:0x%04x\n", fwVersion);
+            /*3. open directory patch located*/
+            if (NULL == pStpParamsConfig->pPatchPath) {
+                pStpParamsConfig->pPatchPath = CUST_COMBO_PATCH_PATH;
+            }
+
+            {
+                pDir = opendir(pStpParamsConfig->pPatchPath);
+                if (NULL == pDir) {
+                    ALOGE("patch path cannot be opened");
+                    iRet = -1;
+                    return iRet;
+                }
+                while (NULL != (pDirent = readdir(pDir))) {
+                    patchVer = 0;
+
+                    if (0 == (strncmp(pDirent->d_name, chipName, strlen(chipName)))) {
+                        /*4.1. search patch name begined with chipName*/
+                        strcpy(patchFullName, pStpParamsConfig->pPatchPath);
+                        strcat(patchFullName, "/");
+                        // robust, if input patch is /etc/firmwre/ no issue should be happened.
+                        strcat(patchFullName, pDirent->d_name);
+
+                        ALOGI("%s\n", patchFullName);
+#if (MTK_COMBO_USING_PATCH_NAME==1)
+                        strcpy (patchName, pDirent->d_name);
+#endif /* MTK_COMBO_USING_PATCH_NAME */
+                        /*4.1. search patch name mt[CHIP ID]xxx.bin*/
+                        if (0 <= (patchFd = (open(patchFullName, O_RDONLY)))) {
+                           /*4.2. read patch header and check if metch with 
+                             MAJOR+MINOR number in fw version */
+                            if (-1 != lseek(patchFd, 22, SEEK_SET)) {
+                                memset(&gStpPatchInfo, 0, sizeof(gStpPatchInfo));
+                                memset(patchInfo, 0, sizeof(patchInfo));
+
+                                bytes = read(patchFd, ((char *)&patchVer) + 1, 1);
+                                if (-1 == bytes) {
+                                    ALOGI("read patchVer1 failed!\n");
+                                    goto readfailed;
+                                }
+                                bytes = read(patchFd, ((char *)&patchVer), 1);
+                                if (-1 == bytes) {
+                                    ALOGI("read patchVer failed!\n");
+                                    goto readfailed;
+                                }
+                                  /*print hardware version information in patch*/
+                                ALOGI("fw Ver in patch: 0x%04x\n", patchVer);
+                                if (0 == ((patchVer ^ fwVersion) & 0x00ff)) {
+                                    bytes = read(patchFd, patchInfo, 4);
+                                    if (-1 == bytes) {
+                                        ALOGI("read patchInfo failed!\n");
+                                        goto readfailed;
+                                     }
+                                    patchInfo[4] = '\0';
+                                    ALOGI("read patch info:0x%02x,0x%02x,0x%02x,0x%02x\n",
+                                    patchInfo[0], patchInfo[1], patchInfo[2], patchInfo[3]);
+                                    if (1 == isFirst) {
+                                        gPatchNum = (patchInfo[0] & 0xF0) >> 4;
+                                        ALOGI("gpatchnum = [%d]\n", gPatchNum);
+                                        ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NUM, gPatchNum);
+
+                                        gDwonSeq = (patchInfo[0] & 0x0F);
+                                        ALOGI("gdwonseq = [%d]\n", gDwonSeq);
+                                        gStpPatchInfo.dowloadSeq = gDwonSeq;
+                                        memcpy(gStpPatchInfo.addRess, patchInfo, sizeof(gStpPatchInfo.addRess));
+                                        gStpPatchInfo.addRess[0] = 0x00;
+#if (MTK_COMBO_USING_PATCH_NAME==1)
+                                        strncpy(gStpPatchInfo.patchName, patchName,
+                                            sizeof(gStpPatchInfo.patchName) - 1);
+#else
+                                        strncpy(gStpPatchInfo.patchName, patchFullName,
+                                            sizeof(gStpPatchInfo.patchName) - 1);
+#endif /* MTK_COMBO_USING_PATCH_NAME */
+                                        gStpPatchInfo.patchName[sizeof(gStpPatchInfo.patchName) - 1] = '\0';
+                                        ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_INFO, &gStpPatchInfo);
+                                        isFirst++;
+                                     } else {
+                                        gDwonSeq = (patchInfo[0] & 0x0F);
+                                        ALOGI("gdwonseq = [%d]\n", gDwonSeq);
+                                        gStpPatchInfo.dowloadSeq = gDwonSeq;
+                                        memcpy(gStpPatchInfo.addRess, patchInfo, sizeof(gStpPatchInfo.addRess));
+                                        gStpPatchInfo.addRess[0] = 0x00;
+#if (MTK_COMBO_USING_PATCH_NAME==1)
+                                        strncpy(gStpPatchInfo.patchName, patchName,
+                                            sizeof(gStpPatchInfo.patchName) - 1);
+#else
+                                        strncpy(gStpPatchInfo.patchName, patchFullName,
+                                            sizeof(gStpPatchInfo.patchName) - 1);
+#endif /* MTK_COMBO_USING_PATCH_NAME */
+                                        gStpPatchInfo.patchName[sizeof(gStpPatchInfo.patchName) - 1] = '\0';
+                                        ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_INFO, &gStpPatchInfo);
+                                    }
+                                }
+                            }
+                            else {
+                                ALOGE("seek failed\n");
+                            }
+readfailed:
+                            close(patchFd);
+                            patchFd = -1;
+                        }
+                        else {
+                            ALOGI("open patch file(%s) failed\n", patchFullName);
+                            // ALOGE(patchFullName);
+                        }
+                    }
+                }
+                /*5. return value*/
+                closedir(pDir);
+                pDir = NULL;
+            }
+        }
+    }
+    else {
+        ALOGE("file descriptor is not valid\n");
+        iRet = -2;
+    }
+    return iRet;
+}
+#else
+int cmd_hdr_sch_patch(P_STP_PARAMS_CONFIG pStpParamsConfig) {
+    // #define PATCH_PATH "/system/etc/firmware"
+    int chipId = 0;
+    int hwVersion = 0;
+    int fwVersion = 0;
+    char chipName[16] = {0};
+    char patchFullName[256] = {0};
+    unsigned int patchVer = 0;
+    DIR *pDir = NULL;
+    int patchFd = -1;
+    struct dirent* pDirent = NULL;
+    int iRet = -1;
+
+    if (gWmtFd > 0) {
+    /*1. ioctl to get CHIP ID*/
+        chipId = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 0);
+        strcpy(chipName, "mt");
+        sprintf(chipName + strlen(chipName), "%04x", chipId);
+        strcat(chipName, "_patch");
+        ALOGI("patch name pre-fix:%s\n", chipName);
+        fwVersion = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 2);
+        ALOGI("fwVersion:0x%04x\n", fwVersion);
+    /*3. open directory patch located*/
+        if (NULL == pStpParamsConfig->pPatchPath) {
+            pStpParamsConfig->pPatchPath = CUST_COMBO_PATCH_PATH;
+        }
+        pDir = opendir(pStpParamsConfig->pPatchPath);
+        if (NULL == pDir) {
+            ALOGE("patch path cannot be opened");
+            iRet = -2;
+            return iRet;
+        }
+        while (NULL != (pDirent = readdir(pDir))) {
+            patchVer = 0;
+
+            if (0 == (strncmp(pDirent->d_name, chipName, strlen(chipName)))) {
+                /*4.1. search patch name begined with chipName*/
+                strcpy(patchFullName, pStpParamsConfig->pPatchPath);
+                strcat(patchFullName, "/");  // robust, if input patch is /etc/firmwre/ no issue should be happened.
+                strcat(patchFullName, pDirent->d_name);
+
+                ALOGI("%s\n", patchFullName);
+                /*4.1. search patch name mt[CHIP ID]xxx.bin*/
+                if (0 < (patchFd = (open(patchFullName, O_RDONLY)))) {
+                  /*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */
+                    if (-1 != lseek(patchFd, 22, SEEK_SET)) {
+                        read(patchFd, ((char *)&patchVer) + 1, 1);
+                        read(patchFd, ((char *)&patchVer), 1);
+                        /*print firmware version information in patch*/
+                          ALOGI("fw Ver in patch: 0x%04x\n", patchVer);
+                          if (0 == ((patchVer ^ fwVersion) & 0x00ff)) {
+                                ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, patchFullName);
+                                ALOGI("fw Ver in patch matches with firmware version\n");
+                                iRet = 0;
+                                close(patchFd);
+                                break;
+                            }
+                    }
+                    else {
+                        ALOGE("seek failed\n");
+                    }
+                    close(patchFd);
+                    patchFd = -1;
+                }
+                else {
+                    // printf("open patch file(%s) failed\n", patchFullName);
+                    ALOGE(patchFullName);
+                }
+          }
+        }
+
+        /*5. return value*/
+        closedir(pDir);
+        pDir = NULL;
+    }
+    else {
+        ALOGE("file descriptor is not valid\n");
+        iRet = -1;
+    }
+    return iRet;
+}
+#endif
+/*
+ret 0: success
+ret 1: cmd not found
+ret -x: handler return value
+*/
+int handle_cmd(P_STP_PARAMS_CONFIG pStpParamsConfig, char *cmd, int len) {
+    int ret = 1;
+    int i;
+    int cmd_len;
+
+    for (i = 0; i < (int)(sizeof(cmd_hdr_table)/sizeof(cmd_hdr_table[0])); ++i) {
+        cmd_len = (int)strlen(cmd_hdr_table[i].pCmd);
+        if (!strncmp(cmd_hdr_table[i].pCmd, cmd, (len < cmd_len) ? len : cmd_len)) {
+            ret = (*cmd_hdr_table[i].hdr_func)(pStpParamsConfig);
+        }
+    }
+
+    return ret;
+}
+
+void display_usage(int chipid) {
+    unsigned int index = 0;
+    char * usage1[] = {
+        "MTK WCN combo tool set, version 1.0-release",
+        "Usage: consys_launcher -m mode -p patchfolderpath",
+        "    -m (BT/GPS/FM common interface mode selection)",
+        "        -1: UART mode (common interface: UART)",
+        "        -3: BTIF mode (common interface: BTIF)",
+        "        -4: SDIO mode (common interface: SDIO)",
+        "    -p (MTK WCN soc conssy chip firmware patch location)",
+        "        -e.g. /etc/firmware",
+        "e.g. consys_launcher -m 3 -p /etc/firmware/",
+    };
+        char * usage2[] = {
+        "MTK WCN combo tool set, version 1.0-release",
+        "Usage: 6620_launcher -m mode -p patchfolderpath [-d uartdevicenode] [-b baudrate] [-c uartflowcontrol]",
+//        "    -m (BT/GPS/FM common interface mode selection)",
+//        "        -1: UART mode (common interface: UART)",
+//        "        -1: UART full mode (common interface UART)",
+//        "        -2: UART mandetary mode (common interface UART)",
+        "        -4: UART mode (common interface SDIO)",
+        "    -p (MTK WCN Combo chip firmware patch location)",
+        "        -e.g. /etc/firmware",
+        "    -b (Baudrate set when BT/GPS/FM runs under UART mode, no needed under SDIO mode)",
+        "        -115200/921600/2000000/2500000/3000000/3500000/4000000",
+        "    -d (UART device node, when under UART mode, no needed under SDIO mode)",
+        "        -e.g. /dev/ttyMT1, /dev/ttyMT2, /dev/ttyHS2, etc.",
+        "    -c (UART flowcontrol set)",
+        "        -0, no flowcontrol default value, please donot modify this parameter",
+        "e.g. 6620_launcher 4 /etc/firmware/mt6628_patch_hdr.bin",
+        "e.g. 6620_launcher -m 1 -p /etc/firmware/",
+        "e.g. 6620_launcher -m 1 -n /etc/firmware/mt6628_patch_hdr.bin",
+        "e.g. 6620_launcher -m 4 -d /dev/ttyMT2 -b 4000000 -n /etc/firmware/mt6628_patch_hdr.bin",
+    };
+    if (0x6582 == chipid || 0x8127 == chipid) {
+           for (index = 0; index < sizeof(usage1)/sizeof(usage1[0]); index++) {
+               ALOGI("%s\n", usage1[index]);
+           }
+    } else {
+            for (index = 0; index < sizeof(usage2)/sizeof(usage2[0]); index++) {
+                ALOGI("%s\n", usage2[index]);
+           }
+    }
+    exit(EXIT_FAILURE);
+}
+
+int para_valid_check(P_STP_PARAMS_CONFIG pStpParamConfig) {
+    if ((NULL != pStpParamConfig->pPatchPath) || (NULL != pStpParamConfig->pPatchName)) {
+        if (NULL != pStpParamConfig->pPatchPath) {
+            ALOGI("MCU patch folder path: %s\n", pStpParamConfig->pPatchPath);
+        }
+        if (NULL != pStpParamConfig->pPatchName) {
+            ALOGI("MCU patch full path: %s\n", pStpParamConfig->pPatchName);
+        }
+    }
+    else {
+        puts("MCU patch name or patch not found, exit.");
+        return -1;
+    }
+    if (pStpParamConfig->eStpMode != STP_SDIO && pStpParamConfig->eStpMode != STP_UART_MAND &&
+        pStpParamConfig->eStpMode != STP_UART_FULL) {
+        puts("Stp Mode is not set, common interface use default: SDIO Mode");
+        pStpParamConfig->eStpMode = STP_SDIO;
+        return 0;
+    }
+    // SDIO mode: eStpMode = STP_SDIO && (pPachName != NULL || pPatchPath != NULL)
+    if (pStpParamConfig->eStpMode == STP_SDIO) {
+        ALOGI("Common Interface: SDIO mode\n");
+    }
+    else if (pStpParamConfig->eStpMode == STP_UART_MAND || pStpParamConfig->eStpMode == STP_UART_FULL) {
+        ALOGI("Common Interface: UART mode\n");
+        if (NULL == pStpParamConfig->gStpDev) {
+            pStpParamConfig->gStpDev = CUST_COMBO_STP_DEV;
+            ALOGI("no uart device input, use default: %s\n", pStpParamConfig->gStpDev);
+        }
+        if (pStpParamConfig->iBaudrate < 0) {
+            // FixMe:Chaozhong, add baudrate validation check
+            pStpParamConfig->iBaudrate = 4000000;
+            ALOGI("no baudrate input, use default: %d\n", pStpParamConfig->iBaudrate);
+        }
+    }
+    return 0;
+}
+
+static int wmt_cfg_item_parser(char *pItem) {
+    int maxIndex  = sizeof (gChipModeInfo) / sizeof (gChipModeInfo[0]);
+    int index = 0;
+    int length = 0;
+    char *str = NULL;
+    char *keyStr = NULL;
+    char *valueStr = NULL;
+    if (NULL == pItem) {
+        ALOGI("Warning:pItem is NULL\n");
+        return -1;
+    }
+    /*all item must be start with mt66xx*/
+    str = strstr(pItem, "m");
+    if (NULL == str) {
+        ALOGI("Warning:no string start with 'm' found in %s\n", pItem);
+        return -2;
+    }
+
+    for (index = 0; index < maxIndex; index++) {
+        keyStr = (char*)gChipModeInfo[index].antMode.pCfgItem;
+        if (0 == strncasecmp(str, keyStr, strlen(keyStr))) {
+            str = strstr(str, "=");
+            if (NULL == str) {
+                ALOGI("Warning:no '=' found in %s\n", str);
+                return -3;
+            }
+            str = strstr(str, "m");
+            if (NULL == str) {
+                ALOGI("Warning:no 'm' found in %s\n", str);
+                return -4;
+            }
+            while (((*str) == ' ') || ((*str) == '\t') || ((*str) == '\n')) {
+                if (str >= pItem + strlen(pItem)) {
+                    break;
+                }
+                str++;
+            }
+            valueStr = str;
+            while (((*str) != ' ') && ((*str) != '\t') && ((*str) != '\0') &&
+                ((*str) != '\n') && ((*str) != '\r')) {
+                if (str >= pItem + strlen(pItem)) {
+                    ALOGI("break\n");
+                    break;
+                }
+                str++;
+            }
+            *str = '\0';
+            length = sizeof(gChipModeInfo[index].antMode.cfgItemValue);
+            strncpy(gChipModeInfo[index].antMode.cfgItemValue, valueStr, length - 1);
+            gChipModeInfo[index].antMode.cfgItemValue[length - 1] = '\0';
+            ALOGI("Info:key:%s value:%s\n", keyStr, gChipModeInfo[index].antMode.cfgItemValue);
+            break;
+        }
+    }
+    return 0;
+}
+
+static int get_coredump_flag(void) {
+    return 2; /* default disable */
+}
+
+static void set_coredump_flag(void) {
+#define COREDUMP_CTRL_FILE "/data/coredump"
+    int coredumpEnableFlag = 0;
+    int iRet = -1;
+    int coredumpFd = -1;
+    if (gWmtFd < 0) {
+        ALOGI("%s:invalid wmt fd\n", __func__);
+        return;
+    }
+    /* simplify flag in linux and android property & buildtype cases */
+    coredumpEnableFlag = get_coredump_flag();
+    ioctl(gWmtFd, WMT_IOCTL_WMT_COREDUMP_CTRL, coredumpEnableFlag);
+    return;
+}
+
+static int get_wmt_cfg(int chipId) {
+#define WMTCFGFILEPATH "/system/etc/firmware/WMT.cfg"
+#define OPENMODE "r"
+#define MAXLINELEN 512
+    FILE * file = NULL;
+    int iRet = -1;
+    char *pStr = NULL;
+    char line[MAXLINELEN];
+
+    file = fopen(WMTCFGFILEPATH, OPENMODE);
+    if (NULL == file) {
+        ALOGI("%s cannot be opened, errno:%d\n", WMTCFGFILEPATH, errno);
+        return -2;
+    }
+    iRet = 0;
+    do {
+        pStr = fgets(line, MAXLINELEN, file);
+        if (NULL == pStr) {
+            ALOGI("NULL is returned, eighter EOF or error maybe found\n");
+            break;
+        }
+
+        wmt_cfg_item_parser(line);
+        memset(line, 0, MAXLINELEN);
+    } while (pStr != NULL);
+
+    if (NULL != file) {
+        if (0 == fclose(file)) {
+            ALOGI("close %s succeed\n", WMTCFGFILEPATH);
+        }
+        else {
+            ALOGI("close %s failed, errno:%d\n", WMTCFGFILEPATH, errno);
+        }
+    }
+    return iRet;
+}
+
+
+static int get_chip_info_index(int chipId) {
+    int i = 0;
+    int index = -1;
+    int left = 0;
+    int middle = 0;
+    int right = sizeof(gChipModeInfo) / sizeof(gChipModeInfo[0]) - 1;
+    if ((chipId < gChipModeInfo[left].chipId) || (chipId > gChipModeInfo[right].chipId))
+        return index;
+
+    middle = (left + right) / 2;
+    while (left <= right) {
+        if (chipId > gChipModeInfo[middle].chipId) {
+            left = middle + 1;
+        } else if (chipId < gChipModeInfo[middle].chipId) {
+            right = middle - 1;
+        } else {
+            index = middle;
+            break;
+        }
+        middle = (left + right) / 2;
+    }
+
+    if (0 > index)
+        ALOGI("no supported chipid found\n");
+    else
+        ALOGI("index:%d, chipId:0x%x\n", index, gChipModeInfo[index].chipId);
+
+    return index;
+}
+
+/* TBD in platform-specific way */
+static int get_persist_chip_id(void) { return -1; }
+static int set_persist_chip_id(const int id) { return 0; }
+
+/* return 0 for not ready, otherwise ready */
+static int get_drv_rdy(void) {
+    /* GeK: no property to communicate with wmt_loader, and we need another way
+     * to check driver ready. Maybe query ioctl(COMBO_IOCTL_DO_MODULE_INIT) to
+     * WCN_COMBO_LOADER_DEV is a possible way for both android and non-android.
+     */
+    ALOGI("WARNING!!! Need a correct way to check driver ready!!!");
+    return 1;
+}
+
+static int query_chip_id(void) {
+    int chipId;
+    int chk_id;
+    int iRet = -1;
+
+    chipId = get_persist_chip_id();
+
+    if (get_chip_info_index(chipId) >= 0)
+        return chipId;
+
+    // no persistent information found
+    // get chip id
+    chipId = ioctl(gWmtFd, WMT_IOCTL_WMT_QUERY_CHIPID, NULL);
+    if (chipId <= 0)
+        return -1;
+
+    ALOGI("chip id is 0x%x\n", chipId);
+    iRet = set_persist_chip_id(chipId);
+
+    if (iRet) {
+        ALOGI("set persistent fail:%d\n", iRet);
+        return -1;
+    }
+    return chipId;
+}
+
+static int check_chip_id(void) {
+#define COMBO_IOC_MAGIC        'h'
+#define COMBO_IOCTL_GET_CHIP_ID  _IOR(COMBO_IOC_MAGIC, 0, int)
+#define COMBO_IOCTL_SET_CHIP_ID  _IOW(COMBO_IOC_MAGIC, 1, int)
+    int chipId = -1;
+    int fdHifsdio = -1;
+
+    // read from system property
+    chipId = get_persist_chip_id();
+    // open HIF-SDIO
+    fdHifsdio = open("/dev/hifsdiod", O_RDWR | O_NOCTTY);
+    if (fdHifsdio < 0) {
+        ALOGI("open hifsdiod fail\n");
+        return -1;
+    }
+
+    // read from config file
+    if (0 > get_chip_info_index(chipId)) {
+        int ret;
+        // no wcn.combo.chipid property information found
+        // get chip id
+        chipId = ioctl(fdHifsdio, COMBO_IOCTL_GET_CHIP_ID, NULL);
+        ALOGI("chip id is 0x%x\n", chipId);
+        // assume we get 0x6628 here
+        ALOGI("chiId:0x%x, setting to persistent\n", chipId);
+        ret = set_persist_chip_id(chipId);
+        if (ret)
+            chipId = -1;
+    } else {
+        ioctl(fdHifsdio, COMBO_IOCTL_SET_CHIP_ID, chipId);
+        ALOGI("set chipId(0x%x) to HIF-SDIO module\n", chipId);
+    }
+    // close HIF-SDIO
+    close(fdHifsdio);
+    fdHifsdio = -1;
+    return chipId;
+}
+
+static int setHifInfo(int chipId, char *cfgFilePath) {
+    int index = -1;
+    index = get_chip_info_index(chipId);
+    if ((gStpMode <= STP_MIN) || (STP_SDIO < gStpMode)) {
+        ALOGI("STP Mode is not set, fetching default mode...\n");
+        if (0 <= index) {
+            gStpMode = gChipModeInfo[index].stpMode;
+        } else {
+            // gStpMode = STP_UART_FULL;
+            gStpMode = -1;
+        }
+    }
+
+    if ((0 <= index) && (NULL != cfgFilePath)) {
+#if (MTK_COMBO_USING_PATCH_NAME==1)
+        memset(gWmtCfgName, 0, sizeof(gWmtCfgName));
+        strncpy(gWmtCfgName, gChipModeInfo[index].antMode.cfgItemValue, sizeof(gWmtCfgName) - 1);
+        gWmtCfgName[strlen(gChipModeInfo[index].antMode.cfgItemValue)] = '\0';
+#else
+        memset(gWmtCfgName, 0, sizeof(gWmtCfgName));
+        strncpy (gWmtCfgName, cfgFilePath, sizeof(gWmtCfgName) - 1);
+        gWmtCfgName[sizeof(gWmtCfgName) - 1] = '\0';
+        strcat(gWmtCfgName, "/");
+        strcat(gWmtCfgName, gChipModeInfo[index].antMode.cfgItemValue);
+        gWmtCfgName[strlen(cfgFilePath) + strlen("/") + strlen(gChipModeInfo[index].antMode.cfgItemValue)] = '\0';
+#endif /* MTK_COMBO_USING_PATCH_NAME */
+    } else {
+        memset(gWmtCfgName, 0, sizeof(gWmtCfgName));
+    }
+    ALOGI("chipId(0x%04x), default Mode(%d), strlen(gWmtCfgName)(%u), wmtCfgFile(%s)\n",
+        chipId, gStpMode, strlen(gWmtCfgName), gWmtCfgName);
+    return gStpMode;
+}
+
+#if (MTK_COMBO_ENABLE_WIFI_IN_LAUNCHER==1)
+#define CUST_COMBO_WIFI_DEV "/dev/wmtWifi"
+#define POWER_ON_WIFI "1"
+#define POWER_ON_WIFI_LEN 1
+static int gWifiFd = -1;
+
+static int enable_wifi(void) {
+    int retryCounter = 0;
+    int i_ret = -1;
+
+    gWifiFd = open(CUST_COMBO_WIFI_DEV, O_RDWR | O_NOCTTY);
+    do {
+        if (gWifiFd < 0) {
+            ALOGI("Can't open device node(%s) error:%d \n", CUST_COMBO_WIFI_DEV, gWifiFd);
+            usleep(300000);
+            gWifiFd = open(CUST_COMBO_WIFI_DEV, O_RDWR | O_NOCTTY);
+        } else {
+           break;
+        }
+        retryCounter++;
+    } while (retryCounter < 20);
+
+    if (gWifiFd > 0) {
+        do {
+            i_ret = write(gWifiFd, POWER_ON_WIFI, POWER_ON_WIFI_LEN);
+            if (i_ret == 1) {
+                    ALOGI("Power on device node(%s) gWifiFd:%d succeed !!\n", CUST_COMBO_WIFI_DEV, gWifiFd);
+                    break;
+            } else {
+                   ALOGI("Power on device node(%s) gWifiFd:%d Fail (%d) and retry\n", CUST_COMBO_WIFI_DEV, gWifiFd, i_ret);
+            }
+            retryCounter++;
+            usleep(300000);
+        } while (retryCounter < 20);
+    }
+    close(gWifiFd);
+
+    return 0;
+}
+#endif /* MTK_COMBO_ENABLE_WIFI_IN_LAUNCHER */
+
+static void* launcher_pwr_on_chip(void * arg) {
+        int retryCounter = 0;
+        int i_ret = -1;
+        int chipid = *(int*) arg;
+        char readyStr[PROPERTY_VALUE_MAX] = {0};
+        int iRet = -1;
+
+        pthread_setname_np(pthread_self(), "pwr_on_conn");
+
+        ALOGI("enter power on connsys flow");
+        do {
+                i_ret = ioctl(gWmtFd, WMT_IOCTL_LPBK_POWER_CTRL, 1);
+                if (0 == i_ret) {
+                        break;
+                } else {
+                        ioctl(gWmtFd, WMT_IOCTL_LPBK_POWER_CTRL, 0);
+                        ALOGI("power on %x failed, retrying, retry counter:%d\n", chipid, retryCounter);
+                        usleep(1000000);
+                }
+                retryCounter++;
+        } while (retryCounter < 20);
+
+#if (MTK_COMBO_ENABLE_WIFI_IN_LAUNCHER==1)
+        ALOGI("enter enable wifi");
+        enable_wifi();
+#endif /* MTK_COMBO_ENABLE_WIFI_IN_LAUNCHER */
+
+        pthread_detach(thread_handle);
+        thread_handle = -1;
+
+        return NULL;
+}
+static void* launcher_set_fwdbg_flag(void * arg) {
+    int i_ret = -1;
+    int flag = *(int*) arg;
+
+    pthread_setname_np(pthread_self(), "dump_fwemi_log");
+    ALOGI("dump firmware dbg log from emi buffer ");
+    i_ret = ioctl(gWmtFd, WMT_IOCTL_FW_DBGLOG_CTRL, flag);
+    if (i_ret < 0) {
+        ALOGI("ioctl error: err msg: %s\n", strerror(errno));
+        pthread_detach(thread_handle);
+        thread_handle = -1;
+    }
+    return NULL;
+}
+
+/*
+ * -m: mode (SDIO/UART)
+ * -d: uart device node
+ * -b: baudrate
+ * -c: enable SW FC or not
+ * -p: patch folder path
+ * -n: patch file name (fullpath) 
+ *
+ */
+int main(int argc, char *argv[]) {
+    static const char *opString = "m:d:b:c:p:n:?";
+    struct uart_t *u = NULL;
+    int opt, ld, err;
+    int baud = 0;
+    struct sigaction sa;
+    struct pollfd fds[2];
+    int fd_num = 0;
+    int len = 0;
+    int uartFcCtrl = 0;
+    int argCount = 0;
+    int chipId = -1;
+    int i_ret = 1;
+    int retry = 0;
+    int polling_flag = 0;
+    int fwdbgEnableFlag = 0;
+    char readyStr[PROPERTY_VALUE_MAX] = {0};
+    STP_PARAMS_CONFIG sStpParaConfig;
+    char fwStateStr0[PROPERTY_VALUE_MAX] = {0};
+    char fwStateStr[PROPERTY_VALUE_MAX] = {0};
+
+    do {
+        i_ret = get_drv_rdy();
+        if (i_ret)
+            break;
+        usleep(300000);
+    } while (1);
+
+    do {
+            gWmtFd = open(CUST_COMBO_WMT_DEV, O_RDWR | O_NOCTTY);
+            if (gWmtFd < 0) {
+                ALOGI("Can't open device node(%s) error:%d \n", CUST_COMBO_WMT_DEV, gWmtFd);
+                usleep(300000);
+            } else
+                break;
+    } while (1);
+    ALOGE("open device node succeed.(Node:%s, fd:%d) \n", CUST_COMBO_WMT_DEV, gWmtFd);
+    do {
+            chipId = query_chip_id();
+            if (0 > chipId) {
+                usleep(300000);
+                chipId = ioctl(gWmtFd, WMT_IOCTL_WMT_QUERY_CHIPID, NULL);
+                ALOGI("chiId from kernel by ioctl:0x%04x\n", chipId);
+                if (-1 != chipId)
+                    break;
+                } else
+                    break;
+    } while (1);
+    ALOGI("chiId:0x%04x\n", chipId);
+
+    if ((0x0321 == chipId) || (0x0335 == chipId) || (0x0337 == chipId)) {
+        chipId = 0x6735;
+        ALOGI("for denali chipid convert\n");
+    }
+    if (0x0326 == chipId) {
+            chipId = 0x6755;
+            ALOGI("for jade chipid convert\n");
+    }
+    if ((0x6735 == chipId) || (0x6752 == chipId) || (0x6582 == chipId) || (0x6592 == chipId)
+              || (0x6572 == chipId) || (0x6571 == chipId) || (0x8127 == chipId)
+              || (0x8163 == chipId) || (0x6580 == chipId) || (0x6755 == chipId)
+              || (0x6797 == chipId) || (0x7623 == chipId) || (0x8167 == chipId)) {
+                ALOGI("run SOC chip flow\n");
+                gStpMode = STP_BTIF_FULL;
+                memset(gPatchFolder, 0, sizeof(gPatchFolder));
+                opt = getopt(argc, argv, opString);
+                while (opt != -1) {
+                    switch (opt) {
+                        case 'm':
+                            gStpMode = atoi(optarg);
+                            sStpParaConfig.eStpMode  = gStpMode;
+                            ALOGI("stpmode[%d]\n", gStpMode);
+                            break;
+                        case 'p':
+                            // gPatchFolder = optarg;
+                            strcpy(gPatchFolder, optarg);
+                            sStpParaConfig.pPatchPath = gPatchFolder;
+                            break;
+                        case '?':
+                        default:
+                            display_usage(chipId);
+                            break;
+                    }
+                    opt = getopt(argc, argv, opString);
+                }
+        /* send default patch file name path to driver */
+        ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, gPatchName);
+        /* set fm mode & stp mode*/
+        ioctl(gWmtFd, WMT_IOCTL_SET_STP_MODE, ((gFmMode & 0x0F) << 4)  |(gStpMode & 0x0F));
+#ifndef WMT_PLAT_APEX
+       set_coredump_flag();
+#endif
+       } else {
+           ALOGI("run combo chip flow\n");
+           sStpParaConfig.pPatchPath = NULL;
+           sStpParaConfig.pPatchName = NULL;
+           sStpParaConfig.gStpDev = NULL;
+           sStpParaConfig.eStpMode  = -1;
+           sStpParaConfig.iBaudrate  = -1;
+           sStpParaConfig.sUartConfig.fc = UART_DISABLE_FC;
+           sStpParaConfig.sUartConfig.parity = 0;
+           sStpParaConfig.sUartConfig.stop_bit = 0;
+           /*Default parameters starts*/
+           baud = 4000000;
+           gStpMode = -1;
+           uartFcCtrl = UART_DISABLE_FC;
+           strncpy(gStpDev, CUST_COMBO_STP_DEV, sizeof(gStpDev) - 1);
+           gStpDev[sizeof(gStpDev) - 1] = '\0';
+           memset(gPatchFolder, 0, sizeof(gPatchFolder));
+           memset(gPatchName, 0, sizeof(gPatchName));
+           /*Default parameters ends*/
+           opt = getopt(argc, argv, opString);
+           while (opt != -1) {
+               switch (opt) {
+                   case 'm':
+                        gStpMode = atoi(optarg);
+                        sStpParaConfig.eStpMode  = gStpMode;
+                        break;
+                   case 'd':
+                        strncpy(gStpDev, optarg, sizeof(gStpDev) - 1);
+                        gStpDev[sizeof(gStpDev) - 1] = '\0';
+                        sStpParaConfig.gStpDev = gStpDev;
+                        break;
+                   case 'b':
+                        baud = atoi(optarg);
+                        sStpParaConfig.iBaudrate = baud;
+                        break;
+                   case 'c':
+                        uartFcCtrl = atoi(optarg);
+                        sStpParaConfig.sUartConfig.fc = uartFcCtrl;
+                        ALOGI("c found\n");
+                        break;
+                   case 'p':
+                       // gPatchFolder = optarg;
+                       strcpy(gPatchFolder, optarg);
+                       sStpParaConfig.pPatchPath = gPatchFolder;
+                       break;
+                   case 'n':
+                       // gPatchName = optarg;
+                       strcpy(gPatchName, optarg);
+                       sStpParaConfig.pPatchName = gPatchName;
+                       break;
+                   case '?':
+                   default:
+                       display_usage(chipId);
+                       break;
+              }
+             opt = getopt(argc, argv, opString);
+         }
+         if (0 > get_chip_info_index(chipId)) {
+             ALOGI("invalid chip, check again\n");
+             chipId = query_chip_id();
+             ALOGI("chiId:0x%04x\n", chipId);
+         }
+         ioctl(gWmtFd, WMT_IOCTL_WMT_TELL_CHIPID, chipId);
+         ALOGI("set chipId(0x%x) to HIF-SDIO module\n", chipId);
+
+         get_wmt_cfg(chipId);
+
+         setHifInfo(chipId, sStpParaConfig.pPatchPath);
+         ALOGI("HifConfig:0x%04x, wmtCfgFile:%s\n", sStpParaConfig.eStpMode, gWmtCfgName);
+#ifndef WMT_PLAT_APEX
+        set_coredump_flag();
+#endif
+        if (0 != para_valid_check(&sStpParaConfig)) {
+            // Try to use custom method to check parameters
+            if (argc > optind) {
+            // For this competible usage , we only left STP mode set and firmware patch input, omit flowcontrol set
+                // First baud for STP UART mode, otherwise, SDIO mode
+                baud = atoi(argv[optind]);
+                if (baud >=  CUST_BAUDRATE_DFT) {
+                    ALOGI("get baud rate(%d) for UART mode\n", baud);
+                    gStpMode = STP_UART_FULL;
+                    sStpParaConfig.iBaudrate = baud;
+                }
+                else if (baud == 1) {
+                    ALOGI("Definitively use SDIO mode\n");
+                    gStpMode = STP_SDIO;
+                } else {
+                    ALOGI("invalid baud rate(%d) for UART, use SDIO mode\n", baud);
+                    gStpMode = STP_SDIO;
+                }
+                sStpParaConfig.eStpMode  = gStpMode;
+                // Firmare patch analysis
+                optind++;
+                memset(gPatchName, 0, sizeof(gPatchName));
+                if (argc > optind) {
+                   strncat(gPatchName, argv[optind], sizeof(gPatchName)-1);
+                   sStpParaConfig.pPatchName = gPatchName;
+                   ALOGI("PatchFile:%s\n", sStpParaConfig.pPatchName);
+                } else {
+                   sStpParaConfig.pPatchName = NULL;
+                   ALOGI("no patch file \n");
+                }
+                // Flow Control analysis
+                optind++;
+                if (argc > optind) {
+                    uartFcCtrl = atoi(argv[optind]);
+                    sStpParaConfig.sUartConfig.fc = uartFcCtrl;
+                    ALOGI("flowcontrol flag: %d\n", sStpParaConfig.sUartConfig.fc);
+                } else {
+                    ALOGI("no flow control flat set\n");
+                }
+            }
+        }
+        if (0 != para_valid_check(&sStpParaConfig)) {
+            display_usage(chipId);
+        }
+        /* send default patch file name path to driver */
+        ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, gPatchName);
+        /* send uart name to driver*/
+        if (sStpParaConfig.gStpDev) {
+            gUartName = strstr(sStpParaConfig.gStpDev, "tty");
+            if (!gUartName) {
+                ALOGI("no uart name found in %s\n", sStpParaConfig.gStpDev);
+            } else {
+                ALOGI("uart name %s\n", gUartName);
+            }
+        }
+
+        if (!gUartName) {
+            gUartName = "ttyMT2";
+            ALOGI("use default uart %s\n", gUartName);
+        }
+
+        ioctl(gWmtFd, WMT_IOCTL_PORT_NAME, gUartName);
+
+        /* send hardware interface configuration to driver */
+        ioctl(gWmtFd, WMT_IOCTL_SET_STP_MODE, ((baud & 0xFFFFFF) << 8) | ((gFmMode & 0x0F) << 4)  |(gStpMode & 0x0F));
+
+        /* send WMT config name configuration to driver */
+        ioctl(gWmtFd, WMT_IOCTL_WMT_CFG_NAME, gWmtCfgName);
+    }
+
+    ioctl(gWmtFd, WMT_IOCTL_SET_LAUNCHER_KILL, 0);
+
+    i_ret = ioctl(gWmtFd, WMT_IOCTL_GET_APO_FLAG, NULL);
+    if (i_ret != 0) {
+        if (pthread_create(&thread_handle, NULL, launcher_pwr_on_chip, &chipId)) {
+            ALOGE("create pwr on thread fail\n");
+        } else {
+            ALOGI("create pwr on thread ok\n");
+        }
+    } else {
+        ALOGI("no supported always power on\n");
+    }
+    /*set signal handler*/
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_flags   = SA_NOCLDSTOP;
+    sa.sa_handler = SIG_IGN;
+    sigaction(SIGCHLD, &sa, NULL);
+    sigaction(SIGPIPE, &sa, NULL);
+
+    sa.sa_handler = sig_term;
+    sigaction(SIGTERM, &sa, NULL);
+    sigaction(SIGINT,  &sa, NULL);
+
+    sa.sa_handler = sig_hup;
+    sigaction(SIGHUP, &sa, NULL);
+
+    fds[0].fd = gWmtFd; /* stp_wmt fd */
+    fds[0].events = POLLIN | POLLRDNORM; /* wait read events */
+    ++fd_num;
+
+    while (!__io_canceled) {
+        fds[0].revents = 0;
+        err = poll(fds, fd_num, 2000);  // 5 seconds
+        if (err < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+            else {
+                ALOGI("poll error:%d errno:%d, %s\n", err, errno, strerror(errno));
+                break;
+            }
+        }
+        else if (!err) {
+            continue;
+        }
+        if (fds[0].revents & POLLIN) {
+            memset(gCmdStr, 0, sizeof(gCmdStr));
+            len = read(gWmtFd, gCmdStr, sizeof(gCmdStr)-1);
+            if (len > 0 && len < (int)sizeof(gCmdStr)) {
+                // printf ("POLLIN(%d) and read(%d)\n", gWmtFd, len);
+            }
+            else {
+                ALOGI("POLLIN(%d) but read fail:%d\n", gWmtFd, len);
+                continue;
+            }
+            gCmdStr[len] = '\0';
+            // ALOGI("rx_cmd_str:%s\n", gCmdStr);
+            err = handle_cmd(&sStpParaConfig, gCmdStr, len);
+            if (!err) {
+                // ALOGI("handle_cmd(%s), respond ok \n", gCmdStr);
+                snprintf(gRespStr, sizeof(gRespStr), "ok");
+            }
+            else {
+                if (err == 1) {
+                    snprintf(gRespStr, sizeof(gRespStr), "cmd not found");
+                }
+                else {
+                    snprintf(gRespStr, sizeof(gRespStr), "resp_%d", err);
+                }
+            }
+            ALOGI("cmd(%s) resp(%s)\n", gCmdStr, gRespStr);
+            len = write(gWmtFd, gRespStr, strlen(gRespStr));
+            if (len != (int)strlen(gRespStr)) {
+                fprintf(stderr, "write resp(%d) fail: len(%d), errno(%d, %s)\n",
+                    gWmtFd, len, errno, (len == -1) ? strerror(errno) : "");
+            }
+        }
+    }
+clean_up:
+
+    if (gWmtFd >= 0) {
+        close(gWmtFd);
+        gWmtFd = -1;
+    }
+
+    if (gStpMode == STP_UART_FULL && gTtyFd >= 0) {
+        /* Restore TTY line discipline */
+        ld = N_TTY;
+        if (ioctl(gTtyFd, TIOCSETD, &ld) < 0) {
+            ALOGE("Can't restore line discipline");
+            exit(1);
+        }
+
+        close(gTtyFd);
+        gTtyFd = -1;
+    }
+
+    return 0;
+}
+
diff --git a/src/connectivity/combo_tool/stp_dump-service b/src/connectivity/combo_tool/stp_dump-service
new file mode 100644
index 0000000..87504bf
--- /dev/null
+++ b/src/connectivity/combo_tool/stp_dump-service
@@ -0,0 +1,64 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides: stp_dump
+# Required-Start:	$syslog $local_fs $remote_fs 
+# Required-Stop:	$syslog $local_fs $remote_fs 
+# Default-Start:	2 3 4 5
+# Default-Stop:		0 1 6
+# Short-Description: stp dump Daemon
+### END INIT INFO
+
+. /etc/init.d/init-functions
+prog=stp_dump
+PIDFILE=/var/run/$prog.pid
+DESC="stp dump Daemon"
+start() {
+	log_daemon_msg "Starting $DESC" "$prog"
+	start_daemon_background -p $PIDFILE /usr/bin/stp_dump
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+	exit 0
+}
+
+stop() {
+	log_daemon_msg "Stopping $DESC" "$prog"
+	killproc -p $PIDFILE /usr/bin/stp_dump
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+}
+
+force_reload() {
+	stop
+	start
+
+}
+
+case "$1" in
+	start)
+		start
+		;;
+	stop)
+		stop
+		;;
+	force-reload)
+		force_reload
+		;;
+	restart)
+		stop
+		start
+		;;
+
+	*)
+		echo "$Usage: $prog {start|stop|force-reload|restart}"
+		exit 2
+esac
diff --git a/src/connectivity/combo_tool/stp_dump.service b/src/connectivity/combo_tool/stp_dump.service
new file mode 100755
index 0000000..d08df2d
--- /dev/null
+++ b/src/connectivity/combo_tool/stp_dump.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=stp dump Daemon
+After=wmtd.service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/stp_dump
+
+[Install]
+Alias=stp_dump
+WantedBy=multi-user.target
diff --git a/src/connectivity/combo_tool/wmtd-service b/src/connectivity/combo_tool/wmtd-service
new file mode 100644
index 0000000..c369f41
--- /dev/null
+++ b/src/connectivity/combo_tool/wmtd-service
@@ -0,0 +1,64 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides: wmtd
+# Required-Start:	$syslog $local_fs $remote_fs $network 
+# Required-Stop:	$syslog $local_fs $remote_fs $network 
+# Default-Start:	2 3 4 5
+# Default-Stop:		0 1 6
+# Short-Description: WMT Daemon
+### END INIT INFO
+
+. /etc/init.d/init-functions
+prog=wmtd
+PIDFILE=/var/run/$prog.pid
+DESC="WMT Daemon"
+start() {
+	log_daemon_msg "Starting $DESC" "$prog"
+	start_daemon_background -p $PIDFILE /usr/bin/wmt_loader
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+	exit 0
+}
+
+stop() {
+	log_daemon_msg "Stopping $DESC" "$prog"
+	killproc -p $PIDFILE /usr/bin/wmt_loader
+	if [ $? -ne 0 ]; then
+		log_end_msg 1
+		exit 1
+	fi
+	if [ $? -eq 0 ]; then
+		log_end_msg 0
+	fi
+}
+
+force_reload() {
+	stop
+	start
+
+}
+
+case "$1" in
+	start)
+		start
+		;;
+	stop)
+		stop
+		;;
+	force-reload)
+		force_reload
+		;;
+	restart)
+		stop
+		start
+		;;
+
+	*)
+		echo "$Usage: $prog {start|stop|force-reload|restart}"
+		exit 2
+esac
diff --git a/src/connectivity/combo_tool/wmtd.service b/src/connectivity/combo_tool/wmtd.service
new file mode 100644
index 0000000..dff20b3
--- /dev/null
+++ b/src/connectivity/combo_tool/wmtd.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=WMT Daemon
+After=network.target
+Requires=nvram_daemon.service
+After=nvram_daemon.service
+
+[Service]
+ExecStart=/usr/bin/wmt_loader
+Type=oneshot
+
+[Install]
+Alias=wmtd
+WantedBy=multi-user.target