[Feature]Merge MP1_MR1 from MTK

Change-Id: I3fc364555acf14f1c308b6be7b05f21f92757fd0
diff --git a/src/apps/atom-base/progs/property/libprop/request.h b/src/apps/atom-base/progs/property/libprop/request.h
old mode 100644
new mode 100755
index 8fe4f62..5a005c7
--- a/src/apps/atom-base/progs/property/libprop/request.h
+++ b/src/apps/atom-base/progs/property/libprop/request.h
@@ -8,7 +8,7 @@
 /* REQUEST definitions                                                         */
 /*******************************************************************************/
 #define SNCFG_REQUEST_MAGIC			0x2287
-#define SNCFG_REQUEST_UNIX_SOCKET	"/var/run/sncfg.socket"
+#define SNCFG_REQUEST_UNIX_SOCKET	"/tmp/prop/sncfg.socket"
 
 #ifdef __MEM_COSTDOWN__
 #define SNCFG_REQUEST_MAX_SIZE		512
diff --git a/src/apps/atom-base/progs/property/prop/inc/request.h b/src/apps/atom-base/progs/property/prop/inc/request.h
old mode 100644
new mode 100755
index 7db6006..2f8c39b
--- a/src/apps/atom-base/progs/property/prop/inc/request.h
+++ b/src/apps/atom-base/progs/property/prop/inc/request.h
@@ -39,7 +39,8 @@
 /* REQUEST definitions                                                         */
 /*******************************************************************************/
 #define SNCFG_REQUEST_MAGIC			0x2287
-#define SNCFG_REQUEST_UNIX_SOCKET	"/var/run/sncfg.socket"
+#define SNCFG_REQUEST_FOLDER        "/tmp/prop"
+#define SNCFG_REQUEST_UNIX_SOCKET	"/tmp/prop/sncfg.socket"
 
 #ifdef __MEM_COSTDOWN__
 #define SNCFG_REQUEST_MAX_SIZE		512
diff --git a/src/apps/atom-base/progs/property/prop/prop.service b/src/apps/atom-base/progs/property/prop/prop.service
old mode 100644
new mode 100755
index 63d14f4..8aa6192
--- a/src/apps/atom-base/progs/property/prop/prop.service
+++ b/src/apps/atom-base/progs/property/prop/prop.service
@@ -2,6 +2,8 @@
 Description=prop Daemon
 
 [Service]
+User=prop
+Group=prop
 ExecStart=/usr/bin/prop
 Restart=always
 
diff --git a/src/apps/atom-base/progs/property/prop/property.c b/src/apps/atom-base/progs/property/prop/property.c
old mode 100644
new mode 100755
index 0c579df..18f96c3
--- a/src/apps/atom-base/progs/property/prop/property.c
+++ b/src/apps/atom-base/progs/property/prop/property.c
@@ -63,7 +63,7 @@
 /* SNCFGD local definitions                                                    */
 /*******************************************************************************/
 #ifndef PID_FILE
-#define PID_FILE "/var/run/sncfgd.pid"
+#define PID_FILE "/tmp/prop/sncfgd.pid"
 #endif
 
 #define CONFIG_HASH_SIZE		64
@@ -303,9 +303,14 @@
 
 static int request_init(void)
 {
-	int reqfd;
+	int reqfd, res;
 	const int reuse = 1;
 
+	if (access(SNCFG_REQUEST_FOLDER, F_OK) != 0) {
+        if (mkdir(SNCFG_REQUEST_FOLDER, 0774) == -1)
+            printf("mkdir %s error! %s\n", SNCFG_REQUEST_FOLDER, (char*)strerror(errno));
+    }
+
 	/* force to re-create */
 	unlink(RequestSockAddr.sun_path);
 
diff --git a/src/bach/build.bach/work/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.cpp b/src/bach/build.bach/work/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.cpp
old mode 100644
new mode 100755
index 0f25e12..e397ec9
--- a/src/bach/build.bach/work/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.cpp
+++ b/src/bach/build.bach/work/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.cpp
@@ -92,6 +92,15 @@
     const char audioType_SpeechEchoRef_CategoryName1[1][128] = { "USBAudio" };
     const String8 audioType_SpeechEchoRef_ParamName[] = { String8("EchoRef_para") };
 
+//--------------------------------------------------------------------------------
+//audio type: SpeechDeReverb
+#define MAX_NUM_CATEGORY_TYPE_SPEECH_DEREVERB 2
+#define MAX_NUM_PARAM_SPEECH_DEREVERB 1
+    const String8 audioType_SpeechDereverb_CategoryType[ ] = {String8("Band"), String8("Profile")};
+    const char audioType_SpeechDereverb_CategoryName2[1][128] = {"Handsfree"};
+    const String8 audioType_SpeechDereverb_ParamName[ ] = {String8("derev_para")};
+
+//--------------------------------------------------------------------------------
 #define ENH_SPH_PARSER_VER 0x0001
 
     AppHandle *mAppHandle; // = appHandleGetInstance();
@@ -111,7 +120,8 @@
     //      const uint32_t DebugInfo_offset = 22;
     uint32_t MD_version = 0;
 
-    static const uint32_t SD_SphParamSize = 0xC000;  // 48K
+    //static const uint32_t SD_SphParamSize = 0xC000;  // 48K
+    static const uint32_t SD_SphParamSize = 0x10000;  // 64K
     /*==============================================================================
     *                     Lock
     *============================================================================*/
@@ -326,6 +336,12 @@
             }
             break;
         }
+        case PARSER_AUDIO_TYPE_SPEECH_DEREVERB: {
+            if (strcmp(nameParam, "derev_para") == 0) {
+                sizeDump = 16;
+            }
+            break;
+        }
         }
         snprintf(sphDumpStr, SPH_DUMP_STR_SIZE, "%s[%d]=", nameParam, sizeDump);
 
@@ -444,7 +460,7 @@
                     SpeechParam_size = 64;
                 }
 
-                if ((idxSphType == PARSER_AUDIO_TYPE_SPEECH) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_DMNR) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_GENERAL) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_MAGICLARITY)) {
+                if ((idxSphType == PARSER_AUDIO_TYPE_SPEECH) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_DMNR) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_GENERAL) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_MAGICLARITY) || (idxSphType == PARSER_AUDIO_TYPE_SPEECH_DEREVERB)) {
                     //Add parameter total size at first
                     memcpy(bufParamUnit + *sizeByteTotal, &(SpeechParam_size), sizeof(uint16_t));
                     *sizeByteTotal += sizeof(uint16_t);
@@ -898,7 +914,8 @@
         }
 
 
-        int EMI_48K_MAX_PAYLOAD_DATA_BYTE = 48 * 1024;  // 0xC000 ?
+        //int EMI_48K_MAX_PAYLOAD_DATA_BYTE = 48 * 1024;  // 0xC000 ?
+        int EMI_48K_MAX_PAYLOAD_DATA_BYTE = 64 * 1024;  // 0xC000 ?
         memset(outBuf->bufferAddr, 0, EMI_48K_MAX_PAYLOAD_DATA_BYTE);
 
         int idxProfile_Speech = 0;
@@ -1302,6 +1319,89 @@
 
         //ALOGD("End of getParamBuffer, outBuf->dataSize = %d", outBuf->dataSize);
 
+        //Start setting DEREVERB format-----------------------------------------------------------------------------------------
+        ALOGD("[DEREVERB Parsing Start]");
+
+        uint16_t ParserCheckNum_DEREVERB_End = 0;
+
+        OutDevice_VoiceBand = 0;
+        idxBand = 0;
+        idxProfile = 0;
+        numProfile = 0;
+        numBand = 0;
+
+        memset(&headerParamUnit, 0, sizeof(headerParamUnit));
+
+        headerParamUnit.sphParserVer = ENH_SPH_PARSER_VER;
+        headerParamUnit.ParserCheckingNum = 0x000E;
+        headerParamUnit.SpeechDebugNum = 0x1010;
+        // 5 reserved elements = 0
+
+        size = (16 + 16 + 16 + 3) * 1024; //using a new page for Dereverb since the pervious pages are full
+        memcpy((char *)outBuf->bufferAddr + size, &headerParamUnit, sizeof(headerParamUnit));
+        size += sizeof(headerParamUnit);
+
+        memset(&paramLayerInfo, 0, sizeof(PARSER_AUDIO_TYPE_SPEECH_LAYERINFO_STRUCT));
+
+        paramLayerInfo.audioTypeName = (char *)Parser_audioTypeNameList[PARSER_AUDIO_TYPE_SPEECH_DEREVERB];
+        paramLayerInfo.numCategoryType = MAX_NUM_CATEGORY_TYPE_SPEECH_DEREVERB;
+        paramLayerInfo.numParam = MAX_NUM_PARAM_SPEECH_DEREVERB;
+        paramLayerInfo.categoryType.assign(audioType_SpeechDereverb_CategoryType, audioType_SpeechDereverb_CategoryType + paramLayerInfo.numCategoryType);
+        paramLayerInfo.paramName.assign(audioType_SpeechDereverb_ParamName, audioType_SpeechDereverb_ParamName + paramLayerInfo.numParam);
+
+        appOps = appOpsGetInstance();
+        audioType = NULL;
+        if (appOps == NULL) {
+            ALOGE("Error %s %d", __FUNCTION__, __LINE__);
+            ASSERT(0);
+            return UNKNOWN_ERROR;
+        } else {
+            audioType = appOps->appHandleGetAudioTypeByName(mAppHandle, paramLayerInfo.audioTypeName);
+        }
+
+        char *packedParamUnitFromApp_Dereverb = new char[MAX_BYTE_PARAM_SPEECH];
+        memset(packedParamUnitFromApp_Dereverb, 0, MAX_BYTE_PARAM_SPEECH);
+
+        categoryBand = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDereverb_CategoryType[0].string());
+        numBand = appOps->categoryTypeGetNumOfCategory(categoryBand);
+        categoryProfile = appOps->audioTypeGetCategoryTypeByName(audioType, audioType_SpeechDereverb_CategoryType[1].string());
+        numProfile = appOps->categoryTypeGetNumOfCategory(categoryProfile);
+
+        for (idxBand = 0; idxBand < numBand; idxBand++) { //NB, WB, SWB
+            for (idxProfile = 0; idxProfile < numProfile; idxProfile++) {
+                sizeByteFromApp = 0;
+
+                Category *CateBand = appOps->categoryTypeGetCategoryByIndex(categoryBand, idxBand);
+                paramLayerInfo.categoryName.push_back(String8(CateBand->name));//Band
+                paramLayerInfo.categoryName.push_back(String8(audioType_SpeechDereverb_CategoryName2[idxProfile]));//Profile
+
+                OutDevice_VoiceBand = ((1 << idxBand) << 12) + (idxProfile + 1);
+                memcpy((char *)outBuf->bufferAddr + size, &OutDevice_VoiceBand, sizeof(OutDevice_VoiceBand));
+                size += sizeof(OutDevice_VoiceBand);
+
+                GetSpeechParamFromAppParser_new(PARSER_AUDIO_TYPE_SPEECH_DEREVERB, &paramLayerInfo, packedParamUnitFromApp_Dereverb, &sizeByteFromApp, 1);
+
+                memcpy((char *)outBuf->bufferAddr + size, packedParamUnitFromApp_Dereverb, sizeByteFromApp);
+                size += sizeByteFromApp;
+
+                paramLayerInfo.categoryName.pop_back();
+                paramLayerInfo.categoryName.pop_back();
+
+            }
+        }
+
+        if (packedParamUnitFromApp_Dereverb != NULL) {
+            delete[] packedParamUnitFromApp_Dereverb;
+        }
+
+        ParserCheckNum_DEREVERB_End = 0x0E0E;
+        memcpy((char *)outBuf->bufferAddr + size, &ParserCheckNum_DEREVERB_End, sizeof(ParserCheckNum_DEREVERB_End));
+        size += sizeof(ParserCheckNum_DEREVERB_End);
+
+        count_print = (16 + 16 + 16 + 3) * 1024/2;
+        ALOGD("DEREVERB, SpeechParam->data [%d] = %p, %p, %p, %p, %p, %p, %p, %p", count_print, *((uint16_t *)(outBuf->bufferAddr) + count_print), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 1)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 2)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 3)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 4)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 5)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 6)), *((uint16_t *)(outBuf->bufferAddr) + (count_print + 7)));
+
+
         return 0;   //general case, return 0    when AP&MD version mismatch, use default param, return -1
     }
 
diff --git a/src/bach/build.bach/work/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.h b/src/bach/build.bach/work/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.h
old mode 100644
new mode 100755
index 99926ca..b5a6c72
--- a/src/bach/build.bach/work/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.h
+++ b/src/bach/build.bach/work/libspeech_drv/audio_big_sw/AudioSpeechEnhancement/ENH_Parser/SpeechParser.h
@@ -95,6 +95,7 @@
         PARSER_AUDIO_TYPE_SPEECH_MAGICLARITY = 3,
         PARSER_AUDIO_TYPE_SPEECH_NETWORK = 4,
         PARSER_AUDIO_TYPE_SPEECH_ECHOREF = 5,
+        PARSER_AUDIO_TYPE_SPEECH_DEREVERB = 6,
 
 
         PARSER_NUM_AUDIO_TYPE_SPEECH_TYPE  // the #types of speech_type_dynamic_param_t
@@ -109,7 +110,8 @@
         "SpeechGeneral",
         "SpeechMagiClarity",
         "SpeechNetwork",
-        "SpeechEchoRef"
+        "SpeechEchoRef",
+        "SpeechDeReverb"
     };
 
     /*****************************************************************************
diff --git a/src/bach/build.bach/work/libspeech_drv/audio_big_sw/hardware/src/SpeechParserGen95.cpp b/src/bach/build.bach/work/libspeech_drv/audio_big_sw/hardware/src/SpeechParserGen95.cpp
old mode 100644
new mode 100755
index a443c3f..36a621d
--- a/src/bach/build.bach/work/libspeech_drv/audio_big_sw/hardware/src/SpeechParserGen95.cpp
+++ b/src/bach/build.bach/work/libspeech_drv/audio_big_sw/hardware/src/SpeechParserGen95.cpp
@@ -19,12 +19,13 @@
 *                     define/enum
 * =============================================================================
 */
-#define NUM_NEED_UPDATE_XML 3
+#define NUM_NEED_UPDATE_XML 4
 #define LEN_XML_NAME 128
 const char needUpdateXmlList[NUM_NEED_UPDATE_XML][LEN_XML_NAME] = {
     "Speech",
     "SpeechDMNR",
     "SpeechGeneral",
+    "SpeechDereverb",
 };
 /*==============================================================================
 *                     Callback Function
diff --git a/src/bsp/dramk_2735/dramc_pi_basic_api.c b/src/bsp/dramk_2735/dramc_pi_basic_api.c
old mode 100644
new mode 100755
index 9f489da..be91c1a
--- a/src/bsp/dramk_2735/dramc_pi_basic_api.c
+++ b/src/bsp/dramk_2735/dramc_pi_basic_api.c
@@ -439,11 +439,6 @@
         if (gFreqTbl[u1ShuffleIdx].freq_sel == cur_freq_sel)
             break;
 
-    if(u1ShuffleIdx == DRAM_DFS_SRAM_MAX){
-        mcSHOW_ERR_MSG(("[UpdateHighestFreqInDFSTbl] Update Freq %d fail\n", new_freq_sel));
-        return;
-    }
-
     gFreqTbl[u1ShuffleIdx].freq_sel = new_freq_sel; // update
 
     gUpdateHighestFreq = TRUE;
@@ -7416,7 +7411,7 @@
 
     #if PRINT_CALIBRATION_SUMMARY
     //default set DRAM status = NO K
-    memset(p->aru4CalResultFlag, 0xffffffff, sizeof(p->aru4CalResultFlag));
+    memset(p->aru4CalResultFlag, 0xffff, sizeof(p->aru4CalResultFlag));
     memset(p->aru4CalExecuteFlag, 0, sizeof(p->aru4CalExecuteFlag));
     #if PRINT_CALIBRATION_SUMMARY_FASTK_CHECK
     memset(p->FastKResultFlag, 0xffff, sizeof(p->FastKResultFlag));
diff --git a/src/bsp/dramk_2735/dramc_pi_calibration_api.c b/src/bsp/dramk_2735/dramc_pi_calibration_api.c
old mode 100644
new mode 100755
index cd37c4b..f8b78d6
--- a/src/bsp/dramk_2735/dramc_pi_calibration_api.c
+++ b/src/bsp/dramk_2735/dramc_pi_calibration_api.c
@@ -11998,7 +11998,7 @@
 {
     U8 u1BitTemp, u1BitIdx, u1ByteIdx, u1RankIdx, backup_rank;
     U32 uiFinishCount;
-    PASS_WIN_DATA_T WinPerBit[DQ_DATA_WIDTH], VrefWinPerBit[DQ_DATA_WIDTH] = {0}, FinalWinPerBit[DQ_DATA_WIDTH];
+    PASS_WIN_DATA_T WinPerBit[DQ_DATA_WIDTH], VrefWinPerBit[DQ_DATA_WIDTH], FinalWinPerBit[DQ_DATA_WIDTH];
 
     U16 uiDelay, u2DQDelayBegin, u2DQDelayEnd, u2DQDelayStep = 1;
 
diff --git a/src/bsp/dramk_2735/dramc_top.c b/src/bsp/dramk_2735/dramc_top.c
old mode 100644
new mode 100755
index 3d00b71..2cb5dc6
--- a/src/bsp/dramk_2735/dramc_top.c
+++ b/src/bsp/dramk_2735/dramc_top.c
@@ -2371,7 +2371,7 @@
 	int ret;
 	blkdev_t *bootdev = NULL;
 	DRAM_CALIBRATION_HEADER_T hdr;
-	DRAM_CALIBRATION_MRR_DATA_T mrr_info = {0};
+	DRAM_CALIBRATION_MRR_DATA_T mrr_info;
 	DRAM_CALIBRATION_DATA_T *datap = NULL;
 
 	if (DramInfo == NULL) {
diff --git a/src/bsp/dramk_2735/emi.c b/src/bsp/dramk_2735/emi.c
old mode 100644
new mode 100755
index 3d3d213..c86bd65
--- a/src/bsp/dramk_2735/emi.c
+++ b/src/bsp/dramk_2735/emi.c
@@ -838,11 +838,6 @@
 
 	for (i = 0; i < emi_info->rk_num; i++) {
 
-		if(i >= DRAMC_MAX_RK){
-			emi_log("[update_emi_setting] rank number %d is incorrect\n", i);
-			return -1;
-		}
-
 		row = emi_info->row_width[i] - 13;
 		row_ext = row >> 2;
 		row &= 0x3;
diff --git a/src/bsp/hsm/os/erika2/include/os/os_tick.h b/src/bsp/hsm/os/erika2/include/os/os_tick.h
old mode 100644
new mode 100755
index 1b6ba50..728162c
--- a/src/bsp/hsm/os/erika2/include/os/os_tick.h
+++ b/src/bsp/hsm/os/erika2/include/os/os_tick.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-with-linking-exception
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -43,7 +44,7 @@
 /* HSM uses hsm timer as tick source. Others uses core internal timer. */
 #define OS_COUNTER_HZ		(26000000UL)
 
-#define OS_TICK_RATE_HZ		1000U
+#define OS_TICK_RATE_HZ		500U
 #define OS_TICK_RATE_MS		(1000U / OS_TICK_RATE_HZ)
 #define RTOS_MS_TO_TICK(ms)  	((ms) / OS_TICK_RATE_MS)
 
diff --git a/src/bsp/hsm/src/application/bootloader/mt2735/bootloader.c b/src/bsp/hsm/src/application/bootloader/mt2735/bootloader.c
old mode 100644
new mode 100755
index fe497ad..f0f1472
--- a/src/bsp/hsm/src/application/bootloader/mt2735/bootloader.c
+++ b/src/bsp/hsm/src/application/bootloader/mt2735/bootloader.c
@@ -42,6 +42,7 @@
 #include <config.h>
 #include <crypto_common.h>
 #include <crypto_sb.h>
+#include <crypto_ecc.h>
 #include <mcu_id.h>
 #include <memory_layout.h>
 #include <mtk_proprietary_format.h>
@@ -440,6 +441,33 @@
 	write32((GPIO_BASE + 0x464U), (4U << 24U));   /* GPIO 182 */
 }
 
+void verify_dbg_auth(void)
+{
+	uint32_t en = 0;
+	int32_t ret = SB_OK;
+	uint32_t dpv = 0;
+	uint8_t *cert;
+	uint32_t sej1 = 0, sej4 = 0;
+
+	sb_dbg_ctrl_enable(&en);
+	if (en != 1) {
+		LOGI("secure debug not enable\r\n");
+		return;
+	}
+	LOGI("secure debug enable\r\n");
+
+	cert = (uint8_t*)SEC_JTAG_CERT_BASE;
+	ret = sb_verify_dbg_certificate(cert, &dpv, &sej1, &sej4);
+
+	if (!ret) {
+		sb_config_dbg(dpv);
+		sb_jtag_config(sej1, sej4);
+		LOGI("secure debug verify pass\r\n");
+	} else {
+		LOGE("[%s][%d] JTAG authentication fail! (0x%x)\r\n", __FUNCTION__, __LINE__, ret);
+	}
+}
+
 
 int main(int argc, const char *argv[])
 {
@@ -463,7 +491,9 @@
 		os_api_st.get_resource      = NULL;
 		os_api_st.release_resource  = NULL;
 		crypto_os_set_api(&os_api_st);
+		ecc_manager_init();
 	}
+	verify_dbg_auth();
 
 	bdev_init(BDEV_BUF_BASE, BDEV_BUF_SIZE);
 	partition_init(PART_WORK_BUF_BASE, PART_WORK_BUF_SIZE);
diff --git a/src/bsp/hsm/src/application/bootloader/mt2735/include/memory_layout.h b/src/bsp/hsm/src/application/bootloader/mt2735/include/memory_layout.h
old mode 100644
new mode 100755
index cce9e63..c3477e4
--- a/src/bsp/hsm/src/application/bootloader/mt2735/include/memory_layout.h
+++ b/src/bsp/hsm/src/application/bootloader/mt2735/include/memory_layout.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -66,4 +67,7 @@
 #define BLD_MEM_BASE	(SYSRAM_RSV_BUF_BASE + SYSRAM_RSV_BUF_SIZE)
 #define BLD_MEM_SIZE	(0x20000U)	/* 128KB */
 
+/* for secure jtag certificate */
+#define SEC_JTAG_CERT_BASE (0x00040000UL)
+
 #endif /* APPLICATION_BOOTLOADER_MEMORY_LAYOUT_H */
diff --git a/src/bsp/hsm/src/build/arc_gnu.mk b/src/bsp/hsm/src/build/arc_gnu.mk
old mode 100644
new mode 100755
index cf9f040..578c7cc
--- a/src/bsp/hsm/src/build/arc_gnu.mk
+++ b/src/bsp/hsm/src/build/arc_gnu.mk
@@ -1,4 +1,5 @@
-CROSS_PREFIX := $(ARC_GNU_PATH)/bin/arc-elf32-
+# SPDX-License-Identifier: MediaTekProprietary
+
 ARCH_FLAGS := -mcpu=em4_dmips -mno-sdata -mlittle-endian -mmpy-option=6 \
 		--param l1-cache-size=16384 --param l1-cache-line-size=32 \
 		-mno-millicode -mlong-calls
@@ -25,7 +26,3 @@
 	-Map $(MAPFILE)
 
 AFLAGS := -x assembler-with-cpp
-
-CC := $(CROSS_PREFIX)gcc
-LD := $(CROSS_PREFIX)ld
-OBJCOPY := $(CROSS_PREFIX)objcopy
diff --git a/src/bsp/hsm/src/build/config.mk b/src/bsp/hsm/src/build/config.mk
old mode 100644
new mode 100755
index e1596ef..05d24a1
--- a/src/bsp/hsm/src/build/config.mk
+++ b/src/bsp/hsm/src/build/config.mk
@@ -56,7 +56,6 @@
 HSM_WDT := false
 HSM_SRI := true
 HSM_KEY_MANAGEMENT := true
-ECC_NB := true
 else ifeq ($(TARGET_IC), mt2735)
 HSM_SWITCH_CONTEXT_IRQ := 53
 HSM_CRY_AES_SHA := true
@@ -70,7 +69,7 @@
 HSM_KEY_MANAGEMENT := true
 HSM_CRYPTO_EX := true
 HSM_EFUSE := false
-ECC_NB := false
+HSM_ECC_V1 := true
 endif
 else ifeq ($(TARGET_NAME), bootloader)
 HSM_WDT := true
diff --git a/src/bsp/hsm/src/driver/platform/mt2735/clk_brom.c b/src/bsp/hsm/src/driver/platform/mt2735/clk_brom.c
old mode 100644
new mode 100755
index 50d5a2b..d9fc357
--- a/src/bsp/hsm/src/driver/platform/mt2735/clk_brom.c
+++ b/src/bsp/hsm/src/driver/platform/mt2735/clk_brom.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/bsp/hsm/src/driver/platform/mt2735/crypt_porting.c b/src/bsp/hsm/src/driver/platform/mt2735/crypt_porting.c
old mode 100644
new mode 100755
index 0b94ed5..2e819de
--- a/src/bsp/hsm/src/driver/platform/mt2735/crypt_porting.c
+++ b/src/bsp/hsm/src/driver/platform/mt2735/crypt_porting.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -39,7 +41,11 @@
 #include <crypto_ecc.h>
 #include <mt_defs.h>
 #include <os/os_hal.h>
+#include <soc/irq.h>
 
+ISR(ecc0_isr_handler) {
+	ecc_isr_handler();
+}
 
 static void crypto_porting_get_resource(void) {
 	(void)GetResource(res_crypto);
@@ -58,5 +64,7 @@
 	api_st.get_resource = crypto_porting_get_resource;
 	api_st.release_resource = crypto_porting_release_resource;
 	crypto_os_set_api(&api_st);
+
+	ecc_manager_init();
 }
 
diff --git a/src/bsp/hsm/src/driver/platform/mt2735/driver_init.c b/src/bsp/hsm/src/driver/platform/mt2735/driver_init.c
old mode 100644
new mode 100755
index 7fa05cb..6bf0e8c
--- a/src/bsp/hsm/src/driver/platform/mt2735/driver_init.c
+++ b/src/bsp/hsm/src/driver/platform/mt2735/driver_init.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/bsp/hsm/src/driver/platform/mt2735/include/soc/clk_brom.h b/src/bsp/hsm/src/driver/platform/mt2735/include/soc/clk_brom.h
old mode 100644
new mode 100755
index a82bae7..92f7daf
--- a/src/bsp/hsm/src/driver/platform/mt2735/include/soc/clk_brom.h
+++ b/src/bsp/hsm/src/driver/platform/mt2735/include/soc/clk_brom.h
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/bsp/hsm/src/driver/platform/mt2735/include/soc/topckgen_hw_brom.h b/src/bsp/hsm/src/driver/platform/mt2735/include/soc/topckgen_hw_brom.h
old mode 100644
new mode 100755
index e6be6bc..99fe986
--- a/src/bsp/hsm/src/driver/platform/mt2735/include/soc/topckgen_hw_brom.h
+++ b/src/bsp/hsm/src/driver/platform/mt2735/include/soc/topckgen_hw_brom.h
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/bsp/hsm/src/driver/platform/mt2735/mt_irq_handlers_hsm.c b/src/bsp/hsm/src/driver/platform/mt2735/mt_irq_handlers_hsm.c
old mode 100644
new mode 100755
index 2731cd0..7ec0114
--- a/src/bsp/hsm/src/driver/platform/mt2735/mt_irq_handlers_hsm.c
+++ b/src/bsp/hsm/src/driver/platform/mt2735/mt_irq_handlers_hsm.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -42,6 +44,7 @@
 #include <soc/mbox.h>
 #include <soc/mt_irq_entry.h>
 #include <soc/uart_isr.h>
+#include <crypto_ecc.h>
 
 EXC_ENTRY irq_handler_table[NUM_EXC_ALL] = {
 	[0] = mt_exc_reset,
@@ -77,7 +80,7 @@
 	[30] = mt_irq_30, /* RNG */
 	[31] = mt_irq_31, /* SIC Whirpool */
 	[32] = mt_irq_32, /* SIC TRNG */
-	[33] = mt_irq_33, /* ECC */
+	[33] = ecc0_isr_handler, /* ECC */
 	[34] = mt_irq_34, /* HASH */
 	[35] = mt_irq_35, /* RSA */
 	[36] = mt_irq_36,
diff --git a/src/bsp/hsm/src/middleware/libraries/include/aes_sha_task.h b/src/bsp/hsm/src/middleware/libraries/include/aes_sha_task.h
old mode 100644
new mode 100755
index 42def42..b48af9b
--- a/src/bsp/hsm/src/middleware/libraries/include/aes_sha_task.h
+++ b/src/bsp/hsm/src/middleware/libraries/include/aes_sha_task.h
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -136,6 +138,7 @@
     CRYPTO_ALGOFAM_ECCNIST          = 0x19,
     CRYPTO_ALGOFAM_SECURECOUNTER    = 0x1A,
     CRYPTO_ALGOFAM_RNG              = 0x1B,
+    CRYPTO_ALGOFAM_ECCNIST_SM2      = 0x1C
 
 //    CRYPTO_ALGOFAM_SIPHASH          = 0x1C,
 //    CRYPTO_ALGOFAM_ECIES            = 0x1D,
diff --git a/src/bsp/hsm/src/middleware/libraries/include/sm2_verify.h b/src/bsp/hsm/src/middleware/libraries/include/sm2_verify.h
new file mode 100755
index 0000000..4ab8d72
--- /dev/null
+++ b/src/bsp/hsm/src/middleware/libraries/include/sm2_verify.h
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: MediaTekProprietary

+

+/* 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.

+ *

+ * Copyright  (C) 2020  MediaTek Inc. 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 _SM2_VERIFY_H_

+#define _SM2_VERIFY_H_

+

+#include <stdint.h>

+#include <crypto_ecc.h>

+

+extern int kt_get_sm2_key(struct st_ecc_param_t *ecdsaParam);

+

+extern int do_sm2_trng(struct st_ecc_param_t *ecdsaParam);

+

+#endif

diff --git a/src/bsp/hsm/src/middleware/libraries/makefile b/src/bsp/hsm/src/middleware/libraries/makefile
old mode 100644
new mode 100755
index a6b742b..632da0e
--- a/src/bsp/hsm/src/middleware/libraries/makefile
+++ b/src/bsp/hsm/src/middleware/libraries/makefile
@@ -34,10 +34,9 @@
 endif
 
 ifeq ($(HSM_CRY_ECC), true)
-ifeq ($(ECC_NB), true)
 LOCAL_SRC_FILES += services/$(TEE_OS)/ecc_task_nb.c
-else
-LOCAL_SRC_FILES += services/$(TEE_OS)/ecc_task.c
+ifeq ($(HSM_ECC_V1), true)
+LOCAL_SRC_FILES += services/$(TEE_OS)/sm2_verify.c
 endif
 endif
 
diff --git a/src/bsp/hsm/src/middleware/libraries/services/optee/aes_sha_task.c b/src/bsp/hsm/src/middleware/libraries/services/optee/aes_sha_task.c
old mode 100644
new mode 100755
index 64d167e..a661089
--- a/src/bsp/hsm/src/middleware/libraries/services/optee/aes_sha_task.c
+++ b/src/bsp/hsm/src/middleware/libraries/services/optee/aes_sha_task.c
@@ -802,11 +802,11 @@
 #if defined(CONFIG_DRIVER_SOC_MT2735)
         case CRYPTO_ALGOFAM_WHP:
             msg_size = sizeof(msg_buf);
-            smi_msg_addr = 0xD0;
+            smi_msg_addr = 0xEA;
             smi_msg_size = (msg_size / 64);
-            smi_random_addr = 0x0;
+            smi_random_addr = 0xFE;
             smi_random_size = 0x10;
-            smi_digest_addr = 0x40;
+            smi_digest_addr = 0xFA;
 
             smi_random_addr_byte = smi_random_addr*16;  // smi address in bytes
             smi_msg_addr_byte = smi_msg_addr*16;        // smi address in bytes
diff --git a/src/bsp/hsm/src/middleware/libraries/services/optee/ecc_task.c b/src/bsp/hsm/src/middleware/libraries/services/optee/ecc_task.c
deleted file mode 100644
index 14ff33e..0000000
--- a/src/bsp/hsm/src/middleware/libraries/services/optee/ecc_task.c
+++ /dev/null
@@ -1,411 +0,0 @@
-// SPDX-License-Identifier: MediaTekProprietary
-
-/* 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) 2020. 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 <arch/reg_op.h>
-#include <config.h>
-#include <mt_defs.h>
-#include <os/os_hal.h>
-#include <stdint.h>
-#include <syslog.h>
-
-#include <mbox_serv.h>
-#include <string.h>
-#include <aes_sha_task.h>
-#include <ecc_debug.h>
-
-#include <os/stopwatch.h>
-
-//#include <crypto_test.h>
-#include <crypto_ecc.h>
-#include <crypto_common.h>
-#include <crypto_dma.h>
-
-#include <crypto_smc_drv.h>
-
-#include "key_management.h"
-#include "key_table.h"
-
-void ecc_task_init(void);
-
-struct mbox_serv_queue ecc_queue;
-static TaskType task_id;
-
-DeclareTask(ecc_task);
-DeclareEvent(ECC_EVENT);
-
-//==== Internal Structure
-#define ECC_ENG_MAX 12
-
-uint8_t id = 0;
-
-typedef struct {
-	struct st_ecc_param_t ecdsaParam;
-	uint8_t buffer1[48];
-	uint8_t buffer2[48];
-    uint32_t output_len;
-    uint32_t job_id;
-    uint8_t ecdsa_verify_tmp_buf[48];
-    uint8_t *real_outptr;
-    uint32_t retValPtr;
-} ecc_storage_node;
-
-static ecc_storage_node Ecc_Storage_Node[ECC_ENG_MAX];
-
-extern int do_trng(uint8_t *dest, unsigned size);
-
-static void ECDSA_Sign_Callback(void* param, int32_t err_code)
-{
-
-    int32_t  fg_ret = CRYPTO_OK;
-    struct st_ecc_param_t *ecdsaParam = (struct st_ecc_param_t *) param;
-
-    ECC_TASK_FLOW(" == ECDSA_Sign_Callback ==\r\n");
-    __SHOW_VAL("r", ecdsaParam->r, Ecc_Storage_Node[id].output_len);
-    __SHOW_VAL("s", ecdsaParam->s, Ecc_Storage_Node[id].output_len);
-
-	if(fg_ret == 0)
-	{
-		ECC_TASK_FLOW("[ECDSA signature Test PASS.]\r\n");
-		
-        *(uint8_t*)Ecc_Storage_Node[id].retValPtr = MBOX_SERV_FEEDBACK_MAGIC_NUM;
-	}
-}
-
-int32_t crypto_ecdsa_sign_srv(job_struct *pJobRsv)
-{
-    if (pJobRsv == NULL)
-    {
-        return CRYPTO_ERROR_NULL_PARAM;
-    }
-
-    ECC_TASK_FLOW(" == ECDSA Sign %d ==\r\n", pJobRsv->keyLength);
-
-    int32_t retval = 0;
-
-    uint8_t *inptr                    = (uint8_t*)pJobRsv->inputPtr;
-    uint32_t inputLength              = pJobRsv->inputLength;
-    ECC_TASK_DEBUG("inputLength: %d\r\n", inputLength);
-
-    uint8_t *outptr                   = (uint8_t*)pJobRsv->outputPtr;
-    ECC_TASK_DEBUG("outputLength: %d\r\n", pJobRsv->outputLength);
-
-    uint8_t *outptr2                  = (uint8_t*)pJobRsv->secondaryOutputPtr;
-    ECC_TASK_DEBUG("outputLength2: %d\r\n", pJobRsv->secondaryOutputLength);
-
-    struct st_ecc_param_t *ecdsaParam;
-
-    Ecc_Storage_Node[id].output_len = pJobRsv->keyLength / 8; // bits --> bytes
-    Ecc_Storage_Node[id].job_id     = pJobRsv->job_id;
-    Ecc_Storage_Node[id].retValPtr  = pJobRsv->retValPtr;
-
-    ecdsaParam = &Ecc_Storage_Node[id].ecdsaParam;
-    (void)crypto_memset(ecdsaParam, 0, sizeof(struct st_ecc_param_t));
-
-    ecdsaParam->e = inptr;
-    __SHOW_VAL("e", ecdsaParam->e, inputLength);
-
-    ecdsaParam->r = outptr;
-    ecdsaParam->s = outptr2;
-
-    ECC_TASK_DEBUG("keyLength: %d\r\n", pJobRsv->keyLength);
-    ECC_TASK_DEBUG("cryptoKeyId: 0x%x\r\n", pJobRsv->cryptoKeyId);
-    ecc_keypair_datastruct *ecc_key = NULL;
-    uint8_t ecc_k_key[48] = {0};
-
-    retval = kt_get_key(pJobRsv->cryptoKeyId, (uint8_t **)&ecc_key);
-    if (retval != KT_OK) {
-        ECC_TASK_ERROR("[TEST ERROR] kt_get_key fail!!\r\n");
-    } else {
-        ecdsaParam->d = ecc_key->private;
-    }
-
-    do_trng(ecc_k_key, sizeof(ecc_k_key));
-    ecdsaParam->k = ecc_k_key;
-    ecdsaParam->endian_mode = ECC_BIG_ENDIAN;
-
-    switch(pJobRsv->keyLength)
-    {
-        case 192:
-            retval = crypto_ecdsa_p192_sign(ecdsaParam);
-            break;
-
-        case 224:
-            retval = crypto_ecdsa_p224_sign(ecdsaParam);
-            break;
-
-        case 256:
-            retval = crypto_ecdsa_p256_sign(ecdsaParam);
-            break;
-
-        case 384:
-            retval = crypto_ecdsa_p384_sign(ecdsaParam);
-            break;
-
-        default:
-            retval = -1;
-            break;
-    }
-
-    if (0 != retval)
-    {
-        ECC_TASK_ERROR(" fail at crypto_ecdsa_p%d_sign!!\r\n", pJobRsv->keyLength);
-    }
-
-    ECDSA_Sign_Callback(ecdsaParam, 0);
-
-    return retval;
-}
-
-static void ECDSA_Verify_Callback(void* param, int32_t err_code)
-{
-    int32_t  fg_ret = CRYPTO_OK;
-    struct st_ecc_param_t *ecdsaParam = (struct st_ecc_param_t *) param;;
-
-    ECC_TASK_FLOW(" == ECDSA_Verify_Callback ==\r\n");
-
-    __SHOW_VAL("verify result -- v", ecdsaParam->v, Ecc_Storage_Node[id].output_len);
-
-    if(crypto_memcmp(Ecc_Storage_Node[id].buffer1, ecdsaParam->v, Ecc_Storage_Node[id].output_len))
-    {
-        fg_ret = -1;
-        ECC_TASK_ERROR("[ECDSA BE verify Fail!]\r\n");
-    }
-
-
-    if(fg_ret == 0)
-    {
-        ECC_TASK_FLOW("[ECDSA verification Test PASS.]\r\n");
-
-        *(uint8_t*)Ecc_Storage_Node[id].retValPtr = MBOX_SERV_FEEDBACK_MAGIC_NUM;
-    }
-    else
-    {
-         *(uint8_t*)Ecc_Storage_Node[id].retValPtr = MBOX_SERV_FEEDBACK_VERIFY_FAIL;
-    }
-
-    ECC_TASK_FLOW("[ECDSA verification end.]\r\n");
-}
-
-static int32_t crypto_ecdsa_verify_srv(job_struct *pJobRsv)
-{
-    if (pJobRsv == NULL)
-    {
-        return CRYPTO_ERROR_NULL_PARAM;
-    }
-
-    ECC_TASK_FLOW(" == ECDSA Verify %d ==\r\n", pJobRsv->keyLength);
-
-    int32_t retval = 0;
-    struct st_ecc_param_t *ecdsaParam;
-    //enum ecc_engine_id id;
-
-    uint8_t *inptr                      = (uint8_t*)pJobRsv->inputPtr;
-    uint32_t inputLength                = pJobRsv->inputLength;
-    ECC_TASK_DEBUG("inputLength: %d\r\n", inputLength);
-
-    uint8_t *inptr2                   = (uint8_t*)pJobRsv->secondaryInputPtr;
-    uint32_t inputLength2             = pJobRsv->secondaryInputLength;
-    ECC_TASK_DEBUG("inputLength2: %d\r\n", inputLength2);
-
-    uint8_t *inptr3         			= (uint8_t*)pJobRsv->tertiaryInputPtr;
-    uint32_t inputLength3        		= pJobRsv->tertiaryInputLength;
-    ECC_TASK_DEBUG("inputLength3: %d\r\n", inputLength3);
-
-    Ecc_Storage_Node[id].output_len		= pJobRsv->keyLength / 8; // bits --> bytes
-    Ecc_Storage_Node[id].job_id       	= pJobRsv->job_id;
-    Ecc_Storage_Node[id].real_outptr 	= (uint8_t*)pJobRsv->outputPtr;
-
-    uint8_t *outptr                  	=  Ecc_Storage_Node[id].ecdsa_verify_tmp_buf;
-
-    ecdsaParam = &Ecc_Storage_Node[id].ecdsaParam;
-    (void)crypto_memset(ecdsaParam, 0, sizeof(struct st_ecc_param_t));
-
-    ecdsaParam->e = inptr;
-    __SHOW_VAL("e", ecdsaParam->e, inputLength);
-
-    ecdsaParam->r = inptr2;
-    __SHOW_VAL("r", ecdsaParam->r, inputLength2);
-    memcpy(Ecc_Storage_Node[id].buffer1, ecdsaParam->r, inputLength2);
-    Ecc_Storage_Node[id].output_len = inputLength2;
-
-    ecdsaParam->s = inptr3;
-    __SHOW_VAL("s", ecdsaParam->s, inputLength3);
-
-    ecdsaParam->v   = outptr;
-    ecdsaParam->endian_mode = ECC_BIG_ENDIAN;
-
-    ecc_keypair_datastruct *ecc_key = NULL;
-
-    retval = kt_get_key(pJobRsv->cryptoKeyId, (uint8_t **)&ecc_key);
-    if (retval != KT_OK) {
-        ECC_TASK_ERROR("[TEST ERROR] kt_get_key fail!!\r\n");
-    } else {
-        ecdsaParam->Qx  = ecc_public_Qx(ecc_key->public, pJobRsv->keyLength);
-        ecdsaParam->Qy  = ecc_public_Qy(ecc_key->public, pJobRsv->keyLength);
-        __SHOW_VAL("ecc public Qx", ecdsaParam->Qx, pJobRsv->keyLength >> 3);
-        __SHOW_VAL("ecc public Qy", ecdsaParam->Qy, pJobRsv->keyLength >> 3);
-    }
-
-
-    switch(pJobRsv->keyLength)
-    {
-    case 192:
-        retval = crypto_ecdsa_p192_verify(ecdsaParam);
-        break;
-
-    case 224:
-        retval = crypto_ecdsa_p224_verify(ecdsaParam);
-        break;
-
-    case 256:
-        retval = crypto_ecdsa_p256_verify(ecdsaParam);
-        break;
-
-    case 384:
-        retval = crypto_ecdsa_p384_verify(ecdsaParam);
-        break;
-
-    default:
-        ECC_TASK_ERROR("[%s][%d] imposible to be here\r\n", __FUNCTION__, __LINE__);
-        break;
-    }
-
-    if(0 != retval)
-    {
-        ECC_TASK_ERROR("[FAIL] fail at crypto_ecdsa_p%d_verify!!!\n", pJobRsv->keyLength);
-    }
-
-    ECDSA_Verify_Callback(ecdsaParam, 0);
-
-    return retval;
-}
-
-void ecc_cmd_handler(job_struct *pjob)
-{
-    uint32_t result = -1;
-    switch(pjob->service)
-    {
-    case CRYPTO_SIGNATUREGENERATE:
-        ECC_TASK_FLOW("--> CRYPTO_SIGNATUREGENERATE\r\n");
-
-        // Check if paras is valid?
-        // ASSERT(check output len > xxx bits)
-
-        result = crypto_ecdsa_sign_srv(pjob);
-        if (result != 0)
-        {
-            ECC_TASK_ERROR("Job fail\r\n");
-            break;
-        }
-        break;
-
-    case CRYPTO_SIGNATUREVERIFY:
-        ECC_TASK_FLOW("--> CRYPTO_SIGNATUREVERIFY\r\n");
-
-        // Check if paras is valid?
-        // ASSERT(check output len > xxx bits)
-
-        result = crypto_ecdsa_verify_srv(pjob);
-        if (result != 0)
-        {
-            ECC_TASK_ERROR("Job fail\r\n");
-            break;
-        }
-        break;
-
-    default:
-        break;
-    }
-
-}
-
-TASK(ecc_task)
-{
-    struct sys_event* p_rx = NULL;
-    ecc_task_init();
-
-    while (1U == 1U) {
-        EventMaskType event_mask = 0UL;
-        (void)WaitEvent(ECC_EVENT);
-        GetEvent(task_id, &event_mask);
-        (void)ClearEvent(ECC_EVENT);
-
-        ECC_TASK_FLOW(" => 888 in ECC_task!!\r\n");
-
-        /* Wake up. Start to received message from queue */
-        if (0UL != (event_mask & ECC_EVENT)) {
-            do
-            {
-                p_rx = mbox_serv_rx(&ecc_queue);
-                if (NULL != p_rx) {
-                    job_struct *pJobRsv = (job_struct *)p_rx->data.data[0];
-
-                    ECC_TASK_DEBUG("jobId: 0x%x\r\n",     pJobRsv->job_id);
-                    ECC_TASK_DEBUG("service: 0x%x\r\n",   pJobRsv->service);
-                    ECC_TASK_DEBUG("family: 0x%x\r\n",    pJobRsv->family);
-                    ECC_TASK_DEBUG("keyLength: %d\r\n",   pJobRsv->keyLength);
-                    ECC_TASK_DEBUG("mode: %d\r\n",        pJobRsv->mode);
-                    ECC_TASK_DEBUG("jobState: 0x%x\r\n",  pJobRsv->operation_mode);
-
-                    ecc_cmd_handler(pJobRsv);
-
-                    /* The data is used. Dequeue */
-                    mbox_serv_dequeue(&ecc_queue);
-                }
-
-            } while(NULL != p_rx);
-        }
-    }
-    (void)TerminateTask();
-}
-
-static struct mbox_serv_registry registry;
-void ecc_task_init(void)
-{
-    memset(&ecc_queue, 0, sizeof(ecc_queue));
-
-    /* registry */
-    GetTaskID(&task_id);
-    ECC_TASK_INFO("[ecc_task_init] task_id : %d\r\n", task_id);
-
-    registry.task_id = task_id;
-    registry.rx_mask = ECC_EVENT;
-    registry.q = &ecc_queue;
-    mbox_serv_register_event(SYS_EVENT_CRY_ECC, &registry);
-}
diff --git a/src/bsp/hsm/src/middleware/libraries/services/optee/ecc_task_nb.c b/src/bsp/hsm/src/middleware/libraries/services/optee/ecc_task_nb.c
old mode 100644
new mode 100755
index 5d7e09a..3034da4
--- a/src/bsp/hsm/src/middleware/libraries/services/optee/ecc_task_nb.c
+++ b/src/bsp/hsm/src/middleware/libraries/services/optee/ecc_task_nb.c
@@ -45,6 +45,7 @@
 #include <mbox_serv.h>
 #include <string.h>
 #include <aes_sha_task.h>
+#include <ecc_debug.h>
 
 #include <os/stopwatch.h>
 
@@ -67,7 +68,12 @@
 DeclareEvent(ECC_EVENT);
 
 //==== Internal Structure
+#ifdef CONFIG_HSM_ECC_V1
+#include <sm2_verify.h>
+#define ECC_ENG_MAX 2
+#else
 #define ECC_ENG_MAX 12
+#endif
 
 typedef struct {
 	struct st_ecc_param_t ecdsaParam;
@@ -83,36 +89,21 @@
 static ecc_storage_node Ecc_Storage_Node[ECC_ENG_MAX];
 
 extern int do_trng(uint8_t *dest, unsigned size);
-//--------------------------------------------------------------------------------
-// ECDSA 192
-// no case
-
-//uint32_t _before_sys_time_us;
-//uint32_t _after_sys_time_us;
 
 static void ECDSA_Sign_Callback(void* param, int32_t err_code)
 {
-//    LOGE("[KH] Enter ECDSA_Sign_Callback\r\n");
-//    _after_sys_time_us = get_time_us();
-//    _after_sys_time_us = _after_sys_time_us - _before_sys_time_us;
-//    LOGI(" crypto_ecdsa API excution time: %d (us)\r\n", _after_sys_time_us);
-//    LOGI(" ==> %d(s), %d(ms), %d(us) \r\n", _after_sys_time_us / (US_TO_MS * MS_TO_S),
-//                                                             _after_sys_time_us % (US_TO_MS * MS_TO_S) / US_TO_MS,
-//                                                             _after_sys_time_us % US_TO_MS );
 
     int32_t  fg_ret = CRYPTO_OK;
     struct st_ecc_param_t *ecdsaParam = (struct st_ecc_param_t *) param;
 
-    LOGI(" == ECDSA_Sign_Callback ==\r\n");
+    ECC_TASK_FLOW(" == ECDSA_Sign_Callback ==\r\n");
     __SHOW_VAL("r", ecdsaParam->r, Ecc_Storage_Node[ecdsaParam->id].output_len);
     __SHOW_VAL("s", ecdsaParam->s, Ecc_Storage_Node[ecdsaParam->id].output_len);
 
 	if(fg_ret == 0)
 	{
-		LOGI("[ECDSA signature Test PASS.]\r\n");
+		ECC_TASK_FLOW("[ECDSA signature Test PASS.]\r\n");
 
-        // Write jobId & result to MBOX
-//        WriteBackJobId(Ecc_Storage_Node[ecdsaParam->id].job_id);
         *(uint8_t*)Ecc_Storage_Node[ecdsaParam->id].retValPtr = MBOX_SERV_FEEDBACK_MAGIC_NUM;
 	}
 }
@@ -124,25 +115,21 @@
         return CRYPTO_ERROR_NULL_PARAM;
     }
 
-    LOGI(" == ECDSA Sign %d ==\r\n", pJobRsv->keyLength);
+    ECC_TASK_FLOW(" == ECDSA Sign %d ==\r\n", pJobRsv->keyLength);
 
     int32_t retval = 0;
 
     uint8_t *inptr                    = (uint8_t*)pJobRsv->inputPtr;
     uint32_t inputLength              = pJobRsv->inputLength;
-    LOGI("inputLength: %d\r\n", inputLength);
-
-//  uint8_t *inptr2                   = (uint8_t*)pJobRsv->secondaryInputPtr;
-//  uint32_t inputLength2             = pJobRsv->secondaryInputLength;
-//  LOGI("inputLength2: %d\r\n", inputLength2);
+    ECC_TASK_DEBUG("inputLength: %d\r\n", inputLength);
 
     uint8_t *outptr                   = (uint8_t*)pJobRsv->outputPtr;
     uint32_t outputLength             = pJobRsv->outputLength;
-    LOGI("outputLength: %d\r\n", outputLength);
+    ECC_TASK_DEBUG("outputLength: %d\r\n", outputLength);
 
     uint8_t *outptr2                  = (uint8_t*)pJobRsv->secondaryOutputPtr;
     uint32_t outputLength2            = pJobRsv->secondaryOutputLength;
-    LOGI("outputLength2: %d\r\n", outputLength2);
+    ECC_TASK_DEBUG("outputLength2: %d\r\n", outputLength2);
 
     struct st_ecc_param_t *ecdsaParam;
     enum ecc_engine_id id;
@@ -156,14 +143,10 @@
     Ecc_Storage_Node[id].output_len = pJobRsv->keyLength / 8; // bits --> bytes
     Ecc_Storage_Node[id].job_id     = pJobRsv->job_id;
     Ecc_Storage_Node[id].retValPtr  = pJobRsv->retValPtr;
-//    LOGI("[DBG] ECC get id %d <-- job_id: 0x%x, ret %d\r\n", id, pJobRsv->job_id, retval);
-//    LOGI("[DBG] output_len: %d\r\n", Ecc_Storage_Node[id].output_len);
 
     ecdsaParam = &Ecc_Storage_Node[id].ecdsaParam;
     (void)crypto_memset(ecdsaParam, 0, sizeof(struct st_ecc_param_t));
 
-//    LOGI("inputLength: %d\r\n", inputLength);
-
     ecdsaParam->e = inptr;
     __SHOW_VAL("e", ecdsaParam->e, inputLength);
 
@@ -171,86 +154,93 @@
     ecdsaParam->s = outptr2;
     ecdsaParam->id = id;
 
-    LOGI("keyLength: %d\r\n", pJobRsv->keyLength);
-    LOGI("cryptoKeyId: 0x%x\r\n", pJobRsv->cryptoKeyId);
+    ECC_TASK_DEBUG("keyLength: %d\r\n", pJobRsv->keyLength);
+    ECC_TASK_DEBUG("cryptoKeyId: 0x%x\r\n", pJobRsv->cryptoKeyId);
     ecc_keypair_datastruct *ecc_key = NULL;
     uint8_t ecc_k_key[48] = {0};
 
-//    LOGI(" ECDSA sign GO\r\n");
-//  _before_sys_time_us = get_time_us();
+#ifdef CONFIG_HSM_ECC_V1
+    ecdsaParam->endian_mode = ECC_BIG_ENDIAN;
+    if (pJobRsv->family == CRYPTO_ALGOFAM_ECCNIST_SM2) {
+        kt_get_sm2_key(ecdsaParam);
+        do_sm2_trng(ecdsaParam);
+        retval = crypto_ecdsa_sm2_sign_nb(ecdsaParam);
+
+        goto sm2_sign_result;
+    }
+#endif
+
     retval = kt_get_key(pJobRsv->cryptoKeyId, (uint8_t **)&ecc_key);
+    do_trng(ecc_k_key, sizeof(ecc_k_key));
+    ecdsaParam->k = ecc_k_key;
+
     if (retval != KT_OK) {
-        LOGE("[TEST ERROR] kt_get_key fail!!\r\n");
+        ECC_TASK_ERROR("[TEST ERROR] kt_get_key fail!!\r\n");
     } else {
         ecdsaParam->d = ecc_key->private;
     }
 
-    do_trng(ecc_k_key, sizeof(ecc_k_key));
-    ecdsaParam->k = ecc_k_key;
-
-    switch(pJobRsv->keyLength)
+    switch (pJobRsv->keyLength)
     {
-        case 192:
-            retval = crypto_ecdsa_p192_sign_nb(ecdsaParam);
-            break;
+    case 192:
+        retval = crypto_ecdsa_p192_sign_nb(ecdsaParam);
+        break;
 
-        case 224:
-            retval = crypto_ecdsa_p224_sign_nb(ecdsaParam);
-            break;
+    case 224:
+        retval = crypto_ecdsa_p224_sign_nb(ecdsaParam);
+        break;
 
-        case 256:
-            retval = crypto_ecdsa_p256_sign_nb(ecdsaParam);
-            break;
+    case 256:
+        retval = crypto_ecdsa_p256_sign_nb(ecdsaParam);
+        break;
 
-        case 384:
-            retval = crypto_ecdsa_p384_sign_nb(ecdsaParam);
-            break;
+    case 384:
+        retval = crypto_ecdsa_p384_sign_nb(ecdsaParam);
+        break;
 
-        default:
-            retval = -1;
-            break;
+    default:
+        retval = -1;
+        break;
+    }
+
+#ifdef CONFIG_HSM_ECC_V1
+    sm2_sign_result:
+#endif
+
+    if (0 != retval)
+    {
+        ECC_TASK_ERROR("[FAIL] fail at crypto_ecdsa_p%d_verify!!!\n", pJobRsv->keyLength);
     }
 
     if (0 != retval)
     {
-        LOGE(" fail at crypto_ecdsa_p%d_sign_nb!!\r\n", pJobRsv->keyLength);
+        ECC_TASK_ERROR(" fail at crypto_ecdsa_p%d_sign!!\r\n", pJobRsv->keyLength);
     }
 
+
     return retval;
 }
 
 static void ECDSA_Verify_Callback(void* param, int32_t err_code)
 {
-//    _after_sys_time_us = get_time_us();
-//    _after_sys_time_us = _after_sys_time_us - _before_sys_time_us;
-//    LOGI(" crypto_ecdsa API excution time: %d (us)\r\n", _after_sys_time_us);
-//    LOGI(" ==> %d(s), %d(ms), %d(us) \r\n", _after_sys_time_us / (US_TO_MS * MS_TO_S),
-//                                                             _after_sys_time_us % (US_TO_MS * MS_TO_S) / US_TO_MS,
-//                                                             _after_sys_time_us % US_TO_MS );
-
-
     int32_t  fg_ret = CRYPTO_OK;
     struct st_ecc_param_t *ecdsaParam = (struct st_ecc_param_t *) param;;
 
-//    LOGI("[KH] Enter ECDSA_Verify_Callback, output length: %d\r\n", Ecc_Storage_Node[ecdsaParam->id].output_len);
-    LOGI(" == ECDSA_Verify_Callback ==\r\n");
+    ECC_TASK_FLOW(" == ECDSA_Verify_Callback ==\r\n");
 
     __SHOW_VAL("verify result -- v", ecdsaParam->v, Ecc_Storage_Node[ecdsaParam->id].output_len);
 
     if(crypto_memcmp(Ecc_Storage_Node[ecdsaParam->id].buffer1, ecdsaParam->v, Ecc_Storage_Node[ecdsaParam->id].output_len))
     {
         fg_ret = -1;
-        LOGE("[ECDSA BE verify Fail!]\r\n");
+        ECC_TASK_ERROR("[ECDSA BE verify Fail!]\r\n");
     }
 
-//    LOGI("[DBG] real_outptr: 0x%x\r\n", (uint32_t)Ecc_Storage_Node[ecdsaParam->id].real_outptr);
 
     if(fg_ret == 0)
     {
-        LOGI("[ECDSA verification Test PASS.]\r\n");
+        ECC_TASK_FLOW("[ECDSA verification Test PASS.]\r\n");
 
-        // Write jobId & result to MBOX
-//      WriteBackJobId(Ecc_Storage_Node[ecdsaParam->id].job_id);
         *(uint8_t*)Ecc_Storage_Node[ecdsaParam->id].retValPtr = MBOX_SERV_FEEDBACK_MAGIC_NUM;
     }
     else
@@ -258,7 +248,7 @@
          *(uint8_t*)Ecc_Storage_Node[ecdsaParam->id].retValPtr = MBOX_SERV_FEEDBACK_VERIFY_FAIL;
     }
 
-    LOGI("[ECDSA verification end.]\r\n");
+    ECC_TASK_FLOW("[ECDSA verification end.]\r\n");
 }
 
 static int32_t crypto_ecdsa_verify_srv(job_struct *pJobRsv)
@@ -268,43 +258,33 @@
         return CRYPTO_ERROR_NULL_PARAM;
     }
 
-    LOGI(" == ECDSA Verify %d ==\r\n", pJobRsv->keyLength);
+    ECC_TASK_FLOW(" == ECDSA Verify %d ==\r\n", pJobRsv->keyLength);
 
     int32_t retval = 0;
     struct st_ecc_param_t *ecdsaParam;
+
     enum ecc_engine_id id;
 
     uint8_t *inptr                      = (uint8_t*)pJobRsv->inputPtr;
     uint32_t inputLength                = pJobRsv->inputLength;
-    LOGI("inputLength: %d\r\n", inputLength);
+    ECC_TASK_DEBUG("inputLength: %d\r\n", inputLength);
 
     uint8_t *inptr2                   = (uint8_t*)pJobRsv->secondaryInputPtr;
     uint32_t inputLength2             = pJobRsv->secondaryInputLength;
-    LOGI("inputLength2: %d\r\n", inputLength2);
+    ECC_TASK_DEBUG("inputLength2: %d\r\n", inputLength2);
 
     uint8_t *inptr3         			= (uint8_t*)pJobRsv->tertiaryInputPtr;
     uint32_t inputLength3        		= pJobRsv->tertiaryInputLength;
-    LOGI("inputLength3: %d\r\n", inputLength3);
-
-//    uint8_t *outptr                     = pJobRsv->outputPtr;
-//    uint32_t outputLength               = *pJobRsv->outputLengthPtr;
-//    uint8_t *secondaryOutputPtr         = pJobRsv->secondaryOutputPtr;
-//    uint32_t secondaryOutputLengthPtr   = *pJobRsv->secondaryOutputLengthPtr;
+    ECC_TASK_DEBUG("inputLength3: %d\r\n", inputLength3);
 
     retval = ecc_manager_get_id(&id, ECDSA_Verify_Callback);
+
     Ecc_Storage_Node[id].output_len		= pJobRsv->keyLength / 8; // bits --> bytes
     Ecc_Storage_Node[id].job_id       	= pJobRsv->job_id;
     Ecc_Storage_Node[id].real_outptr 	= (uint8_t*)pJobRsv->outputPtr;
 
     uint8_t *outptr                  	=  Ecc_Storage_Node[id].ecdsa_verify_tmp_buf;
 
-//    LOGI("[DBG] ECC get id %d <-- jobId: 0x%x, ret %d\r\n", id, pJobRsv->jobId, retval);
-//    LOGI("[DBG] output_len: %d\r\n", Ecc_Storage_Node[id].output_len);
-
-//    LOGI("[DBG] real_outptr: 0x%x\r\n", (uint32_t)Ecc_Storage_Node[id].real_outptr);
-//    LOGI("[DBG] outptr[0]: 0x%x, [1]: 0x%x\r\n", *Ecc_Storage_Node[id].real_outptr
-//                                               , *(Ecc_Storage_Node[id].real_outptr + 1));
-
     ecdsaParam = &Ecc_Storage_Node[id].ecdsaParam;
     (void)crypto_memset(ecdsaParam, 0, sizeof(struct st_ecc_param_t));
 
@@ -321,15 +301,21 @@
 
     ecdsaParam->v   = outptr;
     ecdsaParam->id  = id;
-
     ecc_keypair_datastruct *ecc_key = NULL;
 
-//    LOGI(" ECDSA verify GO\r\n");
-//    _before_sys_time_us = get_time_us();
+#ifdef CONFIG_HSM_ECC_V1
+    ecdsaParam->endian_mode = ECC_BIG_ENDIAN;
+    if (pJobRsv->family == CRYPTO_ALGOFAM_ECCNIST_SM2) {
+        kt_get_sm2_key(ecdsaParam);
+        retval = crypto_ecdsa_sm2_verify_nb(ecdsaParam);
+
+        goto sm2_verify_result;
+    }
+#endif
 
     retval = kt_get_key(pJobRsv->cryptoKeyId, (uint8_t **)&ecc_key);
     if (retval != KT_OK) {
-        LOGE("[TEST ERROR] kt_get_key fail!!\r\n");
+        ECC_TASK_ERROR("[TEST ERROR] kt_get_key fail!!\r\n");
     } else {
         ecdsaParam->Qx  = ecc_public_Qx(ecc_key->public, pJobRsv->keyLength);
         ecdsaParam->Qy  = ecc_public_Qy(ecc_key->public, pJobRsv->keyLength);
@@ -337,8 +323,7 @@
         __SHOW_VAL("ecc public Qy", ecdsaParam->Qy, pJobRsv->keyLength >> 3);
     }
 
-
-    switch(pJobRsv->keyLength)
+    switch (pJobRsv->keyLength)
     {
     case 192:
         retval = crypto_ecdsa_p192_verify_nb(ecdsaParam);
@@ -357,13 +342,17 @@
         break;
 
     default:
-        LOGE("[%s][%d] imposible to be here\r\n", __FUNCTION__, __LINE__);
+        ECC_TASK_ERROR("[%s][%d] imposible to be here\r\n", __FUNCTION__, __LINE__);
         break;
     }
 
+#ifdef CONFIG_HSM_ECC_V1
+    sm2_verify_result:
+#endif
+
     if(0 != retval)
     {
-        LOGE("[FAIL] fail at crypto_ecdsa_p%d_verify_nb!!!\n", pJobRsv->keyLength);
+        ECC_TASK_ERROR("[FAIL] fail at crypto_ecdsa_p%d_verify!!!\n", pJobRsv->keyLength);
     }
 
     return retval;
@@ -375,7 +364,7 @@
     switch(pjob->service)
     {
     case CRYPTO_SIGNATUREGENERATE:
-        LOGI("--> CRYPTO_SIGNATUREGENERATE\r\n");
+        ECC_TASK_FLOW("--> CRYPTO_SIGNATUREGENERATE\r\n");
 
         // Check if paras is valid?
         // ASSERT(check output len > xxx bits)
@@ -383,13 +372,13 @@
         result = crypto_ecdsa_sign_srv(pjob);
         if (result != 0)
         {
-            LOGI("Job fail\r\n");
+            ECC_TASK_ERROR("Job fail\r\n");
             break;
         }
         break;
 
     case CRYPTO_SIGNATUREVERIFY:
-        LOGI("--> CRYPTO_SIGNATUREVERIFY\r\n");
+        ECC_TASK_FLOW("--> CRYPTO_SIGNATUREVERIFY\r\n");
 
         // Check if paras is valid?
         // ASSERT(check output len > xxx bits)
@@ -397,7 +386,7 @@
         result = crypto_ecdsa_verify_srv(pjob);
         if (result != 0)
         {
-            LOGE("Job fail\r\n");
+            ECC_TASK_ERROR("Job fail\r\n");
             break;
         }
         break;
@@ -419,7 +408,7 @@
         GetEvent(task_id, &event_mask);
         (void)ClearEvent(ECC_EVENT);
 
-        LOGI(" => 888 in ECC_task!!\r\n");
+        ECC_TASK_FLOW(" => 888 in ECC_task!!\r\n");
 
         /* Wake up. Start to received message from queue */
         if (0UL != (event_mask & ECC_EVENT)) {
@@ -429,12 +418,12 @@
                 if (NULL != p_rx) {
                     job_struct *pJobRsv = (job_struct *)p_rx->data.data[0];
 
-                    LOGI("jobId: 0x%x\r\n",     pJobRsv->job_id);
-                    LOGI("service: 0x%x\r\n",   pJobRsv->service);
-                    LOGI("family: 0x%x\r\n",    pJobRsv->family);
-                    LOGI("keyLength: %d\r\n",   pJobRsv->keyLength);
-                    LOGI("mode: %d\r\n",        pJobRsv->mode);
-                    LOGI("jobState: 0x%x\r\n",  pJobRsv->operation_mode);
+                    ECC_TASK_DEBUG("jobId: 0x%x\r\n",     pJobRsv->job_id);
+                    ECC_TASK_DEBUG("service: 0x%x\r\n",   pJobRsv->service);
+                    ECC_TASK_DEBUG("family: 0x%x\r\n",    pJobRsv->family);
+                    ECC_TASK_DEBUG("keyLength: %d\r\n",   pJobRsv->keyLength);
+                    ECC_TASK_DEBUG("mode: %d\r\n",        pJobRsv->mode);
+                    ECC_TASK_DEBUG("jobState: 0x%x\r\n",  pJobRsv->operation_mode);
 
                     ecc_cmd_handler(pJobRsv);
 
@@ -455,7 +444,7 @@
 
     /* registry */
     GetTaskID(&task_id);
-    LOGI("[ecc_task_init] task_id : %d\r\n", task_id);
+    ECC_TASK_INFO("[ecc_task_init] task_id : %d\r\n", task_id);
 
     registry.task_id = task_id;
     registry.rx_mask = ECC_EVENT;
diff --git a/src/bsp/hsm/src/middleware/libraries/services/optee/sm2_verify.c b/src/bsp/hsm/src/middleware/libraries/services/optee/sm2_verify.c
new file mode 100755
index 0000000..a6007d3
--- /dev/null
+++ b/src/bsp/hsm/src/middleware/libraries/services/optee/sm2_verify.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: MediaTekProprietary

+

+/* 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) 2020. 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 <string.h>

+#include <stdio.h>

+#include <unistd.h>

+#include <stdio.h>

+#include <unistd.h>

+#include <stdint.h>

+#include "key_management.h"

+#include "key_table.h"

+#include "sm2_verify.h"

+#include <crypto_ecc.h>

+

+unsigned char trm_privkey_d[32] = {

+	0xC8, 0x33, 0x90, 0x28, 0x8D, 0xB7, 0xA9, 0xFF, 0x5F, 0x08, 0xFA, 0x13, 0x8B, 0xEB, 0xAF, 0xA4,

+	0x69, 0x5C, 0x9B, 0x8D, 0x7B, 0x33, 0x4F, 0x4B, 0xB3, 0xB8, 0x26, 0x60, 0x59, 0x17, 0x34, 0x83,

+};

+unsigned char trm_random_k[32] = {

+	0xB1, 0xEA, 0x83, 0x95, 0xA9, 0xC3, 0xDB, 0xC1, 0xB3, 0x8D, 0xD4, 0x46, 0x63, 0xB3, 0x63, 0xA6,

+	0x98, 0x2B, 0x2D, 0xEF, 0x68, 0x73, 0x3E, 0xCE, 0x97, 0x63, 0x8E, 0xA6, 0xED, 0x48, 0xBA, 0xA2,

+};

+unsigned char trm_pubkey_x[64] = {

+	0x10, 0x7A, 0xD1, 0xDC, 0x3F, 0x49, 0xFD, 0x0B, 0x01, 0xF2, 0x47, 0xE9, 0x6A, 0x2E, 0x32, 0x4B,

+	0x78, 0x8F, 0xC7, 0x86, 0x89, 0x60, 0x68, 0x08, 0xAC, 0x87, 0x19, 0x0D, 0x78, 0x61, 0x35, 0xFC,

+};

+unsigned char trm_pubkey_y[64] = {

+	0xEB, 0x23, 0x71, 0x7D, 0x21, 0xB8, 0x32, 0xDD, 0xB5, 0xCF, 0x90, 0x4D, 0x48, 0x66, 0x90, 0xBA,

+	0x52, 0xF9, 0xA1, 0x94, 0x04, 0xDF, 0x0E, 0x6C, 0xF8, 0x71, 0x58, 0x01, 0x90, 0xA9, 0xD3, 0xEB,

+};

+

+int kt_get_sm2_key(struct st_ecc_param_t *ecdsaParam)

+{

+	ecdsaParam->d = trm_privkey_d;

+	ecdsaParam->Qx = trm_pubkey_x;

+	ecdsaParam->Qy = trm_pubkey_y;

+	return KT_OK;

+}

+

+int do_sm2_trng(struct st_ecc_param_t *ecdsaParam)

+{

+	ecdsaParam->k = trm_random_k;

+	return KT_OK;

+}
\ No newline at end of file
diff --git a/src/bsp/lk/lib/aee/KEDump.c b/src/bsp/lk/lib/aee/KEDump.c
old mode 100644
new mode 100755
index 3b394b3..78a69b5
--- a/src/bsp/lk/lib/aee/KEDump.c
+++ b/src/bsp/lk/lib/aee/KEDump.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2018 MediaTek Inc.
  *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
  */
 
 #include <arch/mmu.h>
@@ -29,6 +15,7 @@
 #include <lib/cksum.h>
 #include <lib/mempool.h>
 #include <lib/partition.h>
+#include <platform/mboot_expdb.h>
 #include <platform/mt_reg_base.h>
 #include <platform/mtk_bio_ioctl.h>
 #include <platform/mtk_wdt.h>
@@ -294,7 +281,9 @@
 
 static unsigned long long offset_plat_debug = 0;
 static unsigned long length_plat_debug = 0;
-static unsigned long long kedump_plat_write (void *data, unsigned long sz)
+static ssize_t length_data_written;
+
+static bool kedump_plat_write (void *data, unsigned long sz)
 {
     unsigned long long datasize = 0;
 
@@ -302,7 +291,14 @@
     offset_plat_debug += datasize;
     length_plat_debug += sz;
 
-    return datasize;
+    if (datasize > 0) {
+        length_plat_debug += sz;
+        length_data_written += datasize;
+
+        return true;
+    }
+
+    return false;
 }
 
 static void kedump_dev_close(void)
@@ -533,21 +529,24 @@
     return 0;
 }
 
+extern const struct mboot_expdb_init __mboot_expdb[];
+extern const struct mboot_expdb_init __mboot_expdb_end[];
 static int kedump_platform_debug(unsigned long long *offset)
 {
-    /* platform debug */
-    int len = 0;
-    unsigned int datasize;
-    unsigned int i;
+    int plat_step = 100;
 
-    for (i=0; i<AEE_PLAT_DEBUG_NUM; i++) {
+    for (const struct mboot_expdb_init *ptr = __mboot_expdb; ptr != __mboot_expdb_end; ptr++) {
         offset_plat_debug = *offset;
         length_plat_debug = 0;
-        ram_console_set_dump_step(adfi[i].step);
-        datasize = kedump_plat_savelog(i, offset_plat_debug, &len, kedump_plat_write);
-        if ((datasize > 0) && (datasize <= adfi[i].filesize)) {
-            kedump_add2hdr(*offset, length_plat_debug, datasize, adfi[i].filename);
-            *offset += datasize;
+        length_data_written = 0;
+        plat_step++;
+
+        ram_console_set_dump_step(plat_step);
+        ptr->hook(kedump_plat_write);
+
+        if (length_data_written > 0) {
+            kedump_add2hdr(*offset, length_plat_debug, length_data_written, ptr->name);
+            *offset += length_data_written;
         }
     }
     return 0;
diff --git a/src/bsp/lk/lib/aee/include/kdump.h b/src/bsp/lk/lib/aee/include/kdump.h
old mode 100644
new mode 100755
index 43d346f..8094cc7
--- a/src/bsp/lk/lib/aee/include/kdump.h
+++ b/src/bsp/lk/lib/aee/include/kdump.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * Copyright (c) 2018 MediaTek Inc.
  *
@@ -41,7 +42,7 @@
 #define MRDUMP_DEV_ISTORAGE_VFAT 4
 #define MRDUMP_DEV_USB 5
 
-#define MRDUMP_GO_DUMP "MRDUMP08"
+#define MRDUMP_GO_DUMP "MRDUMP09"
 
 /* for dts */
 #ifdef CFG_DTB_EARLY_LOADER_SUPPORT
diff --git a/src/bsp/lk/lib/aee/include/platform/mboot_expdb.h b/src/bsp/lk/lib/aee/include/platform/mboot_expdb.h
new file mode 100755
index 0000000..cbbe590
--- /dev/null
+++ b/src/bsp/lk/lib/aee/include/platform/mboot_expdb.h
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#pragma once
+
+#include <compiler.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+/* aee lk dump */
+typedef bool (*AEE_DUMP_CALLBACK)(void* data, unsigned long sz);
+
+struct mboot_expdb_init {
+    const char *name;
+    ssize_t size;
+    void (*hook)(AEE_DUMP_CALLBACK plat_dump_write);
+} __ALIGNED(sizeof(void *));
+
+#define AEE_EXPDB_INIT_HOOK(_filename, _filesize, _hook)        \
+    const struct mboot_expdb_init _init_struct_##_filename      \
+        __ALIGNED(sizeof(void *)) __SECTION(".mboot_expdb") = { \
+            .name = #_filename, \
+            .size = _filesize,  \
+            .hook = _hook,      \
+        }
+
+#define AEE_EXPDB_INIT_HOOK_SUFFIX(_filename, _suffix, _filesize, _hook)  \
+    const struct mboot_expdb_init _init_struct_##_filename                \
+        __ALIGNED(sizeof(void *)) __SECTION(".mboot_expdb") = {           \
+            .name = #_filename"."#_suffix, \
+            .size = _filesize,  \
+            .hook = _hook,      \
+        }
diff --git a/src/bsp/lk/lib/aee/mboot_expdb.ld b/src/bsp/lk/lib/aee/mboot_expdb.ld
new file mode 100755
index 0000000..fa9e3a5
--- /dev/null
+++ b/src/bsp/lk/lib/aee/mboot_expdb.ld
@@ -0,0 +1,8 @@
+SECTIONS {
+    .mboot_expdb : {
+        __mboot_expdb = .;
+        KEEP (*(.mboot_expdb))
+        __mboot_expdb_end = .;
+    }
+}
+INSERT AFTER .rodata;
diff --git a/src/bsp/lk/lib/aee/rules.mk b/src/bsp/lk/lib/aee/rules.mk
old mode 100644
new mode 100755
index d4f61ca..9c19ed0
--- a/src/bsp/lk/lib/aee/rules.mk
+++ b/src/bsp/lk/lib/aee/rules.mk
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
 LOCAL_DIR := $(GET_LOCAL_DIR)
 
 MODULE := $(LOCAL_DIR)
@@ -17,6 +18,8 @@
 MODULE_SRCS += $(LOCAL_DIR)/KEDump.c
 MODULE_SRCS += $(LOCAL_DIR)/platform_debug.c
 
+EXTRA_LINKER_SCRIPTS += $(LOCAL_DIR)/mboot_expdb.ld
+
 ifneq ($(MTK_MRDUMP_SUPPORT), yes)
 # for mrdump_reboot when disable mrdump
 MODULE_SRCS += $(LOCAL_DIR)/kdump_aee.c
diff --git a/src/bsp/lk/lib/cksum/crc32.c b/src/bsp/lk/lib/cksum/crc32.c
old mode 100644
new mode 100755
index 7414f28..64cb32f
--- a/src/bsp/lk/lib/cksum/crc32.c
+++ b/src/bsp/lk/lib/cksum/crc32.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /* crc32.c -- compute the CRC-32 of a data stream
  * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
diff --git a/src/bsp/lk/lib/fastboot/dl_commands.c b/src/bsp/lk/lib/fastboot/dl_commands.c
old mode 100644
new mode 100755
index b9043ea..647f8a1
--- a/src/bsp/lk/lib/fastboot/dl_commands.c
+++ b/src/bsp/lk/lib/fastboot/dl_commands.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2016 MediaTek Inc.
  *
@@ -54,7 +55,6 @@
 extern void *download_base;
 extern unsigned download_max;
 extern unsigned download_size;
-extern unsigned fastboot_state;
 
 /*LXO: !Download related command*/
 
@@ -66,9 +66,6 @@
 #define TIME_START {start_time_ms = current_time_hires();}
 #define TIME_ELAPSE (current_time_hires() - start_time_ms)
 
-extern int usb_write(void *buf, unsigned len);
-extern int usb_read(void *buf, unsigned len);
-
 static int create_download_membdev(const char *arg, unsigned sz);
 
 extern struct fastboot_var *varlist;
@@ -153,6 +150,7 @@
     char *response;
     char *endptr;
     unsigned len = strtoul(arg, &endptr, 16);
+    struct fastboot_controller_interface *interface = fastboot_get_active_controller_interface();
     int r;
 
     download_size = 0;
@@ -160,6 +158,8 @@
         fastboot_fail_wrapper("data is too large");
         return;
     }
+    ASSERT(interface != NULL);
+
     response = (char *)memalign(CACHE_LINE, MAX_RSP_SIZE);
     if (!response) {
         fastboot_fail_wrapper("buffer allocation fail");
@@ -167,7 +167,7 @@
     }
 
     snprintf(response, MAX_RSP_SIZE, "DATA%08x", len);
-    r = usb_write(response, strlen(response));
+    r = interface->write_with_timeout(response, strlen(response), WRITE_CMD_TIMEOUT);
     free(response);
     if (r < 0) {
         return;
@@ -175,10 +175,11 @@
 
 
     TIME_START;
-    r = usb_read(download_base, len);
+    r = interface->read(download_base, len);
     if ((r < 0) || ((unsigned) r != len)) {
+        dprintf(INFO, "%s() read error actual:%d expect:%zd\n", __func__, r, len);
         fastboot_fail_wrapper("Read USB error");
-        fastboot_state = STATE_ERROR;
+        fastboot_set_state(STATE_ERROR);
         return;
     }
     download_size = len;
@@ -570,12 +571,11 @@
 }
 #endif
 
-extern unsigned fastboot_state;
 void cmd_continue_boot(const char *arg, void *data, unsigned sz)
 {
     fastboot_okay("");
     /* set state to leave fastboot command loop and handler */
-    fastboot_state = STATE_RETURN;
+    fastboot_set_state(STATE_RETURN);
     mtk_wdt_init();
 }
 
diff --git a/src/bsp/lk/lib/fastboot/ext_boot.c b/src/bsp/lk/lib/fastboot/ext_boot.c
old mode 100644
new mode 100755
index 38183ad..5d3569a
--- a/src/bsp/lk/lib/fastboot/ext_boot.c
+++ b/src/bsp/lk/lib/fastboot/ext_boot.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2016 MediaTek Inc.
  *
@@ -22,12 +23,12 @@
  */
 
 #include <dev/udc.h>
+#include <kernel/timer.h>
 #include <lib/bio.h>
 #include <lib/dl_commands.h>
 #include <lib/fastboot.h>
 #include <lib/fastboot_oem_cmd.h>
 #include <lib/mempool.h>
-#include <platform/mtk_serial_key.h>
 #include <platform/mtk_wdt.h>
 #include <reg.h>
 #include <stdio.h>
@@ -35,19 +36,7 @@
 #include <target/cust_usb.h>
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#ifndef SN_BUF_LEN
-#define SN_BUF_LEN  19  /* fastboot use 13 bytes as default, max is 19 */
-#endif
-#define DEFAULT_SERIAL_NUM "0123456789ABCDEF"
-char sn_buf[SN_BUF_LEN+1] = DEFAULT_SERIAL_NUM;
-
-static struct udc_device surf_udc_device = {
-    .vendor_id  = USB_VENDORID,
-    .product_id = USB_PRODUCTID,
-    .version_id = USB_VERSIONID,
-    .manufacturer   = USB_MANUFACTURER,
-    .product    = USB_PRODUCT_NAME,
-};
+static timer_t wdt_timer;
 
 static void register_commands(void)
 {
@@ -96,64 +85,24 @@
     bio_dump_devices();
 }
 
-static char udc_chr[32] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ456789"};
-static int get_serial(u64 hwkey, u32 chipid, char *ser)
-{
-    u16 hashkey[4];
-    u32 idx, ser_idx;
-
-    /* split to 4 key with 16-bit width each */
-    for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
-        hashkey[idx] = (u16)(hwkey & 0xffff);
-        hwkey >>= 16;
-    }
-
-    /* hash the key with chip id */
-    for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
-        u32 digit = (chipid % 10);
-        hashkey[idx] = (hashkey[idx] >> digit) | (hashkey[idx] << (16-digit));
-        chipid = (chipid / 10);
-    }
-
-    /* generate serail using hashkey */
-    ser_idx = 0;
-    for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
-        ser[ser_idx++] = (hashkey[idx] & 0x001f);
-        ser[ser_idx++] = (hashkey[idx] & 0x00f8) >> 3;
-        ser[ser_idx++] = (hashkey[idx] & 0x1f00) >> 8;
-        ser[ser_idx++] = (hashkey[idx] & 0xf800) >> 11;
-    }
-
-    for (idx = 0; idx < ser_idx; idx++)
-        ser[idx] = udc_chr[(int)ser[idx]];
-
-    ser[ser_idx] = 0x00;
-
-    return 0;
-}
-
 void ext_boot(void)
 {
     void *scratch_buf;
 
-    u64 key = ((u64)readl(SERIAL_KEY_HI) << 32) | readl(SERIAL_KEY_LO);
-    if (key != 0)
-        get_serial(key, MACH_TYPE, sn_buf);
-
-    surf_udc_device.serialno = sn_buf;
-    udc_init(&surf_udc_device);
 
     storage_init();
     mtk_wdt_disable();
+    timer_initialize(&wdt_timer);
+    timer_set_periodic(&wdt_timer, 5000, (timer_callback)mtk_wdt_restart, NULL);
     register_commands();
     register_oem_fastboot_cmds();
     publish_attributes();
-
     scratch_buf = mempool_alloc(SCRATCH_SIZE, MEMPOOL_ANY);
-
     if (!scratch_buf)
         return;
 
     fastboot_init(scratch_buf, (unsigned long long)SCRATCH_SIZE);
     mempool_free(scratch_buf);
+
+    fastboot_unregister_all();
 }
diff --git a/src/bsp/lk/lib/fastboot/fastboot.c b/src/bsp/lk/lib/fastboot/fastboot.c
old mode 100644
new mode 100755
index 43ff0a5..71f649e
--- a/src/bsp/lk/lib/fastboot/fastboot.c
+++ b/src/bsp/lk/lib/fastboot/fastboot.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2016 MediaTek Inc.
  *
@@ -21,45 +22,142 @@
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <assert.h>
 #include <debug.h>
 #include <dev/udc.h>
 #include <err.h>
 #include <kernel/event.h>
+#include <kernel/spinlock.h>
 #include <kernel/thread.h>
 #include <kernel/timer.h>
 #include <lib/fastboot.h>
+#include <list.h>
 #include <platform/udc-common.h>
 #include <stdlib.h>
 #include <string.h>
 #include <trace.h>
 
-#define LOCAL_TRACE 0
+/* Current write cmd timeout of USB and PCIe are the same, so define it here.
+ * If the value of new added controller is different, then consider to extend
+ * the fastboot_controller_interface structure.
+ */
+#define LOCAL_TRACE 2
 
-/* MAX_USBFS_BULK_SIZE: if use USB3 QMU GPD mode: cannot exceed 63 * 1024 */
-#define MAX_USBFS_BULK_SIZE (16 * 1024)
-
-static event_t usb_online;
-static event_t txn_done;
-static struct udc_endpoint *in, *out;
-static struct udc_request *req;
-int txn_status;
+struct fastboot_cmd {
+    struct fastboot_cmd *next;
+    const char *prefix;
+    unsigned int prefix_len;
+    void (*handle)(const char *arg, void *data, unsigned int sz);
+};
 
 void *download_base;
-unsigned download_max;
-unsigned download_size;
-unsigned fastboot_state = STATE_OFFLINE;
+unsigned int download_max;
+unsigned int download_size;
+unsigned int fastboot_state = STATE_OFFLINE;
 
 struct fastboot_cmd *cmdlist;
+struct fastboot_var *varlist;
+struct fastboot_controller_interface *interface;
 
-static void req_complete(struct udc_request *req, unsigned actual, int status)
+static struct {
+    struct list_node list;
+    spin_lock_t lock;
+} interfaces = {
+    .list = LIST_INITIAL_VALUE(interfaces.list),
+    .lock = SPIN_LOCK_INITIAL_VALUE,
+};
+
+struct controller_interface {
+    struct list_node node;
+    struct fastboot_controller_interface *interface;
+};
+
+status_t register_fastboot_controller_interface(struct fastboot_controller_interface *interface)
 {
-    txn_status = status;
-    req->length = actual;
-    event_signal(&txn_done, 0);
+    spin_lock_saved_state_t state;
+
+    struct controller_interface
+        *ci = (struct controller_interface *)malloc(sizeof(struct controller_interface));
+
+    if (!ci)
+        return ERR_NO_MEMORY;
+
+    list_initialize(&ci->node);
+    ci->interface = interface;
+
+    spin_lock_irqsave(&interfaces.lock, state);
+
+    list_add_head(&interfaces.list, &ci->node);
+
+    spin_unlock_irqrestore(&interfaces.lock, state);
+
+    return NO_ERROR;
+}
+
+static void unregister_fastboot_controller_interfaces(void)
+{
+    struct controller_interface *ci, *temp;
+    spin_lock_saved_state_t state;
+
+    spin_lock_irqsave(&interfaces.lock, state);
+    list_for_every_entry_safe(&interfaces.list, ci, temp, struct controller_interface, node) {
+        free(ci);
+    }
+    spin_unlock_irqrestore(&interfaces.lock, state);
+}
+
+__WEAK const char *get_fastboot_controller_interface_name(void)
+{
+    static const char *name = "usb";
+
+    return name;
+}
+
+static struct fastboot_controller_interface *fastboot_get_controller_interface(const char *name)
+{
+    struct controller_interface *ci, *temp;
+    spin_lock_saved_state_t state;
+
+    spin_lock_irqsave(&interfaces.lock, state);
+    list_for_every_entry_safe(&interfaces.list, ci, temp, struct controller_interface, node) {
+        if (strncmp(ci->interface->name, name, strlen(ci->interface->name)) == 0) {
+            spin_unlock_irqrestore(&interfaces.lock, state);
+            return ci->interface;
+        }
+    }
+    spin_unlock_irqrestore(&interfaces.lock, state);
+
+    return NULL;
+}
+
+struct fastboot_controller_interface *fastboot_get_active_controller_interface()
+{
+    return interface;
+}
+
+unsigned int fastboot_get_state(void)
+{
+    return fastboot_state;
+}
+
+void fastboot_set_state(unsigned int state)
+{
+    fastboot_state = state;
+}
+
+void fastboot_unregister_all(void)
+{
+    struct fastboot_cmd *cmd;
+
+    while (cmdlist != NULL) {
+        cmd = cmdlist;
+        cmdlist = cmd->next;
+        free(cmd);
+    }
 }
 
 void fastboot_register(const char *prefix,
-                       void (*handle)(const char *arg, void *data, unsigned sz))
+                       void (*handle)(const char *arg, void *data, unsigned int sz))
 {
     struct fastboot_cmd *cmd;
 
@@ -73,8 +171,6 @@
     }
 }
 
-struct fastboot_var *varlist;
-
 void fastboot_publish(const char *name, const char *value)
 {
     struct fastboot_var *var;
@@ -87,85 +183,6 @@
     }
 }
 
-/*
- * Read data from USB.
- * _buf: the buffer for reading data. Star address must be cache line aligned!
- * len: the length for reading data. Must be cache line size aligned!
- */
-int usb_read(void *_buf, unsigned len)
-{
-    int r;
-    unsigned xfer;
-    unsigned char *buf = _buf;
-    int count = 0;
-
-    if (fastboot_state == STATE_ERROR)
-        goto oops;
-
-    while (len > 0) {
-        xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
-        req->buffer = buf;
-        req->length = xfer;
-        req->complete = req_complete;
-        r = udc_request_queue(out, req);
-        if (r < 0) {
-            LTRACEF("usb_read() queue failed\n");
-            goto oops;
-        }
-        event_wait(&txn_done);
-
-        if (txn_status < 0) {
-            LTRACEF("usb_read() transaction failed\n");
-            goto oops;
-        }
-
-        count += req->length;
-        buf += req->length;
-        len -= req->length;
-
-        /* short transfer? */
-        if (req->length != xfer) break;
-    }
-
-    return count;
-
-oops:
-    fastboot_state = STATE_ERROR;
-    return -1;
-}
-
-/*
- * Write data to USB.
- * buf: the buffer for writing data. Star address must be cache line aligned!
- * len: the length for writing data. Must be cache line size aligned!
- */
-int usb_write(void *buf, unsigned len)
-{
-    int r;
-
-    if (fastboot_state == STATE_ERROR)
-        goto oops;
-
-    req->buffer = buf;
-    req->length = len;
-    req->complete = req_complete;
-    r = udc_request_queue(in, req);
-    if (r < 0) {
-        LTRACEF("usb_write() queue failed\n");
-        goto oops;
-    }
-    event_wait(&txn_done);
-    if (txn_status < 0) {
-        LTRACEF("usb_write() transaction failed\n");
-        goto oops;
-    }
-    return req->length;
-
-oops:
-    fastboot_state = STATE_ERROR;
-    return -1;
-}
-
 void fastboot_ack(const char *code, const char *reason)
 {
     char *response;
@@ -184,7 +201,7 @@
     snprintf(response, MAX_RSP_SIZE, "%s%s", code, reason);
     fastboot_state = STATE_COMPLETE;
 
-    usb_write(response, strlen(response));
+    interface->write_with_timeout(response, strlen(response), WRITE_CMD_TIMEOUT);
     free(response);
 
 }
@@ -206,7 +223,7 @@
     }
     snprintf(response, MAX_RSP_SIZE, "INFO%s", reason);
 
-    usb_write(response, strlen(response));
+    interface->write_with_timeout(response, strlen(response), WRITE_CMD_TIMEOUT);
     free(response);
 }
 
@@ -236,11 +253,13 @@
 
 again:
     while ((fastboot_state != STATE_ERROR) && (fastboot_state != STATE_RETURN)) {
-        r = usb_read(buffer, MAX_RSP_SIZE);
-        if (r < 0) break; /* no input command */
+        r = interface->read(buffer, MAX_RSP_SIZE);
+        if ((strncmp(interface->name, "usb", strlen(interface->name)) == 0) && r < 0)
+            break; /* no input command */
         buffer[r] = 0;
         dprintf(ALWAYS, "fastboot: %s[len:%d]\n", buffer, r);
-        dprintf(ALWAYS, "fastboot:[download_base:%p][download_size:0x%x]\n",download_base,(unsigned int)download_size);
+        dprintf(ALWAYS, "fastboot:[download_base:%p][download_size:0x%x]\n",
+                download_base, (unsigned int)download_size);
 
         /* Pick up matched command and handle it */
         for (cmd = cmdlist; cmd; cmd = cmd->next) {
@@ -248,7 +267,8 @@
                 continue;
             fastboot_state = STATE_COMMAND;
             dprintf(ALWAYS,"fastboot:[cmd:%s]-[arg:%s]\n", cmd->prefix,  buffer + cmd->prefix_len);
-            cmd->handle((const char *) buffer + cmd->prefix_len, (void *) download_base, download_size);
+            cmd->handle((const char *) buffer + cmd->prefix_len, (void *) download_base,
+                       download_size);
             if (fastboot_state == STATE_COMMAND)
                 fastboot_fail("unknown reason");
             goto again;
@@ -264,84 +284,44 @@
     return fastboot_state;
 }
 
-static int fastboot_handler(void *arg)
+static int fastboot_handler(void)
 {
     int status = 0;
     while (status != STATE_RETURN) {
-        event_wait(&usb_online);
+        if (strncmp(interface->name, "usb", strlen(interface->name)) == 0)
+            interface->event_wait();
         status = fastboot_command_loop();
     }
     return 0;
 }
 
-static void fastboot_notify(struct udc_gadget *gadget, unsigned event)
-{
-    if (event == UDC_EVENT_ONLINE) {
-        event_signal(&usb_online, 0);
-    } else if (event == UDC_EVENT_OFFLINE) {
-        event_unsignal(&usb_online);
-    }
-}
-
-static struct udc_endpoint *fastboot_endpoints[2];
-
-static struct udc_gadget fastboot_gadget = {
-    .notify     = fastboot_notify,
-    .ifc_class  = 0xff,
-    .ifc_subclass   = 0x42,
-    .ifc_protocol   = 0x03,
-    .ifc_endpoints  = 2,
-    .ifc_string = "fastboot",
-    .ept        = fastboot_endpoints,
-};
-
 int fastboot_init(void *base, unsigned size)
 {
-    thread_t *thr;
+    const char *name;
 
-    dprintf(ALWAYS, "fastboot_init()\n");
+    LTRACEF("%s()\n", __func__);
     download_base = base;
     download_max = size;
 
-    event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
-    event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
+    name = get_fastboot_controller_interface_name();
+    ASSERT(name);
 
-    in = udc_endpoint_alloc(UDC_BULK_IN, 512);
-    if (!in)
-        goto fail_alloc_in;
-    out = udc_endpoint_alloc(UDC_BULK_OUT, 512);
-    if (!out)
-        goto fail_alloc_out;
+    interface = fastboot_get_controller_interface(name);
+    ASSERT(interface);
 
-    fastboot_endpoints[0] = in;
-    fastboot_endpoints[1] = out;
+    if (interface->init() < 0)
+        return -1;
 
-    req = udc_request_alloc();
-    if (!req)
-        goto fail_alloc_req;
+    interface->start();
 
-    if (udc_register_gadget(&fastboot_gadget))
-        goto fail_udc_register;
+    fastboot_handler();
 
-    thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
-    if (!thr) {
-        goto fail_alloc_in;
-    }
-    thread_resume(thr);
+    interface->stop();
 
-    udc_start();
-    thread_join(thr, NULL, INFINITE_TIME);
-    udc_stop();
+    interface->fini();
+
+    unregister_fastboot_controller_interfaces();
 
     return 0;
-
-fail_udc_register:
-    udc_request_free(req);
-fail_alloc_req:
-    udc_endpoint_free(out);
-fail_alloc_out:
-    udc_endpoint_free(in);
-fail_alloc_in:
-    return -1;
 }
 
diff --git a/src/bsp/lk/lib/fastboot/include/lib/fastboot.h b/src/bsp/lk/lib/fastboot/include/lib/fastboot.h
old mode 100644
new mode 100755
index 411c724..e16df5a
--- a/src/bsp/lk/lib/fastboot/include/lib/fastboot.h
+++ b/src/bsp/lk/lib/fastboot/include/lib/fastboot.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2016 MediaTek Inc.
  *
@@ -22,13 +23,26 @@
  */
 #pragma once
 
-#define MAX_RSP_SIZE 64
+#include <sys/types.h>
 
-struct fastboot_cmd {
-    struct fastboot_cmd *next;
-    const char *prefix;
-    unsigned prefix_len;
-    void (*handle)(const char *arg, void *data, unsigned sz);
+#define MAX_RSP_SIZE 64
+#define WRITE_CMD_TIMEOUT 5000
+
+#define STATE_OFFLINE   0
+#define STATE_COMMAND   1
+#define STATE_COMPLETE  2
+#define STATE_ERROR     3
+#define STATE_RETURN    4
+
+struct fastboot_controller_interface {
+    const char *name;
+    status_t (*init)(void);
+    void (*fini)(void);
+    status_t (*start)(void);
+    status_t (*stop)(void);
+    int (*read)(void *buf, unsigned int len);
+    int (*write_with_timeout)(void *buf, unsigned int len, lk_time_t timeout);
+    status_t (*event_wait)(void);
 };
 
 struct fastboot_var {
@@ -40,12 +54,12 @@
 void fastboot_okay(const char *info);
 void fastboot_fail(const char *reason);
 void fastboot_register(const char *prefix, void (*handle)(const char *arg, void *data, unsigned sz));
+void fastboot_unregister_all(void);
 void fastboot_publish(const char *name, const char *value);
 void fastboot_info(const char *reason);
 int fastboot_init(void *base, unsigned size);
-
-#define STATE_OFFLINE   0
-#define STATE_COMMAND   1
-#define STATE_COMPLETE  2
-#define STATE_ERROR     3
-#define STATE_RETURN    4
+void fastboot_set_state(unsigned int state);
+unsigned int fastboot_get_state(void);
+struct fastboot_controller_interface *fastboot_get_active_controller_interface(void);
+status_t register_fastboot_controller_interface(struct fastboot_controller_interface *interface);
+const char *get_fastboot_controller_interface_name(void);
\ No newline at end of file
diff --git a/src/bsp/lk/lib/fastboot/rules.mk b/src/bsp/lk/lib/fastboot/rules.mk
old mode 100644
new mode 100755
index edb4fc6..b77b378
--- a/src/bsp/lk/lib/fastboot/rules.mk
+++ b/src/bsp/lk/lib/fastboot/rules.mk
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
 LOCAL_DIR := $(GET_LOCAL_DIR)
 
 MODULE := $(LOCAL_DIR)
@@ -9,7 +10,8 @@
 
 MODULE_DEPS += \
     lib/bio \
-    lib/mempool
+    lib/mempool \
+    $(LOCAL_DIR)/usb
 
 MODULE_COMPILEFLAGS += -Wno-sign-compare
 
diff --git a/src/bsp/lk/lib/fastboot/usb/rules.mk b/src/bsp/lk/lib/fastboot/usb/rules.mk
new file mode 100755
index 0000000..92c7eae
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/usb/rules.mk
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: MIT
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+	$(LOCAL_DIR)/usb.c
+
+include make/module.mk
diff --git a/src/bsp/lk/lib/fastboot/usb/usb.c b/src/bsp/lk/lib/fastboot/usb/usb.c
new file mode 100755
index 0000000..d0fba72
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/usb/usb.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <dev/udc.h>
+#include <err.h>
+#include <kernel/event.h>
+#include <lib/fastboot.h>
+#include <lk/init.h>
+#include <platform/mtk_serial_key.h>
+#include <sys/types.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 2
+
+/* would be replaced. ex: in cust_usb.h */
+#ifndef USB_VENDORID
+#define USB_VENDORID            (0x0E8D)
+#define USB_PRODUCTID           (0x201C)
+#define USB_VERSIONID           (0x0100)
+#define USB_MANUFACTURER        "MediaTek"
+#define USB_PRODUCT_NAME        "Android"
+#endif
+
+/* MAX_USBFS_BULK_SIZE: if use USB3 QMU GPD mode: cannot exceed 63 * 1024 */
+#define MAX_USBFS_BULK_SIZE     (16 * 1024)
+#define USB_CMD_TIMEOUT         5000
+
+#ifndef SN_BUF_LEN
+#define SN_BUF_LEN  19  /* fastboot use 13 bytes as default, max is 19 */
+#endif
+#define DEFAULT_SERIAL_NUM "0123456789ABCDEF"
+char sn_buf[SN_BUF_LEN+1] = DEFAULT_SERIAL_NUM;
+#define ARRAY_SIZE(arr) (countof(arr))
+
+static event_t usb_online;
+static event_t txn_done;
+static struct udc_endpoint *in, *out;
+static struct udc_request *req;
+static int txn_status;
+
+static struct udc_endpoint *fastboot_endpoints[2];
+
+static struct udc_device surf_udc_device = {
+    .vendor_id    = USB_VENDORID,
+    .product_id   = USB_PRODUCTID,
+    .version_id   = USB_VERSIONID,
+    .manufacturer = USB_MANUFACTURER,
+    .product      = USB_PRODUCT_NAME,
+};
+
+static void req_complete(struct udc_request *req, unsigned int actual, int status)
+{
+    txn_status = status;
+    req->length = actual;
+    event_signal(&txn_done, 0);
+}
+
+/*
+ * Read data from USB.
+ * buf: the buffer for reading data. Star address must be cache line aligned!
+ * len: the length for reading data. Must be cache line size aligned!
+ */
+static int usb_read_with_timeout(void *buf, unsigned int len, lk_time_t timeout)
+{
+    int r;
+    unsigned int xfer;
+    int count = 0;
+    status_t ret = NO_ERROR;
+
+    if (fastboot_get_state() == STATE_ERROR)
+        goto oops;
+
+    while (len > 0) {
+        xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
+        req->buffer = buf;
+        req->length = xfer;
+        req->complete = req_complete;
+        r = udc_request_queue(out, req);
+        if (r < 0) {
+            dprintf(INFO, "%s() queue failed\n", __func__);
+            goto oops;
+        }
+        ret = event_wait_timeout(&txn_done, timeout);
+        if (ret != NO_ERROR)
+            goto oops;
+
+        if (txn_status < 0) {
+            dprintf(INFO, "%s() transaction failed\n", __func__);
+            goto oops;
+        }
+
+        count += req->length;
+        buf += req->length;
+        len -= req->length;
+
+        /* short transfer? */
+        if (req->length != xfer)
+            break;
+    }
+
+    return count;
+
+oops:
+    fastboot_set_state(STATE_ERROR);
+    return -1;
+}
+
+int usb_read(void *buf, unsigned int len)
+{
+    return usb_read_with_timeout(buf, len, INFINITE_TIME);
+}
+
+/*
+ * Write data to USB.
+ * buf: the buffer for writing data. Star address must be cache line aligned!
+ * len: the length for writing data. Must be cache line size aligned!
+ */
+static int usb_write_with_timeout(void *buf, unsigned int len, lk_time_t timeout)
+{
+    int r;
+    status_t ret = NO_ERROR;
+
+    if (fastboot_get_state() == STATE_ERROR)
+        goto oops;
+
+    req->buffer = buf;
+    req->length = len;
+    req->complete = req_complete;
+    r = udc_request_queue(in, req);
+    if (r < 0) {
+        dprintf(INFO, "%s() queue failed\n", __func__);
+        goto oops;
+    }
+    ret = event_wait_timeout(&txn_done, timeout);
+    if (ret != NO_ERROR)
+        goto oops;
+
+    if (txn_status < 0) {
+        dprintf(INFO, "%s() transaction failed\n", __func__);
+        goto oops;
+    }
+    return req->length;
+
+oops:
+    fastboot_set_state(STATE_ERROR);
+    return -1;
+}
+
+int usb_write(void *buf, unsigned int len)
+{
+    return usb_write_with_timeout(buf, len, INFINITE_TIME);
+}
+
+static void fastboot_notify(struct udc_gadget *gadget, unsigned int event)
+{
+    if (event == UDC_EVENT_ONLINE)
+        event_signal(&usb_online, 0);
+    else if (event == UDC_EVENT_OFFLINE)
+        event_unsignal(&usb_online);
+}
+
+static struct udc_gadget fastboot_gadget = {
+    .notify        = fastboot_notify,
+    .ifc_class     = 0xff,
+    .ifc_subclass  = 0x42,
+    .ifc_protocol  = 0x03,
+    .ifc_endpoints = 2,
+    .ifc_string    = "fastboot",
+    .ept           = fastboot_endpoints,
+};
+
+static char udc_chr[32] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ456789"};
+static int get_serial(u64 hwkey, u32 chipid, char *ser)
+{
+    u16 hashkey[4];
+    u32 idx, ser_idx;
+
+    /* split to 4 key with 16-bit width each */
+    for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
+        hashkey[idx] = (u16)(hwkey & 0xffff);
+        hwkey >>= 16;
+    }
+
+    /* hash the key with chip id */
+    for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
+        u32 digit = (chipid % 10);
+        hashkey[idx] = (hashkey[idx] >> digit) | (hashkey[idx] << (16-digit));
+        chipid = (chipid / 10);
+    }
+
+    /* generate serail using hashkey */
+    ser_idx = 0;
+    for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
+        ser[ser_idx++] = (hashkey[idx] & 0x001f);
+        ser[ser_idx++] = (hashkey[idx] & 0x00f8) >> 3;
+        ser[ser_idx++] = (hashkey[idx] & 0x1f00) >> 8;
+        ser[ser_idx++] = (hashkey[idx] & 0xf800) >> 11;
+    }
+
+    for (idx = 0; idx < ser_idx; idx++)
+        ser[idx] = udc_chr[(int)ser[idx]];
+
+    ser[ser_idx] = 0x00;
+
+    return 0;
+}
+
+static int usb_init(void)
+{
+    u64 key;
+    LTRACEF("call udc_init... USB_VID=%x USB_PID=%x\n", surf_udc_device.vendor_id,
+            surf_udc_device.product_id);
+    key = ((u64)readl(SERIAL_KEY_HI) << 32) | readl(SERIAL_KEY_LO);
+    if (key != 0)
+        get_serial(key, MACH_TYPE, sn_buf);
+    surf_udc_device.serialno = sn_buf;
+    udc_init(&surf_udc_device);
+
+    event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
+    event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
+
+    in = udc_endpoint_alloc(UDC_BULK_IN, 512);
+    if (!in)
+        goto fail_alloc_in;
+    out = udc_endpoint_alloc(UDC_BULK_OUT, 512);
+    if (!out)
+        goto fail_alloc_out;
+
+    fastboot_endpoints[0] = in;
+    fastboot_endpoints[1] = out;
+
+    req = udc_request_alloc();
+    if (!req)
+        goto fail_alloc_req;
+
+    if (udc_register_gadget(&fastboot_gadget))
+        goto fail_udc_register;
+
+    return 0;
+
+fail_udc_register:
+    udc_request_free(req);
+fail_alloc_req:
+    udc_endpoint_free(out);
+fail_alloc_out:
+    udc_endpoint_free(in);
+fail_alloc_in:
+    return -1;
+}
+
+static void usb_fini(void)
+{
+    udc_request_free(req);
+    udc_endpoint_free(out);
+    udc_endpoint_free(in);
+}
+
+static status_t usb_event_wait(void)
+{
+    status_t ret;
+
+    ret = event_wait(&usb_online);
+    return ret;
+}
+
+static struct fastboot_controller_interface interface = {
+    .name               = "usb",
+    .init               = usb_init,
+    .fini               = usb_fini,
+    .start              = udc_start,
+    .stop               = udc_stop,
+    .read               = usb_read,
+    .write_with_timeout = usb_write_with_timeout,
+    .event_wait         = usb_event_wait,
+};
+
+static void usb_register_fastboot_controller_interface(unsigned int level)
+{
+    register_fastboot_controller_interface(&interface);
+}
+
+LK_INIT_HOOK(usb_register_fastboot_controller_interface,
+            &usb_register_fastboot_controller_interface,
+            LK_INIT_LEVEL_APPS - 1);
diff --git a/src/bsp/lk/lib/fdt/fdt.c b/src/bsp/lk/lib/fdt/fdt.c
old mode 100644
new mode 100755
index 22286a1..da8a627
--- a/src/bsp/lk/lib/fdt/fdt.c
+++ b/src/bsp/lk/lib/fdt/fdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
@@ -55,6 +56,25 @@
 
 #include "libfdt_internal.h"
 
+size_t fdt_header_size_(uint32_t version)
+{
+	if (version <= 1)
+		return FDT_V1_SIZE;
+	else if (version <= 2)
+		return FDT_V2_SIZE;
+	else if (version <= 3)
+		return FDT_V3_SIZE;
+	else if (version <= 16)
+		return FDT_V16_SIZE;
+	else
+		return FDT_V17_SIZE;
+}
+
+size_t fdt_header_size(const void *fdt)
+{
+	return fdt_header_size_(fdt_version(fdt));
+}
+
 int fdt_check_header(const void *fdt)
 {
 	if (fdt_magic(fdt) == FDT_MAGIC) {
diff --git a/src/bsp/lk/lib/fdt/fdt_check.c b/src/bsp/lk/lib/fdt/fdt_check.c
new file mode 100755
index 0000000..8b43936
--- /dev/null
+++ b/src/bsp/lk/lib/fdt/fdt_check.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: MIT
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+#include <stdbool.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_full(const void *fdt, size_t bufsize)
+{
+    int err;
+    int num_memrsv;
+    int offset, nextoffset = 0;
+    uint32_t tag;
+    unsigned int depth = 0;
+    const void *prop;
+    const char *propname;
+    bool expect_end = false;
+
+    if (bufsize < FDT_V1_SIZE)
+        return -FDT_ERR_TRUNCATED;
+    if (bufsize < fdt_header_size(fdt))
+        return -FDT_ERR_TRUNCATED;
+    err = fdt_check_header(fdt);
+    if (err != 0)
+        return err;
+    if (bufsize < fdt_totalsize(fdt))
+        return -FDT_ERR_TRUNCATED;
+
+    num_memrsv = fdt_num_mem_rsv(fdt);
+    if (num_memrsv < 0)
+        return num_memrsv;
+
+    while (1) {
+        offset = nextoffset;
+        tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+        if (nextoffset < 0)
+            return nextoffset;
+
+        /* If we see two root nodes, something is wrong */
+        if (expect_end && tag != FDT_END)
+            return -FDT_ERR_BADSTRUCTURE;
+
+        switch (tag) {
+        case FDT_NOP:
+            break;
+
+        case FDT_END:
+            if (depth != 0)
+                return -FDT_ERR_BADSTRUCTURE;
+            return 0;
+
+        case FDT_BEGIN_NODE:
+            depth++;
+            if (depth > INT_MAX)
+                return -FDT_ERR_BADSTRUCTURE;
+
+            /* The root node must have an empty name */
+            if (depth == 1) {
+                const char *name;
+                int len;
+
+                name = fdt_get_name(fdt, offset, &len);
+                if (*name || len)
+                    return -FDT_ERR_BADSTRUCTURE;
+            }
+            break;
+
+        case FDT_END_NODE:
+            if (depth == 0)
+                return -FDT_ERR_BADSTRUCTURE;
+            depth--;
+            if (depth == 0)
+                expect_end = true;
+            break;
+
+        case FDT_PROP:
+            prop = fdt_getprop_by_offset(fdt, offset, &propname,
+                             &err);
+            if (!prop)
+                return err;
+            break;
+
+        default:
+            return -FDT_ERR_INTERNAL;
+        }
+    }
+}
diff --git a/src/bsp/lk/lib/fdt/include/libfdt.h b/src/bsp/lk/lib/fdt/include/libfdt.h
old mode 100644
new mode 100755
index 540de76..9a47621
--- a/src/bsp/lk/lib/fdt/include/libfdt.h
+++ b/src/bsp/lk/lib/fdt/include/libfdt.h
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: MIT 
+
 #ifndef _LIBFDT_H
 #define _LIBFDT_H
 /*
@@ -243,6 +245,17 @@
 #undef __fdt_set_hdr
 
 /**
+ * fdt_header_size - return the size of the tree's header
+ * @fdt: pointer to a flattened device tree
+ */
+size_t fdt_header_size(const void *fdt);
+
+/**
+ * fdt_header_size_ - internal function which takes a version number
+ */
+size_t fdt_header_size_(uint32_t version);
+
+/**
  * fdt_check_header - sanity check a device tree or possible device tree
  * @fdt: pointer to data which might be a flattened device tree
  *
@@ -284,6 +297,20 @@
 /**********************************************************************/
 
 /**
+ * fdt_check_full - full check fdt validity.
+ * @fdt: pointer to the device tree blob
+ * @bufsize: size of device tree blob
+ *
+ * fdt_check_full() checks fdt completely, includes fdt header,
+ * totalsize field of fdt and its structure.
+ *
+ * returns:
+ *     0, on success
+ *     other value, if an error occurred
+ */
+int fdt_check_full(const void *fdt, size_t bufsize);
+
+/**
  * fdt_string - retrieve a string from the strings block of a device tree
  * @fdt: pointer to the device tree blob
  * @stroffset: offset of the string within the strings block (native endian)
diff --git a/src/bsp/lk/lib/fdt/rules.mk b/src/bsp/lk/lib/fdt/rules.mk
old mode 100644
new mode 100755
index 6777af5..e9bc2b3
--- a/src/bsp/lk/lib/fdt/rules.mk
+++ b/src/bsp/lk/lib/fdt/rules.mk
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: MIT
+
 LOCAL_DIR := $(GET_LOCAL_DIR)
 
 MODULE := $(LOCAL_DIR)
@@ -5,6 +7,7 @@
 MODULE_SRCS += \
     $(LOCAL_DIR)/fdt.c \
     $(LOCAL_DIR)/fdt_addresses.c \
+    $(LOCAL_DIR)/fdt_check.c \
     $(LOCAL_DIR)/fdt_empty_tree.c \
     $(LOCAL_DIR)/fdt_overlay.c \
     $(LOCAL_DIR)/fdt_ro.c \
diff --git a/src/bsp/lk/lib/fdt/version.lds b/src/bsp/lk/lib/fdt/version.lds
old mode 100644
new mode 100755
index cff0358..cf7c8c5
--- a/src/bsp/lk/lib/fdt/version.lds
+++ b/src/bsp/lk/lib/fdt/version.lds
@@ -19,6 +19,7 @@
 		fdt_get_alias_namelen;
 		fdt_get_alias;
 		fdt_get_path;
+		fdt_header_size;
 		fdt_supernode_atdepth_offset;
 		fdt_node_depth;
 		fdt_parent_offset;
@@ -62,6 +63,7 @@
 		fdt_stringlist_contains;
 		fdt_resize;
 		fdt_overlay_apply;
+		fdt_check_full;
 
 	local:
 		*;
diff --git a/src/bsp/lk/lib/fit/fit.c b/src/bsp/lk/lib/fit/fit.c
old mode 100644
new mode 100755
index 299a095..4ddeb93
--- a/src/bsp/lk/lib/fit/fit.c
+++ b/src/bsp/lk/lib/fit/fit.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2016 MediaTek Inc.
  *
@@ -23,12 +24,14 @@
 
 #include <arch/ops.h>
 #include <errno.h>
+#include <kernel/thread.h>
+#include <kernel/vm.h>
 #include <lib/bio.h>
 #include <libfdt.h>
 #include <lib/decompress.h>
 #include <lib/mempool.h>
-#include <kernel/thread.h>
-#include <kernel/vm.h>
+#include <list.h>
+#include <string.h>
 #include <trace.h>
 
 #include "fit.h"
@@ -165,6 +168,133 @@
     return cfg_noffset;
 }
 
+/* check whether fit contains unit address ('@') in node name */
+static int fit_check_unit_address(const void *fit, int parent)
+{
+    struct list_node node_list = LIST_INITIAL_VALUE(node_list);
+    struct _fit_node {
+        struct list_node node;
+        int offset;
+    };
+
+    struct _fit_node *node;
+    struct _fit_node *subnode;
+    int subnode_offset;
+    const char *name;
+    int offset;
+
+    /* root name has been checked in fdt_check_full(), skip the check */
+    if (parent != 0) {
+        name = fdt_get_name(fit, parent, NULL);
+        if (!name || strchr(name, '@')) {
+            LTRACEF("Node name error: offset=0x%x, name='%s'.\n", parent, name);
+            goto _err;
+        }
+    }
+
+    node = malloc(sizeof(struct _fit_node));
+    if (!node) {
+        LTRACEF("Malloc for node offset=0x%x failed.\n", offset);
+        goto _err;
+    }
+    node->offset = parent;
+    list_add_tail(&node_list, &node->node);
+
+    /* BFS traversal to check subnode name */
+    do {
+        node = (struct _fit_node *)list_remove_head(&node_list);
+        if (!node)
+            break;
+
+        offset = node->offset;
+        free(node);
+        fdt_for_each_subnode(subnode_offset, fit, offset) {
+            name = fdt_get_name(fit, subnode_offset, NULL);
+            if (!name || strchr(name, '@'))
+                goto _err;
+
+            node = malloc(sizeof(struct _fit_node));
+            if (!node)
+                goto _err;
+
+            node->offset = subnode_offset;
+            list_add_tail(&node_list, &node->node);
+        }
+    } while (1);
+
+    return 0;
+
+_err:
+    do {
+        node = (struct _fit_node *)list_remove_head(&node_list);
+        if (!node)
+            break;
+        free(node);
+    } while (1);
+
+    return -1;
+}
+
+static int fdt_check_format(const void *fit)
+{
+    int ret;
+    size_t totalsize;
+
+    /* valid fdt? */
+    ret = fdt_check_header(fit);
+    if (ret) {
+        LTRACEF("Error! Not valid fdt format, ret=%d, fit=%p\n", ret, fit);
+        return ret;
+    }
+
+    /* full check */
+    totalsize = fdt_totalsize(fit);
+    ret = fdt_check_full(fit, totalsize);
+    if (ret) {
+        LTRACEF("Error! Fdt full check fail, ret=%d, fit=%p\n", ret, fit);
+        return ret;
+    }
+
+    return 0;
+}
+
+static int fit_check_format(const void *fit)
+{
+    int ret;
+
+    ret = fdt_check_format(fit);
+    if (ret) {
+        LTRACEF("Error! fdt_check_format fail, ret=%d\n", ret);
+        return -1;
+    }
+
+    ret = fit_check_unit_address(fit, 0);
+    if (ret) {
+        LTRACEF("Error! Fit node names have '@' symbol, not allowed.\n");
+        return ret;
+    }
+
+    /* must have 'description' property */
+    if (!fdt_getprop(fit, 0, FIT_DESC_PROP, NULL)) {
+        LTRACEF("Error! FIT without '%s' property.\n", FIT_DESC_PROP);
+        return -2;
+    }
+
+    /* must have 'timestamp' property */
+    if (!fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL)) {
+        LTRACEF("Error! FIT without '%s' property.\n", FIT_TIMESTAMP_PROP);
+        return -3;
+    }
+
+    /* must have '/images' node */
+    if (fdt_path_offset(fit, FIT_IMAGES_PATH) < 0) {
+        LTRACEF("Error! FIT without '%s' subnode.\n", FIT_IMAGES_PATH);
+        return -4;
+    }
+
+    return 0;
+}
+
 int fit_get_image(const char *label, void **load_buf)
 {
     bdev_t *bdev;
@@ -202,7 +332,26 @@
         ret = -EIO;
         goto closebdev;
     }
-    *load_buf = fit_buf;
+
+    /* check fit or fdt format */
+    if ((fdt_path_offset((const void *)fit_buf, FIT_IMAGES_PATH) >= 0) ||
+        (fdt_path_offset((const void *)fit_buf, FIT_CONFIGS_PATH) >= 0)) {
+        /*
+         * fdt image (such as legacy dtbo image) doesn't have '/images' or
+         * '/configurations' node, if the image have either one of these, do
+         * fit image check.
+         */
+        ret = fit_check_format((const void *)fit_buf);
+        if (ret)
+            dprintf(CRITICAL, "%s: %s check format failed, ret=%d.\n", label, "fit", ret);
+    } else {
+        ret = fdt_check_format((const void *)fit_buf);
+        if (ret)
+            dprintf(CRITICAL, "%s: %s check format failed, ret=%d.\n", label, "fdt", ret);
+    }
+
+    if (ret == 0)
+        *load_buf = fit_buf;
 
 closebdev:
     bio_close(bdev);
@@ -363,7 +512,7 @@
     int ret;
     int noffset;
 
-    /* get defualt configuration offset (conf@1, conf@2,...or confg@n) */
+    /* get defualt configuration offset (conf_1, conf_2,...or conf_n) */
     noffset = fit_get_def_cfg_offset(fit, conf);
     if (noffset < 0)
         return noffset;
@@ -400,12 +549,12 @@
     const char *image_name;
     thread_t *integrity_verify_t;
 
-    /* get defualt configuration offset (conf@1, conf@2,...or confg@n) */
+    /* get defualt configuration offset (conf_1, conf_2,...or conf_n) */
     cfg_noffset = fit_get_def_cfg_offset(fit, conf);
     if (cfg_noffset < 0)
         return cfg_noffset;
 
-    /* unit name: fdt@1, kernel@2, ramdisk@3 and so on */
+    /* unit name: fdt_1, kernel_2, ramdisk_3 and so on */
     image_name = (char *)fdt_getprop(fit, cfg_noffset, img_pro, &len);
     if (image_name == NULL) {
         LTRACEF("%s get image name failed\n", img_pro);
diff --git a/src/bsp/lk/lib/fit/image_verify.c b/src/bsp/lk/lib/fit/image_verify.c
old mode 100644
new mode 100755
index 7ba606b..63b75b0
--- a/src/bsp/lk/lib/fit/image_verify.c
+++ b/src/bsp/lk/lib/fit/image_verify.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 #include <debug.h>
 #include <fit.h>
 #include <malloc.h>
@@ -585,6 +586,8 @@
     int region_num = 0;
     int region_offset = -1;
     int record = 0;
+    bool reach_root_end = false;
+
     ppath = path;
 
     do {
@@ -598,6 +601,12 @@
         tag = fdt_next_tag(fit, startoffset, &nextoffset);
         stopoffset = nextoffset;
 
+        /* not allow to have multiple root */
+        if (reach_root_end && tag != FDT_END) {
+            LTRACEF("Error! More than one roots?\n");
+            return -FDT_ERR_BADLAYOUT;
+        }
+
         /* Start of node*/
         if (tag == FDT_BEGIN_NODE) {
             path_level++;
@@ -605,6 +614,13 @@
                 return -FDT_ERR_BADSTRUCTURE;
 
             node_name = fdt_get_name(fit, startoffset, &node_name_len);
+            if (!node_name)
+                return -FDT_ERR_BADSTRUCTURE;
+
+            /* root node can't have a name */
+            if ((path_level == 0) && *node_name)
+                return -FDT_ERR_BADLAYOUT;
+
             if (ppath - path + 2 + node_name_len >= path_len)
                 return -FDT_ERR_NOSPACE;
             if (ppath != path + 1)
@@ -631,6 +647,9 @@
                     break;
                 }
             }
+            /* */
+            if (path_level == -1)
+                reach_root_end = true;
         } else if (tag == FDT_PROP) {
             /* Property node: contain: name, size, content */
             is_region_recorded = fdt_prop_check(fit, startoffset, property_list,
@@ -722,8 +741,7 @@
 
     strings = fdt_getprop(fit, noffset, FDT_HASHED_STR, NULL);
     if (strings) {
-        fdt_regions[node_num].offset = fdt_off_dt_strings(fit) +
-                                       fdt32_to_cpu(strings[0]);
+        fdt_regions[node_num].offset = fdt_off_dt_strings(fit);
         fdt_regions[node_num].size = fdt32_to_cpu(strings[1]);
         node_num++;
     }
diff --git a/src/bsp/lk/lib/fit/include/image.h b/src/bsp/lk/lib/fit/include/image.h
old mode 100644
new mode 100755
index ff5d14c..2b45889
--- a/src/bsp/lk/lib/fit/include/image.h
+++ b/src/bsp/lk/lib/fit/include/image.h
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: MIT
+
 #ifndef _IMAGE_H_
 #define _IMAGE_H_
 
@@ -14,6 +16,9 @@
 #define IMAGE_ENABLE_TIMESTAMP 0
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
+/* root properties and subnode paths */
+#define FIT_DESC_PROP       "description"
+#define FIT_TIMESTAMP_PROP  "timestamp"
 #define FIT_IMAGES_PATH     "/images"
 #define FIT_CONFIGS_PATH    "/configurations"
 
diff --git a/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_mac_cmd.c b/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_mac_cmd.c
old mode 100644
new mode 100755
index 4d2fb57..2ef34c6
--- a/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_mac_cmd.c
+++ b/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_mac_cmd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2019 MediaTek Inc.
  *
@@ -155,6 +156,31 @@
 
         mac_overlay->node_offset = fdt_path_offset(dtbo, mac_overlay->node_path);
         mac_overlay->prop_name = ETHMAC_OVERLAY_PROP_NAME;
+
+    } else if (strcmp(mac_overlay->tag, "snps") == 0) {
+        mac_overlay->node_path = fdt_getprop(dtbo, noffset, "snps_mac", NULL);
+        if (mac_overlay->node_path == NULL)
+            goto err;
+
+        mac_overlay->node_offset = fdt_path_offset(dtbo, mac_overlay->node_path);
+        mac_overlay->prop_name = ETHMAC_OVERLAY_PROP_NAME;
+
+    } else if (strcmp(mac_overlay->tag, "netsys0") == 0) {
+        mac_overlay->node_path = fdt_getprop(dtbo, noffset, "gmac0", NULL);
+        if (mac_overlay->node_path == NULL)
+            goto err;
+
+        mac_overlay->node_offset = fdt_path_offset(dtbo, mac_overlay->node_path);
+        mac_overlay->prop_name = ETHMAC_OVERLAY_PROP_NAME;
+
+    } else if (strcmp(mac_overlay->tag, "netsys1") == 0) {
+        mac_overlay->node_path = fdt_getprop(dtbo, noffset, "gmac1", NULL);
+        if (mac_overlay->node_path == NULL)
+            goto err;
+
+        mac_overlay->node_offset = fdt_path_offset(dtbo, mac_overlay->node_path);
+        mac_overlay->prop_name = ETHMAC_OVERLAY_PROP_NAME;
+
     } else {
         dprintf(CRITICAL, "tag not found\n");
         goto err;
@@ -335,8 +361,14 @@
  * cmd_oem_btmac_read():    read bt mac address from bt mac overlay node
  * cmd_oem_ethmac_write():  update eth mac address in eth mac overlay node
  * cmd_oem_ethmac_read():   read eth mac address from eth mac overlay node
+ * cmd_oem_snpsmac_write():     update snps mac address in snps mac overlay node
+ * cmd_oem_snpsmac_read():      read snps mac address from snps mac overlay node
+ * cmd_oem_netsys0mac_write():  update netsys0 mac address in eth mac overlay node
+ * cmd_oem_netsys0mac_read():   read netsys0 mac address from eth mac overlay node
+ * cmd_oem_netsys1mac_write():  update netsys1 mac address in eth mac overlay node
+ * cmd_oem_netsys1mac_read():   read netsys1 mac address from eth mac overlay node
  *
- * This command looks for the [wifi|bt|eth] overlay node in dto partitions
+ * This command looks for the [wifi|bt|eth|snps|netsys0|netsys1] overlay node in dto partitions
  * (vpd or dtbo), and
  *   *_write(): update the specified mac address to the image, and write back
  *              to the partition.
@@ -409,6 +441,66 @@
     mac_read(&mac_overlay);
 }
 
+static void cmd_oem_snpsmac_write(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "snps";
+
+    mac_write(arg, &mac_overlay);
+}
+
+static void cmd_oem_snpsmac_read(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "snps";
+
+    mac_read(&mac_overlay);
+}
+
+static void cmd_oem_netsys0mac_write(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "netsys0";
+
+    mac_write(arg, &mac_overlay);
+}
+
+static void cmd_oem_netsys0mac_read(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "netsys0";
+
+    mac_read(&mac_overlay);
+}
+
+static void cmd_oem_netsys1mac_write(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "netsys1";
+
+    mac_write(arg, &mac_overlay);
+}
+
+static void cmd_oem_netsys1mac_read(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "netsys1";
+
+    mac_read(&mac_overlay);
+}
+
 /* fastboot oem mac read/write commands registeration */
 FASTBOOT_OEM_CMD_START(cmd_oem_wifimac_write)
     .cmd_str = "oem writewifimac",
@@ -439,3 +531,33 @@
     .cmd_str = "oem readethmac",
     .cmd_handler = cmd_oem_ethmac_read,
 FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_snpsmac_write)
+    .cmd_str = "oem writesnpsmac",
+    .cmd_handler = cmd_oem_snpsmac_write,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_snpsmac_read)
+    .cmd_str = "oem readsnpsmac",
+    .cmd_handler = cmd_oem_snpsmac_read,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_netsys0mac_write)
+    .cmd_str = "oem writenetsys0mac",
+    .cmd_handler = cmd_oem_netsys0mac_write,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_netsys0mac_read)
+    .cmd_str = "oem readnetsys0mac",
+    .cmd_handler = cmd_oem_netsys0mac_read,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_netsys1mac_write)
+    .cmd_str = "oem writenetsys1mac",
+    .cmd_handler = cmd_oem_netsys1mac_write,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_netsys1mac_read)
+    .cmd_str = "oem readnetsys1mac",
+    .cmd_handler = cmd_oem_netsys1mac_read,
+FASTBOOT_OEM_CMD_END
diff --git a/src/bsp/lk/platform/mt2731/drivers/musb/mt_usb.c b/src/bsp/lk/platform/mt2731/drivers/musb/mt_usb.c
old mode 100644
new mode 100755
index fbf9dc6..8bdb13a
--- a/src/bsp/lk/platform/mt2731/drivers/musb/mt_usb.c
+++ b/src/bsp/lk/platform/mt2731/drivers/musb/mt_usb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /* Copyright Statement:
 *
 * This software/firmware and related documentation ("MediaTek Software") are
@@ -903,7 +904,7 @@
 	}
 
 	/* this is required for error handling during data transfer */
-	txn_status = -1;
+//  txn_status = -1;
 
 #if defined(SUPPORT_QMU)
 
@@ -1017,7 +1018,7 @@
 
 	/* enable suspend */
 	writeb((INTRUSB_SUSPEND | INTRUSB_RESUME | INTRUSB_RESET |INTRUSB_DISCON), INTRUSBE);
-	txn_status = 0;
+//  txn_status = 0;
 }
 
 static void mt_udc_ep0_write(void)
@@ -1660,7 +1661,7 @@
 	unsigned int actual;
 	int status;
 	struct udc_request *req;
-	extern int txn_status;
+//  extern int txn_status;
 
 	req = ept->req;
 	if (req) {
diff --git a/src/bsp/lk/platform/mt2731/include/platform/udc-common.h b/src/bsp/lk/platform/mt2731/include/platform/udc-common.h
old mode 100644
new mode 100755
index bee93e9..b4c1c24
--- a/src/bsp/lk/platform/mt2731/include/platform/udc-common.h
+++ b/src/bsp/lk/platform/mt2731/include/platform/udc-common.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2018 MediaTek Inc.
  *
@@ -22,7 +23,7 @@
  */
 #pragma once
 
-extern int txn_status;
+//extern int txn_status;
 
 #define GET_STATUS           0
 #define CLEAR_FEATURE        1
diff --git a/src/bsp/lk/platform/mt2735/drivers/gpio/mt_gpio.c b/src/bsp/lk/platform/mt2735/drivers/gpio/mt_gpio.c
old mode 100644
new mode 100755
index 4428ba7..228958d
--- a/src/bsp/lk/platform/mt2735/drivers/gpio/mt_gpio.c
+++ b/src/bsp/lk/platform/mt2735/drivers/gpio/mt_gpio.c
@@ -825,6 +825,7 @@
 	mt_set_gpio_mode(GPIO69, 0);
 	mt_set_gpio_dir(GPIO69, GPIO_DIR_OUT);
 	mt_set_gpio_out(GPIO69, GPIO_OUT_ZERO);*/
+	
 //tianyan@2021.12.1 modify for DTR/RI gpio start		
 	mt_set_gpio_mode(GPIO6, 1);
 	mt_set_gpio_dir(GPIO6, GPIO_DIR_IN);
diff --git a/src/bsp/lk/platform/mt2735/drivers/rules.mk b/src/bsp/lk/platform/mt2735/drivers/rules.mk
old mode 100644
new mode 100755
index 4c5ade4..adbdbb7
--- a/src/bsp/lk/platform/mt2735/drivers/rules.mk
+++ b/src/bsp/lk/platform/mt2735/drivers/rules.mk
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
 LOCAL_DIR := $(GET_LOCAL_DIR)
 MODULE := $(LOCAL_DIR)
 
@@ -113,5 +114,11 @@
     $(LOCAL_DIR)/hsm
 endif
 
+ifeq ($(MTK_KEDUMP_MINI_SUPPORT), yes)
+MODULE_SRCS += \
+	$(LOCAL_DIR)/spm/spm_aee_dump.c \
+	$(LOCAL_DIR)/sspm/sspm_expdb.c
+endif
+
 include make/module.mk
 include $(LOCAL_DIR)/audio/rules.mk
diff --git a/src/bsp/lk/platform/mt2735/drivers/spm/spm_aee_dump.c b/src/bsp/lk/platform/mt2735/drivers/spm/spm_aee_dump.c
new file mode 100755
index 0000000..014545f
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/spm/spm_aee_dump.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <debug.h>
+#include <kernel/vm.h>
+#include <lib/mempool.h>
+#include <platform/mboot_expdb.h>
+#include <platform/spm.h>
+#include <reg.h>
+#include <stdlib.h>
+
+#define PCM_FIRMWARE_VERSION_SIZE 128
+static char *spm_dump_data(char *buf, int buf_size)
+{
+    char *buff_end = buf + buf_size;
+    unsigned long i;
+    int ret;
+    char spmfw_version[PCM_FIRMWARE_VERSION_SIZE];
+
+    for (i = SPM_DUMP_START; i <= SPM_DUMP_END; i += 4) {
+        buf += snprintf(buf, buff_end - buf,
+            "SPM regs(0x%x) = 0x%08x\n", (unsigned int)i, readl(i));
+    }
+/*
+    ret = get_spmfw_version(spmfw_version, PCM_FIRMWARE_VERSION_SIZE);
+    if (ret < 0)
+        return buf;
+
+    buf += snprintf(buf, buff_end - buf,
+            "SPM firmware version = %s\n", spmfw_version);
+*/
+    return buf;
+}
+
+static void save_spm_data(AEE_DUMP_CALLBACK dev_write)
+{
+    unsigned long len;
+    void *buf, *output;
+
+    buf = mempool_alloc(SPM_BUF_LENGTH, MEMPOOL_ANY);
+    if (buf == NULL) {
+        dprintf(CRITICAL, "[spm] can not alloc buffer\n");
+        return;
+    }
+
+    output = spm_dump_data(buf, SPM_BUF_LENGTH);
+    len = output - buf;
+
+    if (!dev_write(buf, len))
+        dprintf(CRITICAL, "[spm] AEE EXPDB dump fail\n");
+
+    mempool_free(buf);
+}
+AEE_EXPDB_INIT_HOOK(SYS_LAST_SPM_DATA, SPM_BUF_LENGTH, save_spm_data);
diff --git a/src/bsp/lk/platform/mt2735/drivers/sspm/sspm_expdb.c b/src/bsp/lk/platform/mt2735/drivers/sspm/sspm_expdb.c
new file mode 100755
index 0000000..5a44752
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/sspm/sspm_expdb.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <debug.h>
+#include <kernel/vm.h>
+#include <lib/mempool.h>
+#include <platform/mboot_expdb.h>
+#include <platform/sspm.h>
+#include <reg.h>
+#include <stdio.h>
+#include <string.h>
+#include <trace.h>
+
+
+#define LOCAL_TRACE 0
+
+static void save_sspm_last_log(AEE_DUMP_CALLBACK dev_write)
+{
+    unsigned int addr = readl(SSPM_LASTK_ADDR);
+    unsigned int len = readl(SSPM_LASTK_SZ);
+
+    LTRACEF("buf@0x%x, len is %d bytes\n", addr, len);
+
+    if (len) {
+        if (!dev_write(paddr_to_kvaddr(addr), (unsigned long)len))
+            dprintf(CRITICAL, "[SSPM] AEE EXPDB last_log fail\n");
+    } else {
+        dprintf(INFO, "[SSPM] AEE EXPDB without last_log\n");
+    }
+}
+AEE_EXPDB_INIT_HOOK(SYS_SSPM_LAST_LOG, AEE_LKDUMP_SSPM_LAST_LOG_SZ, save_sspm_last_log);
+
+
+static void save_sspm_data(AEE_DUMP_CALLBACK dev_write)
+{
+    char *buf = NULL;
+    unsigned int tbufl, tbufh, r, i, j;
+    int length = 0;
+    char dispatch;
+    unsigned int ahb_status, ahb_addr_m0, ahb_addr_m1, ahb_addr_m2;
+
+    buf = mempool_alloc(AEE_LKDUMP_SSPM_DATA_SZ, MEMPOOL_ANY);
+    if (!buf) {
+        dprintf(CRITICAL, "[SSPM] Can't alloc buffer\n");
+        return;
+    }
+
+    ahb_status  = readl(SSPM_AHB_STATUS);
+    ahb_addr_m0 = readl(SSPM_AHB_M0_ADDR);
+    ahb_addr_m1 = readl(SSPM_AHB_M1_ADDR);
+    ahb_addr_m2 = readl(SSPM_AHB_M2_ADDR);
+
+#define CHK_PENDING(n)  ((ahb_status & (1 << (n))) == 0)
+#define CHK_MASTER(n)   ((ahb_status & (1 << (n))) != 0)
+
+    if (CHK_PENDING(17)) {
+        /* M0 trans is pending*/
+        if (((ahb_addr_m0 >= SSPM_SYSREG_START) && (ahb_addr_m0 < SSPM_SYSREG_END))
+            || (ahb_addr_m0 >= SSPM_DRAM_REGION))
+            dispatch = 'P'; /* Platform owner */
+        else
+            dispatch = 'S'; /* SSPM owner */
+    } else if ((CHK_PENDING(18) && CHK_MASTER(3)) || CHK_PENDING(19)) {
+        /* M1 or M2 trans is pending*/
+        dispatch = 'P'; /* Platform owner */
+    } else {
+        dispatch = 'L'; /* To see SSPM_LAST_LOG */
+    }
+
+    memset(buf, 0, AEE_LKDUMP_SSPM_DATA_SZ);
+    length += snprintf(buf + length, (AEE_LKDUMP_SSPM_DATA_SZ-1) - length,
+                       "AHB_STATUS: 0x%08x\n"
+                       "AHB_M0_ADDR: 0x%x\n"
+                       "AHB_M1_ADDR: 0x%x\n"
+                       "AHB_M2_ADDR: 0x%x\n"
+                       "LastSP: 0x%x\n"
+                       "LastLR: 0x%x\n"
+                       "LastPC: 0x%x\n"
+                       "Dispatch: %c\n",
+                       ahb_status, ahb_addr_m0, ahb_addr_m1, ahb_addr_m2,
+                       readl(SSPM_SP), readl(SSPM_LR), readl(SSPM_PC), dispatch);
+
+#if SSPM_TBUF_SUPPORT
+    r = readl(SSPM_TBUF_WPTR);
+    length += snprintf(buf + length, (AEE_LKDUMP_SSPM_DATA_SZ-1) - length,
+                       "\nTBUF_WPTR=%u\n", r);
+
+    for (i = 0, j = r; i < 16; ++i, j = (j-1) & 0xF) {
+        writel(j, SSPM_DBG_SEL);
+        tbufl = readl(SSPM_TBUFL);
+        tbufh = readl(SSPM_TBUFH);
+        length += snprintf(buf + length, (AEE_LKDUMP_SSPM_DATA_SZ-1) - length,
+                           "%u: TBUF[%u] H=0x%x L=0x%x\n", i, j, tbufh, tbufl);
+    }
+#endif
+
+    LTRACEF("buf@0x%x, len is %d bytes\n", *buf, length);
+    if (!dev_write(buf, (unsigned long)length))
+        dprintf(CRITICAL, "[SSPM] AEE EXPDB data fail\n");
+
+    mempool_free(buf);
+}
+AEE_EXPDB_INIT_HOOK(SYS_SSPM_DATA, AEE_LKDUMP_SSPM_DATA_SZ, save_sspm_data);
+
+
+static void save_sspm_coredump(AEE_DUMP_CALLBACK dev_write)
+{
+    unsigned int addr;
+    unsigned int len;
+    int retry = SSPM_COREDUP_RETRY;
+
+    if (!readl(SSPM_BACKUP)) {
+        dprintf(CRITICAL, "[SSPM] Can't find coredump\n");
+        return;
+    }
+
+    do {
+        addr = readl(SSPM_DM_ADDR);
+        len = readl(SSPM_DM_SZ);
+        LTRACEF("dm buf@0x%x, len is %d bytes\n", addr, len);
+        if (len) {
+            if (!dev_write(paddr_to_kvaddr(addr), (unsigned long)len))
+                dprintf(CRITICAL, "[SSPM] AEE EXPDB Coredump(DM) fail\n");
+
+            break;
+        } else {
+            spin(100); //delay 100us
+        }
+    } while (--retry);
+
+    addr = readl(SSPM_RM_ADDR);
+    len = readl(SSPM_RM_SZ);
+    LTRACEF("rm buf@0x%x, len is %d bytes\n", addr, len);
+    if (!dev_write(paddr_to_kvaddr(addr), (unsigned long)len))
+        dprintf(CRITICAL, "[SSPM] AEE EXPDB Coredump(RM) fail\n");
+
+}
+AEE_EXPDB_INIT_HOOK(SYS_SSPM_COREDUMP, AEE_LKDUMP_SSPM_COREDUMP_SZ, save_sspm_coredump);
diff --git a/src/bsp/lk/platform/mt2735/drivers/ssusb/mtu3.c b/src/bsp/lk/platform/mt2735/drivers/ssusb/mtu3.c
old mode 100644
new mode 100755
index 2f2010b..9db63b7
--- a/src/bsp/lk/platform/mt2735/drivers/ssusb/mtu3.c
+++ b/src/bsp/lk/platform/mt2735/drivers/ssusb/mtu3.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2019 MediaTek Inc.
  *
@@ -1771,6 +1772,7 @@
 
 int udc_stop(void)
 {
+    mask_interrupt(SSUSB_DEV_INT_ID);
     mu3d_soft_disconnect();
     mt_usb_phy_poweroff();
 
diff --git a/src/bsp/lk/platform/mt2735/fastboot/fastboot_custom.c b/src/bsp/lk/platform/mt2735/fastboot/fastboot_custom.c
new file mode 100755
index 0000000..a67bceb
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/fastboot/fastboot_custom.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+#include <debug.h>
+#include <lib/fastboot.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+const char *get_fastboot_controller_interface_name(void)
+{
+    static const char *name = "usb";
+
+    return name;
+}
diff --git a/src/bsp/lk/platform/mt2735/fastboot/rules.mk b/src/bsp/lk/platform/mt2735/fastboot/rules.mk
new file mode 100755
index 0000000..b290dde
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/fastboot/rules.mk
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: MIT
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+	$(LOCAL_DIR)/fastboot_custom.c
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mt2735/include/platform/mt2735.h b/src/bsp/lk/platform/mt2735/include/platform/mt2735.h
old mode 100644
new mode 100755
index e2b47e4..7cb5c7e
--- a/src/bsp/lk/platform/mt2735/include/platform/mt2735.h
+++ b/src/bsp/lk/platform/mt2735/include/platform/mt2735.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2018 MediaTek Inc.
  *
@@ -49,7 +50,7 @@
 
 /* non-secure accessible internal SRAM region */
 #define SRAM_BASE_PHYS          (0x118000)
-#define SRAM_BASE_SIZE          (0x30000UL)
+#define SRAM_BASE_SIZE          (0x18000UL)
 #endif
 
 /* peripheral */
@@ -111,7 +112,7 @@
 
 /* temp modify for 32 bit kernel */
 #define DRAM_ARENA_BASE         (DRAM_BASE_PHY+0x2008000UL)
-#define DRAM_ARENA_SIZE         SRAM_BASE_SIZE
+#define DRAM_ARENA_SIZE         (0x30000UL)
 
 /* 64KB use for LK2.0 transfer bootargs to BL33 */
 #define DRAM_BOOTARG_OFFSET     0x2038000
diff --git a/src/bsp/lk/platform/mt2735/include/platform/spm.h b/src/bsp/lk/platform/mt2735/include/platform/spm.h
old mode 100644
new mode 100755
index d69d28b..a0146e4
--- a/src/bsp/lk/platform/mt2735/include/platform/spm.h
+++ b/src/bsp/lk/platform/mt2735/include/platform/spm.h
@@ -1,9 +1,14 @@
+// SPDX-License-Identifier: MIT
 #ifndef _SPM_
 #define _SPM_
 
 #include <platform/mt_spm_reg.h>
 #include <platform/mt_typedefs.h>
 
+#define SPM_DUMP_START        (SPM_BASE + 0x800)
+#define SPM_DUMP_END          (SPM_BASE + 0x8F4)
+#define SPM_BUF_LENGTH        0x1000
+
 /* Macro and Inline */
 #define spm_read(addr)			DRV_Reg32(addr)
 #define spm_write(addr, val)		DRV_WriteReg32(addr, val)
diff --git a/src/bsp/lk/platform/mt2735/include/platform/sspm.h b/src/bsp/lk/platform/mt2735/include/platform/sspm.h
new file mode 100755
index 0000000..e58e4e3
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/include/platform/sspm.h
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+#pragma once
+#include <platform/mt_reg_base.h>
+
+#define SSPM_TBUF_SUPPORT   1
+#define SSPM_COREDUP_RETRY  10
+
+#define SRAM_BASE_PHY       SRAM_BASE_PHYS
+#define SRAM_SIZE           SRAM_BASE_SIZE
+
+#define SSPM_SRAM_BASE      (IO_PHYS + 0x00400000) // IO_PHYS define in mt_reg_base.h
+#define SSPM_CFGREG_BASE    (IO_PHYS + 0x00440000)
+
+#define SSPM_BACKUP         (SSPM_CFGREG_BASE + 0x24)  //GPR1
+#define SSPM_TBUF_WPTR      (SSPM_CFGREG_BASE + 0x4C)
+#define SSPM_PC             (SSPM_CFGREG_BASE + 0x64)
+#define SSPM_AHB_STATUS     (SSPM_CFGREG_BASE + 0x6C)
+#define SSPM_AHB_M0_ADDR    (SSPM_CFGREG_BASE + 0x70)
+#define SSPM_AHB_M1_ADDR    (SSPM_CFGREG_BASE + 0x74)
+#define SSPM_AHB_M2_ADDR    (SSPM_CFGREG_BASE + 0xBC)
+#define SSPM_PLT_LOADER_INFO (SSPM_SRAM_BASE + 0x17C00) //GPR0
+#define SSPM_LASTK_SZ       (SSPM_SRAM_BASE + 0x17C1C) //GPR7
+#define SSPM_LASTK_ADDR     (SSPM_SRAM_BASE + 0x17C20) //GPR8
+#define PLT_CD_AEE_SZ       (SSPM_SRAM_BASE + 0x17C24) //GPR9
+#define PLT_CD_AEE_START    (SSPM_SRAM_BASE + 0x17C28) //GPR10
+#define SSPM_RM_ADDR        (SSPM_SRAM_BASE + 0x17C30) //GPR12
+#define SSPM_RM_SZ          (SSPM_SRAM_BASE + 0x17C34) //GPR13
+#define SSPM_DM_ADDR        (SSPM_SRAM_BASE + 0x17C38) //GPR14
+#define SSPM_DM_SZ          (SSPM_SRAM_BASE + 0x17C3C) //GPR15
+#define SSPM_SP             (SSPM_CFGREG_BASE + 0x14C)
+#define SSPM_LR             (SSPM_CFGREG_BASE + 0x150)
+#define SSPM_TBUFL          (SSPM_CFGREG_BASE + 0x154)
+#define SSPM_TBUFH          (SSPM_CFGREG_BASE + 0x158)
+#define SSPM_DBG_SEL        (SSPM_CFGREG_BASE + 0x15C)
+
+#define SSPM_SYSREG_START   (SRAM_BASE_PHY + 0x40000000)
+#define SSPM_SYSREG_END     (SSPM_SYSREG_START + SRAM_SIZE)
+#define SSPM_DRAM_REGION    0x80000000
+
+#define AEE_LKDUMP_SSPM_COREDUMP_SZ 0x40080 /* 256KB + 128Byte */
+#define AEE_LKDUMP_SSPM_DATA_SZ     0x400   /* 1KB */
+#define AEE_LKDUMP_SSPM_LAST_LOG_SZ 0x400   /* 1KB */
+#define AEE_LKDUMP_SSPM_XFILE_SZ    0x80000 /* 512KB */
diff --git a/src/bsp/lk/platform/mt2735/include/platform/udc-common.h b/src/bsp/lk/platform/mt2735/include/platform/udc-common.h
old mode 100644
new mode 100755
index bee93e9..b4c1c24
--- a/src/bsp/lk/platform/mt2735/include/platform/udc-common.h
+++ b/src/bsp/lk/platform/mt2735/include/platform/udc-common.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MIT
 /*
  * Copyright (c) 2018 MediaTek Inc.
  *
@@ -22,7 +23,7 @@
  */
 #pragma once
 
-extern int txn_status;
+//extern int txn_status;
 
 #define GET_STATUS           0
 #define CLEAR_FEATURE        1
diff --git a/src/bsp/lk/platform/mt2735/rules.mk b/src/bsp/lk/platform/mt2735/rules.mk
old mode 100644
new mode 100755
index 50b2f36..a5f78f6
--- a/src/bsp/lk/platform/mt2735/rules.mk
+++ b/src/bsp/lk/platform/mt2735/rules.mk
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: MIT
 LOCAL_DIR := $(GET_LOCAL_DIR)
 
 MODULE := $(LOCAL_DIR)
@@ -97,6 +98,7 @@
 CA35_FREQ ?= CA35_FREQ_1196MHZ
 
 MODULE_DEPS += \
+    $(LOCAL_DIR)/fastboot \
     dev/interrupt/arm_gic_v3 \
     dev/timer/arm_generic \
     lib/bio \
@@ -105,7 +107,7 @@
     lib/fit \
     lib/kcmdline \
     lib/mempool \
-    lib/partition \
+    lib/partition
 
 # if BOOTAPP is not specified elsewhere, and AVB is required, choose 'avbboot'
 ifeq ($(strip $(SECURE_BOOT_ENABLE)),yes)
diff --git a/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/aarch64/platform_common.c b/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/aarch64/platform_common.c
old mode 100644
new mode 100755
index c509fd7..0af1a0f
--- a/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/aarch64/platform_common.c
+++ b/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/aarch64/platform_common.c
@@ -63,8 +63,9 @@
 			MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(DBGSYS_DEM_BASE, DBGSYS_DEM_SIZE,
 			MT_DEVICE | MT_RW | MT_SECURE),
-	MAP_REGION_FLAT(RAM_CONSOLE_BASE, RAM_CONSOLE_MAPPING_SIZE,
-			MT_MEMORY | MT_RW | MT_SECURE),
+// FIXME: RAM_CONSOLE doesn't support DRAM base
+//	MAP_REGION_FLAT(RAM_CONSOLE_BASE, RAM_CONSOLE_MAPPING_SIZE,
+//			MT_MEMORY | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(MTK_WDT_BASE, MTK_WDT_SIZE,
 			MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(MTK_MCDI_SRAM_BASE, MTK_MCDI_SRAM_MAP_SIZE,
diff --git a/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/common/plat_aee_debug.c b/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/common/plat_aee_debug.c
old mode 100644
new mode 100755
index 11cf26a..dc65287
--- a/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/common/plat_aee_debug.c
+++ b/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/common/plat_aee_debug.c
@@ -1,31 +1,7 @@
 /*
- * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) since 2019, ARM Limited and Contributors. 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 ARM 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 HOLDER 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.
+ * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <arch_helpers.h>
@@ -57,6 +33,7 @@
 
 unsigned char ram_console_set_exp_type_atf(unsigned int exp_type)
 {
+#if 0
 	unsigned char ret = false;
 	struct ram_console_buffer_atf *ram_console =
 			(struct ram_console_buffer_atf *)RAM_CONSOLE_BASE;
@@ -76,10 +53,16 @@
 			, __func__, "FATAL", ram_console->off_linux,
 			ram_console->sig, ram_console->sz_buffer, exp_type);
 		}
-	} else
+	} else {
 		NOTICE("FATAL ERROR ram_console init failed\n");
-
+		NOTICE("%s:%s:off_linux:0x%x sig:0x%x sz_buffer:0x%x\n",
+			__func__, "FATAL", ram_console->off_linux, ram_console->sig, ram_console->sz_buffer);
+	}
 	return ret;
+#else
+	NOTICE("ram_console non-sram type NOT supported\n");
+	return 0;
+#endif
 }
 
 void aee_wdt_dump(void __unused *cookie)
diff --git a/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/drivers/hsm/hsm.c b/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/drivers/hsm/hsm.c
old mode 100644
new mode 100755
index 5ca7554..0ec933a
--- a/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/drivers/hsm/hsm.c
+++ b/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/drivers/hsm/hsm.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: MediaTekProprietary
+
 #include <mcucfg.h>
 #include <plat_private.h>
 #include <platform_def.h>
@@ -34,11 +36,9 @@
 void hsm_clock_on(void)
 {
 	HSM_SET_BITS(HSM_CLK_SEL_ENABLE_CRYPTO, BIT(CLK_CRYPTO_SEL_BIT));
-	HSM_SET_BITS(HSM_CLK_SEL_ENABLE_ARC, BIT(CLK_ARC_SEL_BIT));
 }
 
 void hsm_clock_off(void)
 {
 	HSM_SET_BITS(HSM_CLK_SEL_DISABLE_CRYPTO, BIT(CLK_CRYPTO_SEL_BIT));
-	HSM_SET_BITS(HSM_CLK_SEL_DISABLE_ARC, BIT(CLK_ARC_SEL_BIT));
 }
\ No newline at end of file
diff --git a/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/include/platform_def.h b/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/include/platform_def.h
old mode 100644
new mode 100755
index 6e37cab..a183001
--- a/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/include/platform_def.h
+++ b/src/bsp/trustzone/atf/v1.6/mt2xxx/plat/mediatek/mt2735/include/platform_def.h
@@ -430,9 +430,9 @@
 
 /* align LK RAM_CONSOLE_DEF_ADDR in ram_console_def.h and
  * align kernel ram-console-reserved-memory in mt2735.dtsi */
-#define RAM_CONSOLE_BASE (0x0011D000)
-#define RAM_CONSOLE_SIZE (0x800)
-#define RAM_CONSOLE_MAPPING_SIZE (0x1000)  // PAGE align for MMU mappling
+#define RAM_CONSOLE_BASE (0x4351a000)
+#define RAM_CONSOLE_SIZE (0x10000)
+#define RAM_CONSOLE_MAPPING_SIZE (0x10000)  // PAGE align for MMU mappling
 
 /*MD BOOT EN*/
 #define MD_BOOT_EN_BASE    (IO_PHYS + 0x10000000)
diff --git a/src/bsp/trustzone/optee/optee_test/mt2xxx/Android.mk b/src/bsp/trustzone/optee/optee_test/mt2xxx/Android.mk
old mode 100644
new mode 100755
index b388d42..ec247ff
--- a/src/bsp/trustzone/optee/optee_test/mt2xxx/Android.mk
+++ b/src/bsp/trustzone/optee/optee_test/mt2xxx/Android.mk
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: BSD-2-Clause
+
 LOCAL_PATH := $(call my-dir)
 
 ## include variants like TA_DEV_KIT_DIR
diff --git a/src/bsp/trustzone/optee/optee_test/mt2xxx/host/xtest/pkcs11_1000.c b/src/bsp/trustzone/optee/optee_test/mt2xxx/host/xtest/pkcs11_1000.c
old mode 100644
new mode 100755
index a7b113d..3969934
--- a/src/bsp/trustzone/optee/optee_test/mt2xxx/host/xtest/pkcs11_1000.c
+++ b/src/bsp/trustzone/optee/optee_test/mt2xxx/host/xtest/pkcs11_1000.c
@@ -4663,6 +4663,11 @@
 //     0x3f, 0x3a, 0x52, 0x84, 0x16, 0x90, 0x1f, 0xc6, 0x6e, 0xe6, 0xca, 0xf1, 0x58, 0x69, 0x87, 0x9c,
 //     0x1d, 0xfc, 0x64, 0xe5, 0x1e, 0xaf, 0xc4, 0xc5, 0x58, 0xf7, 0x29, 0x32, 0x61, 0x66, 0xfb, 0x7a,
 // };
+// ECDSA sm2 sign
+static uint8_t ecdsasm2_sign_hashval_e[32] = {
+    0x5B, 0xF4, 0xBD, 0x14, 0xA1, 0x6B, 0x7E, 0x3C, 0xE0, 0xD7, 0x77, 0xFC, 0xB1, 0x46, 0x8B, 0xB0,
+    0x88, 0xD5, 0xB4, 0x80, 0x1C, 0x00, 0x78, 0xA3, 0x87, 0xE9, 0x78, 0x71, 0x7B, 0xC8, 0x3F, 0x7A,
+};
 
 static CK_RV verify_signature(CK_SESSION_HANDLE session,
                               CK_OBJECT_HANDLE key,
@@ -4963,6 +4968,75 @@
 	return 0;
 }
 
+static CK_RV ec_sm2_main(CK_SESSION_HANDLE session, uint32_t key_len) {
+	CK_RV rv;
+
+	CK_BYTE_PTR data = NULL;
+	CK_ULONG data_length = 0;
+
+	CK_OBJECT_HANDLE pubkey = CK_INVALID_HANDLE;
+	CK_OBJECT_HANDLE privkey = CK_INVALID_HANDLE;
+	CK_ULONG pubkey_id;
+	CK_ULONG privkey_id;
+	CK_BYTE prime256v1[] = {0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
+
+	CK_BYTE_PTR curve = NULL;
+	CK_ULONG curve_oid_len = 0;
+
+	// Assign signature data
+	curve = prime256v1;
+	curve_oid_len = sizeof(prime256v1);
+	data = ecdsasm2_sign_hashval_e;
+	data_length = sizeof(ecdsasm2_sign_hashval_e);
+
+	pubkey_id = XTEST_EC_PUB_KEY_ID_2;
+	privkey_id = XTEST_EC_PRIV_KEY_ID_2;
+
+	CK_BYTE signature[MAX_SIGNATURE_LENGTH];
+	CK_ULONG signature_length = key_len / 8 * 2; // Including r + s
+
+	// Set the PKCS11 signature mechanism type.
+	CK_MECHANISM_TYPE mechanism = CKM_MTK_HSM_ECDSA_SM2;
+
+	/**
+	 * Curve OIDs generated using OpenSSL on the command line.
+	 * Visit https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-key-types.html for a list
+	 * of supported curves.
+	 * openssl ecparam -name prime256v1 -outform DER | hexdump -C
+	 */
+
+	rv = find_ec_keypair(session, &pubkey, &privkey, pubkey_id, privkey_id);
+	if (rv != CKR_OK)
+	{
+		rv = generate_ec_keypair(session, curve, curve_oid_len, pubkey_id, privkey_id, &pubkey, &privkey);
+		if (rv == CKR_OK) {
+			printf("prime256v1 key generated. Public key handle: %lu, Private key handle: %lu\n", pubkey,
+			       privkey);
+		} else {
+			printf("prime256v1 key generation failed: %lu\n", rv);
+			return rv;
+		}
+	}
+
+	rv = generate_signature(session, privkey, mechanism,
+	                        data, data_length, signature, &signature_length);
+
+	printf(" == ECDSA-SM2 Sign %d == \r\n", key_len);
+	__SHOW_VAL("ECDSA-SM2 output", signature, signature_length);
+
+
+	printf(" == ECDSA-SM2 Verify %d == \r\n", key_len);
+	rv = verify_signature(session, pubkey, mechanism, data, data_length, signature, signature_length);
+	if (rv == CKR_OK) {
+		printf(" Verification successful PASS!!  \n");
+	} else {
+		printf(" Verification successful FAIL!!  \n");
+		return rv;
+	}
+
+	return 0;
+}
+
 static void xtest_hsm_pkcs_11_test_6001(ADBG_Case_t *c)
 {
 	CK_RV rv = CKR_GENERAL_ERROR;
@@ -5131,7 +5205,6 @@
 	if (!ADBG_EXPECT_CK_OK(c, rv))
 		goto out;
 
-//	rv = ec_main(session, 256);
 	rv = ec_sha_main(session, 256);
 	if (!ADBG_EXPECT_CK_OK(c, rv))
 		goto out;
@@ -5150,6 +5223,43 @@
 ADBG_CASE_DEFINE(hsm_pkcs_11, 6005, xtest_hsm_pkcs_11_test_6005,
                  "PKCS11: ECDSA-SHA");
 
+static void xtest_hsm_pkcs_11_test_6006(ADBG_Case_t *c)
+{
+	CK_RV rv = CKR_GENERAL_ERROR;
+	CK_SLOT_ID slot = 0;
+	CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
+	CK_FLAGS session_flags = CKF_RW_SESSION | CKF_SERIAL_SESSION;
+
+	Do_ADBG_Log("======== Test ========");
+
+	/* Initial */
+	rv = init_lib_and_find_token_slot(&slot);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		return;
+
+	/* open session */
+	rv = C_OpenSession(slot, session_flags, NULL, 0, &session);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		goto out;
+
+	rv = ec_sm2_main(session, 256);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		goto out;
+
+	Do_ADBG_Log("[ECDSA SM2(256) Sign --> Verify pass]\n");
+
+out:
+
+	rv = C_CloseSession(session);
+	ADBG_EXPECT_CK_OK(c, rv);
+
+	rv = close_lib();
+	ADBG_EXPECT_CK_OK(c, rv);
+
+}
+ADBG_CASE_DEFINE(hsm_pkcs_11, 6006, xtest_hsm_pkcs_11_test_6006,
+                 "PKCS11: ECDSA-SM2");
+
 static CK_RV import_symmetric_key(CK_SESSION_HANDLE session,
                                   CK_KEY_TYPE keyType,
                                   CK_BYTE_PTR key_content,
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/pkcs11.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/pkcs11.h
old mode 100644
new mode 100755
index 6be8973..a580990
--- a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/pkcs11.h
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/pkcs11.h
@@ -342,6 +342,7 @@
 #define CKM_ECDSA_SHA256		0x01044
 #define CKM_ECDSA_SHA384		0x01045
 #define CKM_ECDSA_SHA512		0x01046
+#define CKM_ECDSA_SM2			0x01047
 #define CKM_ECDH1_DERIVE		0x01050
 #define CKM_ECDH1_COFACTOR_DERIVE	0x01051
 #define CKM_ECMQV_DERIVE		0x01052
@@ -396,7 +397,7 @@
 #define CKM_MTK_HSM_EC_KEY_PAIR_GEN	(CKM_MTK_HSM_EXT | CKM_EC_KEY_PAIR_GEN)
 #define CKM_MTK_HSM_EC_KEY_PAIR_IMPORT	(CKM_MTK_HSM_EXT | CKM_EC_KEY_PAIR_IMPORT)
 #define CKM_MTK_HSM_DUMP_LOG 		(CKM_MTK_HSM_EXT | CKM_DUMP_LOG)
-
+#define CKM_MTK_HSM_ECDSA_SM2		(CKM_MTK_HSM_EXT | CKM_ECDSA_SM2)
 
 typedef struct CK_MECHANISM_INFO	CK_MECHANISM_INFO;
 typedef struct CK_MECHANISM_INFO *	CK_MECHANISM_INFO_PTR;
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_helpers.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_helpers.c
old mode 100644
new mode 100755
index 5ca9510..adcde18
--- a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_helpers.c
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_helpers.c
@@ -446,6 +446,7 @@
 	CK2SKS_ID(CKM_MTK_HSM_EC_KEY_PAIR_IMPORT),
 	CK2SKS_ID(CKM_MTK_HSM_WHP),
 	CK2SKS_ID(CKM_MTK_HSM_DUMP_LOG),
+	CK2SKS_ID(CKM_MTK_HSM_ECDSA_SM2),
 
 	CK2SKS_ID_BRACE(CK_VENDOR_INVALID_ID, SKS_UNDEFINED_ID),
 };
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serialize_ck.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serialize_ck.c
old mode 100644
new mode 100755
index 717f2f8..d5454c9
--- a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serialize_ck.c
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serialize_ck.c
@@ -1049,6 +1049,7 @@
 	case CKM_MTK_HSM_EC_KEY_PAIR_IMPORT:
 	case CKM_MTK_HSM_WHP:
 	case CKM_MTK_HSM_DUMP_LOG:
+	case CKM_MTK_HSM_ECDSA_SM2:
 		/* No parameter expected, size shall be 0 */
 		if (mechanism->ulParameterLen)
 			return CKR_MECHANISM_PARAM_INVALID;
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/mtk_crypto.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/mtk_crypto.h
old mode 100644
new mode 100755
index dc03801..e2e1d96
--- a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/mtk_crypto.h
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/mtk_crypto.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: BSD-2-Clause
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -117,6 +118,7 @@
 	CRYPTO_ALGOFAM_ECCNIST          = 0x19,
 	CRYPTO_ALGOFAM_SECURECOUNTER    = 0x1A,
 	CRYPTO_ALGOFAM_RNG              = 0x1B,
+	CRYPTO_ALGOFAM_ECCNIST_SM2      = 0x1C,
 };
 
 enum Crypto_AlgorithmModeType
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/sks_ta.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/sks_ta.h
old mode 100644
new mode 100755
index 76706c1..bdf8965
--- a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/sks_ta.h
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/sks_ta.h
@@ -940,6 +940,7 @@
 #define SKS_CKM_EC_KEY_PAIR_IMPORT		0x044
 #define SKS_CKM_WHP				0x045
 #define SKS_CKM_DUMP_LOG			0x046
+#define SKS_CKM_ECDSA_SM2			0x047
 
 
 #define SKS_CKM_MTK_HSM_EXT			0x20000
@@ -967,6 +968,7 @@
 #define SKS_CKM_MTK_HSM_EC_KEY_PAIR_IMPORT	(SKS_CKM_MTK_HSM_EXT | SKS_CKM_EC_KEY_PAIR_IMPORT)
 #define SKS_CKM_MTK_HSM_WHP			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_WHP)
 #define SKS_CKM_MTK_HSM_DUMP_LOG		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_DUMP_LOG)
+#define SKS_CKM_MTK_HSM_ECDSA_SM2		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_ECDSA_SM2)
 
 
 /* SKS added IDs for operation without cryptoki mechanism ID defined */
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_attributes.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_attributes.c
old mode 100644
new mode 100755
index 5eb2af8..02d38d2
--- a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_attributes.c
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_attributes.c
@@ -121,6 +121,7 @@
 	SKS_M(ECDSA_SHA256,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
 	SKS_M(ECDSA_SHA384,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
 	SKS_M(ECDSA_SHA512,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(ECDSA_SM2,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
 	SKS_M(ECDH1_DERIVE,		0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0),
 	SKS_M(ECDH1_COFACTOR_DERIVE,	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0),
 	SKS_M(ECMQV_DERIVE,		0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0),
@@ -131,6 +132,7 @@
 	SKS_M(MTK_HSM_ECDSA_SHA256,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
 	SKS_M(MTK_HSM_ECDSA_SHA384,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
 	SKS_M(MTK_HSM_ECDSA_SHA512,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
+	SKS_M(MTK_HSM_ECDSA_SM2,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
 	SKS_M(MTK_HSM_EC_KEY_PAIR_GEN,	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0),
 	/* Mechanism			Di|En|De|Si|Ve|Sr|Vr|Dr|Wr|Uw|Ge|Gp|1 */
 	SKS_M(RSA_PKCS_KEY_PAIR_GEN,	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0),
@@ -1657,6 +1659,7 @@
 	case SKS_CKM_MTK_HSM_ECDSA_SHA256:
 	case SKS_CKM_MTK_HSM_ECDSA_SHA384:
 	case SKS_CKM_MTK_HSM_ECDSA_SHA512:
+	case SKS_CKM_MTK_HSM_ECDSA_SM2:
 		if (key_type != SKS_CKK_EC) {
 			EMSG("Invalid key %s for mechanism %s",
 				sks2str_type(key_type, key_class),
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing.c
old mode 100644
new mode 100755
index 5b08152..73a850a
--- a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing.c
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing.c
@@ -970,6 +970,7 @@
 			break;
 
 		case SKS_CKM_MTK_HSM_ECDSA:
+		case SKS_CKM_MTK_HSM_ECDSA_SM2:
 			rv = mtk_ECDSA_init(session, proc_params, obj);
 			break;
 
@@ -1066,7 +1067,6 @@
 	if (rv)
 		goto bail;
 
-
 	mecha_type = session->processing->mecha_type;
 	rv = check_mechanism_against_processing(session, mecha_type,
 						function, step);
@@ -1106,6 +1106,7 @@
 			break;
 
 		case SKS_CKM_MTK_HSM_ECDSA:
+		case SKS_CKM_MTK_HSM_ECDSA_SM2:
 			rv = mtk_ECDSA_step(session, in, out, function, step);
 			break;
 
@@ -1234,6 +1235,7 @@
 			break;
 
 		case SKS_CKM_MTK_HSM_ECDSA:
+		case SKS_CKM_MTK_HSM_ECDSA_SM2:
 			rv = mtk_ECDSA_step(session, in, in2, function, step);
 			break;
 
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_hsm.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_hsm.c
old mode 100644
new mode 100755
index 6b55ab9..4ed627c
--- a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_hsm.c
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_hsm.c
@@ -1494,8 +1494,16 @@
 		_job.service                = CRYPTO_SIGNATUREGENERATE;

 	else

 		_job.service                = CRYPTO_SIGNATUREVERIFY;

-

-	_job.family                 = CRYPTO_ALGOFAM_ECCNIST;

+	

+	uint32_t mecha_type = session->processing->mecha_type;

+    

+	if (mecha_type == SKS_CKM_MTK_HSM_ECDSA_SM2){

+		_job.family                 = CRYPTO_ALGOFAM_ECCNIST_SM2;

+	}else{

+		_job.family                 = CRYPTO_ALGOFAM_ECCNIST;

+	}

+	SKS_HSM_DEBUG(" ==> _job.family: %d\n", _job.family);

+	

 	_job.mode                   = CRYPTO_ALGOMODE_NOT_SET;

 

 	_job.cryptoKeyId            = _ptr->key1_id;

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_if_impl.c b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_if_impl.c
old mode 100644
new mode 100755
index 12a7d63..9d3b30a
--- a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_if_impl.c
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_if_impl.c
@@ -86,11 +86,12 @@
 	case CRYPTO_ALGOFAM_SHA2_256:
 	case CRYPTO_ALGOFAM_SHA2_384:
 	case CRYPTO_ALGOFAM_SHA2_512:
-        case CRYPTO_ALGOFAM_WHP:
+	case CRYPTO_ALGOFAM_WHP:
 	case CRYPTO_ALGOFAM_AES:
 		event_id = SYS_EVENT_CRY_AES_SHA;
 		break;
 	case CRYPTO_ALGOFAM_ECCNIST:
+	case CRYPTO_ALGOFAM_ECCNIST_SM2:
 		event_id = SYS_EVENT_CRY_ECC;
 		break;
 	case CRYPTO_ALGOFAM_RNG:
diff --git a/src/bsp/trustzone/teeloader/mt8139/Makefile b/src/bsp/trustzone/teeloader/mt8139/Makefile
old mode 100644
new mode 100755
index 61662f1..a4ebb0c
--- a/src/bsp/trustzone/teeloader/mt8139/Makefile
+++ b/src/bsp/trustzone/teeloader/mt8139/Makefile
@@ -1,3 +1,4 @@
+#SPDX-License-Identifier: MediaTekProprietary
 CC := ${CROSS_COMPILE}gcc
 AR := ${CROSS_COMPILE}ar
 LD := ${CROSS_COMPILE}ld
@@ -23,6 +24,8 @@
 SOBJS = $(wildcard $(DIR_PREBUILT)/*.a)
 OBJS = $(AOBJS) $(COBJS) $(SOBJS)
 
+KASAN_SUPPORT ?= 0
+
 TARGET = teeloader
 BIN_TARGET = $(DIR_BIN)/$(TARGET)
 
@@ -40,7 +43,7 @@
 	@if [ ! -d `dirname $@` ] ; then \
 		mkdir -p `dirname $@`; \
 	fi
-	$(CC) -I$(DIR_INC) -DBASE_ADDR=${BASE_ADDR} -DTL_ALIGN_SIZE=${TL_ALIGN_SIZE} -DTRUSTEDOS_ENTRYPOINT=${TRUSTEDOS_ENTRYPOINT} -c $(filter %$(patsubst %.o,%.c,$(notdir $@)),$(CSRCS)) -o $@
+	$(CC) -I$(DIR_INC) -DKASAN_SUPPORT=${KASAN_SUPPORT} -DBASE_ADDR=${BASE_ADDR} -DTL_ALIGN_SIZE=${TL_ALIGN_SIZE} -DTRUSTEDOS_ENTRYPOINT=${TRUSTEDOS_ENTRYPOINT} -c $(filter %$(patsubst %.o,%.c,$(notdir $@)),$(CSRCS)) -o $@
 
 $(DIR_OBJ)/%.o: %.s
 	@if [ ! -d `dirname $@` ] ; then \
diff --git a/src/bsp/trustzone/teeloader/mt8139/include/tz_init.h b/src/bsp/trustzone/teeloader/mt8139/include/tz_init.h
old mode 100644
new mode 100755
index 5254e36..2959420
--- a/src/bsp/trustzone/teeloader/mt8139/include/tz_init.h
+++ b/src/bsp/trustzone/teeloader/mt8139/include/tz_init.h
@@ -32,15 +32,23 @@
 *  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
 *
 *****************************************************************************/
+// SPDX-License-Identifier: MediaTekProprietary
 
 #ifndef TRUSTZONE_H
 #define TRUSTZONE_H
 
 #include "typedefs.h"
 
+#if (KASAN_SUPPORT == 1)
+#define BL31        0x47081000UL
+#define BL33        0x47280000UL
+#define BL31_BASE   0x47080000UL
+#else
 #define BL31        0x43001000UL
 #define BL33        0x43200000UL
 #define BL31_BASE   0x43000000UL
+#endif
+
 #define BL31_SIZE   0x00060000UL  /* default is 384K Bytes */
 
 #define ATF_BOOT_ARG_ADDR (0x40000000)
diff --git a/src/bsp/trustzone/teeloader/mt8139/src/main.c b/src/bsp/trustzone/teeloader/mt8139/src/main.c
old mode 100644
new mode 100755
index b7e8e6a..dca94bf
--- a/src/bsp/trustzone/teeloader/mt8139/src/main.c
+++ b/src/bsp/trustzone/teeloader/mt8139/src/main.c
@@ -34,6 +34,7 @@
  * Software") have been modified by MediaTek Inc. All revisions are subject to
  * any receiver's applicable license agreements with MediaTek Inc.
  */
+// SPDX-License-Identifier: MediaTekProprietary
 
 #include "typedefs.h"
 #include "tz_init.h"
@@ -68,7 +69,11 @@
     tee_arg->atf_magic = 0x4D415446;
     tee_arg->tee_support = 0x1;
     tee_arg->tee_entry = TRUSTEDOS_ENTRYPOINT;
+#if (KASAN_SUPPORT == 1)
+    tee_arg->tee_boot_arg_addr = 0x47080100;
+#else
     tee_arg->tee_boot_arg_addr = 0x43000100;
+#endif
     tee_arg->hwuid[0] = 0x55C09893;
     tee_arg->hwuid[1] = 0x2B404DDF;
     tee_arg->hwuid[2] = 0x3ACE08B;
diff --git a/src/bsp/trustzone/teeloader/mt8169/Makefile b/src/bsp/trustzone/teeloader/mt8169/Makefile
old mode 100644
new mode 100755
index 5e4b689..7d96dfa
--- a/src/bsp/trustzone/teeloader/mt8169/Makefile
+++ b/src/bsp/trustzone/teeloader/mt8169/Makefile
@@ -12,7 +12,7 @@
 
 DIR_INC = ./include
 DIR_SRC = ./src
-DIR_PREBUILT = ./prebuild
+DIR_PREBUILT = ./prebuilt
 DIR_OBJ = ${TL_RAW_OUT}/obj
 DIR_BIN = ${TL_RAW_OUT}/bin
 
@@ -49,7 +49,7 @@
 	@if [ ! -d `dirname $@` ] ; then \
 		mkdir -p `dirname $@`; \
 	fi
-	$(CC) -I$(DIR_INC) -DBASE_ADDR=${BASE_ADDR} -DTL_ALIGN_SIZE=${TL_ALIGN_SIZE} -DTRUSTEDOS_ENTRYPOINT=${TRUSTEDOS_ENTRYPOINT} -DATFLOGBUF_SIZE=${ATFLOGBUF_SIZE} -c $(filter %$(patsubst %.o,%.c,$(notdir $@)),$(CSRCS)) -o $@
+	$(CC) -I$(DIR_INC) -DTL_VERIFY_ENABLE=${TL_VERIFY_ENABLE} -DBASE_ADDR=${BASE_ADDR} -DTL_ALIGN_SIZE=${TL_ALIGN_SIZE} -DTRUSTEDOS_ENTRYPOINT=${TRUSTEDOS_ENTRYPOINT} -DATFLOGBUF_SIZE=${ATFLOGBUF_SIZE} -c $(filter %$(patsubst %.o,%.c,$(notdir $@)),$(CSRCS)) -o $@
 
 $(DIR_OBJ)/%.o: %.s
 	@if [ ! -d `dirname $@` ] ; then \
diff --git a/src/bsp/trustzone/teeloader/mt8169/prebuilt/libcrypto.a b/src/bsp/trustzone/teeloader/mt8169/prebuilt/libcrypto.a
new file mode 100755
index 0000000..6027c03
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8169/prebuilt/libcrypto.a
Binary files differ
diff --git a/src/bsp/trustzone/teeloader/mt8169/prebuilt/libsec.a b/src/bsp/trustzone/teeloader/mt8169/prebuilt/libsec.a
new file mode 100755
index 0000000..2b45431
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8169/prebuilt/libsec.a
Binary files differ
diff --git a/src/bsp/trustzone/teeloader/mt8169/src/main.c b/src/bsp/trustzone/teeloader/mt8169/src/main.c
old mode 100644
new mode 100755
index dce4a75..512ddb8
--- a/src/bsp/trustzone/teeloader/mt8169/src/main.c
+++ b/src/bsp/trustzone/teeloader/mt8169/src/main.c
@@ -11,6 +11,7 @@
 typedef void (*jump_atf)(u64 addr ,u64 arg1) __attribute__ ((__noreturn__));
 
 extern void tz_emi_mpu_init(u32 start_add, u32 end_addr, u32 mpu_region);
+extern int teeloader_prepare_tee(u32 pt_addr);
 
 static u64 trustzone_get_atf_boot_param_addr(void)
 {
@@ -64,6 +65,12 @@
     mtk_bl_param_t *atf_arg = (mtk_bl_param_t *)trustzone_get_atf_boot_param_addr();
     atf_arg_t *tee_arg = (atf_arg_t *)trustzone_get_tee_boot_param_addr();
 
+#if TL_VERIFY_ENABLE != 0
+    teeloader_prepare_tee((BASE_ADDR + TL_ALIGN_SIZE));
+    teeloader_prepare_tee(TRUSTEDOS_ENTRYPOINT);
+    tl_printf("tee decrypt successfully!\n");
+#endif
+
 #if 0
     tz_emi_mpu_init((BL31_BASE & 0xffff0000),
                     (BL31_BASE & 0xffff0000) + BL31_SIZE - 1,
diff --git a/src/bsp/trustzone/teeloader/mt8696/Makefile b/src/bsp/trustzone/teeloader/mt8696/Makefile
new file mode 100755
index 0000000..f050f01
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/Makefile
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: MediaTekProprietary
+CC := ${CROSS_COMPILE}gcc
+AR := ${CROSS_COMPILE}ar
+LD := ${CROSS_COMPILE}ld
+OBJCOPY := ${CROSS_COMPILE}objcopy
+
+LDS = tllink.lds
+
+DIR_INC = ./include
+DIR_SRC = ./src
+DIR_PREBUILT = ./prebuild
+DIR_OBJ = ${TL_RAW_OUT}/obj
+DIR_BIN = ${TL_RAW_OUT}/bin
+
+ASRCS = $(wildcard $(DIR_SRC)/*.s)
+CSRCS = $(wildcard $(DIR_SRC)/*.c)
+CSRCS += \
+	$(DIR_SRC)/drivers/tz_emi_mpu.c
+
+VPATH = $(DIR_SRC):$(DIR_SRC)/drivers
+SRCS = $(ASRCS) $(CSRCS)
+AOBJS = $(patsubst %.s, $(DIR_OBJ)/%.o, $(notdir $(ASRCS)))
+COBJS = $(patsubst %.c, $(DIR_OBJ)/%.o, $(notdir $(CSRCS)))
+SOBJS = $(wildcard $(DIR_PREBUILT)/*.a)
+OBJS = $(AOBJS) $(COBJS) $(SOBJS)
+
+TARGET = teeloader
+BIN_TARGET = $(DIR_BIN)/$(TARGET)
+
+ifeq ($(strip $(ATFLOGBUF_SIZE)),)
+ATFLOGBUF_SIZE := 0
+endif
+
+all: $(OBJS)
+	@if [ ! -d `dirname $(BIN_TARGET).elf` ] ; then \
+		mkdir -p `dirname $(BIN_TARGET).elf`; \
+	fi
+	sed "s/%BASE_ADDR%/${BASE_ADDR}/g" $(LDS) > $(DIR_OBJ)/$(LDS)
+	$(LD) --start-group $^ --end-group -T$(DIR_OBJ)/$(LDS) -o $(BIN_TARGET).elf
+	-echo "teeloader binary created"
+	$(OBJCOPY) -O binary $(BIN_TARGET).elf $(BIN_TARGET).bin
+	./zero_padding.sh $(BIN_TARGET).bin ${TL_ALIGN_SIZE}
+
+$(DIR_OBJ)/%.o: %.c
+	@if [ ! -d `dirname $@` ] ; then \
+		mkdir -p `dirname $@`; \
+	fi
+	$(CC) -I$(DIR_INC) -DBASE_ADDR=${BASE_ADDR} -DTL_ALIGN_SIZE=${TL_ALIGN_SIZE} -DTRUSTEDOS_ENTRYPOINT=${TRUSTEDOS_ENTRYPOINT} -DATFLOGBUF_SIZE=${ATFLOGBUF_SIZE} -c $(filter %$(patsubst %.o,%.c,$(notdir $@)),$(CSRCS)) -o $@
+
+$(DIR_OBJ)/%.o: %.s
+	@if [ ! -d `dirname $@` ] ; then \
+		mkdir -p `dirname $@`; \
+	fi
+	$(CC) -c $^ -o $@
+
+.PHONY: clean
+clean:
+	-@rm -rf $(DIR_OBJ)/* $(DIR_BIN)/*
diff --git a/src/bsp/trustzone/teeloader/mt8696/include/print.h b/src/bsp/trustzone/teeloader/mt8696/include/print.h
new file mode 100755
index 0000000..3de1a3c
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/include/print.h
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* 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) 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.
+ */
+
+#ifndef __PRINT_H__
+#define __PRINT_H__
+
+void tl_printf(char *fmt, ...);
+
+#endif /* __PRINT_H__ */
diff --git a/src/bsp/trustzone/teeloader/mt8696/include/typedefs.h b/src/bsp/trustzone/teeloader/mt8696/include/typedefs.h
new file mode 100755
index 0000000..d382b00
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/include/typedefs.h
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* 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) 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.
+ */
+
+#ifndef __TYPEDEFS_H__
+#define __TYPEDEFS_H__
+
+typedef unsigned long ulong;
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef signed char int8;
+typedef signed short int16;
+typedef signed long int32;
+typedef signed int intx;
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+typedef unsigned int uintx;
+
+typedef unsigned int UINT32;
+typedef volatile unsigned int *P_U32;
+
+typedef unsigned char u8;
+typedef signed char s8;
+typedef unsigned short u16;
+typedef signed short s16;
+typedef unsigned int u32;
+typedef signed int s32;
+typedef unsigned long long u64;
+typedef signed long long s64;
+
+#endif /* __TYPEDEFS_H__ */
diff --git a/src/bsp/trustzone/teeloader/mt8696/include/tz_emi_mpu.h b/src/bsp/trustzone/teeloader/mt8696/include/tz_emi_mpu.h
new file mode 100755
index 0000000..4a591ec
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/include/tz_emi_mpu.h
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* 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) 2017 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 TZ_EMI_MPU_H
+#define TZ_EMI_MPU_H
+
+#define EMI_PHY_OFFSET       (0x40000000UL)
+
+#define EMI_MPU_REGION_NUMBER       (32)
+#define EMI_MPU_DOMAIN_NUMBER       (16)
+
+#define LOCK       1
+#define UNLOCK     0
+
+typedef enum {
+    NO_PROTECTION = 0,
+    NSEC_W_FORBIDDEN = 0x1,
+    NSEC_R_FORBIDDEN = 0x2,
+    NSEC_RW_FORBIDDEN = 0x3,
+    SEC_W_FORBIDDEN = 0x4,
+    SEC_W_NSEC_W_FORBIDDEN = 0x5,
+    SEC_W_NSEC_R_FORBIDDEN = 0x6,
+    SEC_W_NSEC_RW_FORBIDDEN = 0x7,
+    SEC_R_FORBIDDEN = 0x8,
+    SEC_R_NSEC_W_FORBIDDEN = 0x9,
+    SEC_R_NSEC_R_FORBIDDEN = 0xA,
+    SEC_R_NSEC_RW_FORBIDDEN = 0xB,
+    SEC_RW_FORBIDDEN = 0xC,
+    SEC_RW_NSEC_W_FORBIDDEN = 0xD,
+    SEC_RW_NSEC_R_FORBIDDEN = 0xE,
+    ALL_FORBIDDEN = 0xF,
+    EMI_MPU_ACCESS_PERM_NUMS = 0x10
+} ACCESS_PERM;
+
+#define SECURE_OS_MPU_REGION_ID    (0)
+#define ATF_MPU_REGION_ID          (1)
+
+#define SET_ACCESS_PERMISSION(d15, d14, d13, d12, d11, d10, d9,d8, d7, d6, d5, d4, d3, d2, d1, d0) \
+((((unsigned long long) d15)  << 60) | (((unsigned long long) d14)  << 56) | (((unsigned long long) d13)  << 52) | (((unsigned long long) d12)  << 48) | \
+(((unsigned long long) d11)  << 44) | (((unsigned long long) d10)  << 40) | (((unsigned long long) d9)  << 36) | (((unsigned long long) d8)  << 32) | \
+(((unsigned long long) d7)  << 28) | (((unsigned long long) d6)  << 24) | (((unsigned long long) d5)  << 20) | (((unsigned long long) d4)  << 16) | \
+(((unsigned long long) d3)  <<  12) | (((unsigned long long) d2)  <<  8) | (((unsigned long long) d1)  <<  4) | ((unsigned long long) d0))
+
+#endif /* TZ_EMI_MPU_H */
diff --git a/src/bsp/trustzone/teeloader/mt8696/include/tz_emi_reg.h b/src/bsp/trustzone/teeloader/mt8696/include/tz_emi_reg.h
new file mode 100755
index 0000000..2816658
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/include/tz_emi_reg.h
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* 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 __TZ_EMI_REG_H__
+#define __TZ_EMI_REG_H__
+
+#define IO_PHYS            	    0x10000000
+#define EMI_APB_BASE            (IO_PHYS + 0x00203000)
+#define EMI_MPU_BASE            (IO_PHYS + 0x00226000)
+
+#define EMI_CONA        (EMI_APB_BASE + 0x000)
+#define EMI_CONB        (EMI_APB_BASE + 0x008)
+#define EMI_CONC        (EMI_APB_BASE + 0x010)
+#define EMI_COND        (EMI_APB_BASE + 0x018)
+#define EMI_CONE        (EMI_APB_BASE + 0x020)
+#define EMI_CONF        (EMI_APB_BASE + 0x028)
+#define EMI_CONG        (EMI_APB_BASE + 0x030)
+#define EMI_CONH        (EMI_APB_BASE + 0x038)
+#define EMI_CONH_2ND    (EMI_APB_BASE + 0x03c)
+#define EMI_CONI        (EMI_APB_BASE + 0x040)
+#define EMI_CONJ        (EMI_APB_BASE + 0x048)
+#define EMI_CONM        (EMI_APB_BASE + 0x060)
+#define EMI_CONN        (EMI_APB_BASE + 0x068)
+#define EMI_CONO        (EMI_APB_BASE + 0x070)
+#define EMI_MDCT        (EMI_APB_BASE + 0x078)
+#define EMI_MDCT_2ND        (EMI_APB_BASE + 0x07c)
+#define EMI_IOCL        (EMI_APB_BASE + 0x0d0)
+#define EMI_IOCL_2ND        (EMI_APB_BASE + 0x0d4)
+#define EMI_IOCM        (EMI_APB_BASE + 0x0d8)
+#define EMI_IOCM_2ND        (EMI_APB_BASE + 0x0dc)
+#define EMI_TESTB       (EMI_APB_BASE + 0x0e8)
+#define EMI_TESTC       (EMI_APB_BASE + 0x0f0)
+#define EMI_TESTD       (EMI_APB_BASE + 0x0f8)
+#define EMI_SLVA        (EMI_APB_BASE + 0x800)
+#define EMI_ARBA        (EMI_APB_BASE + 0x100)
+#define EMI_ARBB        (EMI_APB_BASE + 0x108)
+#define EMI_ARBC        (EMI_APB_BASE + 0x110)
+#define EMI_ARBD        (EMI_APB_BASE + 0x118)
+#define EMI_ARBE        (EMI_APB_BASE + 0x120)
+#define EMI_ARBE_2ND    (EMI_APB_BASE + 0x124)
+#define EMI_ARBF        (EMI_APB_BASE + 0x128)
+#define EMI_ARBG        (EMI_APB_BASE + 0x130)
+#define EMI_ARBH        (EMI_APB_BASE + 0x138)
+#define EMI_ARBI        (EMI_APB_BASE + 0x140)
+#define EMI_ARBI_2ND    (EMI_APB_BASE + 0x144)
+#define EMI_ARBJ        (EMI_APB_BASE + 0x148)
+#define EMI_ARBJ_2ND    (EMI_APB_BASE + 0x14c)
+#define EMI_ARBK        (EMI_APB_BASE + 0x150)
+#define EMI_ARBK_2ND    (EMI_APB_BASE + 0x154)
+#define EMI_SLCT        (EMI_APB_BASE + 0x158)
+#define EMI_BMEN        (EMI_APB_BASE + 0x400)
+#define EMI_SHF0        (EMI_APB_BASE + 0x710)
+#define EMI_SHF1        (EMI_APB_BASE + 0x718)
+#define EMI_CLUA        (EMI_APB_BASE + 0x71c)
+#define EMI_BWCT0       (EMI_APB_BASE + 0x5B0)
+#define EMI_BWCT1       (EMI_APB_BASE + 0x5B4)
+#define EMI_BWCT2       (EMI_APB_BASE + 0x5B8)
+#define EMI_BWCT3       (EMI_APB_BASE + 0x5BC)
+#define EMI_BWCT4       (EMI_APB_BASE + 0x5C0)
+#define EMI_BWST0       (EMI_APB_BASE + 0x5C4)
+#define EMI_BWCT0_3RD   (EMI_APB_BASE + 0x770)
+#define EMI_BWCT0_4TH   (EMI_APB_BASE + 0x780)
+#define EMI_BWCT0_5TH   (EMI_APB_BASE + 0x7B0)
+
+#define CHN_EMI_CONA(base)  (base + 0x000)
+#define CHN_EMI_CONB(base)  (base + 0x008)
+#define CHN_EMI_CONC(base)  (base + 0x010)
+#define CHN_EMI_MDCT(base)  (base + 0x018)
+#define CHN_EMI_COND(base)  (base + 0x020)
+#define CHN_EMI_TESTB(base) (base + 0x048)
+#define CHN_EMI_TESTC(base) (base + 0x050)
+#define CHN_EMI_TESTD(base) (base + 0x058)
+#define CHN_EMI_MD_PRE_MASK(base) (base + 0x080)
+#define CHN_EMI_MD_PRE_MASK_SHF(base) (base + 0x088)
+#define CHN_EMI_AP_ERALY_CKE(base) (base + 0x090)
+#define CHN_EMI_DQFR(base) (base + 0x098)
+#define CHN_EMI_ARBI(base)  (base + 0x140)
+#define CHN_EMI_ARBI_2ND(base)  (base + 0x144)
+#define CHN_EMI_ARBJ(base)  (base + 0x148)
+#define CHN_EMI_ARBJ_2ND(base)  (base + 0x14c)
+#define CHN_EMI_ARBK(base)  (base + 0x150)
+#define CHN_EMI_ARBK_2ND(base)  (base + 0x154)
+#define CHN_EMI_SLCT(base)  (base + 0x158)
+#define CHN_EMI_ARB_REF(base)   (base + 0x15c)
+#define CHN_EMI_DRS_MON0(base)   (base + 0x16c)
+#define CHN_EMI_DRS_MON1(base)   (base + 0x170)
+#define CHN_EMI_RKARB0(base)   (base + 0x1b0)
+#define CHN_EMI_RKARB1(base)   (base + 0x1b4)
+#define CHN_EMI_RKARB2(base)   (base + 0x1b8)
+#define CHN_EMI_SHF0(base)   (base + 0x710)
+#define CHN_EMI_BISTC(base) (base + 0xa08)
+
+#define EMI_MPU_CTRL                (EMI_MPU_BASE+0x000)
+#define EMI_MPU_DBG                 (EMI_MPU_BASE+0x004)
+#define EMI_MPU_SA0                 (EMI_MPU_BASE+0x100)
+#define EMI_MPU_EA0                 (EMI_MPU_BASE+0x200)
+#define EMI_MPU_APC0                (EMI_MPU_BASE+0x300)
+#define EMI_MPU_LOCK0               (EMI_MPU_BASE+0x500)
+#define EMI_MPU_SA(region)           (EMI_MPU_SA0 + (region*4))
+#define EMI_MPU_EA(region)           (EMI_MPU_EA0 + (region*4))
+#define EMI_MPU_APC(region, domain)  (EMI_MPU_APC0 + (region*4) + ((domain/8)*0x100))
+#define EMI_MPU_LOCK(region)         (EMI_MPU_LOCK0 + (region*4))
+
+#endif // __TZ_EMI_REG_H__
diff --git a/src/bsp/trustzone/teeloader/mt8696/include/tz_init.h b/src/bsp/trustzone/teeloader/mt8696/include/tz_init.h
new file mode 100755
index 0000000..6bc77eb
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/include/tz_init.h
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2011
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER 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 BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'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 BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. 
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+#ifndef TRUSTZONE_H
+#define TRUSTZONE_H
+
+#include "typedefs.h"
+
+#define BL31        0x43001000UL
+#define BL33        0x43a00000UL
+#define BL31_BASE   0x43000000UL
+#define BL31_SIZE   0x00030000UL  /* default is 192K Bytes */
+
+#define ATF_BOOT_ARG_ADDR (0x40000000)
+#define TEE_BOOT_ARG_ADDR (0x40001000)
+#define ATF_BOOTCFG_MAGIC (0x4D415446) // String MATF in little-endian
+
+#define DEVINFO_SIZE 4
+
+/* bootarg for ATF */
+typedef struct {
+    u64 bootarg_loc;
+    u64 bootarg_size;
+    u64 bl33_start_addr;
+    u64 tee_info_addr;
+} mtk_bl_param_t;
+
+typedef struct {
+    u32 atf_magic;
+    u32 tee_support;
+    u32 tee_entry;
+    u32 tee_boot_arg_addr;
+    u32 hwuid[4];     // HW Unique id for t-base used
+    u32 atf_hrid_size;
+    u32 HRID[8];      // HW random id for t-base used
+    u32 atf_log_port;
+    u32 atf_log_baudrate;
+    u32 atf_log_buf_start;
+    u32 atf_log_buf_size;
+    u32 atf_irq_num;
+    u32 devinfo[DEVINFO_SIZE];
+    u32 atf_aee_debug_buf_start;
+    u32 atf_aee_debug_buf_size;
+#if CFG_TEE_SUPPORT
+    u32 tee_rpmb_size;
+#endif
+} atf_arg_t, *atf_arg_t_ptr;
+
+#endif /* TRUSTZONE_H */
+
diff --git a/src/bsp/trustzone/teeloader/mt8696/include/uart.h b/src/bsp/trustzone/teeloader/mt8696/include/uart.h
new file mode 100755
index 0000000..95dce51
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/include/uart.h
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* 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) 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.
+ */
+
+#ifndef __UART_H__
+#define __UART_H__
+
+typedef unsigned int    uint32_t;
+typedef unsigned long   uintptr_t;
+
+#define REG32(addr) ((volatile uint32_t *)(uintptr_t)(addr))
+
+#define writel(v, a) (*REG32(a) = (v))
+#define readl(a) (*REG32(a))
+
+#define UART_BASE(uart)    (uart)
+#define UART_LSR(uart)     (UART_BASE(uart)+0x14)
+#define UART_LSR_THRE      (1 << 5)
+#define UART_THR(uart)     (UART_BASE(uart)+0x0)  /* Write only */
+
+#define IO_PHYS            0x10000000
+#define UART0_BASE         (IO_PHYS + 0x01002000)
+#define UART1_BASE         (IO_PHYS + 0x01002400)
+#define UART2_BASE         (IO_PHYS + 0x01002800)
+
+int uart_putc(char c);
+
+#endif /* __UART_H__ */
+
diff --git a/src/bsp/trustzone/teeloader/mt8696/prebuilt/HwCryptoLib.a b/src/bsp/trustzone/teeloader/mt8696/prebuilt/HwCryptoLib.a
new file mode 100755
index 0000000..4d87bfc
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/prebuilt/HwCryptoLib.a
Binary files differ
diff --git a/src/bsp/trustzone/teeloader/mt8696/prebuilt/libsec_img.a b/src/bsp/trustzone/teeloader/mt8696/prebuilt/libsec_img.a
new file mode 100755
index 0000000..0474c7e
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/prebuilt/libsec_img.a
Binary files differ
diff --git a/src/bsp/trustzone/teeloader/mt8696/src/drivers/tz_emi_mpu.c b/src/bsp/trustzone/teeloader/mt8696/src/drivers/tz_emi_mpu.c
new file mode 100755
index 0000000..c592932
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/src/drivers/tz_emi_mpu.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: MediaTekProprietary
+#include "print.h"
+#include "typedefs.h"
+#include "tz_init.h"
+#include "tz_emi_reg.h"
+#include "tz_emi_mpu.h"
+
+#define MOD "[TZ_EMI_MPU]"
+
+#define READ_REGISTER_UINT32(reg) \
+    (*(volatile UINT32 * const)(reg))
+
+#define WRITE_REGISTER_UINT32(reg, val) \
+    (*(volatile UINT32 * const)(reg)) = (val)
+
+#define readl(addr) (READ_REGISTER_UINT32(addr))
+#define writel(b,addr) (WRITE_REGISTER_UINT32(addr, b))
+#define IOMEM(reg) (reg)
+#define print tl_printf
+
+#define ENABLE_EMI_MPU_SW_LOCK      0
+
+static unsigned char region_lock_state[EMI_MPU_REGION_NUMBER];
+
+/*
+ * emi_mpu_set_region_protection: protect a region.
+ * @start: start address of the region
+ * @end: end address of the region
+ * @region: EMI MPU region id
+ * @access_permission: EMI MPU access permission
+ * Return 0 for success, otherwise negative status code.
+ */
+int emi_mpu_set_region_protection(unsigned long long start, unsigned long long end, unsigned int region, unsigned long long access_permission, unsigned int lock_status)
+{
+    unsigned int apc0, apc8;
+
+    if(region >= EMI_MPU_REGION_NUMBER)
+    {
+        print("Invalid region! Region should not larger than Max[%d].\n", (EMI_MPU_REGION_NUMBER-1));
+        return -1;
+    }
+
+#if ENABLE_EMI_MPU_SW_LOCK
+    if(region_lock_state[region] == LOCK)
+    {
+        print("Invalid region! Region%d was locked by SW.\n", region);
+        return -1;
+    }
+#endif
+
+    if (((readl(EMI_MPU_LOCK(region)))>>31)&0x01 == LOCK)
+    {
+        print("Invalid region! Region%d was locked by HW.\n", region);
+        return -1;
+    }
+
+    if(end <= start)
+    {
+        print("Invalid address! End address should larger than start address.\n");
+        return -1;
+    }
+
+    if(((start & 0xFFFF) != 0x0) || (((end & 0xFFFF) != 0x0) && (end & 0xFFFF) != 0xFFFF))
+    {
+        print("Invalid address! Address should be 16bit aligned. Please check the start and end address.\n");
+        return -1;
+    }
+
+    if((end & 0xFFFF) == 0x0)
+    {
+        end = end - 1;
+    }
+
+    start = ((start - EMI_PHY_OFFSET) >> 16) & 0x3FFFF;
+    end = ((end - EMI_PHY_OFFSET) >> 16) & 0x3FFFF;
+
+    apc0 = (unsigned int)(access_permission & 0xFFFFFFFF);
+    apc8 = (unsigned int)((access_permission >> 32) & 0xFFFFFFFF);
+
+    writel(((unsigned int)(UNLOCK) << 31), EMI_MPU_LOCK(region));
+    writel(0, EMI_MPU_APC(region, 8));
+    writel(0, EMI_MPU_APC(region, 0));
+
+    writel((unsigned int)start, EMI_MPU_SA(region));
+    writel((unsigned int)end, EMI_MPU_EA(region));
+    writel(apc8, EMI_MPU_APC(region, 8));
+    writel(apc0, EMI_MPU_APC(region, 0));
+#if ENABLE_EMI_MPU_SW_LOCK
+    if (lock_status)
+        region_lock_state[region] = LOCK;
+#endif
+    writel(((unsigned int)lock_status << 31), EMI_MPU_LOCK(region));
+
+    return 0;
+}
+
+void tz_emi_mpu_init(u64 start_add, u64 end_addr, u32 mpu_region)
+{
+    int ret = 0;
+    unsigned long long sec_mem_mpu_attr = 0;
+    u64 sec_mem_phy_start = 0;
+    u64 sec_mem_phy_end = 0;
+
+    /* Caculate start/end address */
+    sec_mem_phy_start = start_add;
+    sec_mem_phy_end = end_addr;
+
+    switch(mpu_region)
+    {
+        case SECURE_OS_MPU_REGION_ID:
+            sec_mem_mpu_attr = SET_ACCESS_PERMISSION(ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN,
+                    ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, NSEC_RW_FORBIDDEN);
+            break;
+
+        case ATF_MPU_REGION_ID:
+            sec_mem_mpu_attr = SET_ACCESS_PERMISSION(ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, SEC_RW_NSEC_W_FORBIDDEN, ALL_FORBIDDEN,
+                    ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, ALL_FORBIDDEN, NSEC_RW_FORBIDDEN);
+            break;
+
+        default:
+            print("%s ERROR - MPU region '%d' is not supported for preloader!\n", MOD, mpu_region);
+            return;
+    }
+
+    print("%s MPU [0x%x-0x%x]\n", MOD, sec_mem_phy_start, sec_mem_phy_end);
+
+    ret = emi_mpu_set_region_protection(sec_mem_phy_start,  /*START_ADDR*/
+                                        sec_mem_phy_end,    /*END_ADDR*/
+                                        mpu_region,         /*region*/
+                                        sec_mem_mpu_attr,   /*access permission*/
+                                        LOCK);
+
+    if(ret)
+    {
+        print("%s MPU error, hang here!!\n", MOD);
+        while(1);
+    }
+}
diff --git a/src/bsp/trustzone/teeloader/mt8696/src/main.c b/src/bsp/trustzone/teeloader/mt8696/src/main.c
new file mode 100755
index 0000000..fd6c4f7
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/src/main.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* 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) 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 "typedefs.h"
+#include "tz_init.h"
+#include "tz_emi_mpu.h"
+#include "uart.h"
+#include "print.h"
+
+typedef void (*jump_atf)(u64 addr ,u64 arg1) __attribute__ ((__noreturn__));
+
+extern void tz_emi_mpu_init(u32 start_add, u32 end_addr, u32 mpu_region);
+
+static u64 trustzone_get_atf_boot_param_addr(void)
+{
+    return ATF_BOOT_ARG_ADDR;
+}
+
+static u64 trustzone_get_tee_boot_param_addr(void)
+{
+    return TEE_BOOT_ARG_ADDR;
+}
+
+static void set_atf_parameters(mtk_bl_param_t *atf_arg)
+{
+    atf_arg->bootarg_loc = 0;
+    atf_arg->bootarg_size = 0;
+    atf_arg->bl33_start_addr = BL33;
+    atf_arg->tee_info_addr = TEE_BOOT_ARG_ADDR;
+}
+
+static void set_tee_parameters(atf_arg_t *tee_arg)
+{
+    /* tee arguments */
+    tee_arg->atf_magic = 0x4D415446;
+    tee_arg->tee_support = 0x1;
+    tee_arg->tee_entry = TRUSTEDOS_ENTRYPOINT;
+    tee_arg->tee_boot_arg_addr = 0x43000100;
+    tee_arg->hwuid[0] = 0x55C09893;
+    tee_arg->hwuid[1] = 0x2B404DDF;
+    tee_arg->hwuid[2] = 0x3ACE08B;
+    tee_arg->hwuid[3] = 0x1092600D;
+    tee_arg->HRID[0] = 0;
+    tee_arg->HRID[1] = 0;
+    tee_arg->atf_log_port = UART1_BASE;
+    tee_arg->atf_log_baudrate = 0xE1000;
+    tee_arg->atf_log_buf_start = (ATFLOGBUF_SIZE==0)?(0):(BL31_BASE - ATFLOGBUF_SIZE);
+    tee_arg->atf_log_buf_size = ATFLOGBUF_SIZE;
+    tee_arg->atf_irq_num = 0x180; /* reserve SPI ID 352 for ATF log, which is ID 384 */
+    tee_arg->devinfo[0] = 0;
+    tee_arg->devinfo[1] = 0;
+    tee_arg->devinfo[2] = 0xFFFFFFFF;
+    tee_arg->devinfo[3] = 0xFFFFFFFF;
+    tee_arg->atf_aee_debug_buf_start = 0x0;
+    tee_arg->atf_aee_debug_buf_size = 0x0;
+}
+
+int teeloader_main(unsigned long long bl31_addr, unsigned long long bl33_addr,unsigned long long bl32_addr)
+{
+    u32 bl31_reserve = 0;
+    jump_atf atf_entry;
+
+    mtk_bl_param_t *atf_arg = (mtk_bl_param_t *)trustzone_get_atf_boot_param_addr();
+    atf_arg_t *tee_arg = (atf_arg_t *)trustzone_get_tee_boot_param_addr();
+
+#if 0
+    tz_emi_mpu_init((BL31_BASE & 0xffff0000),
+                    (BL31_BASE & 0xffff0000) + BL31_SIZE - 1,
+                    ATF_MPU_REGION_ID);
+#endif
+
+    set_atf_parameters(atf_arg);
+    set_tee_parameters(tee_arg);
+
+    if(bl32_addr)
+        tee_arg->tee_entry = bl32_addr;
+
+    if(bl33_addr)
+        atf_arg->bl33_start_addr = bl33_addr;
+
+    atf_entry = (jump_atf)BL31;
+    /* jump to tz */
+
+    (*atf_entry)(ATF_BOOT_ARG_ADDR, bl31_reserve);
+
+    return 0;
+}
diff --git a/src/bsp/trustzone/teeloader/mt8696/src/print.c b/src/bsp/trustzone/teeloader/mt8696/src/print.c
new file mode 100755
index 0000000..95d45d6
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/src/print.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* 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) 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 "typedefs.h"
+#include "print.h"
+#include "uart.h"
+#include <stdarg.h>
+
+static void outchar(const char c)
+{
+	uart_putc(c);
+}
+
+static void outstr(const unsigned char *s)
+{
+	while (*s) {
+		if (*s == '\n')
+			outchar('\r');
+		outchar(*s++);
+	}
+}
+
+static void outdec(unsigned long n)
+{
+	if (n >= 10) {
+		outdec(n / 10);
+		n %= 10;
+	}
+	outchar((unsigned char)(n + '0'));
+}
+
+static void outhex(unsigned long n, long depth)
+{
+	if (depth)
+		depth--;
+
+	if ((n & ~0xf) || depth) {
+		outhex(n >> 4, depth);
+		n &= 0xf;
+	}
+
+	if (n < 10) {
+		outchar((unsigned char)(n + '0'));
+	} else {
+		outchar((unsigned char)(n - 10 + 'A'));
+	}
+}
+
+void tl_vprint(char *fmt, va_list vl)
+{
+	unsigned char c;
+	unsigned int reg = 1;	/* argument register number (32-bit) */
+
+	while (*fmt) {
+		c = *fmt++;
+		switch (c) {
+		case '%':
+			c = *fmt++;
+			switch (c) {
+			case 'x':
+				outhex(va_arg(vl, unsigned long), 0);
+				break;
+			case 'B':
+				outhex(va_arg(vl, unsigned long), 2);
+				break;
+			case 'H':
+				outhex(va_arg(vl, unsigned long), 4);
+				break;
+			case 'X':
+				outhex(va_arg(vl, unsigned long), 8);
+				break;
+			case 'l':
+				if (*fmt == 'l' && *(fmt + 1) == 'x') {
+					u32 ltmp;
+					u32 htmp;
+
+					ltmp = va_arg(vl, unsigned int);
+					htmp = va_arg(vl, unsigned int);
+
+					outhex(htmp, 8);
+					outhex(ltmp, 8);
+					fmt += 2;
+				}
+				break;
+			case 'd':
+				{
+					long l;
+
+					l = va_arg(vl, long);
+					if (l < 0) {
+						outchar('-');
+						l = -l;
+					}
+					outdec((unsigned long)l);
+				}
+				break;
+			case 'u':
+				outdec(va_arg(vl, unsigned long));
+				break;
+			case 's':
+				outstr((const unsigned char *)
+				       va_arg(vl, char *));
+				break;
+			case '%':
+				outchar('%');
+				break;
+			case 'c':
+				c = va_arg(vl, int);
+				outchar(c);
+				break;
+			default:
+				outchar(' ');
+				break;
+			}
+			reg++;	/* one argument uses 32-bit register */
+			break;
+		case '\r':
+			if (*fmt == '\n')
+				fmt++;
+			c = '\n';
+			// fall through
+		case '\n':
+			outchar('\r');
+			// fall through
+		default:
+			outchar(c);
+		}
+	}
+}
+
+void tl_printf(char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	tl_vprint(fmt, args);
+	va_end(args);
+}
+
diff --git a/src/bsp/trustzone/teeloader/mt8696/src/start.s b/src/bsp/trustzone/teeloader/mt8696/src/start.s
new file mode 100755
index 0000000..6c1d4e1
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/src/start.s
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* 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) 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.
+ */
+
+.section .text.start
+
+.globl _start
+_start:
+	b teeloader_main
diff --git a/src/bsp/trustzone/teeloader/mt8696/src/uart.c b/src/bsp/trustzone/teeloader/mt8696/src/uart.c
new file mode 100755
index 0000000..24410ef
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/src/uart.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "uart.h"
+
+int uart_putc(char c)
+{
+	while (!(readl(UART_LSR(UART1_BASE)) & UART_LSR_THRE));
+
+	if (c == '\n')
+		writel((unsigned int)'\r', UART_THR(UART1_BASE));
+
+	writel((unsigned int)c, UART_THR(UART1_BASE));
+
+	return 0;
+}
diff --git a/src/bsp/trustzone/teeloader/mt8696/tllink.lds b/src/bsp/trustzone/teeloader/mt8696/tllink.lds
new file mode 100755
index 0000000..dc5a82b
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/tllink.lds
@@ -0,0 +1,38 @@
+OUTPUT_ARCH(aarch64)
+
+ENTRY(_start)
+
+SECTIONS {
+
+	. = %BASE_ADDR%;
+	.start ALIGN(4) : {
+		*(.text.start)
+	}
+
+	. = . + 0x01FC;
+	.text ALIGN(4) : {
+		*(.text)
+		*(.text.*)
+	}
+	.rodata ALIGN(4) : {
+		*(.rodata)
+		*(.rodata.*)
+	}
+	.data ALIGN(4) : {
+		*(.data)
+		*(.data.*)
+	}
+
+	. = %BASE_ADDR%-0x100000 ;
+	.bss ALIGN(16) : {
+		_bss_start = .;
+		*(.bss)
+		*(.bss.*)
+		*(COMMON)
+		/* make _bss_end as 4 bytes alignment */
+		. = ALIGN(4);
+		_bss_end = .;
+	}
+
+}
+
diff --git a/src/bsp/trustzone/teeloader/mt8696/zero_padding.sh b/src/bsp/trustzone/teeloader/mt8696/zero_padding.sh
new file mode 100755
index 0000000..e3fb84e
--- /dev/null
+++ b/src/bsp/trustzone/teeloader/mt8696/zero_padding.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+FILE_PATH=$1
+ALIGNMENT=$2
+PADDING_SIZE=0
+
+FILE_SIZE=$(($(wc -c < "${FILE_PATH}")))
+REMAINDER=$((${FILE_SIZE} % ${ALIGNMENT}))
+FILE_DIR=$(dirname "${FILE_PATH}")
+if [ ${REMAINDER} -ne 0 ]; then
+	PADDING_SIZE=$((${ALIGNMENT} - ${REMAINDER}))
+	dd if=/dev/zero of=${FILE_DIR}/padding.txt bs=$PADDING_SIZE count=1
+	cat ${FILE_DIR}/padding.txt>>${FILE_PATH}
+	rm ${FILE_DIR}/padding.txt
+fi
diff --git a/src/connectivity/agps/2.0/lbs_em/src/lbs_em.c b/src/connectivity/agps/2.0/lbs_em/src/lbs_em.c
index 9dcf1c4..ffd914c 100755
--- a/src/connectivity/agps/2.0/lbs_em/src/lbs_em.c
+++ b/src/connectivity/agps/2.0/lbs_em/src/lbs_em.c
@@ -1,3 +1,4 @@
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <pthread.h>
@@ -8,6 +9,8 @@
 #include <errno.h>
 #include <semaphore.h>
 #include <math.h>
+#include <dirent.h>
+#include <sys/stat.h>
 
 #include "mtk_tree.h"
 #include "agps_interface.h"
@@ -164,18 +167,18 @@
     UI_AT_SETTINGS_REFERENCE_TIME_RESPONSE,
     UI_AT_SETTINGS_NMEA_CONFIG_SET = 15,
     UI_AT_SETTINGS_LOOPBACK_REQUEST,
-    
+
     UI_AT_SETTINGS_GEOFENCE_MAX_NUMBER_REQUEST = 31,
     UI_AT_SETTINGS_GEOFENCE_ADD_CIRCLE_REQUEST,
     UI_AT_SETTINGS_GEOFENCE_ADD_CIRCLE_WITH_WAKE_LOCK_RELEASE,
     UI_AT_SETTINGS_GEOFENCE_DELETE_REQUEST,
     UI_AT_SETTINGS_GEOFENCE_DELETE_ALL_REQUEST,
-    
+
     UI_AT_SETTINGS_CERTIFICATE_INJECT = 51,
     UI_AT_SETTINGS_CERTIFICATE_NAME_LIST_REQUEST,
     UI_AT_SETTINGS_CERTIFICATE_DELETE,
     UI_AT_SETTINGS_CERTIFICATE_DELETE_ALL,
-    
+
     UI_AT_SETTINGS_INPUT_A_GNSS_AT_COMMAND_MANUALLY = 99,
 } ui_at_test_type;
 
@@ -185,6 +188,7 @@
     UI_NLP_TEST_TYPE_STOP_RQUEST,
     UI_NLP_TEST_TYPE_GET_LAST_LOC,
     UI_NLP_TEST_TYPE_GET_SINGLE_UPDATE,
+    UI_NLP_TEST_TYPE_GET_PRESSURE_SENSOR,
 } ui_nlp_test_type;
 
 typedef enum {
@@ -324,6 +328,9 @@
 
     gettimeofday(&tv, &tz);
     tm = localtime(&tv.tv_sec);
+    if (tm == NULL) {
+        return 0;
+    }
 
     memset(buf, 0, len);
     sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d.%03d",
@@ -4419,6 +4426,77 @@
     return true;
 }
 
+bool mtk_nlp_find_file_in_dir(char *dir, char *target_dir, char *target_file, char *target_path) {
+    bool target_found = false;
+    DIR *dp;
+    struct dirent *entry;
+    struct stat statbuf;
+    char new_dir[256];
+
+    if((dp = opendir(dir)) == NULL) {
+        fprintf(stderr,"cannot open directory: %s\n", dir);
+        return false;
+    }
+    //LOGD("switch to dir: %s\n", dir);
+    chdir(dir);
+
+    while ((entry = readdir(dp)) != NULL) {
+        lstat(entry->d_name, &statbuf);
+
+        if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)
+            continue;
+        if (strncmp(entry->d_name, target_file, strlen(target_file)) == 0) {
+            target_found = true;
+            snprintf(target_path, 255, "%s/%s", dir, entry->d_name);
+            break;
+        }
+
+        if (strncmp(entry->d_name, target_dir, strlen(target_dir)) ==0) {
+            snprintf(new_dir, 255, "%s/%s", dir, entry->d_name);
+            target_found = mtk_nlp_find_file_in_dir(new_dir, target_dir, target_file, target_path);
+            if (target_found) {
+                break;
+            }
+        }
+    }
+    closedir(dp);
+    return target_found;
+}
+
+void mtk_nlp_request_pressure_sensor() {
+    char iio_barometer_path[256] = "";
+    char pressure_value[32];
+    int pressure_value_pa;
+    bool found = false;
+    char *IIO_SENSOR_PATH = "/sys/bus/iio/devices";
+    char *IIO_SENSOR_DEVICE_PREFIX = "iio:";
+    char *IIO_SENSOR_PRESSURE_RAW_ATTRIBUTE = "in_pressure_raw";
+    int fd;
+    int count;
+
+    //printf("Directory scan events dir:\n");
+    found = mtk_nlp_find_file_in_dir(IIO_SENSOR_PATH, IIO_SENSOR_DEVICE_PREFIX,
+            IIO_SENSOR_PRESSURE_RAW_ATTRIBUTE, iio_barometer_path);
+    if (!found || iio_barometer_path[0] == '\0') {
+        LOGD("Unable to find barometer device with raw attribute in %s", IIO_SENSOR_PATH);
+    }
+
+    fd = open(iio_barometer_path, O_RDWR);
+    if (fd < 0) {
+        LOGD("Failed to open %s\n", iio_barometer_path);
+        return;
+    }
+    count = read(fd, pressure_value, 32);
+    pressure_value[31] = '\0';
+    if (count > 0) {
+        pressure_value_pa = atoi(pressure_value);
+        LOGD("Pressure sensor value :%d\n", pressure_value_pa);
+    } else {
+        LOGD("Failed to get pressure ensor value!\n");
+    }
+    close(fd);
+}
+
 void ui_nlp_test() {
     LOGD("=== NLP Test ====");
     LOGD("0.  Back");
@@ -4427,6 +4505,7 @@
     LOGD("2.  NLP Stop Request");
     LOGD("3.  Get Last Location");
     LOGD("4.  Single Location Request");
+    LOGD("5.  Pressure Sensor Request");
 
     LOGD("input: ");
     ui_gps_control_type input = scanf_int(INVALID_VALUE, true);
@@ -4455,6 +4534,10 @@
             LOGD("Get single location update");
             MtkNlp_get_single_update(&g_nlpservice_fd);
             break;
+        case UI_NLP_TEST_TYPE_GET_PRESSURE_SENSOR:
+            LOGD("Get Pressure sensor update");
+            mtk_nlp_request_pressure_sensor();
+            break;
         default:
             LOGE("ERR: read unhandled value=[%d]", input);
             return;
@@ -5238,7 +5321,9 @@
                     break;
                 }
             }
-            memcpy(buff2, p1, (p2 - p1) + 1);
+            if (p2-p1 < sizeof(buff2)) {
+                memcpy(buff2, p1, (p2 - p1) + 1);
+            }
             mtk_at_client_parser(fd, buff2, &g_gnss_at_client_callbacks);
             p2++;
         }
diff --git a/src/connectivity/gps/2.0/gnss_test/mnld_client/inc/mnld_test.h b/src/connectivity/gps/2.0/gnss_test/mnld_client/inc/mnld_test.h
old mode 100644
new mode 100755
index a49ba31..f8f29bf
--- a/src/connectivity/gps/2.0/gnss_test/mnld_client/inc/mnld_test.h
+++ b/src/connectivity/gps/2.0/gnss_test/mnld_client/inc/mnld_test.h
@@ -11,6 +11,8 @@
 #define MNLD_TEST_NETWORK_MOBILE "mobile"
 #define MNLD_TEST_NETWORK_ROAMING "roaming"
 #define MNLD_TEST_NETWORK_DISABLE "disable"
+#define MNLD_TEST_RAW_MEAS_START "raw_start"
+
 
 #define MNL_VER_LEN 52
 #define MNL_UTC_TIME_LEN 11
@@ -21,6 +23,7 @@
     MNLD_TEST_ACTION_GNSS_OPEN,
     MNLD_TEST_ACTION_GNSS_CLOSE,
     MNLD_TEST_ACTION_SET_NETWORK,
+    MNLD_TEST_ACTION_GNSS_RAW,
     MNLD_TEST_ACTION_MAX
 } MNLD_TEST_ACTION;
 
@@ -76,6 +79,9 @@
 GpsCallbacks_ext* mnld_test__get_gps_callbacks(void);
 //GpsInterface* gps_device__get_gps_interface(struct gps_device_t* device);
 
+//for get gps raw measurement callbacks
+GpsMeasurementCallbacks_ext* mnld_test_get_raw_callbacks(void);
+
 void mnld_test_show_test_result(mnld_test_result* result);
 void mnld_test_get_mnl_ver(void);
 
diff --git a/src/connectivity/gps/2.0/gnss_test/mnld_client/src/mnld_client.c b/src/connectivity/gps/2.0/gnss_test/mnld_client/src/mnld_client.c
old mode 100644
new mode 100755
index 8030a1b..a5aef8d
--- a/src/connectivity/gps/2.0/gnss_test/mnld_client/src/mnld_client.c
+++ b/src/connectivity/gps/2.0/gnss_test/mnld_client/src/mnld_client.c
@@ -44,6 +44,9 @@
 GpsCallbacks_ext* mnld_test_cbs = NULL;
 GpsInterface_ext* mnld_test_gpsinfs = NULL;
 
+GpsMeasurementInterface_ext* raw_measinfs = NULL;
+GpsMeasurementCallbacks_ext* raw_cbs = NULL;
+int raw_flag = 0;
 
 int valid_ttff_cnt = 0;
 int valid_ttff_sum = 0;
@@ -238,8 +241,8 @@
         gpsinterface->init(cbs);
         //hal2mnl_update_network_state(1,NETWORK_TYPE_WIFI,0,"NULL");
         //hal2mnl_update_network_state(mnld_test_network_on,mnld_test_network_type,mnld_test_network_roaming,"NULL");
-        gpsinterface->start();
         gpsinterface->delete_aiding_data(delete_flags);
+        gpsinterface->start();
         memset(&(mnld_test_result_body.location),0,sizeof(GpsLocation));
         mnld_test_result_body.fix_type = 0;
         mnld_test_ttff = 0;
@@ -270,6 +273,31 @@
     }
 }
 
+void mnld_test_raw_meas_start(GpsInterface_ext* gps_interface, GpsCallbacks_ext* gps_cbs,
+                        GpsMeasurementInterface_ext* gps_meas_interface, GpsMeasurementCallbacks_ext* gps_raw_cbs) {
+    if (gps_interface == NULL || gps_cbs == NULL || gps_meas_interface == NULL || gps_raw_cbs == NULL) {
+        LOGE("param error");
+        return;
+    }
+
+    //init gps then start gps raw measurement
+    gps_interface->init(gps_cbs);
+    gps_meas_interface->init(gps_raw_cbs, true);
+    LOGD("start gps raw measurement.");
+}
+
+void mnld_test_raw_meas_stop(GpsInterface_ext* gps_interface, GpsMeasurementInterface_ext* gps_meas_interface) {
+    if (gps_interface == NULL || gps_meas_interface == NULL) {
+        LOGE("param error");
+        return;
+    }
+
+    //close gps raw measurement and clean up gps
+    gps_meas_interface->close();
+    gps_interface->cleanup();
+    LOGD("stop gps raw measurement.");
+}
+
 void mnld_test_update_network(GpsInterface_ext* gps_interface, GpsCallbacks_ext* gps_cbs)
 {
     GpsCallbacks_ext* cbs = gps_cbs;
@@ -466,7 +494,12 @@
 {
     if ((signo == SIGUSR1) || (signo == SIGINT) || (signo == SIGTERM) ||((signo == SIGKILL))) {
         LOGD("catch signal:%d, stop mnld_test\n", signo);
-        mnld_test_close_gnss(mnld_test_gpsinfs);
+        //if use raw measurement, stop it
+        if(raw_flag) {
+            mnld_test_raw_meas_stop(mnld_test_gpsinfs, raw_measinfs);
+        } else {
+            mnld_test_close_gnss(mnld_test_gpsinfs);
+        }
         mnld_test_block_exit();
     }
     else if (signo == SIGPIPE || signo == SIGTTIN)
@@ -587,6 +620,10 @@
 
             LOGD("network, type:%s, on:%d, roaming:%d.\r\n",mnld_test_network_type_str[mnld_test_network_type], mnld_test_network_on, mnld_test_network_roaming);
             action = MNLD_TEST_ACTION_SET_NETWORK;
+        }else if(!strncmp(argv[1],MNLD_TEST_RAW_MEAS_START, strlen(MNLD_TEST_RAW_MEAS_START))){//raw measurement start
+            action = MNLD_TEST_ACTION_GNSS_RAW;
+            LOGD("mnld_test raw measurement start.\r\n");
+            exit_flag = 0;
         }else{
             LOGE("Unknown command!\r\n");
             mnld_test_show_help();
@@ -605,6 +642,10 @@
         mnld_test_gpsinfs = (GpsInterface_ext*)gpsdev->get_gps_interface(gpsdev);
 
         mnld_test_cbs = mnld_test__get_gps_callbacks();//&mnld_test_gps_callbacks;
+
+        raw_measinfs = (GpsMeasurementInterface_ext*)mnld_test_gpsinfs->get_extension("gps_measurement");
+        raw_cbs = mnld_test_get_raw_callbacks();
+
         switch(action)
         {
             case MNLD_TEST_ACTION_GNSS_OPEN: {
@@ -635,6 +676,13 @@
                 exit_flag = 1;
                 break;
             }
+            case MNLD_TEST_ACTION_GNSS_RAW: {
+                mnld_test_raw_meas_start(mnld_test_gpsinfs, mnld_test_cbs, raw_measinfs, raw_cbs);
+                exit_flag = 1;
+                raw_flag = 1;
+                mnld_test_block_here();
+                break;
+            }
             default: {
                 LOGW("Unknown action(%d)\r\n",action);
                 mnld_test_show_help();
diff --git a/src/connectivity/gps/2.0/gnss_test/mnld_client/src/mnld_client_gps_cb.c b/src/connectivity/gps/2.0/gnss_test/mnld_client/src/mnld_client_gps_cb.c
old mode 100644
new mode 100755
index 6cb021d..0b8a52a
--- a/src/connectivity/gps/2.0/gnss_test/mnld_client/src/mnld_client_gps_cb.c
+++ b/src/connectivity/gps/2.0/gnss_test/mnld_client/src/mnld_client_gps_cb.c
@@ -3,6 +3,7 @@
 #include<unistd.h>
 #include<errno.h>
 #include<string.h>
+#include<inttypes.h>
 
 #include"mnld_test.h"
 #include"mtk_lbs_utility.h"
@@ -254,3 +255,92 @@
 {
     return &mnld_test_gps_callbacks;
 }
+
+void mnld_test_gnss_measurement_callback(GnssData_ext* data) {
+    int i;
+    int meas_cnt;
+    GnssMeasurement_ext* raw_meas;
+    GnssClock_ext* clk;
+    ElapsedRealtime* elap_realtime;
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#define LOG_TAG "raw_meas"
+#endif
+
+    if (data == NULL) {
+        LOGE("param error");
+        return;
+    }
+
+    meas_cnt = data->measurement_count;
+    LOGD("==================== print_gnss_measurement ====================");
+    LOGD("measurement count is: %d", meas_cnt);
+    for (i = 0; i < meas_cnt; i++) {
+        raw_meas = &(data->measurements[i]);
+        LOGD("********* measurement message %d *********", i+1);
+        LOGD("flags=0x%x", raw_meas->legacyMeasurement.flags);
+        LOGD("svid=%d", raw_meas->legacyMeasurement.svid);
+        LOGD("constellation=0x%x", raw_meas->legacyMeasurement.constellation);
+        LOGD("time_offset_ns=%f", raw_meas->legacyMeasurement.time_offset_ns);
+        LOGD("state=0x%x", raw_meas->legacyMeasurement.state);
+        LOGD("received_gps_tow_ns=%"PRId64, raw_meas->legacyMeasurement.received_sv_time_in_ns);
+        LOGD("received_gps_tow_uncertainty_ns=%"PRId64, raw_meas->legacyMeasurement.received_sv_time_uncertainty_in_ns);
+        LOGD("c_n0_dbhz=%f", raw_meas->legacyMeasurement.c_n0_dbhz);
+        LOGD("pseudorange_rate_mps=%f", raw_meas->legacyMeasurement.pseudorange_rate_mps);
+        LOGD("pseudorange_rate_uncertainty_mps=%f", raw_meas->legacyMeasurement.pseudorange_rate_uncertainty_mps);
+        LOGD("accumulated_delta_range_state=0x%x", raw_meas->legacyMeasurement.accumulated_delta_range_state);
+        LOGD("accumulated_delta_range_m=%f", raw_meas->legacyMeasurement.accumulated_delta_range_m);
+        LOGD("accumulated_delta_range_uncertainty_m=%f", raw_meas->legacyMeasurement.accumulated_delta_range_uncertainty_m);
+        LOGD("carrier_frequency_hz=%f", raw_meas->legacyMeasurement.carrier_frequency_hz);
+        LOGD("carrier_cycles=%"PRId64, raw_meas->legacyMeasurement.carrier_cycles);
+        LOGD("carrier_phase=%f", raw_meas->legacyMeasurement.carrier_phase);
+        LOGD("carrier_phase_uncertainty=%f", raw_meas->legacyMeasurement.carrier_phase_uncertainty);
+        LOGD("multipath_indicator=%d", raw_meas->legacyMeasurement.multipath_indicator);
+        LOGD("snr_db=%f", raw_meas->legacyMeasurement.snr_db);
+
+        LOGD("agc_level_db=%f", raw_meas->agc_level_db);
+        LOGD("codeType=%s", raw_meas->codeType);
+        LOGD("fullInterSignalBiasNs=%f", raw_meas->fullInterSignalBiasNs);
+        LOGD("fullInterSignalBiasUncertaintyNs=%f", raw_meas->fullInterSignalBiasUncertaintyNs);
+        LOGD("satelliteInterSignalBiasNs=%f", raw_meas->satelliteInterSignalBiasNs);
+        LOGD("satelliteInterSignalBiasUncertaintyNs=%f", raw_meas->satelliteInterSignalBiasUncertaintyNs);
+        LOGD("basebandCN0DbHz=%f", raw_meas->basebandCN0DbHz);
+    }
+
+    clk = &(data->clock);
+    LOGD("======================= print_gnss_clock =======================");
+    LOGD("flags=0x%x", clk->legacyClock.flags);
+    LOGD("leap_second=%d", clk->legacyClock.leap_second);
+    LOGD("time_ns=%"PRId64, clk->legacyClock.time_ns);
+    LOGD("time_uncertainty_ns=%f", clk->legacyClock.time_uncertainty_ns);
+    LOGD("full_bias_ns=%"PRId64, clk->legacyClock.full_bias_ns);
+    LOGD("bias_ns=%f", clk->legacyClock.bias_ns);
+    LOGD("bias_uncertainty_ns=%f", clk->legacyClock.bias_uncertainty_ns);
+    LOGD("drift_nsps=%f", clk->legacyClock.drift_nsps);
+    LOGD("drift_uncertainty_nsps=%f", clk->legacyClock.drift_uncertainty_nsps);
+    LOGD("hw_clock_discontinuity_count=%d", clk->legacyClock.hw_clock_discontinuity_count);
+    LOGD("constellation=%d", clk->referenceSignalTypeForIsb.constellation);
+    LOGD("carrierFrequencyHz=%f", clk->referenceSignalTypeForIsb.carrierFrequencyHz);
+    LOGD("codeType=%s", clk->referenceSignalTypeForIsb.codeType);
+
+    elap_realtime = &(data->elapsedRealtime);
+    LOGD("================= print_gnss_elapsed_real_time =================");
+    LOGD("flags=0x%x", elap_realtime->flags);
+    LOGD("timestampNs=%"PRId64, elap_realtime->timestampNs);
+    LOGD("timeUncertaintyNs=%"PRId64, elap_realtime->timeUncertaintyNs);
+
+    return;
+}
+
+GpsMeasurementCallbacks_ext mnld_test_raw_callbacks = {
+    .size = sizeof(GpsMeasurementCallbacks_ext),
+    .measurement_callback = NULL,
+    .gnss_measurement_callback = mnld_test_gnss_measurement_callback,
+};
+
+GpsMeasurementCallbacks_ext* mnld_test_get_raw_callbacks(void) {
+    return &mnld_test_raw_callbacks;
+}
+
+
diff --git a/src/connectivity/gps/2.0/gps_hal/inc/hardware/gps.h b/src/connectivity/gps/2.0/gps_hal/inc/hardware/gps.h
old mode 100644
new mode 100755
index ac749c1..693dd88
--- a/src/connectivity/gps/2.0/gps_hal/inc/hardware/gps.h
+++ b/src/connectivity/gps/2.0/gps_hal/inc/hardware/gps.h
@@ -333,6 +333,22 @@
 typedef uint32_t GnssMeasurementFlags;
 /** A valid 'snr' is stored in the data structure. */
 #define GNSS_MEASUREMENT_HAS_SNR                               (1<<0)
+/** A valid 'elevation' is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_ELEVATION                         (1<<1)
+/** A valid 'elevation uncertainty' is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY             (1<<2)
+/** A valid 'azimuth' is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_AZIMUTH                           (1<<3)
+/** A valid 'azimuth uncertainty' is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY               (1<<4)
+/** A valid 'pseudorange' is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_PSEUDORANGE                       (1<<5)
+/** A valid 'pseudorange uncertainty' is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY           (1<<6)
+/** A valid 'code phase' is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_CODE_PHASE                        (1<<7)
+/** A valid 'code phase uncertainty' is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY            (1<<8)
 /** A valid 'carrier frequency' is stored in the data structure. */
 #define GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY                 (1<<9)
 /** A valid 'carrier cycles' is stored in the data structure. */
@@ -341,6 +357,20 @@
 #define GNSS_MEASUREMENT_HAS_CARRIER_PHASE                     (1<<11)
 /** A valid 'carrier phase uncertainty' is stored in the data structure. */
 #define GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY         (1<<12)
+/** A valid automatic gain control is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_AUTOMATIC_GAIN_CONTROL            (1<<13)
+/** A valid 'time from last bit' is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT                (1<<14)
+/** A valid 'doppler shift' is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT                     (1<<15)
+/** A valid full inter-signal bias is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_HAS_FULL_ISB                      (1<<16)
+/** A valid full inter-signal bias uncertainty is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_HAS_FULL_ISB_UNCERTAINTY          (1<<17)
+/** A valid satellite inter-signal bias is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_HAS_SATELLITE_ISB                 (1<<18)
+/** A valid satellite inter-signal bias uncertainty is stored in the data structure. */
+#define GNSS_MEASUREMENT_HAS_HAS_SATELLITE_ISB_UNCERTAINTY     (1<<19)
 
 /* The following typedef together with its constants below are deprecated, and
  * will be removed in the next release. */
@@ -409,6 +439,9 @@
 #define GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK (1<<11)
 #define GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC     (1<<12)
 #define GNSS_MEASUREMENT_STATE_SBAS_SYNC             (1<<13)
+#define GNSS_MEASUREMENT_STATE_STATE_TOW_KNOWN       (1<<14)
+#define GNSS_MEASUREMENT_STATE_STATE_TOD_KNOWN       (1<<15)
+
 
 /* The following typedef together with its constants below are deprecated, and
  * will be removed in the next release. */
@@ -426,6 +459,9 @@
 #define GNSS_ADR_STATE_VALID                     (1<<0)
 #define GNSS_ADR_STATE_RESET                     (1<<1)
 #define GNSS_ADR_STATE_CYCLE_SLIP                (1<<2)
+#define GNSS_ADR_STATE_HALF_RESOLVED             (1<<3)
+#define GNSS_ADR_STATE_HALF_REPORTED             (1<<4)
+
 
 /* The following typedef together with its constants below are deprecated, and
  * will be removed in the next release. */
diff --git a/src/connectivity/gps/2.0/gps_hal/src/hal2mnl_interface.c b/src/connectivity/gps/2.0/gps_hal/src/hal2mnl_interface.c
old mode 100644
new mode 100755
index d808d55..003260e
--- a/src/connectivity/gps/2.0/gps_hal/src/hal2mnl_interface.c
+++ b/src/connectivity/gps/2.0/gps_hal/src/hal2mnl_interface.c
@@ -119,7 +119,7 @@
 int hal2mnl_set_gps_measurement(bool enabled, bool enableFullTracking) {
     int ret1 = 0, ret2 = 0;
 
-    ret1 = mnldinf_basic_gnss_measurement_enable(g_gpshal_ctx.fd_mnl2hal_ext, enabled);
+    ret1 = mnldinf_basic_gnss_measurement_enable(g_gpshal_ctx.fd_mnl2hal_basic, enabled);
     ret2 = mnldinf_ext_gnss_full_tracking_enable(g_gpshal_ctx.fd_mnl2hal_ext, enableFullTracking);
     if(ret1 < 0 || ret2 < 0) {
         return -1;
diff --git a/src/connectivity/gps/2.0/mtk_mnld/mnl/libs/aarch64/libmnl_gnss.so b/src/connectivity/gps/2.0/mtk_mnld/mnl/libs/aarch64/libmnl_gnss.so
old mode 100644
new mode 100755
index cf56661..93c51df
--- a/src/connectivity/gps/2.0/mtk_mnld/mnl/libs/aarch64/libmnl_gnss.so
+++ b/src/connectivity/gps/2.0/mtk_mnld/mnl/libs/aarch64/libmnl_gnss.so
Binary files differ
diff --git a/src/connectivity/gps/2.0/mtk_mnld/mnld_entity/src/mnl2hal_interface.c b/src/connectivity/gps/2.0/mtk_mnld/mnld_entity/src/mnl2hal_interface.c
old mode 100644
new mode 100755
index 5c2ab6d..8fa283f
--- a/src/connectivity/gps/2.0/mtk_mnld/mnld_entity/src/mnl2hal_interface.c
+++ b/src/connectivity/gps/2.0/mtk_mnld/mnld_entity/src/mnl2hal_interface.c
@@ -225,7 +225,7 @@
     put_int(buff, &offset, HAL_MNL_INTERFACE_VERSION);
 
     put_int(buff, &offset, MNL2HAL_GNSS_MEASUREMENTS);
-    put_binary(buff, &offset, (const char*)&data, sizeof(data));
+    put_binary(buff, &offset, (const char*)data, sizeof(gnss_data));
 
     return mnl2hal_basic( buff, offset);
 }
@@ -513,7 +513,6 @@
         ver = get_int(buff, &offset, sizeof(buff));
         UNUSED(ver);
         cmd = get_int(buff, &offset, sizeof(buff));
-
         switch (cmd) {
 
         case HAL2MNL_GPS_INIT: {
diff --git a/src/connectivity/gps/2.0/mtk_mnld/mnld_entity/src/mnld.c b/src/connectivity/gps/2.0/mtk_mnld/mnld_entity/src/mnld.c
index ded6721..d5cd3b1 100755
--- a/src/connectivity/gps/2.0/mtk_mnld/mnld_entity/src/mnld.c
+++ b/src/connectivity/gps/2.0/mtk_mnld/mnld_entity/src/mnld.c
@@ -3215,6 +3215,11 @@
                 if(events[i].events & EPOLLIN) {
                     hal2mnl_ext_client_hdlr(events[i].data.fd, &g_hal2mnl_ext_interface);
                 }
+            } else if (events[i].data.fd == fd_suspend_timer) {
+                if (events[i].events & EPOLLIN) {
+                    LOGD_ENG("suspend_timeout_event_hdlr");
+                    mnld_gps_suspend_timeout_callback();
+                }
             } else {
                 LOGE("mnld_main_thread() unknown fd=%d",
                     events[i].data.fd);
diff --git a/src/connectivity/gps/2.0/mtk_mnld/utility/src/mtk_lbs_utility.c b/src/connectivity/gps/2.0/mtk_mnld/utility/src/mtk_lbs_utility.c
old mode 100644
new mode 100755
index 6490cb6..790982e
--- a/src/connectivity/gps/2.0/mtk_mnld/utility/src/mtk_lbs_utility.c
+++ b/src/connectivity/gps/2.0/mtk_mnld/utility/src/mtk_lbs_utility.c
@@ -1169,7 +1169,7 @@
     int ret = -1;
 
     for(i = 0; i < g_hal_basic_client_list.num; i++) {
-        if(g_hal_basic_client_list.clients[i].gnss_started) {
+        if(g_hal_basic_client_list.clients[i].gnss_started || g_hal_basic_client_list.clients[i].meas_started) {
             int fd = g_hal_basic_client_list.clients[i].fd;
             ret = socket_tcp_send(fd, buff, len);
         }
diff --git a/src/devtools/adb/MODULE_LICENSE_APACHE2 b/src/devtools/adb/MODULE_LICENSE_APACHE2
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/src/devtools/adb/MODULE_LICENSE_APACHE2
diff --git a/src/devtools/adb/Makefile b/src/devtools/adb/Makefile
new file mode 100755
index 0000000..cf6beac
--- /dev/null
+++ b/src/devtools/adb/Makefile
@@ -0,0 +1,86 @@
+ifeq ($(OPENWRT_BUILD_ADBD),)
+export STAGING_DIR=../../openwrt/staging_dir
+else
+export STAGING_DIR=$(TOPDIR)/staging_dir
+endif
+ifeq ($(ADB_OVER_PCIE),)
+ADB_OVER_PCIE=0
+endif
+
+COMMON_SRC_FILES := \
+	adb.c \
+	fdevent.c \
+	transport.c \
+	transport_local.c \
+	sockets.c \
+	services.c
+ifeq ($(ADB_OVER_PCIE),1)
+	COMMON_SRC_FILES+= transport_pcie.c
+else
+	COMMON_SRC_FILES+= transport_usb.c
+endif
+
+# adbd device daemon
+# =========================================================
+
+ADBD_SRC_FILES := \
+	file_sync_service.c \
+	adb_auth_client.c \
+	jdwp_service.c \
+	framebuffer_service.c \
+	remount_service.c
+ifneq ($(ADB_OVER_PCIE),1)
+	ADBD_SRC_FILES+= usb_linux_client.c
+endif
+
+LOCAL_SRC_FILES += \
+	properties.c \
+	load_file.c \
+	socket_inaddr_any_server.c \
+	socket_local_client.c \
+	socket_local_server.c \
+	socket_loopback_client.c \
+	socket_loopback_server.c \
+	socket_network_client.c \
+	sha.c \
+	rsa.c \
+	sha256.c \
+	logd_write.c \
+	thread_utils.c \
+	b64_pton.c
+
+LOCAL_CFLAGS := \
+	-O2 \
+	-g \
+	-D_XOPEN_SOURCE \
+	-D_GNU_SOURCE \
+	-Wall -Wno-unused-parameter -Wno-deprecated-declarations \
+	-DADB_NON_ANDROID=1 \
+	-DALLOW_ADBD_ROOT=1 \
+	-DHAVE_PTHREADS \
+	-DDEBUG_PACKETS=1
+
+ifeq ($(ADB_OVER_PCIE),1)
+	LOCAL_CFLAGS+= -DADB_OVER_PCIE=1
+endif
+
+CPPFLAGS+= -DDZONE -DHAVE_FORKEXEC=1 -DHAVE_SYMLINKS -DHAVE_TERMIO_H
+CPPFLAGS+= -D_GNU_SOURCE -D_XOPEN_SOURCE
+CPPFLAGS+= -I. -I./include
+CPPFLAGS+= $(LOCAL_CFLAGS)
+
+LIBS += -lpthread -luci
+
+LOCAL_MODULE := adbd
+LOCAL_SRC_FILES+= $(COMMON_SRC_FILES) $(ADBD_SRC_FILES)
+CPPFLAGS+= -DADB_HOST=0
+
+OBJS=$(LOCAL_SRC_FILES:.c=.o)
+
+all: $(LOCAL_MODULE)
+
+$(LOCAL_MODULE): $(OBJS)
+	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
+
+clean:
+	rm -rf $(OBJS) $(LOCAL_MODULE)
diff --git a/src/devtools/adb/NOTICE b/src/devtools/adb/NOTICE
new file mode 100755
index 0000000..f46a084
--- /dev/null
+++ b/src/devtools/adb/NOTICE
@@ -0,0 +1,202 @@
+Copyright (C) 2005-2014 The Android Open Source Project
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+
+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/devtools/adb/OVERVIEW.TXT b/src/devtools/adb/OVERVIEW.TXT
new file mode 100755
index 0000000..c40695a
--- /dev/null
+++ b/src/devtools/adb/OVERVIEW.TXT
@@ -0,0 +1,139 @@
+Implementation notes regarding ADB.
+
+I. General Overview:
+
+The Android Debug Bridge (ADB) is used to:
+
+- keep track of all Android devices and emulators instances
+  connected to or running on a given host developer machine
+
+- implement various control commands (e.g. "adb shell", "adb pull", etc..)
+  for the benefit of clients (command-line users, or helper programs like
+  DDMS). These commands are what is called a 'service' in ADB.
+
+As a whole, everything works through the following components:
+
+  1. The ADB server
+
+    This is a background process that runs on the host machine. Its purpose
+    if to sense the USB ports to know when devices are attached/removed,
+    as well as when emulator instances start/stop.
+
+    It thus maintains a list of "connected devices" and assigns a 'state'
+    to each one of them: OFFLINE, BOOTLOADER, RECOVERY or ONLINE (more on
+    this below).
+
+    The ADB server is really one giant multiplexing loop whose purpose is
+    to orchestrate the exchange of data (packets, really) between clients,
+    services and devices.
+
+
+  2. The ADB daemon (adbd)
+
+    The 'adbd' program runs as a background process within an Android device
+    or emulated system. Its purpose is to connect to the ADB server
+    (through USB for devices, through TCP for emulators) and provide a
+    few services for clients that run on the host.
+
+    The ADB server considers that a device is ONLINE when it has successfully
+    connected to the adbd program within it. Otherwise, the device is OFFLINE,
+    meaning that the ADB server detected a new device/emulator, but could not
+    connect to the adbd daemon.
+
+    the BOOTLOADER and RECOVERY states correspond to alternate states of
+    devices when they are in the bootloader or recovery mode.
+
+  3. The ADB command-line client
+
+    The 'adb' command-line program is used to run adb commands from a shell
+    or a script. It first tries to locate the ADB server on the host machine,
+    and will start one automatically if none is found.
+
+    then, the client sends its service requests to the ADB server. It doesn't
+    need to know.
+
+    Currently, a single 'adb' binary is used for both the server and client.
+    this makes distribution and starting the server easier.
+
+
+  4. Services
+
+    There are essentially two kinds of services that a client can talk to.
+
+    Host Services:
+      these services run within the ADB Server and thus do not need to
+      communicate with a device at all. A typical example is "adb devices"
+      which is used to return the list of currently known devices and their
+      state. They are a few couple other services though.
+
+    Local Services:
+      these services either run within the adbd daemon, or are started by
+      it on the device. The ADB server is used to multiplex streams
+      between the client and the service running in adbd. In this case
+      its role is to initiate the connection, then of being a pass-through
+      for the data.
+
+
+II. Protocol details:
+
+  1. Client <-> Server protocol:
+
+    This details the protocol used between ADB clients and the ADB
+    server itself. The ADB server listens on TCP:localhost:5037.
+
+    A client sends a request using the following format:
+
+        1. A 4-byte hexadecimal string giving the length of the payload
+        2. Followed by the payload itself.
+
+    For example, to query the ADB server for its internal version number,
+    the client will do the following:
+
+        1. Connect to tcp:localhost:5037
+        2. Send the string "000Chost:version" to the corresponding socket
+
+    The 'host:' prefix is used to indicate that the request is addressed
+    to the server itself (we will talk about other kinds of requests later).
+    The content length is encoded in ASCII for easier debugging.
+
+    The server should answer a request with one of the following:
+
+        1. For success, the 4-byte "OKAY" string
+
+        2. For failure, the 4-byte "FAIL" string, followed by a
+           4-byte hex length, followed by a string giving the reason
+           for failure.
+
+        3. As a special exception, for 'host:version', a 4-byte
+           hex string corresponding to the server's internal version number
+
+    Note that the connection is still alive after an OKAY, which allows the
+    client to make other requests. But in certain cases, an OKAY will even
+    change the state of the connection. 
+
+    For example, the case of the 'host:transport:<serialnumber>' request,
+    where '<serialnumber>' is used to identify a given device/emulator; after
+    the "OKAY" answer, all further requests made by the client will go
+    directly to the corresponding adbd daemon.
+
+    The file SERVICES.TXT lists all services currently implemented by ADB.
+
+
+  2. Transports:
+
+    An ADB transport models a connection between the ADB server and one device
+    or emulator. There are currently two kinds of transports:
+
+       - USB transports, for physical devices through USB
+
+       - Local transports, for emulators running on the host, connected to
+         the server through TCP
+
+    In theory, it should be possible to write a local transport that proxies
+    a connection between an ADB server and a device/emulator connected to/
+    running on another machine. This hasn't been done yet though.
+
+    Each transport can carry one or more multiplexed streams between clients
+    and the device/emulator they point to. The ADB server must handle
+    unexpected transport disconnections (e.g. when a device is physically
+    unplugged) properly.
diff --git a/src/devtools/adb/SERVICES.TXT b/src/devtools/adb/SERVICES.TXT
new file mode 100755
index 0000000..63000f2
--- /dev/null
+++ b/src/devtools/adb/SERVICES.TXT
@@ -0,0 +1,259 @@
+This file tries to document all requests a client can make
+to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
+to understand what's going on here.
+
+HOST SERVICES:
+
+host:version
+    Ask the ADB server for its internal version number.
+
+    As a special exception, the server will respond with a 4-byte
+    hex string corresponding to its internal version number, without
+    any OKAY or FAIL.
+
+host:kill
+    Ask the ADB server to quit immediately. This is used when the
+    ADB client detects that an obsolete server is running after an
+    upgrade.
+
+host:devices
+host:devices-l
+    Ask to return the list of available Android devices and their
+    state. devices-l includes the device paths in the state.
+    After the OKAY, this is followed by a 4-byte hex len,
+    and a string that will be dumped as-is by the client, then
+    the connection is closed
+
+host:track-devices
+    This is a variant of host:devices which doesn't close the
+    connection. Instead, a new device list description is sent
+    each time a device is added/removed or the state of a given
+    device changes (hex4 + content). This allows tools like DDMS
+    to track the state of connected devices in real-time without
+    polling the server repeatedly.
+
+host:emulator:<port>
+    This is a special query that is sent to the ADB server when a
+    new emulator starts up. <port> is a decimal number corresponding
+    to the emulator's ADB control port, i.e. the TCP port that the
+    emulator will forward automatically to the adbd daemon running
+    in the emulator system.
+
+    This mechanism allows the ADB server to know when new emulator
+    instances start.
+
+host:transport:<serial-number>
+    Ask to switch the connection to the device/emulator identified by
+    <serial-number>. After the OKAY response, every client request will
+    be sent directly to the adbd daemon running on the device.
+    (Used to implement the -s option)
+
+host:transport-usb
+    Ask to switch the connection to one device connected through USB
+    to the host machine. This will fail if there are more than one such
+    devices. (Used to implement the -d convenience option)
+
+host:transport-local
+    Ask to switch the connection to one emulator connected through TCP.
+    This will fail if there is more than one such emulator instance
+    running. (Used to implement the -e convenience option)
+
+host:transport-any
+    Another host:transport variant. Ask to switch the connection to
+    either the device or emulator connect to/running on the host.
+    Will fail if there is more than one such device/emulator available.
+    (Used when neither -s, -d or -e are provided)
+
+host-serial:<serial-number>:<request>
+    This is a special form of query, where the 'host-serial:<serial-number>:'
+    prefix can be used to indicate that the client is asking the ADB server
+    for information related to a specific device. <request> can be in one
+    of the format described below.
+
+host-usb:<request>
+    A variant of host-serial used to target the single USB device connected
+    to the host. This will fail if there is none or more than one.
+
+host-local:<request>
+    A variant of host-serial used to target the single emulator instance
+    running on the host. This will fail if there is none or more than one.
+
+host:<request>
+    When asking for information related to a device, 'host:' can also be
+    interpreted as 'any single device or emulator connected to/running on
+    the host'.
+
+<host-prefix>:get-product
+    XXX
+
+<host-prefix>:get-serialno
+    Returns the serial number of the corresponding device/emulator.
+    Note that emulator serial numbers are of the form "emulator-5554"
+
+<host-prefix>:get-devpath
+    Returns the device path of the corresponding device/emulator.
+
+<host-prefix>:get-state
+    Returns the state of a given device as a string.
+
+<host-prefix>:forward:<local>;<remote>
+    Asks the ADB server to forward local connections from <local>
+    to the <remote> address on a given device.
+
+    There, <host-prefix> can be one of the
+    host-serial/host-usb/host-local/host prefixes as described previously
+    and indicates which device/emulator to target.
+
+    the format of <local> is one of:
+
+        tcp:<port>      -> TCP connection on localhost:<port>
+        local:<path>    -> Unix local domain socket on <path>
+
+    the format of <remote> is one of:
+
+        tcp:<port>      -> TCP localhost:<port> on device
+        local:<path>    -> Unix local domain socket on device
+        jdwp:<pid>      -> JDWP thread on VM process <pid>
+
+    or even any one of the local services described below.
+
+<host-prefix>:forward:norebind:<local>;<remote>
+    Same as <host-prefix>:forward:<local>;<remote> except that it will
+    fail it there is already a forward connection from <local>.
+
+    Used to implement 'adb forward --no-rebind <local> <remote>'
+
+<host-prefix>:killforward:<local>
+    Remove any existing forward local connection from <local>.
+    This is used to implement 'adb forward --remove <local>'
+
+<host-prefix>:killforward-all
+    Remove all forward network connections.
+    This is used to implement 'adb forward --remove-all'.
+
+<host-prefix>:list-forward
+    List all existing forward connections from this server.
+    This returns something that looks like the following:
+
+       <hex4>: The length of the payload, as 4 hexadecimal chars.
+       <payload>: A series of lines of the following format:
+
+         <serial> " " <local> " " <remote> "\n"
+
+    Where <serial> is a device serial number.
+          <local>  is the host-specific endpoint (e.g. tcp:9000).
+          <remote> is the device-specific endpoint.
+
+    Used to implement 'adb forward --list'.
+
+LOCAL SERVICES:
+
+All the queries below assumed that you already switched the transport
+to a real device, or that you have used a query prefix as described
+above.
+
+shell:command arg1 arg2 ...
+    Run 'command arg1 arg2 ...' in a shell on the device, and return
+    its output and error streams. Note that arguments must be separated
+    by spaces. If an argument contains a space, it must be quoted with
+    double-quotes. Arguments cannot contain double quotes or things
+    will go very wrong.
+
+    Note that this is the non-interactive version of "adb shell"
+
+shell:
+    Start an interactive shell session on the device. Redirect
+    stdin/stdout/stderr as appropriate. Note that the ADB server uses
+    this to implement "adb shell", but will also cook the input before
+    sending it to the device (see interactive_shell() in commandline.c)
+
+remount:
+    Ask adbd to remount the device's filesystem in read-write mode,
+    instead of read-only. This is usually necessary before performing
+    an "adb sync" or "adb push" request.
+
+    This request may not succeed on certain builds which do not allow
+    that.
+
+dev:<path>
+    Opens a device file and connects the client directly to it for
+    read/write purposes. Useful for debugging, but may require special
+    privileges and thus may not run on all devices. <path> is a full
+    path from the root of the filesystem.
+
+tcp:<port>
+    Tries to connect to tcp port <port> on localhost.
+
+tcp:<port>:<server-name>
+    Tries to connect to tcp port <port> on machine <server-name> from
+    the device. This can be useful to debug some networking/proxy
+    issues that can only be revealed on the device itself.
+
+local:<path>
+    Tries to connect to a Unix domain socket <path> on the device
+
+localreserved:<path>
+localabstract:<path>
+localfilesystem:<path>
+    Variants of local:<path> that are used to access other Android
+    socket namespaces.
+
+framebuffer:
+    This service is used to send snapshots of the framebuffer to a client.
+    It requires sufficient privileges but works as follow:
+
+      After the OKAY, the service sends 16-byte binary structure
+      containing the following fields (little-endian format):
+
+            depth:   uint32_t:    framebuffer depth
+            size:    uint32_t:    framebuffer size in bytes
+            width:   uint32_t:    framebuffer width in pixels
+            height:  uint32_t:    framebuffer height in pixels
+
+      With the current implementation, depth is always 16, and
+      size is always width*height*2
+
+      Then, each time the client wants a snapshot, it should send
+      one byte through the channel, which will trigger the service
+      to send it 'size' bytes of framebuffer data.
+
+      If the adbd daemon doesn't have sufficient privileges to open
+      the framebuffer device, the connection is simply closed immediately.
+
+jdwp:<pid>
+    Connects to the JDWP thread running in the VM of process <pid>.
+
+track-jdwp
+    This is used to send the list of JDWP pids periodically to the client.
+    The format of the returned data is the following:
+
+        <hex4>:    the length of all content as a 4-char hexadecimal string
+        <content>: a series of ASCII lines of the following format:
+                        <pid> "\n"
+
+    This service is used by DDMS to know which debuggable processes are running
+    on the device/emulator.
+
+    Note that there is no single-shot service to retrieve the list only once.
+
+sync:
+    This starts the file synchronisation service, used to implement "adb push"
+    and "adb pull". Since this service is pretty complex, it will be detailed
+    in a companion document named SYNC.TXT
+
+reverse:<forward-command>
+    This implements the 'adb reverse' feature, i.e. the ability to reverse
+    socket connections from a device to the host. <forward-command> is one
+    of the forwarding commands that are described above, as in:
+
+      list-forward
+      forward:<local>;<remote>
+      forward:norebind:<local>;<remote>
+      killforward-all
+      killforward:<local>
+
+    Note that in this case, <local> corresponds to the socket on the device
+    and <remote> corresponds to the socket on the host.
+
+    The output of reverse:list-forward is the same as host:list-forward
+    except that <serial> will be just 'host'.
diff --git a/src/devtools/adb/SYNC.TXT b/src/devtools/adb/SYNC.TXT
new file mode 100755
index 0000000..e74d217
--- /dev/null
+++ b/src/devtools/adb/SYNC.TXT
@@ -0,0 +1,84 @@
+This file tries to document file related requests a client can make
+to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
+to understand what's going on here. See the SERVICES.TXT to learn more
+about the other requests that are possible.
+
+SYNC SERVICES:
+
+
+Requesting the sync service ("sync:") using the protocol as described in
+SERVICES.TXT sets the connection in sync mode. This mode is a binary mode that
+differ from the regular adb protocol. The connection stays in sync mode until
+explicitly terminated (see below).
+
+After the initial "sync:" command is sent the server must respond with either
+"OKAY" or "FAIL" as per usual. 
+
+In sync mode both the server and the client will frequently use eight-byte
+packets to communicate in this document called sync request and sync
+responses. The first four bytes is an id and specifies sync request is
+represented by four utf-8 characters. The last four bytes is a Little-Endian
+integer, with various uses. This number will be called "length" below. In fact
+all binary integers are Little-Endian in the sync mode. Sync mode is
+implicitly exited after each sync request, and normal adb communication
+follows as described in SERVICES.TXT.
+
+The following sync requests are accepted:
+LIST - List the files in a folder
+SEND - Send a file to device
+RECV - Retreive a file from device
+
+Not yet documented:
+STAT - Stat a file
+ULNK - Unlink (remove) a file. (Not currently supported)
+
+For all of the sync request above the must be followed by length number of
+bytes containing an utf-8 string with a remote filename.
+
+LIST:
+Lists files in the directory specified by the remote filename. The server will
+respond with zero or more directory entries or "dents".
+
+The directory entries will be returned in the following form
+1. A four-byte sync response id beeing "DENT"
+2. A four-byte integer representing file mode.
+3. A four-byte integer representing file size.
+4. A four-byte integer representing last modified time.
+5. A four-byte integer representing file name length.
+6. length number of bytes containing an utf-8 string representing the file
+   name.
+
+When an sync response "DONE" is received the listing is done.
+
+SEND:
+The remote file name is split into two parts separated by the last
+comma (","). The first part is the actual path, while the second is a decimal
+encoded file mode containing the permissions of the file on device.
+
+Note that some file types will be deleted before the copying starts, and if
+the transfer fails. Some file types will not be deleted, which allows
+  adb push disk_image /some_block_device
+to work.
+
+After this the actual file is sent in chunks. Each chucks has the following
+format.
+A sync request with id "DATA" and length equal to the chunk size. After
+follows chunk size number of bytes. This is repeated until the file is
+transfered. Each chunk must not be larger than 64k.
+
+When the file is tranfered a sync request "DONE" is sent, where length is set
+to the last modified time for the file. The server responds to this last
+request (but not to chuck requests) with an "OKAY" sync response (length can
+be ignored).
+
+
+RECV:
+Retrieves a file from device to a local file. The remote path is the path to
+the file that will be returned. Just as for the SEND sync request the file
+received is split up into chunks. The sync response id is "DATA" and length is
+the chuck size. After follows chunk size number of bytes. This is repeated
+until the file is transfered. Each chuck will not be larger than 64k.
+
+When the file is transfered a sync resopnse "DONE" is retrieved where the
+length can be ignored.
+
diff --git a/src/devtools/adb/adb.c b/src/devtools/adb/adb.c
new file mode 100755
index 0000000..82efb12
--- /dev/null
+++ b/src/devtools/adb/adb.c
@@ -0,0 +1,1814 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define  TRACE_TAG   TRACE_ADB
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <grp.h> //For setgroups
+
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_auth.h"
+#include "transport_pcie.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#if !ADB_HOST
+#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
+//#include <sys/capability.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <getopt.h>
+//#include <selinux/selinux.h>
+#endif
+
+#if ADB_TRACE
+ADB_MUTEX_DEFINE( D_lock );
+#endif
+
+int HOST = 0;
+int gListenAll = 0;
+
+static int auth_enabled = 0;
+
+#if !ADB_HOST
+static const char *adb_device_banner = "device";
+static const char *root_seclabel = NULL;
+#endif
+
+void fatal(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stderr, "error: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+    exit(-1);
+}
+
+void fatal_errno(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stderr, "error: %s: ", strerror(errno));
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+    exit(-1);
+}
+
+int   adb_trace_mask;
+
+/* read a comma/space/colum/semi-column separated list of tags
+ * from the ADB_TRACE environment variable and build the trace
+ * mask from it. note that '1' and 'all' are special cases to
+ * enable all tracing
+ */
+void  adb_trace_init(void)
+{
+    const char*  p = getenv("ADB_TRACE");
+    const char*  q;
+
+    static const struct {
+        const char*  tag;
+        int           flag;
+    } tags[] = {
+        { "1", 0 },
+        { "all", 0 },
+        { "adb", TRACE_ADB },
+        { "sockets", TRACE_SOCKETS },
+        { "packets", TRACE_PACKETS },
+        { "rwx", TRACE_RWX },
+        { "usb", TRACE_USB },
+        { "sync", TRACE_SYNC },
+        { "sysdeps", TRACE_SYSDEPS },
+        { "transport", TRACE_TRANSPORT },
+        { "jdwp", TRACE_JDWP },
+        { "services", TRACE_SERVICES },
+        { "auth", TRACE_AUTH },
+        { NULL, 0 }
+    };
+
+    if (p == NULL)
+            return;
+
+    /* use a comma/column/semi-colum/space separated list */
+    while (*p) {
+        int  len, tagn;
+
+        q = strpbrk(p, " ,:;");
+        if (q == NULL) {
+            q = p + strlen(p);
+        }
+        len = q - p;
+
+        for (tagn = 0; tags[tagn].tag != NULL; tagn++)
+        {
+            int  taglen = strlen(tags[tagn].tag);
+
+            if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
+            {
+                int  flag = tags[tagn].flag;
+                if (flag == 0) {
+                    adb_trace_mask = ~0;
+                    return;
+                }
+                adb_trace_mask |= (1 << flag);
+                break;
+            }
+        }
+        p = q;
+        if (*p)
+            p++;
+    }
+}
+
+#if !ADB_HOST && !ADB_NON_ANDROID
+/*
+ * Implements ADB tracing inside the emulator.
+ */
+
+#include <stdarg.h>
+
+/*
+ * Redefine open and write for qemu_pipe.h that contains inlined references
+ * to those routines. We will redifine them back after qemu_pipe.h inclusion.
+ */
+
+#undef open
+#undef write
+#define open    adb_open
+#define write   adb_write
+#include <hardware/qemu_pipe.h>
+#undef open
+#undef write
+#define open    ___xxx_open
+#define write   ___xxx_write
+
+/* A handle to adb-debug qemud service in the emulator. */
+int   adb_debug_qemu = -1;
+
+/* Initializes connection with the adb-debug qemud service in the emulator. */
+static int adb_qemu_trace_init(void)
+{
+    char con_name[32];
+
+    if (adb_debug_qemu >= 0) {
+        return 0;
+    }
+
+    /* adb debugging QEMUD service connection request. */
+    snprintf(con_name, sizeof(con_name), "qemud:adb-debug");
+    adb_debug_qemu = qemu_pipe_open(con_name);
+    return (adb_debug_qemu >= 0) ? 0 : -1;
+}
+
+void adb_qemu_trace(const char* fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+    char msg[1024];
+
+    if (adb_debug_qemu >= 0) {
+        vsnprintf(msg, sizeof(msg), fmt, args);
+        adb_write(adb_debug_qemu, msg, strlen(msg));
+    }
+}
+#endif  /* !ADB_HOST */
+
+apacket *get_apacket(void)
+{
+    apacket *p = malloc(sizeof(apacket));
+    if(p == 0) fatal("failed to allocate an apacket");
+    memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
+    return p;
+}
+
+void put_apacket(apacket *p)
+{
+    free(p);
+}
+
+void handle_online(atransport *t)
+{
+    D("adb: online\n");
+    t->online = 1;
+#if ADB_HOST && ADB_OVER_PCIE
+#endif
+}
+
+void handle_offline(atransport *t)
+{
+    D("adb: offline\n");
+    //Close the associated usb
+    t->online = 0;
+    run_transport_disconnects(t);
+}
+
+#if DEBUG_PACKETS
+#define DUMPMAX 32
+void print_packet(const char *label, apacket *p)
+{
+    char *tag;
+    char *x;
+    unsigned count;
+
+    switch(p->msg.command){
+    case A_SYNC: tag = "SYNC"; break;
+    case A_CNXN: tag = "CNXN" ; break;
+    case A_OPEN: tag = "OPEN"; break;
+    case A_OKAY: tag = "OKAY"; break;
+    case A_CLSE: tag = "CLSE"; break;
+    case A_WRTE: tag = "WRTE"; break;
+    case A_AUTH: tag = "AUTH"; break;
+    default: tag = "????"; break;
+    }
+
+    fprintf(stderr, "%s: %s %08x %08x %04x \"",
+            label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
+    count = p->msg.data_length;
+    x = (char*) p->data;
+    if(count > DUMPMAX) {
+        count = DUMPMAX;
+        tag = "\n";
+    } else {
+        tag = "\"\n";
+    }
+    while(count-- > 0){
+        if((*x >= ' ') && (*x < 127)) {
+            fputc(*x, stderr);
+        } else {
+            fputc('.', stderr);
+        }
+        x++;
+    }
+    fputs(tag, stderr);
+}
+#endif
+
+static void send_ready(unsigned local, unsigned remote, atransport *t)
+{
+    D("Calling send_ready \n");
+    apacket *p = get_apacket();
+    p->msg.command = A_OKAY;
+    p->msg.arg0 = local;
+    p->msg.arg1 = remote;
+    send_packet(p, t);
+}
+
+static void send_close(unsigned local, unsigned remote, atransport *t)
+{
+    D("Calling send_close \n");
+    apacket *p = get_apacket();
+    p->msg.command = A_CLSE;
+    p->msg.arg0 = local;
+    p->msg.arg1 = remote;
+    send_packet(p, t);
+}
+
+#if (!ADB_HOST && ADB_OVER_PCIE)
+static size_t fill_connect_data(atransport *t, char *buf, size_t bufsize)
+{
+    struct pcie_info *info;
+    size_t remaining = bufsize;
+    size_t len;
+
+    len = snprintf(buf, remaining, "%s::", adb_device_banner);
+    remaining -= len;
+    buf += len;
+
+    if (t->pcie && t->pcie->info) {
+	info = t->pcie->info;
+	D("device: 0x%x\n", info->device);
+	D("vendor: 0x%x\n", info->vendor);
+	D("class: 0x%x\n", info->class);
+
+	len = snprintf(buf, remaining, "device=%x;vendor=%x;class=%x;",
+		       info->device, info->vendor, info->class);
+	remaining -= len;
+	buf += len;
+    }
+
+    return bufsize - remaining + 1;
+}
+#else
+
+#if !ADB_HOST
+static const char *cnxn_props[] = {
+    "ro.product.name",
+    "ro.product.model",
+    "ro.product.device",
+};
+#endif
+
+static size_t fill_connect_data(char *buf, size_t bufsize)
+{
+#if ADB_HOST
+    return snprintf(buf, bufsize, "host::") + 1;
+#else
+    static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
+    int i;
+    size_t remaining = bufsize;
+    size_t len;
+
+    len = snprintf(buf, remaining, "%s::", adb_device_banner);
+    remaining -= len;
+    buf += len;
+    for (i = 0; i < num_cnxn_props; i++) {
+        char value[PROPERTY_VALUE_MAX];
+        property_get(cnxn_props[i], value, "");
+        len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value);
+        remaining -= len;
+        buf += len;
+    }
+
+    return bufsize - remaining + 1;
+#endif
+}
+#endif /* ADB_OVER_PCIE */
+
+#if !ADB_HOST
+static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
+    char header[5];
+    if (msglen > 0xffff)
+        msglen = 0xffff;
+    snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
+    writex(fd, header, 4);
+    writex(fd, msg, msglen);
+}
+#endif
+
+#if ADB_HOST
+static void send_msg_with_okay(int fd, const char* msg, size_t msglen) {
+    char header[9];
+    if (msglen > 0xffff)
+        msglen = 0xffff;
+    snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen);
+    writex(fd, header, 8);
+    writex(fd, msg, msglen);
+}
+#endif // ADB_HOST
+
+static void send_connect(atransport *t)
+{
+    D("Calling send_connect \n");
+    apacket *cp = get_apacket();
+    cp->msg.command = A_CNXN;
+    cp->msg.arg0 = A_VERSION;
+    cp->msg.arg1 = MAX_PAYLOAD;
+#if (!ADB_HOST && ADB_OVER_PCIE)
+    cp->msg.data_length = fill_connect_data(t, (char *)cp->data,
+                                            sizeof(cp->data));
+#else
+    cp->msg.data_length = fill_connect_data((char *)cp->data,
+                                            sizeof(cp->data));
+#endif
+    send_packet(cp, t);
+}
+
+void send_auth_request(atransport *t)
+{
+    D("Calling send_auth_request\n");
+    apacket *p;
+    int ret;
+
+    ret = adb_auth_generate_token(t->token, sizeof(t->token));
+    if (ret != sizeof(t->token)) {
+        D("Error generating token ret=%d\n", ret);
+        return;
+    }
+
+    p = get_apacket();
+    memcpy(p->data, t->token, ret);
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_TOKEN;
+    p->msg.data_length = ret;
+    send_packet(p, t);
+}
+
+static void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
+{
+    D("Calling send_auth_response\n");
+    apacket *p = get_apacket();
+    int ret;
+
+    ret = adb_auth_sign(t->key, token, token_size, p->data);
+    if (!ret) {
+        D("Error signing the token\n");
+        put_apacket(p);
+        return;
+    }
+
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_SIGNATURE;
+    p->msg.data_length = ret;
+    send_packet(p, t);
+}
+
+static void send_auth_publickey(atransport *t)
+{
+    D("Calling send_auth_publickey\n");
+    apacket *p = get_apacket();
+    int ret;
+
+    ret = adb_auth_get_userkey(p->data, sizeof(p->data));
+    if (!ret) {
+        D("Failed to get user public key\n");
+        put_apacket(p);
+        return;
+    }
+
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
+    p->msg.data_length = ret;
+    send_packet(p, t);
+}
+
+void adb_auth_verified(atransport *t)
+{
+    handle_online(t);
+    send_connect(t);
+}
+
+#if ADB_HOST
+static char *connection_state_name(atransport *t)
+{
+    if (t == NULL) {
+        return "unknown";
+    }
+
+    switch(t->connection_state) {
+    case CS_BOOTLOADER:
+        return "bootloader";
+    case CS_DEVICE:
+        return "device";
+    case CS_RECOVERY:
+        return "recovery";
+    case CS_SIDELOAD:
+        return "sideload";
+    case CS_OFFLINE:
+        return "offline";
+    case CS_UNAUTHORIZED:
+        return "unauthorized";
+    default:
+        return "unknown";
+    }
+}
+#endif // ADB_HOST
+
+/* qual_overwrite is used to overwrite a qualifier string.  dst is a
+ * pointer to a char pointer.  It is assumed that if *dst is non-NULL, it
+ * was malloc'ed and needs to freed.  *dst will be set to a dup of src.
+ */
+static void qual_overwrite(char **dst, const char *src)
+{
+    if (!dst)
+        return;
+
+    free(*dst);
+    *dst = NULL;
+
+    if (!src || !*src)
+        return;
+
+    *dst = strdup(src);
+}
+
+void parse_banner(char *banner, atransport *t)
+{
+    static const char *prop_seps = ";";
+    static const char key_val_sep = '=';
+    char *cp;
+    char *type;
+
+    D("parse_banner: %s\n", banner);
+    type = banner;
+    cp = strchr(type, ':');
+    if (cp) {
+        *cp++ = 0;
+        /* Nothing is done with second field. */
+        cp = strchr(cp, ':');
+        if (cp) {
+#if ADB_OVER_PCIE
+	    static const char *dev_info[] = {
+	    	"device",
+		"vendor",
+		"class",
+	    };
+
+            char *save;
+            char *key;
+            key = adb_strtok_r(cp + 1, prop_seps, &save);
+            while (key) {
+                cp = strchr(key, key_val_sep);
+                if (cp) {
+                    *cp++ = '\0';
+                    if (!strcmp(key, dev_info[0]))
+			t->device = cp;
+                    else if (!strcmp(key, dev_info[1]))
+			t->product = cp;
+                    else if (!strcmp(key, dev_info[2]))
+			t->serial = cp;
+                }
+                key = adb_strtok_r(NULL, prop_seps, &save);
+            }
+#else
+	    static const char **dev_info = cnxn_props;
+            char *save;
+            char *key;
+            key = adb_strtok_r(cp + 1, prop_seps, &save);
+            while (key) {
+                cp = strchr(key, key_val_sep);
+                if (cp) {
+                    *cp++ = '\0';
+                    if (!strcmp(key, dev_info[0]))
+                        qual_overwrite(&t->product, cp);
+                    else if (!strcmp(key, dev_info[1]))
+                        qual_overwrite(&t->model, cp);
+                    else if (!strcmp(key, dev_info[2]))
+                        qual_overwrite(&t->device, cp);
+                }
+                key = adb_strtok_r(NULL, prop_seps, &save);
+            }
+#endif
+        }
+    }
+
+    if(!strcmp(type, "bootloader")){
+        D("setting connection_state to CS_BOOTLOADER\n");
+        t->connection_state = CS_BOOTLOADER;
+        update_transports();
+        return;
+    }
+
+    if(!strcmp(type, "device")) {
+        D("setting connection_state to CS_DEVICE\n");
+        t->connection_state = CS_DEVICE;
+        update_transports();
+        return;
+    }
+
+    if(!strcmp(type, "recovery")) {
+        D("setting connection_state to CS_RECOVERY\n");
+        t->connection_state = CS_RECOVERY;
+        update_transports();
+        return;
+    }
+
+    if(!strcmp(type, "sideload")) {
+        D("setting connection_state to CS_SIDELOAD\n");
+        t->connection_state = CS_SIDELOAD;
+        update_transports();
+        return;
+    }
+
+    t->connection_state = CS_HOST;
+}
+
+void handle_packet(apacket *p, atransport *t)
+{
+    asocket *s;
+
+    D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
+            ((char*) (&(p->msg.command)))[1],
+            ((char*) (&(p->msg.command)))[2],
+            ((char*) (&(p->msg.command)))[3]);
+    print_packet("recv", p);
+
+    switch(p->msg.command){
+    case A_SYNC:
+        if(p->msg.arg0){
+            send_packet(p, t);
+            if(HOST) send_connect(t);
+        } else {
+            t->connection_state = CS_OFFLINE;
+            handle_offline(t);
+            send_packet(p, t);
+        }
+        return;
+
+    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
+            /* XXX verify version, etc */
+        if(t->connection_state != CS_OFFLINE) {
+            t->connection_state = CS_OFFLINE;
+            handle_offline(t);
+        }
+
+        parse_banner((char*) p->data, t);
+
+        if (HOST || !auth_enabled) {
+            handle_online(t);
+            if(!HOST) send_connect(t);
+        } else {
+            send_auth_request(t);
+        }
+        break;
+
+    case A_AUTH:
+        if (p->msg.arg0 == ADB_AUTH_TOKEN) {
+            t->connection_state = CS_UNAUTHORIZED;
+            t->key = adb_auth_nextkey(t->key);
+            if (t->key) {
+                send_auth_response(p->data, p->msg.data_length, t);
+            } else {
+                /* No more private keys to try, send the public key */
+                send_auth_publickey(t);
+            }
+        } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
+            if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
+                adb_auth_verified(t);
+                t->failed_auth_attempts = 0;
+            } else {
+                if (t->failed_auth_attempts++ > 10)
+                    adb_sleep_ms(1000);
+                send_auth_request(t);
+            }
+        } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
+            adb_auth_confirm_key(p->data, p->msg.data_length, t);
+        }
+        break;
+
+    case A_OPEN: /* OPEN(local-id, 0, "destination") */
+        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
+            char *name = (char*) p->data;
+            name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
+            s = create_local_service_socket(name);
+            if(s == 0) {
+                send_close(0, p->msg.arg0, t);
+            } else {
+                s->peer = create_remote_socket(p->msg.arg0, t);
+                s->peer->peer = s;
+                send_ready(s->id, s->peer->id, t);
+                s->ready(s);
+            }
+        }
+        break;
+
+    case A_OKAY: /* READY(local-id, remote-id, "") */
+        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
+            if((s = find_local_socket(p->msg.arg1, 0))) {
+                if(s->peer == 0) {
+                    /* On first READY message, create the connection. */
+                    s->peer = create_remote_socket(p->msg.arg0, t);
+                    s->peer->peer = s;
+                    s->ready(s);
+                } else if (s->peer->id == p->msg.arg0) {
+                    /* Other READY messages must use the same local-id */
+                    s->ready(s);
+                } else {
+                    D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n",
+                      p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
+                }
+            }
+        }
+        break;
+
+    case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
+        if (t->online && p->msg.arg1 != 0) {
+            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+                /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
+                 * a failed OPEN only. However, due to a bug in previous ADB
+                 * versions, CLOSE(0, remote-id, "") was also used for normal
+                 * CLOSE() operations.
+                 *
+                 * This is bad because it means a compromised adbd could
+                 * send packets to close connections between the host and
+                 * other devices. To avoid this, only allow this if the local
+                 * socket has a peer on the same transport.
+                 */
+                if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
+                    D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n",
+                      p->msg.arg1, t->serial, s->peer->transport->serial);
+                } else {
+                    s->close(s);
+                }
+            }
+        }
+        break;
+
+    case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
+        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
+            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+                unsigned rid = p->msg.arg0;
+                p->len = p->msg.data_length;
+
+                if(s->enqueue(s, p) == 0) {
+                    D("Enqueue the socket\n");
+                    send_ready(s->id, rid, t);
+                }
+                return;
+            }
+        }
+        break;
+
+    default:
+        printf("handle_packet: what is %08x?!\n", p->msg.command);
+    }
+
+    put_apacket(p);
+}
+
+alistener listener_list = {
+    .next = &listener_list,
+    .prev = &listener_list,
+};
+
+static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
+{
+    asocket *s;
+
+    if(ev & FDE_READ) {
+        struct sockaddr addr;
+        socklen_t alen;
+        int fd;
+
+        alen = sizeof(addr);
+        fd = adb_socket_accept(_fd, &addr, &alen);
+        if(fd < 0) return;
+
+        adb_socket_setbufsize(fd, CHUNK_SIZE);
+
+        s = create_local_socket(fd);
+        if(s) {
+            connect_to_smartsocket(s);
+            return;
+        }
+
+        adb_close(fd);
+    }
+}
+
+static void listener_event_func(int _fd, unsigned ev, void *_l)
+{
+    alistener *l = _l;
+    asocket *s;
+
+    if(ev & FDE_READ) {
+        struct sockaddr addr;
+        socklen_t alen;
+        int fd;
+
+        alen = sizeof(addr);
+        fd = adb_socket_accept(_fd, &addr, &alen);
+        if(fd < 0) return;
+
+        s = create_local_socket(fd);
+        if(s) {
+            s->transport = l->transport;
+            connect_to_remote(s, l->connect_to);
+            return;
+        }
+
+        adb_close(fd);
+    }
+}
+
+static void  free_listener(alistener*  l)
+{
+    if (l->next) {
+        l->next->prev = l->prev;
+        l->prev->next = l->next;
+        l->next = l->prev = l;
+    }
+
+    // closes the corresponding fd
+    fdevent_remove(&l->fde);
+
+    if (l->local_name)
+        free((char*)l->local_name);
+
+    if (l->connect_to)
+        free((char*)l->connect_to);
+
+    if (l->transport) {
+        remove_transport_disconnect(l->transport, &l->disconnect);
+    }
+    free(l);
+}
+
+static void listener_disconnect(void*  _l, atransport*  t)
+{
+    alistener*  l = _l;
+
+    free_listener(l);
+}
+
+int local_name_to_fd(const char *name)
+{
+    int port;
+
+    if(!strncmp("tcp:", name, 4)){
+        int  ret;
+        port = atoi(name + 4);
+
+        if (gListenAll > 0) {
+            ret = socket_inaddr_any_server(port, SOCK_STREAM);
+        } else {
+            ret = socket_loopback_server(port, SOCK_STREAM);
+        }
+
+        return ret;
+    }
+#ifndef HAVE_WIN32_IPC  /* no Unix-domain sockets on Win32 */
+    // It's non-sensical to support the "reserved" space on the adb host side
+    if(!strncmp(name, "local:", 6)) {
+        return socket_local_server(name + 6,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+    } else if(!strncmp(name, "localabstract:", 14)) {
+        return socket_local_server(name + 14,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+    } else if(!strncmp(name, "localfilesystem:", 16)) {
+        return socket_local_server(name + 16,
+                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
+    }
+
+#endif
+    printf("unknown local portname '%s'\n", name);
+    return -1;
+}
+
+// Write a single line describing a listener to a user-provided buffer.
+// Appends a trailing zero, even in case of truncation, but the function
+// returns the full line length.
+// If |buffer| is NULL, does not write but returns required size.
+static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
+    // Format is simply:
+    //
+    //  <device-serial> " " <local-name> " " <remote-name> "\n"
+    //
+    int local_len = strlen(l->local_name);
+    int connect_len = strlen(l->connect_to);
+    int serial_len = strlen(l->transport->serial);
+
+    if (buffer != NULL) {
+        snprintf(buffer, buffer_len, "%s %s %s\n",
+                l->transport->serial, l->local_name, l->connect_to);
+    }
+    // NOTE: snprintf() on Windows returns -1 in case of truncation, so
+    // return the computed line length instead.
+    return local_len + connect_len + serial_len + 3;
+}
+
+// Write the list of current listeners (network redirections) into a
+// user-provided buffer. Appends a trailing zero, even in case of
+// trunctaion, but return the full size in bytes.
+// If |buffer| is NULL, does not write but returns required size.
+static int format_listeners(char* buf, size_t buflen)
+{
+    alistener* l;
+    int result = 0;
+    for (l = listener_list.next; l != &listener_list; l = l->next) {
+        // Ignore special listeners like those for *smartsocket*
+        if (l->connect_to[0] == '*')
+          continue;
+        int len = format_listener(l, buf, buflen);
+        // Ensure there is space for the trailing zero.
+        result += len;
+        if (buf != NULL) {
+          buf += len;
+          buflen -= len;
+          if (buflen <= 0)
+              break;
+        }
+    }
+    return result;
+}
+
+static int remove_listener(const char *local_name, atransport* transport)
+{
+    alistener *l;
+
+    for (l = listener_list.next; l != &listener_list; l = l->next) {
+        if (!strcmp(local_name, l->local_name)) {
+            listener_disconnect(l, l->transport);
+            return 0;
+        }
+    }
+    return -1;
+}
+
+static void remove_all_listeners(void)
+{
+    alistener *l, *l_next;
+    for (l = listener_list.next; l != &listener_list; l = l_next) {
+        l_next = l->next;
+        // Never remove smart sockets.
+        if (l->connect_to[0] == '*')
+            continue;
+        listener_disconnect(l, l->transport);
+    }
+}
+
+// error/status codes for install_listener.
+typedef enum {
+  INSTALL_STATUS_OK = 0,
+  INSTALL_STATUS_INTERNAL_ERROR = -1,
+  INSTALL_STATUS_CANNOT_BIND = -2,
+  INSTALL_STATUS_CANNOT_REBIND = -3,
+} install_status_t;
+
+static install_status_t install_listener(const char *local_name,
+                                         const char *connect_to,
+                                         atransport* transport,
+                                         int no_rebind)
+{
+    alistener *l;
+
+    //printf("install_listener('%s','%s')\n", local_name, connect_to);
+
+    for(l = listener_list.next; l != &listener_list; l = l->next){
+        if(strcmp(local_name, l->local_name) == 0) {
+            char *cto;
+
+                /* can't repurpose a smartsocket */
+            if(l->connect_to[0] == '*') {
+                return INSTALL_STATUS_INTERNAL_ERROR;
+            }
+
+                /* can't repurpose a listener if 'no_rebind' is true */
+            if (no_rebind) {
+                return INSTALL_STATUS_CANNOT_REBIND;
+            }
+
+            cto = strdup(connect_to);
+            if(cto == 0) {
+                return INSTALL_STATUS_INTERNAL_ERROR;
+            }
+
+            //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
+            free((void*) l->connect_to);
+            l->connect_to = cto;
+            if (l->transport != transport) {
+                remove_transport_disconnect(l->transport, &l->disconnect);
+                l->transport = transport;
+                add_transport_disconnect(l->transport, &l->disconnect);
+            }
+            return INSTALL_STATUS_OK;
+        }
+    }
+
+    if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
+    if((l->local_name = strdup(local_name)) == 0) goto nomem;
+    if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
+
+
+    l->fd = local_name_to_fd(local_name);
+    if(l->fd < 0) {
+        free((void*) l->local_name);
+        free((void*) l->connect_to);
+        free(l);
+        printf("cannot bind '%s'\n", local_name);
+        return -2;
+    }
+
+    close_on_exec(l->fd);
+    if(!strcmp(l->connect_to, "*smartsocket*")) {
+        fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
+    } else {
+        fdevent_install(&l->fde, l->fd, listener_event_func, l);
+    }
+    fdevent_set(&l->fde, FDE_READ);
+
+    l->next = &listener_list;
+    l->prev = listener_list.prev;
+    l->next->prev = l;
+    l->prev->next = l;
+    l->transport = transport;
+
+    if (transport) {
+        l->disconnect.opaque = l;
+        l->disconnect.func   = listener_disconnect;
+        add_transport_disconnect(transport, &l->disconnect);
+    }
+    return INSTALL_STATUS_OK;
+
+nomem:
+    fatal("cannot allocate listener");
+    return INSTALL_STATUS_INTERNAL_ERROR;
+}
+
+#if defined(_WIN32)
+static BOOL WINAPI ctrlc_handler(DWORD type)
+{
+    exit(STATUS_CONTROL_C_EXIT);
+    return TRUE;
+}
+#endif
+
+static void adb_cleanup(void)
+{
+#ifndef ADB_OVER_PCIE
+    usb_cleanup();
+#endif
+}
+
+void start_logging(void)
+{
+#if defined(_WIN32)
+    char    temp[ MAX_PATH ];
+    FILE*   fnul;
+    FILE*   flog;
+
+    GetTempPath( sizeof(temp) - 8, temp );
+    strcat( temp, "adb.log" );
+
+    /* Win32 specific redirections */
+    fnul = fopen( "NUL", "rt" );
+    if (fnul != NULL)
+        stdin[0] = fnul[0];
+
+    flog = fopen( temp, "at" );
+    if (flog == NULL)
+        flog = fnul;
+
+    setvbuf( flog, NULL, _IONBF, 0 );
+
+    stdout[0] = flog[0];
+    stderr[0] = flog[0];
+    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
+#else
+    int fd;
+
+    fd = unix_open("/dev/null", O_RDONLY);
+    dup2(fd, 0);
+    adb_close(fd);
+
+    fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
+    if(fd < 0) {
+        fd = unix_open("/dev/null", O_WRONLY);
+    }
+    dup2(fd, 1);
+    dup2(fd, 2);
+    adb_close(fd);
+    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
+#endif
+}
+
+#if !ADB_HOST
+void start_device_log(void)
+{
+    int fd;
+    char    path[PATH_MAX];
+    struct tm now;
+    time_t t;
+    char value[PROPERTY_VALUE_MAX];
+
+    // read the trace mask from persistent property persist.adb.trace_mask
+    // give up if the property is not set or cannot be parsed
+    property_get("persist.adb.trace_mask", value, "");
+    if (sscanf(value, "%x", &adb_trace_mask) != 1)
+        return;
+
+    adb_mkdir("/tmp/adb", 0775);
+    tzset();
+    time(&t);
+    localtime_r(&t, &now);
+    strftime(path, sizeof(path),
+                "/tmp/adb/adb-%Y-%m-%d-%H-%M-%S.txt",
+                &now);
+    fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+    if (fd < 0)
+        return;
+
+    // redirect stdout and stderr to the log file
+    dup2(fd, 1);
+    dup2(fd, 2);
+    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
+    adb_close(fd);
+
+    fd = unix_open("/dev/null", O_RDONLY);
+    dup2(fd, 0);
+    adb_close(fd);
+}
+#endif
+
+#if ADB_HOST
+
+#ifdef WORKAROUND_BUG6558362
+#include <sched.h>
+#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362"
+void adb_set_affinity(void)
+{
+   cpu_set_t cpu_set;
+   const char* cpunum_str = getenv(AFFINITY_ENVVAR);
+   char* strtol_res;
+   int cpu_num;
+
+   if (!cpunum_str || !*cpunum_str)
+       return;
+   cpu_num = strtol(cpunum_str, &strtol_res, 0);
+   if (*strtol_res != '\0')
+     fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR);
+
+   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+   D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+   CPU_ZERO(&cpu_set);
+   CPU_SET(cpu_num, &cpu_set);
+   sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
+   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+   D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+}
+#endif
+
+int launch_server(int server_port)
+{
+#if defined(_WIN32)
+    /* we need to start the server in the background                    */
+    /* we create a PIPE that will be used to wait for the server's "OK" */
+    /* message since the pipe handles must be inheritable, we use a     */
+    /* security attribute                                               */
+    HANDLE                pipe_read, pipe_write;
+    HANDLE                stdout_handle, stderr_handle;
+    SECURITY_ATTRIBUTES   sa;
+    STARTUPINFO           startup;
+    PROCESS_INFORMATION   pinfo;
+    char                  program_path[ MAX_PATH ];
+    int                   ret;
+
+    sa.nLength = sizeof(sa);
+    sa.lpSecurityDescriptor = NULL;
+    sa.bInheritHandle = TRUE;
+
+    /* create pipe, and ensure its read handle isn't inheritable */
+    ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
+    if (!ret) {
+        fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
+        return -1;
+    }
+
+    SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
+
+    /* Some programs want to launch an adb command and collect its output by
+     * calling CreateProcess with inheritable stdout/stderr handles, then
+     * using read() to get its output. When this happens, the stdout/stderr
+     * handles passed to the adb client process will also be inheritable.
+     * When starting the adb server here, care must be taken to reset them
+     * to non-inheritable.
+     * Otherwise, something bad happens: even if the adb command completes,
+     * the calling process is stuck while read()-ing from the stdout/stderr
+     * descriptors, because they're connected to corresponding handles in the
+     * adb server process (even if the latter never uses/writes to them).
+     */
+    stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
+    stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
+    if (stdout_handle != INVALID_HANDLE_VALUE) {
+        SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
+    }
+    if (stderr_handle != INVALID_HANDLE_VALUE) {
+        SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
+    }
+
+    ZeroMemory( &startup, sizeof(startup) );
+    startup.cb = sizeof(startup);
+    startup.hStdInput  = GetStdHandle( STD_INPUT_HANDLE );
+    startup.hStdOutput = pipe_write;
+    startup.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
+    startup.dwFlags    = STARTF_USESTDHANDLES;
+
+    ZeroMemory( &pinfo, sizeof(pinfo) );
+
+    /* get path of current program */
+    GetModuleFileName( NULL, program_path, sizeof(program_path) );
+
+    ret = CreateProcess(
+            program_path,                              /* program path  */
+            "adb fork-server server",
+                                    /* the fork-server argument will set the
+                                       debug = 2 in the child           */
+            NULL,                   /* process handle is not inheritable */
+            NULL,                    /* thread handle is not inheritable */
+            TRUE,                          /* yes, inherit some handles */
+            DETACHED_PROCESS, /* the new process doesn't have a console */
+            NULL,                     /* use parent's environment block */
+            NULL,                    /* use parent's starting directory */
+            &startup,                 /* startup info, i.e. std handles */
+            &pinfo );
+
+    CloseHandle( pipe_write );
+
+    if (!ret) {
+        fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
+        CloseHandle( pipe_read );
+        return -1;
+    }
+
+    CloseHandle( pinfo.hProcess );
+    CloseHandle( pinfo.hThread );
+
+    /* wait for the "OK\n" message */
+    {
+        char  temp[3];
+        DWORD  count;
+
+        ret = ReadFile( pipe_read, temp, 3, &count, NULL );
+        CloseHandle( pipe_read );
+        if ( !ret ) {
+            fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
+            return -1;
+        }
+        if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
+            fprintf(stderr, "ADB server didn't ACK\n" );
+            return -1;
+        }
+    }
+#else /* !defined(_WIN32) */
+    char    path[PATH_MAX];
+    int     fd[2];
+
+    // set up a pipe so the child can tell us when it is ready.
+    // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
+    if (pipe(fd)) {
+        fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
+        return -1;
+    }
+    get_my_path(path, PATH_MAX);
+    pid_t pid = fork();
+    if(pid < 0) return -1;
+
+    if (pid == 0) {
+        // child side of the fork
+
+        // redirect stderr to the pipe
+        // we use stderr instead of stdout due to stdout's buffering behavior.
+        adb_close(fd[0]);
+        dup2(fd[1], STDERR_FILENO);
+        adb_close(fd[1]);
+
+        char str_port[30];
+        snprintf(str_port, sizeof(str_port), "%d",  server_port);
+        // child process
+        int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
+        // this should not return
+        fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
+    } else  {
+        // parent side of the fork
+
+        char  temp[3];
+
+        temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
+        // wait for the "OK\n" message
+        adb_close(fd[1]);
+        int ret = adb_read(fd[0], temp, 3);
+        int saved_errno = errno;
+        adb_close(fd[0]);
+        if (ret < 0) {
+            fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
+            return -1;
+        }
+        if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
+            fprintf(stderr, "ADB server didn't ACK\n" );
+            return -1;
+        }
+
+        setsid();
+    }
+#endif /* !defined(_WIN32) */
+    return 0;
+}
+#endif /* ADB_HOST */
+
+/* Constructs a local name of form tcp:port.
+ * target_str points to the target string, it's content will be overwritten.
+ * target_size is the capacity of the target string.
+ * server_port is the port number to use for the local name.
+ */
+void build_local_name(char* target_str, size_t target_size, int server_port)
+{
+  snprintf(target_str, target_size, "tcp:%d", server_port);
+}
+
+#if !ADB_HOST
+
+static void drop_capabilities_bounding_set_if_needed() {
+#ifdef ALLOW_ADBD_ROOT
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.debuggable", value, "");
+    if (strcmp(value, "1") == 0) {
+        return;
+    }
+#endif
+    int i;
+    for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+        if (i == CAP_SETUID || i == CAP_SETGID) {
+            // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
+            continue;
+        }
+        int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+
+        // Some kernels don't have file capabilities compiled in, and
+        // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
+        // die when we see such misconfigured kernels.
+        if ((err < 0) && (errno != EINVAL)) {
+            exit(1);
+        }
+    }
+}
+
+static int should_drop_privileges() {
+#ifndef ALLOW_ADBD_ROOT
+    return 1;
+#else /* ALLOW_ADBD_ROOT */
+#ifdef ADB_NON_ANDROID
+    return 0;
+#endif /* ADB_NON_ANDROID */
+    int secure = 0;
+    char value[PROPERTY_VALUE_MAX];
+
+   /* run adbd in secure mode if ro.secure is set and
+    ** we are not in the emulator
+    */
+    property_get("ro.kernel.qemu", value, "");
+    if (strcmp(value, "1") != 0) {
+        property_get("ro.secure", value, "1");
+        if (strcmp(value, "1") == 0) {
+            // don't run as root if ro.secure is set...
+            secure = 1;
+
+            // ... except we allow running as root in userdebug builds if the
+            // service.adb.root property has been set by the "adb root" command
+            property_get("ro.debuggable", value, "");
+            if (strcmp(value, "1") == 0) {
+                property_get("service.adb.root", value, "");
+                if (strcmp(value, "1") == 0) {
+                    secure = 0;
+                }
+            }
+        }
+    }
+    return secure;
+#endif /* ALLOW_ADBD_ROOT */
+}
+#endif /* !ADB_HOST */
+
+int adb_main(int is_daemon, int server_port)
+{
+#if !ADB_HOST
+    int port;
+    char value[PROPERTY_VALUE_MAX];
+
+    umask(000);
+#endif
+
+    atexit(adb_cleanup);
+#if defined(_WIN32)
+    SetConsoleCtrlHandler( ctrlc_handler, TRUE );
+#else
+    // No SIGCHLD. Let the service subproc handle its children.
+    signal(SIGPIPE, SIG_IGN);
+#endif
+
+    init_transport_registration();
+
+#if ADB_HOST
+    HOST = 1;
+
+#ifdef WORKAROUND_BUG6558362
+    if(is_daemon) adb_set_affinity();
+#endif
+
+#if ADB_OVER_PCIE
+    fprintf(stderr, "adb path: %s\n", PCIE_ADB_PATH);
+    pcie_host_init();
+#else
+    usb_init();
+#endif
+    local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    adb_auth_init();
+
+    char local_name[30];
+    build_local_name(local_name, sizeof(local_name), server_port);
+    if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
+        exit(1);
+    }
+#else
+    property_get("ro.adb.secure", value, "0");
+    auth_enabled = !strcmp(value, "1");
+    if (auth_enabled)
+        adb_auth_init();
+
+    // Our external storage path may be different than apps, since
+    // we aren't able to bind mount after dropping root.
+    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
+    if (NULL != adb_external_storage) {
+        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
+    } else {
+        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
+          " unchanged.\n");
+    }
+
+    /* add extra groups:
+    ** AID_ADB to access the USB driver
+    ** AID_LOG to read system logs (adb logcat)
+    ** AID_INPUT to diagnose input issues (getevent)
+    ** AID_INET to diagnose network issues (netcfg, ping)
+    ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+    ** AID_SDCARD_R to allow reading from the SD card
+    ** AID_SDCARD_RW to allow writing to the SD card
+    ** AID_NET_BW_STATS to read out qtaguid statistics
+    */
+    gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_NET_BT,
+                       AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
+                       AID_NET_BW_STATS };
+    if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+        exit(1);
+    }
+
+    /* don't listen on a port (default 5037) if running in secure mode */
+    /* don't run as root if we are running in secure mode */
+    if (should_drop_privileges()) {
+        drop_capabilities_bounding_set_if_needed();
+
+        /* then switch user and group to "shell" */
+        if (setgid(AID_SHELL) != 0) {
+            exit(1);
+        }
+        if (setuid(AID_SHELL) != 0) {
+            exit(1);
+        }
+
+        D("Local port disabled\n");
+    } else {
+#ifndef ADB_NON_ANDROID
+        char local_name[30];
+        if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) {
+            // b/12587913: fix setcon to allow const pointers
+            if (setcon((char *)root_seclabel) < 0) {
+                exit(1);
+            }
+        }
+        build_local_name(local_name, sizeof(local_name), server_port);
+        if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
+            exit(1);
+        }
+#endif
+    }
+
+    int usb = 0;
+#ifdef ADB_OVER_PCIE
+    fprintf(stderr, "adbd path: %s\n", PCIE_ADB_PATH);
+    if (access(PCIE_ADB_PATH, F_OK) == 0) {
+	pcie_init();
+	usb = 1;
+    }
+#else
+    if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
+        // listen on USB
+        usb_init();
+        usb = 1;
+    }
+#endif
+
+    // If one of these properties is set, also listen on that port
+    // If one of the properties isn't set and we couldn't listen on usb,
+    // listen on the default port.
+    property_get("service.adb.tcp.port", value, "");
+    if (!value[0]) {
+        property_get("persist.adb.tcp.port", value, "");
+    }
+    if (sscanf(value, "%d", &port) == 1 && port > 0) {
+        printf("using port=%d\n", port);
+        // listen on TCP port specified by service.adb.tcp.port property
+        local_init(port);
+    } else if (!usb) {
+        // listen on default port
+        local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    }
+
+    D("adb_main(): pre init_jdwp()\n");
+    init_jdwp();
+    D("adb_main(): post init_jdwp()\n");
+#endif
+
+    if (is_daemon)
+    {
+        // inform our parent that we are up and running.
+#if defined(_WIN32)
+        DWORD  count;
+        WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
+#else
+        fprintf(stderr, "OK\n");
+#endif
+        start_logging();
+    }
+    D("Event loop starting\n");
+
+    fdevent_loop();
+
+#ifndef ADB_OVER_PCIE
+    usb_cleanup();
+#endif
+
+    return 0;
+}
+
+// Try to handle a network forwarding request.
+// This returns 1 on success, 0 on failure, and -1 to indicate this is not
+// a forwarding-related request.
+int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
+{
+    if (!strcmp(service, "list-forward")) {
+        // Create the list of forward redirections.
+        int buffer_size = format_listeners(NULL, 0);
+        // Add one byte for the trailing zero.
+        char* buffer = malloc(buffer_size + 1);
+        if (buffer == NULL) {
+            sendfailmsg(reply_fd, "not enough memory");
+            return 1;
+        }
+        (void) format_listeners(buffer, buffer_size + 1);
+#if ADB_HOST
+        send_msg_with_okay(reply_fd, buffer, buffer_size);
+#else
+        send_msg_with_header(reply_fd, buffer, buffer_size);
+#endif
+        free(buffer);
+        return 1;
+    }
+
+    if (!strcmp(service, "killforward-all")) {
+        remove_all_listeners();
+#if ADB_HOST
+        /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+        adb_write(reply_fd, "OKAY", 4);
+#endif
+        adb_write(reply_fd, "OKAY", 4);
+        return 1;
+    }
+
+    if (!strncmp(service, "forward:",8) ||
+        !strncmp(service, "killforward:",12)) {
+        char *local, *remote, *err;
+        int r;
+        atransport *transport;
+
+        int createForward = strncmp(service, "kill", 4);
+        int no_rebind = 0;
+
+        local = strchr(service, ':') + 1;
+
+        // Handle forward:norebind:<local>... here
+        if (createForward && !strncmp(local, "norebind:", 9)) {
+            no_rebind = 1;
+            local = strchr(local, ':') + 1;
+        }
+
+        remote = strchr(local,';');
+
+        if (createForward) {
+            // Check forward: parameter format: '<local>;<remote>'
+            if(remote == 0) {
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 1;
+            }
+
+            *remote++ = 0;
+            if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 1;
+            }
+        } else {
+            // Check killforward: parameter format: '<local>'
+            if (local[0] == 0) {
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 1;
+            }
+        }
+
+        transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
+        if (!transport) {
+            sendfailmsg(reply_fd, err);
+            return 1;
+        }
+
+        if (createForward) {
+            r = install_listener(local, remote, transport, no_rebind);
+        } else {
+            r = remove_listener(local, transport);
+        }
+        if(r == 0) {
+#if ADB_HOST
+            /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+            writex(reply_fd, "OKAY", 4);
+#endif
+            writex(reply_fd, "OKAY", 4);
+            return 1;
+        }
+
+        if (createForward) {
+            const char* message;
+            switch (r) {
+              case INSTALL_STATUS_CANNOT_BIND:
+                message = "cannot bind to socket";
+                break;
+              case INSTALL_STATUS_CANNOT_REBIND:
+                message = "cannot rebind existing socket";
+                break;
+              default:
+                message = "internal error";
+            }
+            sendfailmsg(reply_fd, message);
+        } else {
+            sendfailmsg(reply_fd, "cannot remove listener");
+        }
+        return 1;
+    }
+    return 0;
+}
+
+int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
+{
+    if(!strcmp(service, "kill")) {
+        fprintf(stderr,"adb server killed by remote request\n");
+        fflush(stdout);
+        adb_write(reply_fd, "OKAY", 4);
+#ifndef ADB_OVER_PCIE
+        usb_cleanup();
+#endif
+        exit(0);
+    }
+
+#if ADB_HOST
+    atransport *transport = NULL;
+    // "transport:" is used for switching transport with a specified serial number
+    // "transport-usb:" is used for switching transport to the only USB transport
+    // "transport-local:" is used for switching transport to the only local transport
+    // "transport-any:" is used for switching transport to the only transport
+    if (!strncmp(service, "transport", strlen("transport"))) {
+        char* error_string = "unknown failure";
+        transport_type type = kTransportAny;
+
+        if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
+            type = kTransportUsb;
+        } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
+            type = kTransportLocal;
+        } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
+            type = kTransportAny;
+        } else if (!strncmp(service, "transport:", strlen("transport:"))) {
+            service += strlen("transport:");
+            serial = service;
+        }
+
+        transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
+
+        if (transport) {
+            s->transport = transport;
+            adb_write(reply_fd, "OKAY", 4);
+        } else {
+            sendfailmsg(reply_fd, error_string);
+        }
+        return 1;
+    }
+
+    // return a list of all connected devices
+    if (!strncmp(service, "devices", 7)) {
+        char buffer[4096];
+        int use_long = !strcmp(service+7, "-l");
+        if (use_long || service[7] == 0) {
+            memset(buffer, 0, sizeof(buffer));
+            D("Getting device list \n");
+            list_transports(buffer, sizeof(buffer), use_long);
+            D("Wrote device list \n");
+            send_msg_with_okay(reply_fd, buffer, strlen(buffer));
+            return 0;
+        }
+    }
+
+    // remove TCP transport
+    if (!strncmp(service, "disconnect:", 11)) {
+        char buffer[4096];
+        memset(buffer, 0, sizeof(buffer));
+        char* serial = service + 11;
+        if (serial[0] == 0) {
+            // disconnect from all TCP devices
+            unregister_all_tcp_transports();
+        } else {
+            char hostbuf[100];
+            // assume port 5555 if no port is specified
+            if (!strchr(serial, ':')) {
+                snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
+                serial = hostbuf;
+            }
+            atransport *t = find_transport(serial);
+
+            if (t) {
+                unregister_transport(t);
+            } else {
+                snprintf(buffer, sizeof(buffer), "No such device %s", serial);
+            }
+        }
+
+        send_msg_with_okay(reply_fd, buffer, strlen(buffer));
+        return 0;
+    }
+
+    // returns our value for ADB_SERVER_VERSION
+    if (!strcmp(service, "version")) {
+        char version[12];
+        snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
+        send_msg_with_okay(reply_fd, version, strlen(version));
+        return 0;
+    }
+
+    if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
+        char *out = "unknown";
+         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+       if (transport && transport->serial) {
+            out = transport->serial;
+        }
+        send_msg_with_okay(reply_fd, out, strlen(out));
+        return 0;
+    }
+    if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
+        char *out = "unknown";
+         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+       if (transport && transport->devpath) {
+            out = transport->devpath;
+        }
+        send_msg_with_okay(reply_fd, out, strlen(out));
+        return 0;
+    }
+    // indicates a new emulator instance has started
+    if (!strncmp(service,"emulator:",9)) {
+        int  port = atoi(service+9);
+        local_connect(port);
+        /* we don't even need to send a reply */
+        return 0;
+    }
+
+    if(!strncmp(service,"get-state",strlen("get-state"))) {
+        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+        char *state = connection_state_name(transport);
+        send_msg_with_okay(reply_fd, state, strlen(state));
+        return 0;
+    }
+#endif // ADB_HOST
+
+    int ret = handle_forward_request(service, ttype, serial, reply_fd);
+    if (ret >= 0)
+      return ret - 1;
+    return -1;
+}
+
+int main(int argc, char **argv)
+{
+#if ADB_HOST
+    adb_sysdeps_init();
+    adb_trace_init();
+    D("Handling commandline()\n");
+    return adb_commandline(argc - 1, argv + 1);
+#else
+    /* If adbd runs inside the emulator this will enable adb tracing via
+     * adb-debug qemud service in the emulator. */
+    //adb_qemu_trace_init();
+    D("main()\n");
+    while(1) {
+        int c;
+        int option_index = 0;
+        static struct option opts[] = {
+            {"root_seclabel", required_argument, 0, 's' },
+            {"device_banner", required_argument, 0, 'b' }
+        };
+        c = getopt_long(argc, argv, "", opts, &option_index);
+        if (c == -1)
+            break;
+        switch (c) {
+        case 's':
+            root_seclabel = optarg;
+            break;
+        case 'b':
+            adb_device_banner = optarg;
+            break;
+        default:
+            break;
+        }
+    }
+
+    start_device_log();
+    D("Handling main()\n");
+    return adb_main(0, DEFAULT_ADB_PORT);
+#endif
+}
diff --git a/src/devtools/adb/adb.h b/src/devtools/adb/adb.h
new file mode 100755
index 0000000..84d55d8
--- /dev/null
+++ b/src/devtools/adb/adb.h
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ADB_H
+#define __ADB_H
+
+#include <limits.h>
+
+#include "adb_trace.h"
+#include "transport.h"  /* readx(), writex() */
+
+#if ADB_OVER_PCIE
+#define MAX_PAYLOAD 3456
+#else
+#define MAX_PAYLOAD 4096
+#endif
+
+#define A_SYNC 0x434e5953
+#define A_CNXN 0x4e584e43
+#define A_OPEN 0x4e45504f
+#define A_OKAY 0x59414b4f
+#define A_CLSE 0x45534c43
+#define A_WRTE 0x45545257
+#define A_AUTH 0x48545541
+
+#define A_VERSION 0x01000000        // ADB protocol version
+
+#define ADB_VERSION_MAJOR 1         // Used for help/version information
+#define ADB_VERSION_MINOR 0         // Used for help/version information
+
+#define ADB_SERVER_VERSION    32    // Increment this when we want to force users to start a new adb server
+
+typedef struct amessage amessage;
+typedef struct apacket apacket;
+typedef struct asocket asocket;
+typedef struct alistener alistener;
+typedef struct aservice aservice;
+typedef struct atransport atransport;
+typedef struct adisconnect  adisconnect;
+typedef struct usb_handle usb_handle;
+
+struct amessage {
+    unsigned command;       /* command identifier constant      */
+    unsigned arg0;          /* first argument                   */
+    unsigned arg1;          /* second argument                  */
+    unsigned data_length;   /* length of payload (0 is allowed) */
+    unsigned data_check;    /* checksum of data payload         */
+    unsigned magic;         /* command ^ 0xffffffff             */
+};
+
+struct apacket
+{
+    apacket *next;
+
+    unsigned len;
+    unsigned char *ptr;
+
+    amessage msg;
+    unsigned char data[MAX_PAYLOAD];
+};
+
+/* An asocket represents one half of a connection between a local and
+** remote entity.  A local asocket is bound to a file descriptor.  A
+** remote asocket is bound to the protocol engine.
+*/
+struct asocket {
+        /* chain pointers for the local/remote list of
+        ** asockets that this asocket lives in
+        */
+    asocket *next;
+    asocket *prev;
+
+        /* the unique identifier for this asocket
+        */
+    unsigned id;
+
+        /* flag: set when the socket's peer has closed
+        ** but packets are still queued for delivery
+        */
+    int    closing;
+
+        /* flag: quit adbd when both ends close the
+        ** local service socket
+        */
+    int    exit_on_close;
+
+        /* the asocket we are connected to
+        */
+
+    asocket *peer;
+
+        /* For local asockets, the fde is used to bind
+        ** us to our fd event system.  For remote asockets
+        ** these fields are not used.
+        */
+    fdevent fde;
+    int fd;
+
+        /* queue of apackets waiting to be written
+        */
+    apacket *pkt_first;
+    apacket *pkt_last;
+
+        /* enqueue is called by our peer when it has data
+        ** for us.  It should return 0 if we can accept more
+        ** data or 1 if not.  If we return 1, we must call
+        ** peer->ready() when we once again are ready to
+        ** receive data.
+        */
+    int (*enqueue)(asocket *s, apacket *pkt);
+
+        /* ready is called by the peer when it is ready for
+        ** us to send data via enqueue again
+        */
+    void (*ready)(asocket *s);
+
+        /* shutdown is called by the peer before it goes away.
+        ** the socket should not do any further calls on its peer.
+        ** Always followed by a call to close. Optional, i.e. can be NULL.
+        */
+    void (*shutdown)(asocket *s);
+
+        /* close is called by the peer when it has gone away.
+        ** we are not allowed to make any further calls on the
+        ** peer once our close method is called.
+        */
+    void (*close)(asocket *s);
+
+        /* A socket is bound to atransport */
+    atransport *transport;
+};
+
+
+/* the adisconnect structure is used to record a callback that
+** will be called whenever a transport is disconnected (e.g. by the user)
+** this should be used to cleanup objects that depend on the
+** transport (e.g. remote sockets, listeners, etc...)
+*/
+struct  adisconnect
+{
+    void        (*func)(void*  opaque, atransport*  t);
+    void*         opaque;
+    adisconnect*  next;
+    adisconnect*  prev;
+};
+
+
+/* a transport object models the connection to a remote device or emulator
+** there is one transport per connected device/emulator. a "local transport"
+** connects through TCP (for the emulator), while a "usb transport" through
+** USB (for real devices)
+**
+** note that kTransportHost doesn't really correspond to a real transport
+** object, it's a special value used to indicate that a client wants to
+** connect to a service implemented within the ADB server itself.
+*/
+typedef enum transport_type {
+        kTransportUsb,
+        kTransportLocal,
+        kTransportAny,
+        kTransportHost,
+} transport_type;
+
+#define TOKEN_SIZE 20
+
+struct atransport
+{
+    atransport *next;
+    atransport *prev;
+
+    int (*read_from_remote)(apacket *p, atransport *t);
+    int (*write_to_remote)(apacket *p, atransport *t);
+    void (*close)(atransport *t);
+    void (*kick)(atransport *t);
+
+    int fd;
+    int transport_socket;
+    fdevent transport_fde;
+    int ref_count;
+    unsigned sync_token;
+    int connection_state;
+    int online;
+    transport_type type;
+
+        /* usb handle or socket fd as needed */
+    struct usb_handle *usb;
+    struct pcie_handle *pcie;
+    int sfd;
+
+        /* used to identify transports for clients */
+    char *serial;
+    char *product;
+    char *model;
+    char *device;
+    char *devpath;
+    int adb_port; // Use for emulators (local transport)
+
+        /* a list of adisconnect callbacks called when the transport is kicked */
+    int          kicked;
+    adisconnect  disconnects;
+
+    void *key;
+    unsigned char token[TOKEN_SIZE];
+    fdevent auth_fde;
+    unsigned failed_auth_attempts;
+};
+
+
+/* A listener is an entity which binds to a local port
+** and, upon receiving a connection on that port, creates
+** an asocket to connect the new local connection to a
+** specific remote service.
+**
+** TODO: some listeners read from the new connection to
+** determine what exact service to connect to on the far
+** side.
+*/
+struct alistener
+{
+    alistener *next;
+    alistener *prev;
+
+    fdevent fde;
+    int fd;
+
+    const char *local_name;
+    const char *connect_to;
+    atransport *transport;
+    adisconnect  disconnect;
+};
+
+
+void print_packet(const char *label, apacket *p);
+
+asocket *find_local_socket(unsigned local_id, unsigned remote_id);
+void install_local_socket(asocket *s);
+void remove_socket(asocket *s);
+void close_all_sockets(atransport *t);
+
+#define  LOCAL_CLIENT_PREFIX  "emulator-"
+
+asocket *create_local_socket(int fd);
+asocket *create_local_service_socket(const char *destination);
+
+asocket *create_remote_socket(unsigned id, atransport *t);
+void connect_to_remote(asocket *s, const char *destination);
+void connect_to_smartsocket(asocket *s);
+
+void fatal(const char *fmt, ...);
+void fatal_errno(const char *fmt, ...);
+
+void handle_packet(apacket *p, atransport *t);
+void send_packet(apacket *p, atransport *t);
+
+void get_my_path(char *s, size_t maxLen);
+int launch_server(int server_port);
+int adb_main(int is_daemon, int server_port);
+
+
+/* transports are ref-counted
+** get_device_transport does an acquire on your behalf before returning
+*/
+void init_transport_registration(void);
+int  list_transports(char *buf, size_t  bufsize, int long_listing);
+void update_transports(void);
+
+asocket*  create_device_tracker(void);
+
+/* Obtain a transport from the available transports.
+** If state is != CS_ANY, only transports in that state are considered.
+** If serial is non-NULL then only the device with that serial will be chosen.
+** If no suitable transport is found, error is set.
+*/
+atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out);
+void   add_transport_disconnect( atransport*  t, adisconnect*  dis );
+void   remove_transport_disconnect( atransport*  t, adisconnect*  dis );
+void   run_transport_disconnects( atransport*  t );
+void   kick_transport( atransport*  t );
+
+/* initialize a transport object's func pointers and state */
+#if ADB_HOST
+int get_available_local_transport_index();
+#endif
+int  init_socket_transport(atransport *t, int s, int port, int local);
+void init_usb_transport(atransport *t, usb_handle *usb, int state);
+
+/* for MacOS X cleanup */
+void close_usb_devices();
+
+/* cause new transports to be init'd and added to the list */
+int register_socket_transport(int s, const char *serial, int port, int local);
+
+/* these should only be used for the "adb disconnect" command */
+void unregister_transport(atransport *t);
+void unregister_all_tcp_transports();
+
+void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable);
+void init_pcie_transport(atransport *t, struct pcie_handle *h, const char *devpath, int state);
+void register_pcie_transport(struct pcie_handle *h, const char *devpath, unsigned writeable);
+
+/* this should only be used for transports with connection_state == CS_NOPERM */
+void unregister_usb_transport(usb_handle *usb);
+
+atransport *find_transport(const char *serial);
+#if ADB_HOST
+atransport* find_emulator_transport_by_adb_port(int adb_port);
+#endif
+
+int service_to_fd(const char *name);
+#if ADB_HOST
+asocket *host_service_to_socket(const char*  name, const char *serial);
+#endif
+
+#if !ADB_HOST
+int       init_jdwp(void);
+asocket*  create_jdwp_service_socket();
+asocket*  create_jdwp_tracker_service_socket();
+int       create_jdwp_connection_fd(int  jdwp_pid);
+#endif
+
+int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
+
+#if !ADB_HOST
+void framebuffer_service(int fd, void *cookie);
+void remount_service(int fd, void *cookie);
+#endif
+
+/* packet allocator */
+apacket *get_apacket(void);
+void put_apacket(apacket *p);
+
+int check_header(apacket *p);
+int check_data(apacket *p);
+
+#if !DEBUG_PACKETS
+#define print_packet(tag,p) do {} while (0)
+#endif
+
+#if ADB_HOST_ON_TARGET
+/* adb and adbd are coexisting on the target, so use 5038 for adb
+ * to avoid conflicting with adbd's usage of 5037
+ */
+#  define DEFAULT_ADB_PORT 5038
+#else
+#  define DEFAULT_ADB_PORT 5037
+#endif
+
+#define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555
+
+#define ADB_CLASS              0xff
+#define ADB_SUBCLASS           0x42
+#define ADB_PROTOCOL           0x1
+
+
+void local_init(int port);
+int  local_connect(int  port);
+int  local_connect_arbitrary_ports(int console_port, int adb_port);
+
+/* usb host/client interface */
+void usb_init();
+void usb_cleanup();
+int usb_write(usb_handle *h, const void *data, int len);
+int usb_read(usb_handle *h, void *data, int len);
+int usb_close(usb_handle *h);
+void usb_kick(usb_handle *h);
+
+/* used for USB device detection */
+#if ADB_HOST
+int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
+#endif
+
+unsigned host_to_le32(unsigned n);
+int adb_commandline(int argc, char **argv);
+
+int connection_state(atransport *t);
+
+#define CS_ANY       -1
+#define CS_OFFLINE    0
+#define CS_BOOTLOADER 1
+#define CS_DEVICE     2
+#define CS_HOST       3
+#define CS_RECOVERY   4
+#define CS_NOPERM     5 /* Insufficient permissions to communicate with the device */
+#define CS_SIDELOAD   6
+#define CS_UNAUTHORIZED 7
+
+extern int HOST;
+extern int SHELL_EXIT_NOTIFY_FD;
+
+typedef enum {
+    SUBPROC_PTY = 0,
+    SUBPROC_RAW = 1,
+} subproc_mode;
+
+#define CHUNK_SIZE (64*1024)
+
+#if !ADB_HOST
+#define USB_ADB_PATH     "/dev/android_adb"
+
+#define USB_FFS_ADB_PATH  "/dev/usb-ffs/adb/"
+#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x
+
+#define USB_FFS_ADB_EP0   USB_FFS_ADB_EP(ep0)
+#define USB_FFS_ADB_OUT   USB_FFS_ADB_EP(ep1)
+#define USB_FFS_ADB_IN    USB_FFS_ADB_EP(ep2)
+#endif
+
+/* PCIe interface */
+#if ADB_OVER_PCIE
+#if ADB_HOST
+#define PCIE_ADB_PATH     "/dev/ccci_sap_adb"
+#else
+#define PCIE_ADB_PATH     "/dev/ccci_hsapif_adb"
+#define PCIE_INFO_ADB_PATH     "/dev/pcie_dipc1"
+#endif /* ADB_HOST */
+#endif /* ADB_OVER_PCIE */
+
+int sendfailmsg(int fd, const char *reason);
+int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
+
+void pcie_init(void);
+void pcie_host_init(void);
+
+#endif
diff --git a/src/devtools/adb/adb_auth.h b/src/devtools/adb/adb_auth.h
new file mode 100755
index 0000000..b24c674
--- /dev/null
+++ b/src/devtools/adb/adb_auth.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ADB_AUTH_H
+#define __ADB_AUTH_H
+
+void adb_auth_init(void);
+void adb_auth_verified(atransport *t);
+
+void send_auth_request(atransport *t);
+
+/* AUTH packets first argument */
+/* Request */
+#define ADB_AUTH_TOKEN         1
+/* Response */
+#define ADB_AUTH_SIGNATURE     2
+#define ADB_AUTH_RSAPUBLICKEY  3
+
+#if ADB_HOST
+
+int adb_auth_sign(void *key, void *token, size_t token_size, void *sig);
+void *adb_auth_nextkey(void *current);
+int adb_auth_get_userkey(unsigned char *data, size_t len);
+
+static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
+static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
+static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
+
+#else // !ADB_HOST
+
+static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; }
+static inline void *adb_auth_nextkey(void *current) { return NULL; }
+static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
+
+int adb_auth_generate_token(void *token, size_t token_size);
+int adb_auth_verify(void *token, void *sig, int siglen);
+void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
+
+#endif // ADB_HOST
+
+#endif // __ADB_AUTH_H
diff --git a/src/devtools/adb/adb_auth_client.c b/src/devtools/adb/adb_auth_client.c
new file mode 100755
index 0000000..4ce5d1e
--- /dev/null
+++ b/src/devtools/adb/adb_auth_client.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <resolv.h>
+#include <cutils/list.h>
+#include <cutils/sockets.h>
+
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_auth.h"
+#include "fdevent.h"
+#include "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+
+#define TRACE_TAG TRACE_AUTH
+
+#ifdef __GLIBC__
+#ifdef b64_pton
+#undef b64_pton
+#endif
+#endif
+
+struct adb_public_key {
+    struct listnode node;
+    RSAPublicKey key;
+};
+
+static char *key_paths[] = {
+    "/adb_keys",
+    "/data/misc/adb/adb_keys",
+    NULL
+};
+
+static fdevent listener_fde;
+static int framework_fd = -1;
+
+static void usb_disconnected(void* unused, atransport* t);
+static struct adisconnect usb_disconnect = { usb_disconnected, 0, 0, 0 };
+static atransport* usb_transport;
+static bool needs_retry = false;
+
+static void read_keys(const char *file, struct listnode *list)
+{
+    struct adb_public_key *key;
+    FILE *f;
+    char buf[MAX_PAYLOAD];
+    char *sep;
+    int ret;
+
+    f = fopen(file, "re");
+    if (!f) {
+        D("Can't open '%s'\n", file);
+        return;
+    }
+
+    while (fgets(buf, sizeof(buf), f)) {
+        /* Allocate 4 extra bytes to decode the base64 data in-place */
+        key = calloc(1, sizeof(*key) + 4);
+        if (!key) {
+            D("Can't malloc key\n");
+            break;
+        }
+
+        sep = strpbrk(buf, " \t");
+        if (sep)
+            *sep = '\0';
+
+        ret = b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4);
+        if (ret != sizeof(key->key)) {
+            D("%s: Invalid base64 data ret=%d\n", file, ret);
+            free(key);
+            continue;
+        }
+
+        if (key->key.len != RSANUMWORDS) {
+            D("%s: Invalid key len %d\n", file, key->key.len);
+            free(key);
+            continue;
+        }
+
+        list_add_tail(list, &key->node);
+    }
+
+    fclose(f);
+}
+
+static void free_keys(struct listnode *list)
+{
+    struct listnode *item;
+
+    while (!list_empty(list)) {
+        item = list_head(list);
+        list_remove(item);
+        free(node_to_item(item, struct adb_public_key, node));
+    }
+}
+
+static void load_keys(struct listnode *list)
+{
+    char *path;
+    char **paths = key_paths;
+    struct stat buf;
+
+    list_init(list);
+
+    while ((path = *paths++)) {
+        if (!stat(path, &buf)) {
+            D("Loading keys from '%s'\n", path);
+            read_keys(path, list);
+        }
+    }
+}
+
+int adb_auth_generate_token(void *token, size_t token_size)
+{
+    FILE *f;
+    int ret;
+
+    f = fopen("/dev/urandom", "re");
+    if (!f)
+        return 0;
+
+    ret = fread(token, token_size, 1, f);
+
+    fclose(f);
+    return ret * token_size;
+}
+
+int adb_auth_verify(void *token, void *sig, int siglen)
+{
+    struct listnode *item;
+    struct adb_public_key *key;
+    struct listnode key_list;
+    int ret = 0;
+
+    if (siglen != RSANUMBYTES)
+        return 0;
+
+    load_keys(&key_list);
+
+    list_for_each(item, &key_list) {
+        key = node_to_item(item, struct adb_public_key, node);
+        ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE);
+        if (ret)
+            break;
+    }
+
+    free_keys(&key_list);
+
+    return ret;
+}
+
+static void usb_disconnected(void* unused, atransport* t)
+{
+    D("USB disconnect\n");
+    remove_transport_disconnect(usb_transport, &usb_disconnect);
+    usb_transport = NULL;
+    needs_retry = false;
+}
+
+static void adb_auth_event(int fd, unsigned events, void *data)
+{
+    char response[2];
+    int ret;
+
+    if (events & FDE_READ) {
+        ret = unix_read(fd, response, sizeof(response));
+        if (ret <= 0) {
+            D("Framework disconnect\n");
+            if (usb_transport)
+                fdevent_remove(&usb_transport->auth_fde);
+            framework_fd = -1;
+        }
+        else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
+            if (usb_transport)
+                adb_auth_verified(usb_transport);
+        }
+    }
+}
+
+void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
+{
+    char msg[MAX_PAYLOAD];
+    int ret;
+
+    if (!usb_transport) {
+        usb_transport = t;
+        add_transport_disconnect(t, &usb_disconnect);
+    }
+
+    if (framework_fd < 0) {
+        D("Client not connected\n");
+        needs_retry = true;
+        return;
+    }
+
+    if (key[len - 1] != '\0') {
+        D("Key must be a null-terminated string\n");
+        return;
+    }
+
+    ret = snprintf(msg, sizeof(msg), "PK%s", key);
+    if (ret >= (signed)sizeof(msg)) {
+        D("Key too long. ret=%d", ret);
+        return;
+    }
+    D("Sending '%s'\n", msg);
+
+    ret = unix_write(framework_fd, msg, ret);
+    if (ret < 0) {
+        D("Failed to write PK, errno=%d\n", errno);
+        return;
+    }
+
+    fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);
+    fdevent_add(&t->auth_fde, FDE_READ);
+}
+
+static void adb_auth_listener(int fd, unsigned events, void *data)
+{
+    struct sockaddr addr;
+    socklen_t alen;
+    int s;
+
+    alen = sizeof(addr);
+
+    s = adb_socket_accept(fd, &addr, &alen);
+    if (s < 0) {
+        D("Failed to accept: errno=%d\n", errno);
+        return;
+    }
+
+    framework_fd = s;
+
+    if (needs_retry) {
+        needs_retry = false;
+        send_auth_request(usb_transport);
+    }
+}
+
+void adb_auth_init(void)
+{
+    int fd, ret;
+
+    fd = android_get_control_socket("adbd");
+    if (fd < 0) {
+        D("Failed to get adbd socket\n");
+        printf("Failed to get adbd socket\n");
+        return;
+    }
+    fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+    ret = listen(fd, 4);
+    if (ret < 0) {
+        D("Failed to listen on '%d'\n", fd);
+        return;
+    }
+
+    fdevent_install(&listener_fde, fd, adb_auth_listener, NULL);
+    fdevent_add(&listener_fde, FDE_READ);
+}
diff --git a/src/devtools/adb/adb_auth_host.c b/src/devtools/adb/adb_auth_host.c
new file mode 100755
index 0000000..c72fe42
--- /dev/null
+++ b/src/devtools/adb/adb_auth_host.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include "windows.h"
+#  include "shlobj.h"
+#else
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  include <unistd.h>
+#endif
+#include <string.h>
+
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_auth.h"
+
+/* HACK: we need the RSAPublicKey struct
+ * but RSA_verify conflits with openssl */
+#define RSA_verify RSA_verify_mincrypt
+#include "mincrypt/rsa.h"
+#undef RSA_verify
+
+#include <cutils/list.h>
+
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/base64.h>
+#endif
+
+#define TRACE_TAG TRACE_AUTH
+
+#define ANDROID_PATH   ".android"
+#define ADB_KEY_FILE   "adbkey"
+
+
+struct adb_private_key {
+    struct listnode node;
+    RSA *rsa;
+};
+
+static struct listnode key_list;
+
+
+/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */
+static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey)
+{
+    int ret = 1;
+    unsigned int i;
+
+    BN_CTX* ctx = BN_CTX_new();
+    BIGNUM* r32 = BN_new();
+    BIGNUM* rr = BN_new();
+    BIGNUM* r = BN_new();
+    BIGNUM* rem = BN_new();
+    BIGNUM* n = BN_new();
+    BIGNUM* n0inv = BN_new();
+
+    if (RSA_size(rsa) != RSANUMBYTES) {
+        ret = 0;
+        goto out;
+    }
+
+    BN_set_bit(r32, 32);
+    BN_copy(n, rsa->n);
+    BN_set_bit(r, RSANUMWORDS * 32);
+    BN_mod_sqr(rr, r, n, ctx);
+    BN_div(NULL, rem, n, r32, ctx);
+    BN_mod_inverse(n0inv, rem, r32, ctx);
+
+    pkey->len = RSANUMWORDS;
+    pkey->n0inv = 0 - BN_get_word(n0inv);
+    for (i = 0; i < RSANUMWORDS; i++) {
+        BN_div(rr, rem, rr, r32, ctx);
+        pkey->rr[i] = BN_get_word(rem);
+        BN_div(n, rem, n, r32, ctx);
+        pkey->n[i] = BN_get_word(rem);
+    }
+    pkey->exponent = BN_get_word(rsa->e);
+
+out:
+    BN_free(n0inv);
+    BN_free(n);
+    BN_free(rem);
+    BN_free(r);
+    BN_free(rr);
+    BN_free(r32);
+    BN_CTX_free(ctx);
+
+    return ret;
+}
+
+static void get_user_info(char *buf, size_t len)
+{
+    char hostname[1024], username[1024];
+    int ret;
+
+#ifndef _WIN32
+    ret = gethostname(hostname, sizeof(hostname));
+    if (ret < 0)
+#endif
+        strcpy(hostname, "unknown");
+
+#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
+    ret = getlogin_r(username, sizeof(username));
+    if (ret < 0)
+#endif
+        strcpy(username, "unknown");
+
+    ret = snprintf(buf, len, " %s@%s", username, hostname);
+    if (ret >= (signed)len)
+        buf[len - 1] = '\0';
+}
+
+static int write_public_keyfile(RSA *private_key, const char *private_key_path)
+{
+    RSAPublicKey pkey;
+    FILE *outfile = NULL;
+    char path[PATH_MAX], info[MAX_PAYLOAD];
+    uint8_t *encoded = NULL;
+    size_t encoded_length;
+    int ret = 0;
+
+    if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >=
+        (int)sizeof(path)) {
+        D("Path too long while writing public key\n");
+        return 0;
+    }
+
+    if (!RSA_to_RSAPublicKey(private_key, &pkey)) {
+        D("Failed to convert to publickey\n");
+        return 0;
+    }
+
+    outfile = fopen(path, "w");
+    if (!outfile) {
+        D("Failed to open '%s'\n", path);
+        return 0;
+    }
+
+    D("Writing public key to '%s'\n", path);
+
+#if defined(OPENSSL_IS_BORINGSSL)
+    if (!EVP_EncodedLength(&encoded_length, sizeof(pkey))) {
+        D("Public key too large to base64 encode");
+        goto out;
+    }
+#else
+    /* While we switch from OpenSSL to BoringSSL we have to implement
+     * |EVP_EncodedLength| here. */
+    encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4);
+#endif
+
+    encoded = malloc(encoded_length);
+    if (encoded == NULL) {
+        D("Allocation failure");
+        goto out;
+    }
+
+    encoded_length = EVP_EncodeBlock(encoded, (uint8_t*) &pkey, sizeof(pkey));
+    get_user_info(info, sizeof(info));
+
+    if (fwrite(encoded, encoded_length, 1, outfile) != 1 ||
+        fwrite(info, strlen(info), 1, outfile) != 1) {
+        D("Write error while writing public key");
+        goto out;
+    }
+
+    ret = 1;
+
+ out:
+    if (outfile != NULL) {
+        fclose(outfile);
+    }
+    if (encoded != NULL) {
+        free(encoded);
+    }
+    return ret;
+}
+
+static int generate_key(const char *file)
+{
+    EVP_PKEY* pkey = EVP_PKEY_new();
+    BIGNUM* exponent = BN_new();
+    RSA* rsa = RSA_new();
+    mode_t old_mask;
+    FILE *f = NULL;
+    int ret = 0;
+
+    D("generate_key '%s'\n", file);
+
+    if (!pkey || !exponent || !rsa) {
+        D("Failed to allocate key\n");
+        goto out;
+    }
+
+    BN_set_word(exponent, RSA_F4);
+    RSA_generate_key_ex(rsa, 2048, exponent, NULL);
+    EVP_PKEY_set1_RSA(pkey, rsa);
+
+    old_mask = umask(077);
+
+    f = fopen(file, "w");
+    if (!f) {
+        D("Failed to open '%s'\n", file);
+        umask(old_mask);
+        goto out;
+    }
+
+    umask(old_mask);
+
+    if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
+        D("Failed to write key\n");
+        goto out;
+    }
+
+    if (!write_public_keyfile(rsa, file)) {
+        D("Failed to write public key\n");
+        goto out;
+    }
+
+    ret = 1;
+
+out:
+    if (f)
+        fclose(f);
+    EVP_PKEY_free(pkey);
+    RSA_free(rsa);
+    BN_free(exponent);
+    return ret;
+}
+
+static int read_key(const char *file, struct listnode *list)
+{
+    struct adb_private_key *key;
+    FILE *f;
+
+    D("read_key '%s'\n", file);
+
+    f = fopen(file, "r");
+    if (!f) {
+        D("Failed to open '%s'\n", file);
+        return 0;
+    }
+
+    key = malloc(sizeof(*key));
+    if (!key) {
+        D("Failed to alloc key\n");
+        fclose(f);
+        return 0;
+    }
+    key->rsa = RSA_new();
+
+    if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) {
+        D("Failed to read key\n");
+        fclose(f);
+        RSA_free(key->rsa);
+        free(key);
+        return 0;
+    }
+
+    fclose(f);
+    list_add_tail(list, &key->node);
+    return 1;
+}
+
+static int get_user_keyfilepath(char *filename, size_t len)
+{
+    const char *format, *home;
+    char android_dir[PATH_MAX];
+    struct stat buf;
+#ifdef _WIN32
+    char path[PATH_MAX];
+    home = getenv("ANDROID_SDK_HOME");
+    if (!home) {
+        SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, path);
+        home = path;
+    }
+    format = "%s\\%s";
+#else
+    home = getenv("HOME");
+    if (!home)
+        return -1;
+    format = "%s/%s";
+#endif
+
+    D("home '%s'\n", home);
+
+    if (snprintf(android_dir, sizeof(android_dir), format, home,
+                        ANDROID_PATH) >= (int)sizeof(android_dir))
+        return -1;
+
+    if (stat(android_dir, &buf)) {
+        if (adb_mkdir(android_dir, 0750) < 0) {
+            D("Cannot mkdir '%s'", android_dir);
+            return -1;
+        }
+    }
+
+    return snprintf(filename, len, format, android_dir, ADB_KEY_FILE);
+}
+
+static int get_user_key(struct listnode *list)
+{
+    struct stat buf;
+    char path[PATH_MAX];
+    int ret;
+
+    ret = get_user_keyfilepath(path, sizeof(path));
+    if (ret < 0 || ret >= (signed)sizeof(path)) {
+        D("Error getting user key filename");
+        return 0;
+    }
+
+    D("user key '%s'\n", path);
+
+    if (stat(path, &buf) == -1) {
+        if (!generate_key(path)) {
+            D("Failed to generate new key\n");
+            return 0;
+        }
+    }
+
+    return read_key(path, list);
+}
+
+static void get_vendor_keys(struct listnode *list)
+{
+    const char *adb_keys_path;
+    char keys_path[MAX_PAYLOAD];
+    char *path;
+    char *save;
+    struct stat buf;
+
+    adb_keys_path = getenv("ADB_VENDOR_KEYS");
+    if (!adb_keys_path)
+        return;
+    strncpy(keys_path, adb_keys_path, sizeof(keys_path));
+
+    path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save);
+    while (path) {
+        D("Reading: '%s'\n", path);
+
+        if (stat(path, &buf))
+            D("Can't read '%s'\n", path);
+        else if (!read_key(path, list))
+            D("Failed to read '%s'\n", path);
+
+        path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save);
+    }
+}
+
+int adb_auth_sign(void *node, void *token, size_t token_size, void *sig)
+{
+    unsigned int len;
+    struct adb_private_key *key = node_to_item(node, struct adb_private_key, node);
+
+    if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) {
+        return 0;
+    }
+
+    D("adb_auth_sign len=%d\n", len);
+    return (int)len;
+}
+
+void *adb_auth_nextkey(void *current)
+{
+    struct listnode *item;
+
+    if (list_empty(&key_list))
+        return NULL;
+
+    if (!current)
+        return list_head(&key_list);
+
+    list_for_each(item, &key_list) {
+        if (item == current) {
+            /* current is the last item, we tried all the keys */
+            if (item->next == &key_list)
+                return NULL;
+            return item->next;
+        }
+    }
+
+    return NULL;
+}
+
+int adb_auth_get_userkey(unsigned char *data, size_t len)
+{
+    char path[PATH_MAX];
+    char *file;
+    int ret;
+
+    ret = get_user_keyfilepath(path, sizeof(path) - 4);
+    if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
+        D("Error getting user key filename");
+        return 0;
+    }
+    strcat(path, ".pub");
+
+    file = load_file(path, (unsigned*)&ret);
+    if (!file) {
+        D("Can't load '%s'\n", path);
+        return 0;
+    }
+
+    if (len < (size_t)(ret + 1)) {
+        D("%s: Content too large ret=%d\n", path, ret);
+        return 0;
+    }
+
+    memcpy(data, file, ret);
+    data[ret] = '\0';
+
+    return ret + 1;
+}
+
+void adb_auth_init(void)
+{
+    int ret;
+
+    D("adb_auth_init\n");
+
+    list_init(&key_list);
+
+    ret = get_user_key(&key_list);
+    if (!ret) {
+        D("Failed to get user key\n");
+        return;
+    }
+
+    get_vendor_keys(&key_list);
+}
diff --git a/src/devtools/adb/adb_client.c b/src/devtools/adb/adb_client.c
new file mode 100755
index 0000000..b511c4b
--- /dev/null
+++ b/src/devtools/adb/adb_client.c
@@ -0,0 +1,347 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <zipfile/zipfile.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sysdeps.h"
+
+#define  TRACE_TAG  TRACE_ADB
+#include "adb_client.h"
+
+static transport_type __adb_transport = kTransportAny;
+static const char* __adb_serial = NULL;
+
+static int __adb_server_port = DEFAULT_ADB_PORT;
+static const char* __adb_server_name = NULL;
+
+void adb_set_transport(transport_type type, const char* serial)
+{
+    __adb_transport = type;
+    __adb_serial = serial;
+}
+
+void adb_set_tcp_specifics(int server_port)
+{
+    __adb_server_port = server_port;
+}
+
+void adb_set_tcp_name(const char* hostname)
+{
+    __adb_server_name = hostname;
+}
+
+int  adb_get_emulator_console_port(void)
+{
+    const char*   serial = __adb_serial;
+    int           port;
+
+    if (serial == NULL) {
+        /* if no specific device was specified, we need to look at */
+        /* the list of connected devices, and extract an emulator  */
+        /* name from it. two emulators is an error                 */
+        char*  tmp = adb_query("host:devices");
+        char*  p   = tmp;
+        if(!tmp) {
+            printf("no emulator connected\n");
+            return -1;
+        }
+        while (*p) {
+            char*  q = strchr(p, '\n');
+            if (q != NULL)
+                *q++ = 0;
+            else
+                q = p + strlen(p);
+
+            if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) {
+                if (serial != NULL) {  /* more than one emulator listed */
+                    free(tmp);
+                    return -2;
+                }
+                serial = p;
+            }
+
+            p = q;
+        }
+        free(tmp);
+
+        if (serial == NULL)
+            return -1;  /* no emulator found */
+    }
+    else {
+        if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0)
+            return -1;  /* not an emulator */
+    }
+
+    serial += sizeof(LOCAL_CLIENT_PREFIX)-1;
+    port    = strtol(serial, NULL, 10);
+    return port;
+}
+
+static char __adb_error[256] = { 0 };
+
+const char *adb_error(void)
+{
+    return __adb_error;
+}
+
+static int switch_socket_transport(int fd)
+{
+    char service[64];
+    char tmp[5];
+    int len;
+
+    if (__adb_serial)
+        snprintf(service, sizeof service, "host:transport:%s", __adb_serial);
+    else {
+        char* transport_type = "???";
+
+         switch (__adb_transport) {
+            case kTransportUsb:
+                transport_type = "transport-usb";
+                break;
+            case kTransportLocal:
+                transport_type = "transport-local";
+                break;
+            case kTransportAny:
+                transport_type = "transport-any";
+                break;
+            case kTransportHost:
+                // no switch necessary
+                return 0;
+                break;
+        }
+
+        snprintf(service, sizeof service, "host:%s", transport_type);
+    }
+    len = strlen(service);
+    snprintf(tmp, sizeof tmp, "%04x", len);
+
+    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
+        strcpy(__adb_error, "write failure during connection");
+        adb_close(fd);
+        return -1;
+    }
+    D("Switch transport in progress\n");
+
+    if(adb_status(fd)) {
+        adb_close(fd);
+        D("Switch transport failed\n");
+        return -1;
+    }
+    D("Switch transport success\n");
+    return 0;
+}
+
+int adb_status(int fd)
+{
+    unsigned char buf[5];
+    unsigned len;
+
+    if(readx(fd, buf, 4)) {
+        strcpy(__adb_error, "protocol fault (no status)");
+        return -1;
+    }
+
+    if(!memcmp(buf, "OKAY", 4)) {
+        return 0;
+    }
+
+    if(memcmp(buf, "FAIL", 4)) {
+        sprintf(__adb_error,
+                "protocol fault (status %02x %02x %02x %02x?!)",
+                buf[0], buf[1], buf[2], buf[3]);
+        return -1;
+    }
+
+    if(readx(fd, buf, 4)) {
+        strcpy(__adb_error, "protocol fault (status len)");
+        return -1;
+    }
+    buf[4] = 0;
+    len = strtoul((char*)buf, 0, 16);
+    if(len > 255) len = 255;
+    if(readx(fd, __adb_error, len)) {
+        strcpy(__adb_error, "protocol fault (status read)");
+        return -1;
+    }
+    __adb_error[len] = 0;
+    return -1;
+}
+
+int _adb_connect(const char *service)
+{
+    char tmp[5];
+    int len;
+    int fd;
+
+    D("_adb_connect: %s\n", service);
+    len = strlen(service);
+    if((len < 1) || (len > 1024)) {
+        strcpy(__adb_error, "service name too long");
+        return -1;
+    }
+    snprintf(tmp, sizeof tmp, "%04x", len);
+
+    if (__adb_server_name)
+        fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
+    else
+        fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
+
+    if(fd < 0) {
+        strcpy(__adb_error, "cannot connect to daemon");
+        return -2;
+    }
+
+    if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
+        return -1;
+    }
+
+    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
+        strcpy(__adb_error, "write failure during connection");
+        adb_close(fd);
+        return -1;
+    }
+
+    if(adb_status(fd)) {
+        adb_close(fd);
+        return -1;
+    }
+
+    D("_adb_connect: return fd %d\n", fd);
+    return fd;
+}
+
+int adb_connect(const char *service)
+{
+    // first query the adb server's version
+    int fd = _adb_connect("host:version");
+
+    D("adb_connect: service %s\n", service);
+    if(fd == -2 && __adb_server_name) {
+        fprintf(stderr,"** Cannot start server on remote host\n");
+        return fd;
+    } else if(fd == -2) {
+        fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
+                __adb_server_port);
+    start_server:
+        if(launch_server(__adb_server_port)) {
+            fprintf(stderr,"* failed to start daemon *\n");
+            return -1;
+        } else {
+            fprintf(stdout,"* daemon started successfully *\n");
+        }
+        /* give the server some time to start properly and detect devices */
+        adb_sleep_ms(3000);
+        // fall through to _adb_connect
+    } else {
+        // if server was running, check its version to make sure it is not out of date
+        char buf[100];
+        size_t n;
+        int version = ADB_SERVER_VERSION - 1;
+
+        // if we have a file descriptor, then parse version result
+        if(fd >= 0) {
+            if(readx(fd, buf, 4)) goto error;
+
+            buf[4] = 0;
+            n = strtoul(buf, 0, 16);
+            if(n > sizeof(buf)) goto error;
+            if(readx(fd, buf, n)) goto error;
+            adb_close(fd);
+
+            if (sscanf(buf, "%04x", &version) != 1) goto error;
+        } else {
+            // if fd is -1, then check for "unknown host service",
+            // which would indicate a version of adb that does not support the version command
+            if (strcmp(__adb_error, "unknown host service") != 0)
+                return fd;
+        }
+
+        if(version != ADB_SERVER_VERSION) {
+            printf("adb server is out of date.  killing...\n");
+            fd = _adb_connect("host:kill");
+            adb_close(fd);
+
+            /* XXX can we better detect its death? */
+            adb_sleep_ms(2000);
+            goto start_server;
+        }
+    }
+
+    // if the command is start-server, we are done.
+    if (!strcmp(service, "host:start-server"))
+        return 0;
+
+    fd = _adb_connect(service);
+    if(fd == -1) {
+        D("_adb_connect error: %s\n", __adb_error);
+    } else if(fd == -2) {
+        fprintf(stderr,"** daemon still not running\n");
+    }
+    D("adb_connect: return fd %d\n", fd);
+
+    return fd;
+error:
+    adb_close(fd);
+    return -1;
+}
+
+
+int adb_command(const char *service)
+{
+    int fd = adb_connect(service);
+    if(fd < 0) {
+        fprintf(stderr, "error: %s\n", adb_error());
+        return -1;
+    }
+
+    if(adb_status(fd)) {
+        adb_close(fd);
+        return -1;
+    }
+
+    return 0;
+}
+
+char *adb_query(const char *service)
+{
+    char buf[5];
+    unsigned n;
+    char *tmp;
+
+    D("adb_query: %s\n", service);
+    int fd = adb_connect(service);
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", __adb_error);
+        return 0;
+    }
+
+    if(readx(fd, buf, 4)) goto oops;
+
+    buf[4] = 0;
+    n = strtoul(buf, 0, 16);
+    if(n >= 0xffff) {
+        strcpy(__adb_error, "reply is too long (>= 64kB)");
+        goto oops;
+    }
+    D("buf = %s\n", buf);
+
+    tmp = malloc(n + 1);
+    if(tmp == 0) goto oops;
+
+    if(readx(fd, tmp, n) == 0) {
+        tmp[n] = 0;
+        adb_close(fd);
+        return tmp;
+    }
+    free(tmp);
+
+oops:
+    adb_close(fd);
+    return 0;
+}
diff --git a/src/devtools/adb/adb_client.h b/src/devtools/adb/adb_client.h
new file mode 100755
index 0000000..0ec47ca
--- /dev/null
+++ b/src/devtools/adb/adb_client.h
@@ -0,0 +1,57 @@
+#ifndef _ADB_CLIENT_H_
+#define _ADB_CLIENT_H_
+
+#include "adb.h"
+
+/* connect to adb, connect to the named service, and return
+** a valid fd for interacting with that service upon success
+** or a negative number on failure
+*/
+int adb_connect(const char *service);
+int _adb_connect(const char *service);
+
+/* connect to adb, connect to the named service, return 0 if
+** the connection succeeded AND the service returned OKAY
+*/
+int adb_command(const char *service);
+
+/* connect to adb, connect to the named service, return
+** a malloc'd string of its response upon success or NULL
+** on failure.
+*/
+char *adb_query(const char *service);
+
+/* Set the preferred transport to connect to.
+*/
+void adb_set_transport(transport_type type, const char* serial);
+
+/* Set TCP specifics of the transport to use
+*/
+void adb_set_tcp_specifics(int server_port);
+
+/* Set TCP Hostname of the transport to use
+*/
+void adb_set_tcp_name(const char* hostname);
+
+/* Return the console port of the currently connected emulator (if any)
+ * of -1 if there is no emulator, and -2 if there is more than one.
+ * assumes adb_set_transport() was alled previously...
+ */
+int  adb_get_emulator_console_port(void);
+
+/* send commands to the current emulator instance. will fail if there
+ * is zero, or more than one emulator connected (or if you use -s <serial>
+ * with a <serial> that does not designate an emulator)
+ */
+int  adb_send_emulator_command(int  argc, char**  argv);
+
+/* return verbose error string from last operation */
+const char *adb_error(void);
+
+/* read a standard adb status response (OKAY|FAIL) and
+** return 0 in the event of OKAY, -1 in the event of FAIL
+** or protocol error
+*/
+int adb_status(int fd);
+
+#endif
diff --git a/src/devtools/adb/adb_trace.h b/src/devtools/adb/adb_trace.h
new file mode 100755
index 0000000..32c3cc6
--- /dev/null
+++ b/src/devtools/adb/adb_trace.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ADB_TRACE_H
+#define __ADB_TRACE_H
+
+#if !ADB_HOST
+#include <android/log.h>
+#endif
+
+/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
+#define  ADB_TRACE    0
+
+/* IMPORTANT: if you change the following list, don't
+ * forget to update the corresponding 'tags' table in
+ * the adb_trace_init() function implemented in adb.c
+ */
+typedef enum {
+    TRACE_ADB = 0,   /* 0x001 */
+    TRACE_SOCKETS,
+    TRACE_PACKETS,
+    TRACE_TRANSPORT,
+    TRACE_RWX,       /* 0x010 */
+    TRACE_USB,
+    TRACE_SYNC,
+    TRACE_SYSDEPS,
+    TRACE_JDWP,      /* 0x100 */
+    TRACE_SERVICES,
+    TRACE_AUTH,
+    TRACE_FDEVENT,
+} AdbTrace;
+
+#if ADB_TRACE
+
+#if !ADB_HOST
+/*
+ * When running inside the emulator, guest's adbd can connect to 'adb-debug'
+ * qemud service that can display adb trace messages (on condition that emulator
+ * has been started with '-debug adb' option).
+ */
+
+/* Delivers a trace message to the emulator via QEMU pipe. */
+void adb_qemu_trace(const char* fmt, ...);
+/* Macro to use to send ADB trace messages to the emulator. */
+#define DQ(...)    adb_qemu_trace(__VA_ARGS__)
+#else
+#define DQ(...) ((void)0)
+#endif  /* !ADB_HOST */
+
+extern int     adb_trace_mask;
+extern unsigned char    adb_trace_output_count;
+void    adb_trace_init(void);
+
+#  define ADB_TRACING  ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
+
+
+/* you must define TRACE_TAG before using this macro */
+#if ADB_HOST
+#  define  D(...)                                      \
+        do {                                           \
+            if (ADB_TRACING) {                         \
+                int save_errno = errno;                \
+                adb_mutex_lock(&D_lock);               \
+                fprintf(stderr, "%s::%s():",           \
+                        __FILE__, __FUNCTION__);       \
+                errno = save_errno;                    \
+                fprintf(stderr, __VA_ARGS__ );         \
+                fflush(stderr);                        \
+                adb_mutex_unlock(&D_lock);             \
+                errno = save_errno;                    \
+           }                                           \
+        } while (0)
+#  define  DR(...)                                     \
+        do {                                           \
+            if (ADB_TRACING) {                         \
+                int save_errno = errno;                \
+                adb_mutex_lock(&D_lock);               \
+                errno = save_errno;                    \
+                fprintf(stderr, __VA_ARGS__ );         \
+                fflush(stderr);                        \
+                adb_mutex_unlock(&D_lock);             \
+                errno = save_errno;                    \
+           }                                           \
+        } while (0)
+#  define  DD(...)                                     \
+        do {                                           \
+          int save_errno = errno;                      \
+          adb_mutex_lock(&D_lock);                     \
+          fprintf(stderr, "%s::%s():",                 \
+                  __FILE__, __FUNCTION__);             \
+          errno = save_errno;                          \
+          fprintf(stderr, __VA_ARGS__ );               \
+          fflush(stderr);                              \
+          adb_mutex_unlock(&D_lock);                   \
+          errno = save_errno;                          \
+        } while (0)
+#else
+#  define  D(...)                                      \
+        do {                                           \
+            if (ADB_TRACING) {                         \
+                __android_log_print(                   \
+                    ANDROID_LOG_INFO,                  \
+                    __FUNCTION__,                      \
+                    __VA_ARGS__ );                     \
+            }                                          \
+        } while (0)
+#  define  DR(...)                                     \
+        do {                                           \
+            if (ADB_TRACING) {                         \
+                __android_log_print(                   \
+                    ANDROID_LOG_INFO,                  \
+                    __FUNCTION__,                      \
+                    __VA_ARGS__ );                     \
+            }                                          \
+        } while (0)
+#  define  DD(...)                                     \
+        do {                                           \
+          __android_log_print(                         \
+              ANDROID_LOG_INFO,                        \
+              __FUNCTION__,                            \
+              __VA_ARGS__ );                           \
+        } while (0)
+#endif /* ADB_HOST */
+#else
+#  define  D(...)          ((void)0)
+#  define  DR(...)         ((void)0)
+#  define  DD(...)         ((void)0)
+#  define  ADB_TRACING     0
+#endif /* ADB_TRACE */
+
+#endif /* __ADB_TRACE_H */
diff --git a/src/devtools/adb/adbd_pcie.init b/src/devtools/adb/adbd_pcie.init
new file mode 100755
index 0000000..d8bf1af
--- /dev/null
+++ b/src/devtools/adb/adbd_pcie.init
@@ -0,0 +1,16 @@
+#!/bin/sh /etc/rc.common
+
+USE_PROCD=1
+
+START=99
+STOP=99
+
+start_service() {
+    echo "start adbd_pcie"
+    procd_set_param stdout 1
+    procd_set_param stderr 1
+    procd_open_instance adbd_pcie
+    procd_set_param command /sbin/adbd_pcie
+    procd_set_param respawn
+    procd_close_instance
+}
diff --git a/src/devtools/adb/b64_pton.c b/src/devtools/adb/b64_pton.c
new file mode 100755
index 0000000..e5c3153
--- /dev/null
+++ b/src/devtools/adb/b64_pton.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+   The following encoding technique is taken from RFC 1521 by Borenstein
+   and Freed.  It is reproduced here in a slightly edited form for
+   convenience.
+
+   A 65-character subset of US-ASCII is used, enabling 6 bits to be
+   represented per printable character. (The extra 65th character, "=",
+   is used to signify a special processing function.)
+
+   The encoding process represents 24-bit groups of input bits as output
+   strings of 4 encoded characters. Proceeding from left to right, a
+   24-bit input group is formed by concatenating 3 8-bit input groups.
+   These 24 bits are then treated as 4 concatenated 6-bit groups, each
+   of which is translated into a single digit in the base64 alphabet.
+
+   Each 6-bit group is used as an index into an array of 64 printable
+   characters. The character referenced by the index is placed in the
+   output string.
+
+                         Table 1: The Base64 Alphabet
+
+      Value Encoding  Value Encoding  Value Encoding  Value Encoding
+          0 A            17 R            34 i            51 z
+          1 B            18 S            35 j            52 0
+          2 C            19 T            36 k            53 1
+          3 D            20 U            37 l            54 2
+          4 E            21 V            38 m            55 3
+          5 F            22 W            39 n            56 4
+          6 G            23 X            40 o            57 5
+          7 H            24 Y            41 p            58 6
+          8 I            25 Z            42 q            59 7
+          9 J            26 a            43 r            60 8
+         10 K            27 b            44 s            61 9
+         11 L            28 c            45 t            62 +
+         12 M            29 d            46 u            63 /
+         13 N            30 e            47 v
+         14 O            31 f            48 w         (pad) =
+         15 P            32 g            49 x
+         16 Q            33 h            50 y
+
+   Special processing is performed if fewer than 24 bits are available
+   at the end of the data being encoded.  A full encoding quantum is
+   always completed at the end of a quantity.  When fewer than 24 input
+   bits are available in an input group, zero bits are added (on the
+   right) to form an integral number of 6-bit groups.  Padding at the
+   end of the data is performed using the '=' character.
+
+   Since all base64 input is an integral number of octets, only the
+   following cases can arise:
+
+       (1) the final quantum of encoding input is an integral
+           multiple of 24 bits; here, the final unit of encoded
+	   output will be an integral multiple of 4 characters
+	   with no "=" padding,
+       (2) the final quantum of encoding input is exactly 8 bits;
+           here, the final unit of encoded output will be two
+	   characters followed by two "=" padding characters, or
+       (3) the final quantum of encoding input is exactly 16 bits;
+           here, the final unit of encoded output will be three
+	   characters followed by one "=" padding character.
+   */
+
+/* skips all whitespace anywhere.
+   converts characters, four at a time, starting at (or after)
+   src from base - 64 numbers into three 8 bit bytes in the target area.
+   it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+static int b64rmap_initialized = 0;
+static uint8_t b64rmap[256];
+
+static const uint8_t b64rmap_special = 0xf0;
+static const uint8_t b64rmap_end = 0xfd;
+static const uint8_t b64rmap_space = 0xfe;
+static const uint8_t b64rmap_invalid = 0xff;
+
+/**
+ * Initializing the reverse map is not thread safe.
+ * Which is fine for NSD. For now...
+ **/
+static void
+b64_initialize_rmap ()
+{
+	int i;
+	char ch;
+
+	/* Null: end of string, stop parsing */
+	b64rmap[0] = b64rmap_end;
+
+	for (i = 1; i < 256; ++i) {
+		ch = (char)i;
+		/* Whitespaces */
+		if (isspace(ch))
+			b64rmap[i] = b64rmap_space;
+		/* Padding: stop parsing */
+		else if (ch == Pad64)
+			b64rmap[i] = b64rmap_end;
+		/* Non-base64 char */
+		else
+			b64rmap[i] = b64rmap_invalid;
+	}
+
+	/* Fill reverse mapping for base64 chars */
+	for (i = 0; Base64[i] != '\0'; ++i)
+		b64rmap[(uint8_t)Base64[i]] = i;
+
+	b64rmap_initialized = 1;
+}
+
+static int
+b64_pton_do(char const *src, uint8_t *target, size_t targsize)
+{
+	int tarindex, state, ch;
+	uint8_t ofs;
+
+	state = 0;
+	tarindex = 0;
+
+	while (1)
+	{
+		ch = *src++;
+		ofs = b64rmap[ch];
+
+		if (ofs >= b64rmap_special) {
+			/* Ignore whitespaces */
+			if (ofs == b64rmap_space)
+				continue;
+			/* End of base64 characters */
+			if (ofs == b64rmap_end)
+				break;
+			/* A non-base64 character. */
+			return (-1);
+		}
+
+		switch (state) {
+		case 0:
+			if ((size_t)tarindex >= targsize)
+				return (-1);
+			target[tarindex] = ofs << 2;
+			state = 1;
+			break;
+		case 1:
+			if ((size_t)tarindex + 1 >= targsize)
+				return (-1);
+			target[tarindex]   |=  ofs >> 4;
+			target[tarindex+1]  = (ofs & 0x0f)
+						<< 4 ;
+			tarindex++;
+			state = 2;
+			break;
+		case 2:
+			if ((size_t)tarindex + 1 >= targsize)
+				return (-1);
+			target[tarindex]   |=  ofs >> 2;
+			target[tarindex+1]  = (ofs & 0x03)
+						<< 6;
+			tarindex++;
+			state = 3;
+			break;
+		case 3:
+			if ((size_t)tarindex >= targsize)
+				return (-1);
+			target[tarindex] |= ofs;
+			tarindex++;
+			state = 0;
+			break;
+		default:
+			abort();
+		}
+	}
+
+	/*
+	 * We are done decoding Base-64 chars.  Let's see if we ended
+	 * on a byte boundary, and/or with erroneous trailing characters.
+	 */
+
+	if (ch == Pad64) {		/* We got a pad char. */
+		ch = *src++;		/* Skip it, get next. */
+		switch (state) {
+		case 0:		/* Invalid = in first position */
+		case 1:		/* Invalid = in second position */
+			return (-1);
+
+		case 2:		/* Valid, means one byte of info */
+			/* Skip any number of spaces. */
+			for ((void)NULL; ch != '\0'; ch = *src++)
+				if (b64rmap[ch] != b64rmap_space)
+					break;
+			/* Make sure there is another trailing = sign. */
+			if (ch != Pad64)
+				return (-1);
+			ch = *src++;		/* Skip the = */
+			/* Fall through to "single trailing =" case. */
+			/* FALLTHROUGH */
+
+		case 3:		/* Valid, means two bytes of info */
+			/*
+			 * We know this char is an =.  Is there anything but
+			 * whitespace after it?
+			 */
+			for ((void)NULL; ch != '\0'; ch = *src++)
+				if (b64rmap[ch] != b64rmap_space)
+					return (-1);
+
+			/*
+			 * Now make sure for cases 2 and 3 that the "extra"
+			 * bits that slopped past the last full byte were
+			 * zeros.  If we don't check them, they become a
+			 * subliminal channel.
+			 */
+			if (target[tarindex] != 0)
+				return (-1);
+		}
+	} else {
+		/*
+		 * We ended by seeing the end of the string.  Make sure we
+		 * have no partial bytes lying around.
+		 */
+		if (state != 0)
+			return (-1);
+	}
+
+	return (tarindex);
+}
+
+
+static int
+b64_pton_len(char const *src)
+{
+	int tarindex, state, ch;
+	uint8_t ofs;
+
+	state = 0;
+	tarindex = 0;
+
+	while (1)
+	{
+		ch = *src++;
+		ofs = b64rmap[ch];
+
+		if (ofs >= b64rmap_special) {
+			/* Ignore whitespaces */
+			if (ofs == b64rmap_space)
+				continue;
+			/* End of base64 characters */
+			if (ofs == b64rmap_end)
+				break;
+			/* A non-base64 character. */
+			return (-1);
+		}
+
+		switch (state) {
+		case 0:
+			state = 1;
+			break;
+		case 1:
+			tarindex++;
+			state = 2;
+			break;
+		case 2:
+			tarindex++;
+			state = 3;
+			break;
+		case 3:
+			tarindex++;
+			state = 0;
+			break;
+		default:
+			abort();
+		}
+	}
+
+	/*
+	 * We are done decoding Base-64 chars.  Let's see if we ended
+	 * on a byte boundary, and/or with erroneous trailing characters.
+	 */
+
+	if (ch == Pad64) {		/* We got a pad char. */
+		ch = *src++;		/* Skip it, get next. */
+		switch (state) {
+		case 0:		/* Invalid = in first position */
+		case 1:		/* Invalid = in second position */
+			return (-1);
+
+		case 2:		/* Valid, means one byte of info */
+			/* Skip any number of spaces. */
+			for ((void)NULL; ch != '\0'; ch = *src++)
+				if (b64rmap[ch] != b64rmap_space)
+					break;
+			/* Make sure there is another trailing = sign. */
+			if (ch != Pad64)
+				return (-1);
+			ch = *src++;		/* Skip the = */
+			/* Fall through to "single trailing =" case. */
+			/* FALLTHROUGH */
+
+		case 3:		/* Valid, means two bytes of info */
+			/*
+			 * We know this char is an =.  Is there anything but
+			 * whitespace after it?
+			 */
+			for ((void)NULL; ch != '\0'; ch = *src++)
+				if (b64rmap[ch] != b64rmap_space)
+					return (-1);
+
+		}
+	} else {
+		/*
+		 * We ended by seeing the end of the string.  Make sure we
+		 * have no partial bytes lying around.
+		 */
+		if (state != 0)
+			return (-1);
+	}
+
+	return (tarindex);
+}
+
+
+int
+b64_pton(char const *src, uint8_t *target, size_t targsize)
+{
+	if (!b64rmap_initialized)
+		b64_initialize_rmap ();
+
+	if (target)
+		return b64_pton_do (src, target, targsize);
+	else
+		return b64_pton_len (src);
+}
diff --git a/src/devtools/adb/commandline.c b/src/devtools/adb/commandline.c
new file mode 100755
index 0000000..1a85de2
--- /dev/null
+++ b/src/devtools/adb/commandline.c
@@ -0,0 +1,2083 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "sysdeps.h"
+
+#if !defined(_WIN32)
+#include <termios.h>
+#endif
+
+#define  TRACE_TAG  TRACE_ADB
+#include "adb.h"
+#include "adb_client.h"
+#include "file_sync_service.h"
+
+static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
+
+void get_my_path(char *s, size_t maxLen);
+int find_sync_dirs(const char *srcarg,
+        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out);
+int install_app(transport_type transport, char* serial, int argc, char** argv);
+int install_multiple_app(transport_type transport, char* serial, int argc, char** argv);
+int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
+
+static const char *gProductOutPath = NULL;
+extern int gListenAll;
+
+static char *product_file(const char *extra)
+{
+    int n;
+    char *x;
+
+    if (gProductOutPath == NULL) {
+        fprintf(stderr, "adb: Product directory not specified; "
+                "use -p or define ANDROID_PRODUCT_OUT\n");
+        exit(1);
+    }
+
+    n = strlen(gProductOutPath) + strlen(extra) + 2;
+    x = malloc(n);
+    if (x == 0) {
+        fprintf(stderr, "adb: Out of memory (product_file())\n");
+        exit(1);
+    }
+
+    snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
+    return x;
+}
+
+void version(FILE * out) {
+    fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
+         ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
+}
+
+void help()
+{
+    version(stderr);
+
+    fprintf(stderr,
+        "\n"
+        " -a                            - directs adb to listen on all interfaces for a connection\n"
+        " -d                            - directs command to the only connected USB device\n"
+        "                                 returns an error if more than one USB device is present.\n"
+        " -e                            - directs command to the only running emulator.\n"
+        "                                 returns an error if more than one emulator is running.\n"
+        " -s <specific device>          - directs command to the device or emulator with the given\n"
+        "                                 serial number or qualifier. Overrides ANDROID_SERIAL\n"
+        "                                 environment variable.\n"
+        " -p <product name or path>     - simple product name like 'sooner', or\n"
+        "                                 a relative/absolute path to a product\n"
+        "                                 out directory like 'out/target/product/sooner'.\n"
+        "                                 If -p is not specified, the ANDROID_PRODUCT_OUT\n"
+        "                                 environment variable is used, which must\n"
+        "                                 be an absolute path.\n"
+        " -H                            - Name of adb server host (default: localhost)\n"
+        " -P                            - Port of adb server (default: 5037)\n"
+        " devices [-l]                  - list all connected devices\n"
+        "                                 ('-l' will also list device qualifiers)\n"
+        " connect <host>[:<port>]       - connect to a device via TCP/IP\n"
+        "                                 Port 5555 is used by default if no port number is specified.\n"
+        " disconnect [<host>[:<port>]]  - disconnect from a TCP/IP device.\n"
+        "                                 Port 5555 is used by default if no port number is specified.\n"
+        "                                 Using this command with no additional arguments\n"
+        "                                 will disconnect from all connected TCP/IP devices.\n"
+        "\n"
+        "device commands:\n"
+        "  adb push [-p] <local> <remote>\n"
+        "                               - copy file/dir to device\n"
+        "                                 ('-p' to display the transfer progress)\n"
+        "  adb pull [-p] [-a] <remote> [<local>]\n"
+        "                               - copy file/dir from device\n"
+        "                                 ('-p' to display the transfer progress)\n"
+        "                                 ('-a' means copy timestamp and mode)\n"
+        "  adb sync [ <directory> ]     - copy host->device only if changed\n"
+        "                                 (-l means list but don't copy)\n"
+        "                                 (see 'adb help all')\n"
+        "  adb shell                    - run remote shell interactively\n"
+        "  adb shell <command>          - run remote shell command\n"
+        "  adb emu <command>            - run emulator console command\n"
+        "  adb logread [ <filter-spec> ] - View device log\n"
+        "  adb forward --list           - list all forward socket connections.\n"
+        "                                 the format is a list of lines with the following format:\n"
+        "                                    <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
+        "  adb forward <local> <remote> - forward socket connections\n"
+        "                                 forward specs are one of: \n"
+        "                                   tcp:<port>\n"
+        "                                   localabstract:<unix domain socket name>\n"
+        "                                   localreserved:<unix domain socket name>\n"
+        "                                   localfilesystem:<unix domain socket name>\n"
+        "                                   dev:<character device name>\n"
+        "                                   jdwp:<process pid> (remote only)\n"
+        "  adb forward --no-rebind <local> <remote>\n"
+        "                               - same as 'adb forward <local> <remote>' but fails\n"
+        "                                 if <local> is already forwarded\n"
+        "  adb forward --remove <local> - remove a specific forward socket connection\n"
+        "  adb forward --remove-all     - remove all forward socket connections\n"
+        "  adb reverse --list           - list all reverse socket connections from device\n"
+        "  adb reverse <remote> <local> - reverse socket connections\n"
+        "                                 reverse specs are one of:\n"
+        "                                   tcp:<port>\n"
+        "                                   localabstract:<unix domain socket name>\n"
+        "                                   localreserved:<unix domain socket name>\n"
+        "                                   localfilesystem:<unix domain socket name>\n"
+        "  adb reverse --norebind <remote> <local>\n"
+        "                               - same as 'adb reverse <remote> <local>' but fails\n"
+        "                                 if <remote> is already reversed.\n"
+        "  adb reverse --remove <remote>\n"
+        "                               - remove a specific reversed socket connection\n"
+        "  adb reverse --remove-all     - remove all reversed socket connections from device\n"
+        "  adb jdwp                     - list PIDs of processes hosting a JDWP transport\n"
+        "  adb install [-lrtsd] <file>\n"
+        "  adb install-multiple [-lrtsdp] <file...>\n"
+        "                               - push this package file to the device and install it\n"
+        "                                 (-l: forward lock application)\n"
+        "                                 (-r: replace existing application)\n"
+        "                                 (-t: allow test packages)\n"
+        "                                 (-s: install application on sdcard)\n"
+        "                                 (-d: allow version code downgrade)\n"
+        "                                 (-p: partial application install)\n"
+        "  adb uninstall [-k] <package> - remove this app package from the device\n"
+        "                                 ('-k' means keep the data and cache directories)\n"
+        "  adb bugreport                - return all information from the device\n"
+        "                                 that should be included in a bug report.\n"
+        "\n"
+        "  adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n"
+        "                               - write an archive of the device's data to <file>.\n"
+        "                                 If no -f option is supplied then the data is written\n"
+        "                                 to \"backup.ab\" in the current directory.\n"
+        "                                 (-apk|-noapk enable/disable backup of the .apks themselves\n"
+        "                                    in the archive; the default is noapk.)\n"
+        "                                 (-obb|-noobb enable/disable backup of any installed apk expansion\n"
+        "                                    (aka .obb) files associated with each application; the default\n"
+        "                                    is noobb.)\n"
+        "                                 (-shared|-noshared enable/disable backup of the device's\n"
+        "                                    shared storage / SD card contents; the default is noshared.)\n"
+        "                                 (-all means to back up all installed applications)\n"
+        "                                 (-system|-nosystem toggles whether -all automatically includes\n"
+        "                                    system applications; the default is to include system apps)\n"
+        "                                 (<packages...> is the list of applications to be backed up.  If\n"
+        "                                    the -all or -shared flags are passed, then the package\n"
+        "                                    list is optional.  Applications explicitly given on the\n"
+        "                                    command line will be included even if -nosystem would\n"
+        "                                    ordinarily cause them to be omitted.)\n"
+        "\n"
+        "  adb restore <file>           - restore device contents from the <file> backup archive\n"
+        "\n"
+        "  adb help                     - show this help message\n"
+        "  adb version                  - show version num\n"
+        "\n"
+        "scripting:\n"
+        "  adb wait-for-device          - block until device is online\n"
+        "  adb start-server             - ensure that there is a server running\n"
+        "  adb kill-server              - kill the server if it is running\n"
+        "  adb get-state                - prints: offline | bootloader | device\n"
+        "  adb get-serialno             - prints: <serial-number>\n"
+        "  adb get-devpath              - prints: <device-path>\n"
+        "  adb status-window            - continuously print device status for a specified device\n"
+        "  adb remount                  - remounts the /system and /vendor (if present) partitions on the device read-write\n"
+        "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
+        "  adb reboot-bootloader        - reboots the device into the bootloader\n"
+        "  adb root                     - restarts the adbd daemon with root permissions\n"
+        "  adb usb                      - restarts the adbd daemon listening on USB\n"
+        "  adb reconnect                - restarts the adbd daemon\n"
+        "  adb tcpip <port>             - restarts the adbd daemon listening on TCP on the specified port"
+        "\n"
+        "networking:\n"
+        "  adb ppp <tty> [parameters]   - Run PPP over USB.\n"
+        " Note: you should not automatically start a PPP connection.\n"
+        " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
+        " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
+        "\n"
+        "adb sync notes: adb sync [ <directory> ]\n"
+        "  <localdir> can be interpreted in several ways:\n"
+        "\n"
+        "  - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n"
+        "\n"
+        "  - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n"
+        "    is updated.\n"
+        "\n"
+        "environmental variables:\n"
+        "  ADB_TRACE                    - Print debug information. A comma separated list of the following values\n"
+        "                                 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
+        "  ANDROID_SERIAL               - The serial number to connect to. -s takes priority over this if given.\n"
+        "  ANDROID_LOG_TAGS             - When used with the logcat option, only these debug tags are printed.\n"
+        );
+}
+
+int usage()
+{
+    help();
+    return 1;
+}
+
+#if defined(_WIN32)
+
+// Windows does not have <termio.h>.
+static void stdin_raw_init(int fd) {
+
+}
+
+static void stdin_raw_restore(int fd) {
+
+}
+
+#else
+static struct termios tio_save;
+
+static void stdin_raw_init(int fd)
+{
+    struct termios tio;
+
+    if(tcgetattr(fd, &tio)) return;
+    if(tcgetattr(fd, &tio_save)) return;
+
+    tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
+
+        /* no timeout but request at least one character per read */
+    tio.c_cc[VTIME] = 0;
+    tio.c_cc[VMIN] = 1;
+
+    tcsetattr(fd, TCSANOW, &tio);
+    tcflush(fd, TCIFLUSH);
+}
+
+static void stdin_raw_restore(int fd)
+{
+    tcsetattr(fd, TCSANOW, &tio_save);
+    tcflush(fd, TCIFLUSH);
+}
+#endif
+
+static void read_and_dump(int fd)
+{
+    char buf[4096];
+    int len;
+
+    while(fd >= 0) {
+        D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
+        len = adb_read(fd, buf, 4096);
+        D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
+        if(len == 0) {
+            break;
+        }
+
+        if(len < 0) {
+            if(errno == EINTR) continue;
+            break;
+        }
+        fwrite(buf, 1, len, stdout);
+        fflush(stdout);
+    }
+}
+
+static void read_status_line(int fd, char* buf, size_t count)
+{
+    count--;
+    while (count > 0) {
+        int len = adb_read(fd, buf, count);
+        if (len == 0) {
+            break;
+        } else if (len < 0) {
+            if (errno == EINTR) continue;
+            break;
+        }
+
+        buf += len;
+        count -= len;
+    }
+    *buf = '\0';
+}
+
+static void copy_to_file(int inFd, int outFd) {
+    const size_t BUFSIZE = 32 * 1024;
+    char* buf = (char*) malloc(BUFSIZE);
+    int len;
+    long total = 0;
+
+    D("copy_to_file(%d -> %d)\n", inFd, outFd);
+
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_init(STDIN_FILENO);
+    }
+
+    for (;;) {
+        if (inFd == STDIN_FILENO) {
+            len = unix_read(inFd, buf, BUFSIZE);
+        } else {
+            len = adb_read(inFd, buf, BUFSIZE);
+        }
+        if (len == 0) {
+            D("copy_to_file() : read 0 bytes; exiting\n");
+            break;
+        }
+        if (len < 0) {
+            if (errno == EINTR) {
+                D("copy_to_file() : EINTR, retrying\n");
+                continue;
+            }
+            D("copy_to_file() : error %d\n", errno);
+            break;
+        }
+        if (outFd == STDOUT_FILENO) {
+            fwrite(buf, 1, len, stdout);
+            fflush(stdout);
+        } else {
+            adb_write(outFd, buf, len);
+        }
+        total += len;
+    }
+
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_restore(STDIN_FILENO);
+    }
+
+    D("copy_to_file() finished after %lu bytes\n", total);
+    free(buf);
+}
+
+static void *stdin_read_thread(void *x)
+{
+    int fd, fdi;
+    unsigned char buf[1024];
+    int r, n;
+    int state = 0;
+
+    int *fds = (int*) x;
+    fd = fds[0];
+    fdi = fds[1];
+    free(fds);
+
+    for(;;) {
+        /* fdi is really the client's stdin, so use read, not adb_read here */
+        D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
+        r = unix_read(fdi, buf, 1024);
+        D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
+        if(r == 0) break;
+        if(r < 0) {
+            if(errno == EINTR) continue;
+            break;
+        }
+        for(n = 0; n < r; n++){
+            switch(buf[n]) {
+            case '\n':
+                state = 1;
+                break;
+            case '\r':
+                state = 1;
+                break;
+            case '~':
+                if(state == 1) state++;
+                break;
+            case '.':
+                if(state == 2) {
+                    fprintf(stderr,"\n* disconnect *\n");
+                    stdin_raw_restore(fdi);
+                    exit(0);
+                }
+            default:
+                state = 0;
+            }
+        }
+        r = adb_write(fd, buf, r);
+        if(r <= 0) {
+            break;
+        }
+    }
+    return 0;
+}
+
+int interactive_shell(void)
+{
+    adb_thread_t thr;
+    int fdi, fd;
+    int *fds;
+
+    fd = adb_connect("shell:");
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", adb_error());
+        return 1;
+    }
+    fdi = 0; //dup(0);
+
+    fds = malloc(sizeof(int) * 2);
+    fds[0] = fd;
+    fds[1] = fdi;
+
+    stdin_raw_init(fdi);
+    adb_thread_create(&thr, stdin_read_thread, fds);
+    read_and_dump(fd);
+    stdin_raw_restore(fdi);
+    return 0;
+}
+
+
+static void format_host_command(char* buffer, size_t  buflen, const char* command, transport_type ttype, const char* serial)
+{
+    if (serial) {
+        snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
+    } else {
+        const char* prefix = "host";
+        if (ttype == kTransportUsb)
+            prefix = "host-usb";
+        else if (ttype == kTransportLocal)
+            prefix = "host-local";
+
+        snprintf(buffer, buflen, "%s:%s", prefix, command);
+    }
+}
+
+int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
+                        unsigned progress)
+{
+    char buf[4096];
+    unsigned total;
+    int fd;
+    const unsigned char *ptr;
+
+    sprintf(buf,"%s:%d", service, sz);
+    fd = adb_connect(buf);
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", adb_error());
+        return -1;
+    }
+
+    int opt = CHUNK_SIZE;
+    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+
+    total = sz;
+    ptr = data;
+
+    if(progress) {
+        char *x = strrchr(service, ':');
+        if(x) service = x + 1;
+    }
+
+    while(sz > 0) {
+        unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
+        if(writex(fd, ptr, xfer)) {
+            adb_status(fd);
+            fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
+            return -1;
+        }
+        sz -= xfer;
+        ptr += xfer;
+        if(progress) {
+            printf("sending: '%s' %4d%%    \r", fn, (int)(100LL - ((100LL * sz) / (total))));
+            fflush(stdout);
+        }
+    }
+    if(progress) {
+        printf("\n");
+    }
+
+    if(readx(fd, buf, 4)){
+        fprintf(stderr,"* error reading response *\n");
+        adb_close(fd);
+        return -1;
+    }
+    if(memcmp(buf, "OKAY", 4)) {
+        buf[4] = 0;
+        fprintf(stderr,"* error response '%s' *\n", buf);
+        adb_close(fd);
+        return -1;
+    }
+
+    adb_close(fd);
+    return 0;
+}
+
+
+int adb_download(const char *service, const char *fn, unsigned progress)
+{
+    void *data;
+    unsigned sz;
+
+    data = load_file(fn, &sz);
+    if(data == 0) {
+        fprintf(stderr,"* cannot read '%s' *\n", fn);
+        return -1;
+    }
+
+    int status = adb_download_buffer(service, fn, data, sz, progress);
+    free(data);
+    return status;
+}
+
+#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
+
+/*
+ * The sideload-host protocol serves the data in a file (given on the
+ * command line) to the client, using a simple protocol:
+ *
+ * - The connect message includes the total number of bytes in the
+ *   file and a block size chosen by us.
+ *
+ * - The other side sends the desired block number as eight decimal
+ *   digits (eg "00000023" for block 23).  Blocks are numbered from
+ *   zero.
+ *
+ * - We send back the data of the requested block.  The last block is
+ *   likely to be partial; when the last block is requested we only
+ *   send the part of the block that exists, it's not padded up to the
+ *   block size.
+ *
+ * - When the other side sends "DONEDONE" instead of a block number,
+ *   we hang up.
+ */
+int adb_sideload_host(const char* fn) {
+    uint8_t* data;
+    unsigned sz;
+    size_t xfer = 0;
+    int status;
+
+    printf("loading: '%s'", fn);
+    fflush(stdout);
+    data = load_file(fn, &sz);
+    if (data == 0) {
+        printf("\n");
+        fprintf(stderr, "* cannot read '%s' *\n", fn);
+        return -1;
+    }
+
+    char buf[100];
+    sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
+    int fd = adb_connect(buf);
+    if (fd < 0) {
+        // Try falling back to the older sideload method.  Maybe this
+        // is an older device that doesn't support sideload-host.
+        printf("\n");
+        status = adb_download_buffer("sideload", fn, data, sz, 1);
+        goto done;
+    }
+
+    int opt = SIDELOAD_HOST_BLOCK_SIZE;
+    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+
+    int last_percent = -1;
+    for (;;) {
+        if (readx(fd, buf, 8)) {
+            fprintf(stderr, "* failed to read command: %s\n", adb_error());
+            status = -1;
+            goto done;
+        }
+
+        if (strncmp("DONEDONE", buf, 8) == 0) {
+            status = 0;
+            break;
+        }
+
+        buf[8] = '\0';
+        int block = strtol(buf, NULL, 10);
+
+        size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
+        if (offset >= sz) {
+            fprintf(stderr, "* attempt to read past end: %s\n", adb_error());
+            status = -1;
+            goto done;
+        }
+        uint8_t* start = data + offset;
+        size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE;
+        size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
+        if (offset_end > sz) {
+            to_write = sz - offset;
+        }
+
+        if(writex(fd, start, to_write)) {
+            adb_status(fd);
+            fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
+            status = -1;
+            goto done;
+        }
+        xfer += to_write;
+
+        // For normal OTA packages, we expect to transfer every byte
+        // twice, plus a bit of overhead (one read during
+        // verification, one read of each byte for installation, plus
+        // extra access to things like the zip central directory).
+        // This estimate of the completion becomes 100% when we've
+        // transferred ~2.13 (=100/47) times the package size.
+        int percent = (int)(xfer * 47LL / (sz ? sz : 1));
+        if (percent != last_percent) {
+            printf("\rserving: '%s'  (~%d%%)    ", fn, percent);
+            fflush(stdout);
+            last_percent = percent;
+        }
+    }
+
+    printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
+
+  done:
+    if (fd >= 0) adb_close(fd);
+    free(data);
+    return status;
+}
+
+static void status_window(transport_type ttype, const char* serial)
+{
+    char command[4096];
+    char *state = 0;
+    char *laststate = 0;
+
+        /* silence stderr */
+#ifdef _WIN32
+    /* XXX: TODO */
+#else
+    int  fd;
+    fd = unix_open("/dev/null", O_WRONLY);
+    dup2(fd, 2);
+    adb_close(fd);
+#endif
+
+    format_host_command(command, sizeof command, "get-state", ttype, serial);
+
+    for(;;) {
+        adb_sleep_ms(250);
+
+        if(state) {
+            free(state);
+            state = 0;
+        }
+
+        state = adb_query(command);
+
+        if(state) {
+            if(laststate && !strcmp(state,laststate)){
+                continue;
+            } else {
+                if(laststate) free(laststate);
+                laststate = strdup(state);
+            }
+        }
+
+        printf("%c[2J%c[2H", 27, 27);
+        printf("Android Debug Bridge\n");
+        printf("State: %s\n", state ? state : "offline");
+        fflush(stdout);
+    }
+}
+
+static int should_escape(const char c)
+{
+    return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
+}
+
+/* Duplicate and escape given argument. */
+static char *escape_arg(const char *s)
+{
+    const char *ts;
+    size_t alloc_len;
+    char *ret;
+    char *dest;
+
+    alloc_len = 0;
+    for (ts = s; *ts != '\0'; ts++) {
+        alloc_len++;
+        if (should_escape(*ts)) {
+            alloc_len++;
+        }
+    }
+
+    if (alloc_len == 0) {
+        // Preserve empty arguments
+        ret = (char *) malloc(3);
+        ret[0] = '\"';
+        ret[1] = '\"';
+        ret[2] = '\0';
+        return ret;
+    }
+
+    ret = (char *) malloc(alloc_len + 1);
+    dest = ret;
+
+    for (ts = s; *ts != '\0'; ts++) {
+        if (should_escape(*ts)) {
+            *dest++ = '\\';
+        }
+        *dest++ = *ts;
+    }
+    *dest++ = '\0';
+
+    return ret;
+}
+
+/**
+ * Run ppp in "notty" mode against a resource listed as the first parameter
+ * eg:
+ *
+ * ppp dev:/dev/omap_csmi_tty0 <ppp options>
+ *
+ */
+int ppp(int argc, char **argv)
+{
+#if defined(_WIN32)
+    fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
+    return -1;
+#else
+    char *adb_service_name;
+    pid_t pid;
+    int fd;
+
+    if (argc < 2) {
+        fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
+                argv[0]);
+
+        return 1;
+    }
+
+    adb_service_name = argv[1];
+
+    fd = adb_connect(adb_service_name);
+
+    if(fd < 0) {
+        fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
+                adb_service_name, adb_error());
+        return 1;
+    }
+
+    pid = fork();
+
+    if (pid < 0) {
+        perror("from fork()");
+        return 1;
+    } else if (pid == 0) {
+        int err;
+        int i;
+        const char **ppp_args;
+
+        // copy args
+        ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
+        ppp_args[0] = "pppd";
+        for (i = 2 ; i < argc ; i++) {
+            //argv[2] and beyond become ppp_args[1] and beyond
+            ppp_args[i - 1] = argv[i];
+        }
+        ppp_args[i-1] = NULL;
+
+        // child side
+
+        dup2(fd, STDIN_FILENO);
+        dup2(fd, STDOUT_FILENO);
+        adb_close(STDERR_FILENO);
+        adb_close(fd);
+
+        err = execvp("pppd", (char * const *)ppp_args);
+
+        if (err < 0) {
+            perror("execing pppd");
+        }
+        exit(-1);
+    } else {
+        // parent side
+
+        adb_close(fd);
+        return 0;
+    }
+#endif /* !defined(_WIN32) */
+}
+
+static int send_shellcommand(transport_type transport, char* serial, char* buf)
+{
+    int fd, ret;
+
+    for(;;) {
+        fd = adb_connect(buf);
+        if(fd >= 0)
+            break;
+        fprintf(stderr,"- waiting for device -\n");
+        adb_sleep_ms(1000);
+        do_cmd(transport, serial, "wait-for-device", 0);
+    }
+
+    read_and_dump(fd);
+    ret = adb_close(fd);
+    if (ret)
+        perror("close");
+
+    return ret;
+}
+
+static int logcat(transport_type transport, char* serial, int argc, char **argv)
+{
+    char buf[4096];
+
+    char *log_tags;
+    char *quoted;
+
+    log_tags = getenv("ANDROID_LOG_TAGS");
+    quoted = escape_arg(log_tags == NULL ? "" : log_tags);
+    snprintf(buf, sizeof(buf),
+            "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted);
+    free(quoted);
+
+    if (!strcmp(argv[0], "longcat")) {
+        strncat(buf, " -v long", sizeof(buf) - 1);
+    }
+
+    argc -= 1;
+    argv += 1;
+    while(argc-- > 0) {
+        quoted = escape_arg(*argv++);
+        strncat(buf, " ", sizeof(buf) - 1);
+        strncat(buf, quoted, sizeof(buf) - 1);
+        free(quoted);
+    }
+
+    send_shellcommand(transport, serial, buf);
+    return 0;
+}
+
+static int mkdirs(const char *path)
+{
+    int ret;
+    char *x = (char *)path + 1;
+
+    for(;;) {
+        x = adb_dirstart(x);
+        if(x == 0) return 0;
+        *x = 0;
+        ret = adb_mkdir(path, 0775);
+        *x = OS_PATH_SEPARATOR;
+        if((ret < 0) && (errno != EEXIST)) {
+            return ret;
+        }
+        x++;
+    }
+    return 0;
+}
+
+static int backup(int argc, char** argv) {
+    char buf[4096];
+    char default_name[32];
+    const char* filename = strcpy(default_name, "./backup.ab");
+    int fd, outFd;
+    int i, j;
+
+    /* find, extract, and use any -f argument */
+    for (i = 1; i < argc; i++) {
+        if (!strcmp("-f", argv[i])) {
+            if (i == argc-1) {
+                fprintf(stderr, "adb: -f passed with no filename\n");
+                return usage();
+            }
+            filename = argv[i+1];
+            for (j = i+2; j <= argc; ) {
+                argv[i++] = argv[j++];
+            }
+            argc -= 2;
+            argv[argc] = NULL;
+        }
+    }
+
+    /* bare "adb backup" or "adb backup -f filename" are not valid invocations */
+    if (argc < 2) return usage();
+
+    adb_unlink(filename);
+    mkdirs(filename);
+    outFd = adb_creat(filename, 0640);
+    if (outFd < 0) {
+        fprintf(stderr, "adb: unable to open file %s\n", filename);
+        return -1;
+    }
+
+    snprintf(buf, sizeof(buf), "backup");
+    for (argc--, argv++; argc; argc--, argv++) {
+        strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
+        strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
+    }
+
+    D("backup. filename=%s buf=%s\n", filename, buf);
+    fd = adb_connect(buf);
+    if (fd < 0) {
+        fprintf(stderr, "adb: unable to connect for backup\n");
+        adb_close(outFd);
+        return -1;
+    }
+
+    printf("Now unlock your device and confirm the backup operation.\n");
+    copy_to_file(fd, outFd);
+
+    adb_close(fd);
+    adb_close(outFd);
+    return 0;
+}
+
+static int restore(int argc, char** argv) {
+    const char* filename;
+    int fd, tarFd;
+
+    if (argc != 2) return usage();
+
+    filename = argv[1];
+    tarFd = adb_open(filename, O_RDONLY);
+    if (tarFd < 0) {
+        fprintf(stderr, "adb: unable to open file %s\n", filename);
+        return -1;
+    }
+
+    fd = adb_connect("restore:");
+    if (fd < 0) {
+        fprintf(stderr, "adb: unable to connect for restore\n");
+        adb_close(tarFd);
+        return -1;
+    }
+
+    printf("Now unlock your device and confirm the restore operation.\n");
+    copy_to_file(tarFd, fd);
+
+    adb_close(fd);
+    adb_close(tarFd);
+    return 0;
+}
+
+#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
+static int top_works(const char *top)
+{
+    if (top != NULL && adb_is_absolute_host_path(top)) {
+        char path_buf[PATH_MAX];
+        snprintf(path_buf, sizeof(path_buf),
+                "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
+        return access(path_buf, F_OK) == 0;
+    }
+    return 0;
+}
+
+static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
+{
+    strcpy(path_buf, indir);
+    while (1) {
+        if (top_works(path_buf)) {
+            return path_buf;
+        }
+        char *s = adb_dirstop(path_buf);
+        if (s != NULL) {
+            *s = '\0';
+        } else {
+            path_buf[0] = '\0';
+            return NULL;
+        }
+    }
+}
+
+static char *find_top(char path_buf[PATH_MAX])
+{
+    char *top = getenv("ANDROID_BUILD_TOP");
+    if (top != NULL && top[0] != '\0') {
+        if (!top_works(top)) {
+            fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
+            return NULL;
+        }
+    } else {
+        top = getenv("TOP");
+        if (top != NULL && top[0] != '\0') {
+            if (!top_works(top)) {
+                fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
+                return NULL;
+            }
+        } else {
+            top = NULL;
+        }
+    }
+
+    if (top != NULL) {
+        /* The environment pointed to a top directory that works.
+         */
+        strcpy(path_buf, top);
+        return path_buf;
+    }
+
+    /* The environment didn't help.  Walk up the tree from the CWD
+     * to see if we can find the top.
+     */
+    char dir[PATH_MAX];
+    top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
+    if (top == NULL) {
+        /* If the CWD isn't under a good-looking top, see if the
+         * executable is.
+         */
+        get_my_path(dir, PATH_MAX);
+        top = find_top_from(dir, path_buf);
+    }
+    return top;
+}
+
+/* <hint> may be:
+ * - A simple product name
+ *   e.g., "sooner"
+TODO: debug?  sooner-debug, sooner:debug?
+ * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
+ *   e.g., "out/target/product/sooner"
+ * - An absolute path to the PRODUCT_OUT dir
+ *   e.g., "/src/device/out/target/product/sooner"
+ *
+ * Given <hint>, try to construct an absolute path to the
+ * ANDROID_PRODUCT_OUT dir.
+ */
+static const char *find_product_out_path(const char *hint)
+{
+    static char path_buf[PATH_MAX];
+
+    if (hint == NULL || hint[0] == '\0') {
+        return NULL;
+    }
+
+    /* If it's already absolute, don't bother doing any work.
+     */
+    if (adb_is_absolute_host_path(hint)) {
+        strcpy(path_buf, hint);
+        return path_buf;
+    }
+
+    /* If there are any slashes in it, assume it's a relative path;
+     * make it absolute.
+     */
+    if (adb_dirstart(hint) != NULL) {
+        if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
+            fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
+            return NULL;
+        }
+        if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
+            fprintf(stderr, "adb: Couldn't assemble path\n");
+            return NULL;
+        }
+        strcat(path_buf, OS_PATH_SEPARATOR_STR);
+        strcat(path_buf, hint);
+        return path_buf;
+    }
+
+    /* It's a string without any slashes.  Try to do something with it.
+     *
+     * Try to find the root of the build tree, and build a PRODUCT_OUT
+     * path from there.
+     */
+    char top_buf[PATH_MAX];
+    const char *top = find_top(top_buf);
+    if (top == NULL) {
+        fprintf(stderr, "adb: Couldn't find top of build tree\n");
+        return NULL;
+    }
+//TODO: if we have a way to indicate debug, look in out/debug/target/...
+    snprintf(path_buf, sizeof(path_buf),
+            "%s" OS_PATH_SEPARATOR_STR
+            "out" OS_PATH_SEPARATOR_STR
+            "target" OS_PATH_SEPARATOR_STR
+            "product" OS_PATH_SEPARATOR_STR
+            "%s", top_buf, hint);
+    if (access(path_buf, F_OK) < 0) {
+        fprintf(stderr, "adb: Couldn't find a product dir "
+                "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
+        return NULL;
+    }
+    return path_buf;
+}
+
+static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2,
+                                 int *show_progress, int *copy_attrs) {
+    *show_progress = 0;
+    *copy_attrs = 0;
+
+    while (narg > 0) {
+        if (!strcmp(*arg, "-p")) {
+            *show_progress = 1;
+        } else if (!strcmp(*arg, "-a")) {
+            *copy_attrs = 1;
+        } else {
+            break;
+        }
+        ++arg;
+        --narg;
+    }
+
+    if (narg > 0) {
+        *path1 = *arg;
+        ++arg;
+        --narg;
+    }
+
+    if (narg > 0) {
+        *path2 = *arg;
+    }
+}
+
+int adb_commandline(int argc, char **argv)
+{
+    char buf[4096];
+    int no_daemon = 0;
+    int is_daemon = 0;
+    int is_server = 0;
+    int persist = 0;
+    int r;
+    transport_type ttype = kTransportAny;
+    char* serial = NULL;
+    char* server_port_str = NULL;
+
+        /* If defined, this should be an absolute path to
+         * the directory containing all of the various system images
+         * for a particular product.  If not defined, and the adb
+         * command requires this information, then the user must
+         * specify the path using "-p".
+         */
+    gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
+    if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
+        gProductOutPath = NULL;
+    }
+    // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
+
+    serial = getenv("ANDROID_SERIAL");
+
+    /* Validate and assign the server port */
+    server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
+    int server_port = DEFAULT_ADB_PORT;
+    if (server_port_str && strlen(server_port_str) > 0) {
+        server_port = (int) strtol(server_port_str, NULL, 0);
+        if (server_port <= 0 || server_port > 65535) {
+            fprintf(stderr,
+                    "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
+                    server_port_str);
+            return usage();
+        }
+    }
+
+    /* modifiers and flags */
+    while(argc > 0) {
+        if(!strcmp(argv[0],"server")) {
+            is_server = 1;
+        } else if(!strcmp(argv[0],"nodaemon")) {
+            no_daemon = 1;
+        } else if (!strcmp(argv[0], "fork-server")) {
+            /* this is a special flag used only when the ADB client launches the ADB Server */
+            is_daemon = 1;
+        } else if(!strcmp(argv[0],"persist")) {
+            persist = 1;
+        } else if(!strncmp(argv[0], "-p", 2)) {
+            const char *product = NULL;
+            if (argv[0][2] == '\0') {
+                if (argc < 2) return usage();
+                product = argv[1];
+                argc--;
+                argv++;
+            } else {
+                product = argv[0] + 2;
+            }
+            gProductOutPath = find_product_out_path(product);
+            if (gProductOutPath == NULL) {
+                fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
+                        product);
+                return usage();
+            }
+        } else if (argv[0][0]=='-' && argv[0][1]=='s') {
+            if (isdigit(argv[0][2])) {
+                serial = argv[0] + 2;
+            } else {
+                if(argc < 2 || argv[0][2] != '\0') return usage();
+                serial = argv[1];
+                argc--;
+                argv++;
+            }
+        } else if (!strcmp(argv[0],"-d")) {
+            ttype = kTransportUsb;
+        } else if (!strcmp(argv[0],"-e")) {
+            ttype = kTransportLocal;
+        } else if (!strcmp(argv[0],"-a")) {
+            gListenAll = 1;
+        } else if(!strncmp(argv[0], "-H", 2)) {
+            const char *hostname = NULL;
+            if (argv[0][2] == '\0') {
+                if (argc < 2) return usage();
+                hostname = argv[1];
+                argc--;
+                argv++;
+            } else {
+                hostname = argv[0] + 2;
+            }
+            adb_set_tcp_name(hostname);
+
+        } else if(!strncmp(argv[0], "-P", 2)) {
+            if (argv[0][2] == '\0') {
+                if (argc < 2) return usage();
+                server_port_str = argv[1];
+                argc--;
+                argv++;
+            } else {
+                server_port_str = argv[0] + 2;
+            }
+            if (strlen(server_port_str) > 0) {
+                server_port = (int) strtol(server_port_str, NULL, 0);
+                if (server_port <= 0 || server_port > 65535) {
+                    fprintf(stderr,
+                            "adb: port number must be a positive number less than 65536. Got \"%s\"\n",
+                            server_port_str);
+                    return usage();
+                }
+            } else {
+                fprintf(stderr,
+                "adb: port number must be a positive number less than 65536. Got empty string.\n");
+                return usage();
+            }
+        } else {
+                /* out of recognized modifiers and flags */
+            break;
+        }
+        argc--;
+        argv++;
+    }
+
+    adb_set_transport(ttype, serial);
+    adb_set_tcp_specifics(server_port);
+
+    if (is_server) {
+        if (no_daemon || is_daemon) {
+            r = adb_main(is_daemon, server_port);
+        } else {
+            r = launch_server(server_port);
+        }
+        if(r) {
+            fprintf(stderr,"* could not start server *\n");
+        }
+        return r;
+    }
+
+top:
+    if(argc == 0) {
+        return usage();
+    }
+
+    /* adb_connect() commands */
+
+    if(!strcmp(argv[0], "devices")) {
+        char *tmp;
+        char *listopt;
+        if (argc < 2)
+            listopt = "";
+        else if (argc == 2 && !strcmp(argv[1], "-l"))
+            listopt = argv[1];
+        else {
+            fprintf(stderr, "Usage: adb devices [-l]\n");
+            return 1;
+        }
+        snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
+        tmp = adb_query(buf);
+        if(tmp) {
+            printf("List of devices attached \n");
+            printf("%s\n", tmp);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    if(!strcmp(argv[0], "connect")) {
+        char *tmp;
+        if (argc != 2) {
+            fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
+            return 1;
+        }
+        snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
+        tmp = adb_query(buf);
+        if(tmp) {
+            printf("%s\n", tmp);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    if(!strcmp(argv[0], "disconnect")) {
+        char *tmp;
+        if (argc > 2) {
+            fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
+            return 1;
+        }
+        if (argc == 2) {
+            snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
+        } else {
+            snprintf(buf, sizeof buf, "host:disconnect:");
+        }
+        tmp = adb_query(buf);
+        if(tmp) {
+            printf("%s\n", tmp);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    if (!strcmp(argv[0], "emu")) {
+        return adb_send_emulator_command(argc, argv);
+    }
+
+    if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
+        int r;
+        int fd;
+
+        char h = (argv[0][0] == 'h');
+
+        if (h) {
+            printf("\x1b[41;33m");
+            fflush(stdout);
+        }
+
+        if(argc < 2) {
+            D("starting interactive shell\n");
+            r = interactive_shell();
+            if (h) {
+                printf("\x1b[0m");
+                fflush(stdout);
+            }
+            return r;
+        }
+
+        snprintf(buf, sizeof(buf), "shell:%s", argv[1]);
+        argc -= 2;
+        argv += 2;
+        while (argc-- > 0) {
+            char *quoted = escape_arg(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
+        }
+
+        for(;;) {
+            D("interactive shell loop. buff=%s\n", buf);
+            fd = adb_connect(buf);
+            if(fd >= 0) {
+                D("about to read_and_dump(fd=%d)\n", fd);
+                read_and_dump(fd);
+                D("read_and_dump() done.\n");
+                adb_close(fd);
+                r = 0;
+            } else {
+                fprintf(stderr,"error: %s\n", adb_error());
+                r = -1;
+            }
+
+            if(persist) {
+                fprintf(stderr,"\n- waiting for device -\n");
+                adb_sleep_ms(1000);
+                do_cmd(ttype, serial, "wait-for-device", 0);
+            } else {
+                if (h) {
+                    printf("\x1b[0m");
+                    fflush(stdout);
+                }
+                D("interactive shell loop. return r=%d\n", r);
+                return r;
+            }
+        }
+    }
+
+    if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
+        int exec_in = !strcmp(argv[0], "exec-in");
+        int fd;
+
+        snprintf(buf, sizeof buf, "exec:%s", argv[1]);
+        argc -= 2;
+        argv += 2;
+        while (argc-- > 0) {
+            char *quoted = escape_arg(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
+        }
+
+        fd = adb_connect(buf);
+        if (fd < 0) {
+            fprintf(stderr, "error: %s\n", adb_error());
+            return -1;
+        }
+
+        if (exec_in) {
+            copy_to_file(STDIN_FILENO, fd);
+        } else {
+            copy_to_file(fd, STDOUT_FILENO);
+        }
+
+        adb_close(fd);
+        return 0;
+    }
+
+    if(!strcmp(argv[0], "kill-server")) {
+        int fd;
+        fd = _adb_connect("host:kill");
+        if(fd == -1) {
+            fprintf(stderr,"* server not running *\n");
+            return 1;
+        }
+        return 0;
+    }
+
+    if(!strcmp(argv[0], "sideload")) {
+        if(argc != 2) return usage();
+        if (adb_sideload_host(argv[1])) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
+            || !strcmp(argv[0], "reboot-bootloader")
+            || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
+            || !strcmp(argv[0], "root") || !strcmp(argv[0], "reconnect")) {
+        char command[100];
+        if (!strcmp(argv[0], "reboot-bootloader"))
+            snprintf(command, sizeof(command), "reboot:bootloader");
+        else if (argc > 1)
+            snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
+        else
+            snprintf(command, sizeof(command), "%s:", argv[0]);
+        int fd = adb_connect(command);
+        if(fd >= 0) {
+            read_and_dump(fd);
+            adb_close(fd);
+            return 0;
+        }
+        fprintf(stderr,"error: %s\n", adb_error());
+        return 1;
+    }
+
+    if(!strcmp(argv[0], "bugreport")) {
+        if (argc != 1) return usage();
+        do_cmd(ttype, serial, "shell", "bugreport", 0);
+        return 0;
+    }
+
+    /* adb_command() wrapper commands */
+
+    if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
+        char* service = argv[0];
+        if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
+            if (ttype == kTransportUsb) {
+                service = "wait-for-usb";
+            } else if (ttype == kTransportLocal) {
+                service = "wait-for-local";
+            } else {
+                service = "wait-for-any";
+            }
+        }
+
+        format_host_command(buf, sizeof buf, service, ttype, serial);
+
+        if (adb_command(buf)) {
+            D("failure: %s *\n",adb_error());
+            fprintf(stderr,"error: %s\n", adb_error());
+            return 1;
+        }
+
+        /* Allow a command to be run after wait-for-device,
+            * e.g. 'adb wait-for-device shell'.
+            */
+        if(argc > 1) {
+            argc--;
+            argv++;
+            goto top;
+        }
+        return 0;
+    }
+
+    if(!strcmp(argv[0], "forward") ||
+       !strcmp(argv[0], "reverse"))
+    {
+        char host_prefix[64];
+        char reverse = (char) !strcmp(argv[0], "reverse");
+        char remove = 0;
+        char remove_all = 0;
+        char list = 0;
+        char no_rebind = 0;
+
+        // Parse options here.
+        while (argc > 1 && argv[1][0] == '-') {
+            if (!strcmp(argv[1], "--list"))
+                list = 1;
+            else if (!strcmp(argv[1], "--remove"))
+                remove = 1;
+            else if (!strcmp(argv[1], "--remove-all"))
+                remove_all = 1;
+            else if (!strcmp(argv[1], "--no-rebind"))
+                no_rebind = 1;
+            else {
+                return usage();
+            }
+            argc--;
+            argv++;
+        }
+
+        // Ensure we can only use one option at a time.
+        if (list + remove + remove_all + no_rebind > 1) {
+            return usage();
+        }
+
+        // Determine the <host-prefix> for this command.
+        if (reverse) {
+            snprintf(host_prefix, sizeof host_prefix, "reverse");
+        } else {
+            if (serial) {
+                snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
+                        serial);
+            } else if (ttype == kTransportUsb) {
+                snprintf(host_prefix, sizeof host_prefix, "host-usb");
+            } else if (ttype == kTransportLocal) {
+                snprintf(host_prefix, sizeof host_prefix, "host-local");
+            } else {
+                snprintf(host_prefix, sizeof host_prefix, "host");
+            }
+        }
+
+        // Implement forward --list
+        if (list) {
+            if (argc != 1)
+                return usage();
+            snprintf(buf, sizeof buf, "%s:list-forward", host_prefix);
+            char* forwards = adb_query(buf);
+            if (forwards == NULL) {
+                fprintf(stderr, "error: %s\n", adb_error());
+                return 1;
+            }
+            printf("%s", forwards);
+            free(forwards);
+            return 0;
+        }
+
+        // Implement forward --remove-all
+        else if (remove_all) {
+            if (argc != 1)
+                return usage();
+            snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix);
+        }
+
+        // Implement forward --remove <local>
+        else if (remove) {
+            if (argc != 2)
+                return usage();
+            snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]);
+        }
+        // Or implement one of:
+        //    forward <local> <remote>
+        //    forward --no-rebind <local> <remote>
+        else
+        {
+          if (argc != 3)
+            return usage();
+          const char* command = no_rebind ? "forward:norebind:" : "forward";
+          snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
+        }
+
+        if(adb_command(buf)) {
+            fprintf(stderr,"error: %s\n", adb_error());
+            return 1;
+        }
+        return 0;
+    }
+
+    /* do_sync_*() commands */
+
+    if(!strcmp(argv[0], "ls")) {
+        if(argc != 2) return usage();
+        return do_sync_ls(argv[1]);
+    }
+
+    if(!strcmp(argv[0], "push")) {
+        int show_progress = 0;
+        int copy_attrs = 0; // unused
+        const char* lpath = NULL, *rpath = NULL;
+
+        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, &copy_attrs);
+
+        if ((lpath != NULL) && (rpath != NULL)) {
+            return do_sync_push(lpath, rpath, show_progress);
+        }
+
+        return usage();
+    }
+
+    if(!strcmp(argv[0], "pull")) {
+        int show_progress = 0;
+        int copy_attrs = 0;
+        const char* rpath = NULL, *lpath = ".";
+
+        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, &copy_attrs);
+
+        if (rpath != NULL) {
+            return do_sync_pull(rpath, lpath, show_progress, copy_attrs);
+        }
+
+        return usage();
+    }
+
+    if (!strcmp(argv[0], "install")) {
+        if (argc < 2) return usage();
+        return install_app(ttype, serial, argc, argv);
+    }
+
+    if (!strcmp(argv[0], "install-multiple")) {
+        if (argc < 2) return usage();
+        return install_multiple_app(ttype, serial, argc, argv);
+    }
+
+    if (!strcmp(argv[0], "uninstall")) {
+        if (argc < 2) return usage();
+        return uninstall_app(ttype, serial, argc, argv);
+    }
+
+    if(!strcmp(argv[0], "sync")) {
+        char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath;
+        int listonly = 0;
+
+        int ret;
+        if(argc < 2) {
+            /* No local path was specified. */
+            srcarg = NULL;
+        } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
+            listonly = 1;
+            if (argc == 3) {
+                srcarg = argv[2];
+            } else {
+                srcarg = NULL;
+            }
+        } else if(argc == 2) {
+            /* A local path or "android"/"data" arg was specified. */
+            srcarg = argv[1];
+        } else {
+            return usage();
+        }
+        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath, &vendor_srcpath);
+        if(ret != 0) return usage();
+
+        if(android_srcpath != NULL)
+            ret = do_sync_sync(android_srcpath, "/system", listonly);
+        if(ret == 0 && vendor_srcpath != NULL)
+            ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
+        if(ret == 0 && data_srcpath != NULL)
+            ret = do_sync_sync(data_srcpath, "/data", listonly);
+
+        free(android_srcpath);
+        free(vendor_srcpath);
+        free(data_srcpath);
+        return ret;
+    }
+
+    /* passthrough commands */
+
+    if(!strcmp(argv[0],"get-state") ||
+        !strcmp(argv[0],"get-serialno") ||
+        !strcmp(argv[0],"get-devpath"))
+    {
+        char *tmp;
+
+        format_host_command(buf, sizeof buf, argv[0], ttype, serial);
+        tmp = adb_query(buf);
+        if(tmp) {
+            printf("%s\n", tmp);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    /* other commands */
+
+    if(!strcmp(argv[0],"status-window")) {
+        status_window(ttype, serial);
+        return 0;
+    }
+
+    if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat")
+	|| !strcmp(argv[0],"longcat") || !strcmp(argv[0], "logread")) {
+        return logcat(ttype, serial, argc, argv);
+    }
+
+    if(!strcmp(argv[0],"ppp")) {
+        return ppp(argc, argv);
+    }
+
+    if (!strcmp(argv[0], "start-server")) {
+        return adb_connect("host:start-server");
+    }
+
+    if (!strcmp(argv[0], "backup")) {
+        return backup(argc, argv);
+    }
+
+    if (!strcmp(argv[0], "restore")) {
+        return restore(argc, argv);
+    }
+
+    if (!strcmp(argv[0], "jdwp")) {
+        int  fd = adb_connect("jdwp");
+        if (fd >= 0) {
+            read_and_dump(fd);
+            adb_close(fd);
+            return 0;
+        } else {
+            fprintf(stderr, "error: %s\n", adb_error());
+            return -1;
+        }
+    }
+
+    /* "adb /?" is a common idiom under Windows */
+    if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
+        help();
+        return 0;
+    }
+
+    if(!strcmp(argv[0], "version")) {
+        version(stdout);
+        return 0;
+    }
+
+    usage();
+    return 1;
+}
+
+#define MAX_ARGV_LENGTH 16
+static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
+{
+    char *argv[MAX_ARGV_LENGTH];
+    int argc;
+    va_list ap;
+
+    va_start(ap, cmd);
+    argc = 0;
+
+    if (serial) {
+        argv[argc++] = "-s";
+        argv[argc++] = serial;
+    } else if (ttype == kTransportUsb) {
+        argv[argc++] = "-d";
+    } else if (ttype == kTransportLocal) {
+        argv[argc++] = "-e";
+    }
+
+    argv[argc++] = cmd;
+    while(argc < MAX_ARGV_LENGTH &&
+        (argv[argc] = va_arg(ap, char*)) != 0) argc++;
+    assert(argc < MAX_ARGV_LENGTH);
+    va_end(ap);
+
+#if 0
+    int n;
+    fprintf(stderr,"argc = %d\n",argc);
+    for(n = 0; n < argc; n++) {
+        fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
+    }
+#endif
+
+    return adb_commandline(argc, argv);
+}
+
+int find_sync_dirs(const char *srcarg,
+        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out)
+{
+    char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL;
+    struct stat st;
+
+    if(srcarg == NULL) {
+        android_srcdir = product_file("system");
+        data_srcdir = product_file("data");
+        vendor_srcdir = product_file("vendor");
+        /* Check if vendor partition exists */
+        if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
+            vendor_srcdir = NULL;
+    } else {
+        /* srcarg may be "data", "system" or NULL.
+         * if srcarg is NULL, then both data and system are synced
+         */
+        if(strcmp(srcarg, "system") == 0) {
+            android_srcdir = product_file("system");
+        } else if(strcmp(srcarg, "data") == 0) {
+            data_srcdir = product_file("data");
+        } else if(strcmp(srcarg, "vendor") == 0) {
+            vendor_srcdir = product_file("vendor");
+        } else {
+            /* It's not "system", "vendor", or "data".
+             */
+            return 1;
+        }
+    }
+
+    if(android_srcdir_out != NULL)
+        *android_srcdir_out = android_srcdir;
+    else
+        free(android_srcdir);
+
+    if(vendor_srcdir_out != NULL)
+        *vendor_srcdir_out = vendor_srcdir;
+    else
+        free(vendor_srcdir);
+
+    if(data_srcdir_out != NULL)
+            *data_srcdir_out = data_srcdir;
+        else
+            free(data_srcdir);
+    return 0;
+}
+
+static int pm_command(transport_type transport, char* serial,
+                      int argc, char** argv)
+{
+    char buf[4096];
+
+    snprintf(buf, sizeof(buf), "shell:pm");
+
+    while(argc-- > 0) {
+        char *quoted = escape_arg(*argv++);
+        strncat(buf, " ", sizeof(buf) - 1);
+        strncat(buf, quoted, sizeof(buf) - 1);
+        free(quoted);
+    }
+
+    send_shellcommand(transport, serial, buf);
+    return 0;
+}
+
+int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
+{
+    /* if the user choose the -k option, we refuse to do it until devices are
+       out with the option to uninstall the remaining data somehow (adb/ui) */
+    if (argc == 3 && strcmp(argv[1], "-k") == 0)
+    {
+        printf(
+            "The -k option uninstalls the application while retaining the data/cache.\n"
+            "At the moment, there is no way to remove the remaining data.\n"
+            "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
+            "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
+        return -1;
+    }
+
+    /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
+    return pm_command(transport, serial, argc, argv);
+}
+
+static int delete_file(transport_type transport, char* serial, char* filename)
+{
+    char buf[4096];
+    char* quoted;
+
+    snprintf(buf, sizeof(buf), "shell:rm -f ");
+    quoted = escape_arg(filename);
+    strncat(buf, quoted, sizeof(buf)-1);
+    free(quoted);
+
+    send_shellcommand(transport, serial, buf);
+    return 0;
+}
+
+static const char* get_basename(const char* filename)
+{
+    const char* basename = adb_dirstop(filename);
+    if (basename) {
+        basename++;
+        return basename;
+    } else {
+        return filename;
+    }
+}
+
+int install_app(transport_type transport, char* serial, int argc, char** argv)
+{
+    static const char *const DATA_DEST = "/data/local/tmp/%s";
+    static const char *const SD_DEST = "/sdcard/tmp/%s";
+    const char* where = DATA_DEST;
+    int i;
+    struct stat sb;
+
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "-s")) {
+            where = SD_DEST;
+        }
+    }
+
+    // Find last APK argument.
+    // All other arguments passed through verbatim.
+    int last_apk = -1;
+    for (i = argc - 1; i >= 0; i--) {
+        char* file = argv[i];
+        char* dot = strrchr(file, '.');
+        if (dot && !strcasecmp(dot, ".apk")) {
+            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
+                fprintf(stderr, "Invalid APK file: %s\n", file);
+                return -1;
+            }
+
+            last_apk = i;
+            break;
+        }
+    }
+
+    if (last_apk == -1) {
+        fprintf(stderr, "Missing APK file\n");
+        return -1;
+    }
+
+    char* apk_file = argv[last_apk];
+    char apk_dest[PATH_MAX];
+    snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
+    int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
+    if (err) {
+        goto cleanup_apk;
+    } else {
+        argv[last_apk] = apk_dest; /* destination name, not source location */
+    }
+
+    pm_command(transport, serial, argc, argv);
+
+cleanup_apk:
+    delete_file(transport, serial, apk_dest);
+    return err;
+}
+
+int install_multiple_app(transport_type transport, char* serial, int argc, char** argv)
+{
+    char buf[1024];
+    int i;
+    struct stat sb;
+    unsigned long long total_size = 0;
+
+    // Find all APK arguments starting at end.
+    // All other arguments passed through verbatim.
+    int first_apk = -1;
+    for (i = argc - 1; i >= 0; i--) {
+        char* file = argv[i];
+        char* dot = strrchr(file, '.');
+        if (dot && !strcasecmp(dot, ".apk")) {
+            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
+                fprintf(stderr, "Invalid APK file: %s\n", file);
+                return -1;
+            }
+
+            total_size += sb.st_size;
+            first_apk = i;
+        } else {
+            break;
+        }
+    }
+
+    if (first_apk == -1) {
+        fprintf(stderr, "Missing APK file\n");
+        return 1;
+    }
+
+    snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size);
+    for (i = 1; i < first_apk; i++) {
+        char *quoted = escape_arg(argv[i]);
+        strncat(buf, " ", sizeof(buf) - 1);
+        strncat(buf, quoted, sizeof(buf) - 1);
+        free(quoted);
+    }
+
+    // Create install session
+    int fd = adb_connect(buf);
+    if (fd < 0) {
+        fprintf(stderr, "Connect error for create: %s\n", adb_error());
+        return -1;
+    }
+    read_status_line(fd, buf, sizeof(buf));
+    adb_close(fd);
+
+    int session_id = -1;
+    if (!strncmp("Success", buf, 7)) {
+        char* start = strrchr(buf, '[');
+        char* end = strrchr(buf, ']');
+        if (start && end) {
+            *end = '\0';
+            session_id = strtol(start + 1, NULL, 10);
+        }
+    }
+    if (session_id < 0) {
+        fprintf(stderr, "Failed to create session\n");
+        fputs(buf, stderr);
+        return -1;
+    }
+
+    // Valid session, now stream the APKs
+    int success = 1;
+    for (i = first_apk; i < argc; i++) {
+        char* file = argv[i];
+        if (stat(file, &sb) == -1) {
+            fprintf(stderr, "Failed to stat %s\n", file);
+            success = 0;
+            goto finalize_session;
+        }
+
+        snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -",
+                (long long int) sb.st_size, session_id, i, get_basename(file));
+
+        int localFd = adb_open(file, O_RDONLY);
+        if (localFd < 0) {
+            fprintf(stderr, "Failed to open %s: %s\n", file, adb_error());
+            success = 0;
+            goto finalize_session;
+        }
+
+        int remoteFd = adb_connect(buf);
+        if (remoteFd < 0) {
+            fprintf(stderr, "Connect error for write: %s\n", adb_error());
+            adb_close(localFd);
+            success = 0;
+            goto finalize_session;
+        }
+
+        copy_to_file(localFd, remoteFd);
+        read_status_line(remoteFd, buf, sizeof(buf));
+
+        adb_close(localFd);
+        adb_close(remoteFd);
+
+        if (strncmp("Success", buf, 7)) {
+            fprintf(stderr, "Failed to write %s\n", file);
+            fputs(buf, stderr);
+            success = 0;
+            goto finalize_session;
+        }
+    }
+
+finalize_session:
+    // Commit session if we streamed everything okay; otherwise abandon
+    if (success) {
+        snprintf(buf, sizeof(buf), "exec:pm install-commit %d", session_id);
+    } else {
+        snprintf(buf, sizeof(buf), "exec:pm install-abandon %d", session_id);
+    }
+
+    fd = adb_connect(buf);
+    if (fd < 0) {
+        fprintf(stderr, "Connect error for finalize: %s\n", adb_error());
+        return -1;
+    }
+    read_status_line(fd, buf, sizeof(buf));
+    adb_close(fd);
+
+    if (!strncmp("Success", buf, 7)) {
+        fputs(buf, stderr);
+        return 0;
+    } else {
+        fprintf(stderr, "Failed to finalize session\n");
+        fputs(buf, stderr);
+        return -1;
+    }
+}
diff --git a/src/devtools/adb/console.c b/src/devtools/adb/console.c
new file mode 100755
index 0000000..b813d33
--- /dev/null
+++ b/src/devtools/adb/console.c
@@ -0,0 +1,45 @@
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_client.h"
+#include <stdio.h>
+
+static int  connect_to_console(void)
+{
+    int  fd, port;
+
+    port = adb_get_emulator_console_port();
+    if (port < 0) {
+        if (port == -2)
+            fprintf(stderr, "error: more than one emulator detected. use -s option\n");
+        else
+            fprintf(stderr, "error: no emulator detected\n");
+        return -1;
+    }
+    fd = socket_loopback_client( port, SOCK_STREAM );
+    if (fd < 0) {
+        fprintf(stderr, "error: could not connect to TCP port %d\n", port);
+        return -1;
+    }
+    return  fd;
+}
+
+
+int  adb_send_emulator_command(int  argc, char**  argv)
+{
+    int   fd, nn;
+
+    fd = connect_to_console();
+    if (fd < 0)
+        return 1;
+
+#define  QUIT  "quit\n"
+
+    for (nn = 1; nn < argc; nn++) {
+        adb_write( fd, argv[nn], strlen(argv[nn]) );
+        adb_write( fd, (nn == argc-1) ? "\n" : " ", 1 );
+    }
+    adb_write( fd, QUIT, sizeof(QUIT)-1 );
+    adb_close(fd);
+
+    return 0;
+}
diff --git a/src/devtools/adb/fdevent.c b/src/devtools/adb/fdevent.c
new file mode 100755
index 0000000..43e600c
--- /dev/null
+++ b/src/devtools/adb/fdevent.c
@@ -0,0 +1,686 @@
+/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c
+**
+** Copyright 2006, Brian Swetland <swetland@frotz.net>
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include <sys/ioctl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <fcntl.h>
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#include "adb_trace.h"
+#include "fdevent.h"
+#include "transport.h"
+#include "sysdeps.h"
+
+#define TRACE_TAG  TRACE_FDEVENT
+
+/* !!! Do not enable DEBUG for the adb that will run as the server:
+** both stdout and stderr are used to communicate between the client
+** and server. Any extra output will cause failures.
+*/
+#define DEBUG 0   /* non-0 will break adb server */
+
+// This socket is used when a subproc shell service exists.
+// It wakes up the fdevent_loop() and cause the correct handling
+// of the shell's pseudo-tty master. I.e. force close it.
+int SHELL_EXIT_NOTIFY_FD = -1;
+
+static void fatal(const char *fn, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stderr, "%s:", fn);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    abort();
+}
+
+#define FATAL(x...) fatal(__FUNCTION__, x)
+
+#if DEBUG
+static void dump_fde(fdevent *fde, const char *info)
+{
+    adb_mutex_lock(&D_lock);
+    fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
+            fde->state & FDE_READ ? 'R' : ' ',
+            fde->state & FDE_WRITE ? 'W' : ' ',
+            fde->state & FDE_ERROR ? 'E' : ' ',
+            info);
+    adb_mutex_unlock(&D_lock);
+}
+#else
+#define dump_fde(fde, info) do { } while(0)
+#endif
+
+#define FDE_EVENTMASK  0x00ff
+#define FDE_STATEMASK  0xff00
+
+#define FDE_ACTIVE     0x0100
+#define FDE_PENDING    0x0200
+#define FDE_CREATED    0x0400
+
+static void fdevent_plist_enqueue(fdevent *node);
+static void fdevent_plist_remove(fdevent *node);
+static fdevent *fdevent_plist_dequeue(void);
+static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
+
+static fdevent list_pending = {
+    .next = &list_pending,
+    .prev = &list_pending,
+};
+
+static fdevent **fd_table = 0;
+static int fd_table_max = 0;
+
+#ifdef CRAPTASTIC
+//HAVE_EPOLL
+
+#include <sys/epoll.h>
+
+static int epoll_fd = -1;
+
+static void fdevent_init()
+{
+        /* XXX: what's a good size for the passed in hint? */
+    epoll_fd = epoll_create(256);
+
+    if(epoll_fd < 0) {
+        perror("epoll_create() failed");
+        exit(1);
+    }
+
+        /* mark for close-on-exec */
+    fcntl(epoll_fd, F_SETFD, FD_CLOEXEC);
+}
+
+static void fdevent_connect(fdevent *fde)
+{
+    struct epoll_event ev;
+
+    memset(&ev, 0, sizeof(ev));
+    ev.events = 0;
+    ev.data.ptr = fde;
+
+#if 0
+    if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
+        perror("epoll_ctl() failed\n");
+        exit(1);
+    }
+#endif
+}
+
+static void fdevent_disconnect(fdevent *fde)
+{
+    struct epoll_event ev;
+
+    memset(&ev, 0, sizeof(ev));
+    ev.events = 0;
+    ev.data.ptr = fde;
+
+        /* technically we only need to delete if we
+        ** were actively monitoring events, but let's
+        ** be aggressive and do it anyway, just in case
+        ** something's out of sync
+        */
+    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);
+}
+
+static void fdevent_update(fdevent *fde, unsigned events)
+{
+    struct epoll_event ev;
+    int active;
+
+    active = (fde->state & FDE_EVENTMASK) != 0;
+
+    memset(&ev, 0, sizeof(ev));
+    ev.events = 0;
+    ev.data.ptr = fde;
+
+    if(events & FDE_READ) ev.events |= EPOLLIN;
+    if(events & FDE_WRITE) ev.events |= EPOLLOUT;
+    if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
+
+    fde->state = (fde->state & FDE_STATEMASK) | events;
+
+    if(active) {
+            /* we're already active. if we're changing to *no*
+            ** events being monitored, we need to delete, otherwise
+            ** we need to just modify
+            */
+        if(ev.events) {
+            if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
+                perror("epoll_ctl() failed\n");
+                exit(1);
+            }
+        } else {
+            if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
+                perror("epoll_ctl() failed\n");
+                exit(1);
+            }
+        }
+    } else {
+            /* we're not active.  if we're watching events, we need
+            ** to add, otherwise we can just do nothing
+            */
+        if(ev.events) {
+            if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
+                perror("epoll_ctl() failed\n");
+                exit(1);
+            }
+        }
+    }
+}
+
+static void fdevent_process()
+{
+    struct epoll_event events[256];
+    fdevent *fde;
+    int i, n;
+
+    n = epoll_wait(epoll_fd, events, 256, -1);
+
+    if(n < 0) {
+        if(errno == EINTR) return;
+        perror("epoll_wait");
+        exit(1);
+    }
+
+    for(i = 0; i < n; i++) {
+        struct epoll_event *ev = events + i;
+        fde = ev->data.ptr;
+
+        if(ev->events & EPOLLIN) {
+            fde->events |= FDE_READ;
+        }
+        if(ev->events & EPOLLOUT) {
+            fde->events |= FDE_WRITE;
+        }
+        if(ev->events & (EPOLLERR | EPOLLHUP)) {
+            fde->events |= FDE_ERROR;
+        }
+        if(fde->events) {
+            if(fde->state & FDE_PENDING) continue;
+            fde->state |= FDE_PENDING;
+            fdevent_plist_enqueue(fde);
+        }
+    }
+}
+
+#else /* USE_SELECT */
+
+#ifdef HAVE_WINSOCK
+#include <winsock2.h>
+#else
+#include <sys/select.h>
+#endif
+
+static fd_set read_fds;
+static fd_set write_fds;
+static fd_set error_fds;
+
+static int select_n = 0;
+
+static void fdevent_init(void)
+{
+    FD_ZERO(&read_fds);
+    FD_ZERO(&write_fds);
+    FD_ZERO(&error_fds);
+}
+
+static void fdevent_connect(fdevent *fde)
+{
+    if(fde->fd >= select_n) {
+        select_n = fde->fd + 1;
+    }
+}
+
+static void fdevent_disconnect(fdevent *fde)
+{
+    int i, n;
+
+    FD_CLR(fde->fd, &read_fds);
+    FD_CLR(fde->fd, &write_fds);
+    FD_CLR(fde->fd, &error_fds);
+
+    for(n = 0, i = 0; i < select_n; i++) {
+        if(fd_table[i] != 0) n = i;
+    }
+    select_n = n + 1;
+}
+
+static void fdevent_update(fdevent *fde, unsigned events)
+{
+    if(events & FDE_READ) {
+        FD_SET(fde->fd, &read_fds);
+    } else {
+        FD_CLR(fde->fd, &read_fds);
+    }
+    if(events & FDE_WRITE) {
+        FD_SET(fde->fd, &write_fds);
+    } else {
+        FD_CLR(fde->fd, &write_fds);
+    }
+    if(events & FDE_ERROR) {
+        FD_SET(fde->fd, &error_fds);
+    } else {
+        FD_CLR(fde->fd, &error_fds);
+    }
+
+    fde->state = (fde->state & FDE_STATEMASK) | events;
+}
+
+/* Looks at fd_table[] for bad FDs and sets bit in fds.
+** Returns the number of bad FDs.
+*/
+static int fdevent_fd_check(fd_set *fds)
+{
+    int i, n = 0;
+    fdevent *fde;
+
+    for(i = 0; i < select_n; i++) {
+        fde = fd_table[i];
+        if(fde == 0) continue;
+        if(fcntl(i, F_GETFL, NULL) < 0) {
+            FD_SET(i, fds);
+            n++;
+            // fde->state |= FDE_DONT_CLOSE;
+
+        }
+    }
+    return n;
+}
+
+#if !DEBUG
+static inline void dump_all_fds(const char *extra_msg) {}
+#else
+static void dump_all_fds(const char *extra_msg)
+{
+int i;
+    fdevent *fde;
+    // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
+    char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
+    size_t max_chars = FD_SETSIZE * 6 + 1;
+    int printed_out;
+#define SAFE_SPRINTF(...)                                                    \
+    do {                                                                     \
+        printed_out = snprintf(pb, max_chars, __VA_ARGS__);                  \
+        if (printed_out <= 0) {                                              \
+            D("... snprintf failed.\n");                                     \
+            return;                                                          \
+        }                                                                    \
+        if (max_chars < (unsigned int)printed_out) {                         \
+            D("... snprintf out of space.\n");                               \
+            return;                                                          \
+        }                                                                    \
+        pb += printed_out;                                                   \
+        max_chars -= printed_out;                                            \
+    } while(0)
+
+    for(i = 0; i < select_n; i++) {
+        fde = fd_table[i];
+        SAFE_SPRINTF("%d", i);
+        if(fde == 0) {
+            SAFE_SPRINTF("? ");
+            continue;
+        }
+        if(fcntl(i, F_GETFL, NULL) < 0) {
+            SAFE_SPRINTF("b");
+        }
+        SAFE_SPRINTF(" ");
+    }
+    D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
+}
+#endif
+
+static void fdevent_process()
+{
+    int i, n;
+    fdevent *fde;
+    unsigned events;
+    fd_set rfd, wfd, efd;
+
+    memcpy(&rfd, &read_fds, sizeof(fd_set));
+    memcpy(&wfd, &write_fds, sizeof(fd_set));
+    memcpy(&efd, &error_fds, sizeof(fd_set));
+
+    dump_all_fds("pre select()");
+
+    n = select(select_n, &rfd, &wfd, &efd, NULL);
+    int saved_errno = errno;
+    D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
+
+    dump_all_fds("post select()");
+
+    if(n < 0) {
+        switch(saved_errno) {
+        case EINTR: return;
+        case EBADF:
+            // Can't trust the FD sets after an error.
+            FD_ZERO(&wfd);
+            FD_ZERO(&efd);
+            FD_ZERO(&rfd);
+            break;
+        default:
+            D("Unexpected select() error=%d\n", saved_errno);
+            return;
+        }
+    }
+    if(n <= 0) {
+        // We fake a read, as the rest of the code assumes
+        // that errors will be detected at that point.
+        n = fdevent_fd_check(&rfd);
+    }
+
+    for(i = 0; (i < select_n) && (n > 0); i++) {
+        events = 0;
+        if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
+        if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
+        if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
+
+        if(events) {
+            fde = fd_table[i];
+            if(fde == 0)
+              FATAL("missing fde for fd %d\n", i);
+
+            fde->events |= events;
+
+            D("got events fde->fd=%d events=%04x, state=%04x\n",
+                fde->fd, fde->events, fde->state);
+            if(fde->state & FDE_PENDING) continue;
+            fde->state |= FDE_PENDING;
+            fdevent_plist_enqueue(fde);
+        }
+    }
+}
+
+#endif
+
+static void fdevent_register(fdevent *fde)
+{
+    if(fde->fd < 0) {
+        FATAL("bogus negative fd (%d)\n", fde->fd);
+    }
+
+    if(fde->fd >= fd_table_max) {
+        int oldmax = fd_table_max;
+        if(fde->fd > 32000) {
+            FATAL("bogus huuuuge fd (%d)\n", fde->fd);
+        }
+        if(fd_table_max == 0) {
+            fdevent_init();
+            fd_table_max = 256;
+        }
+        while(fd_table_max <= fde->fd) {
+            fd_table_max *= 2;
+        }
+        fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
+        if(fd_table == 0) {
+            FATAL("could not expand fd_table to %d entries\n", fd_table_max);
+        }
+        memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
+    }
+
+    fd_table[fde->fd] = fde;
+}
+
+static void fdevent_unregister(fdevent *fde)
+{
+    if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
+        FATAL("fd out of range (%d)\n", fde->fd);
+    }
+
+    if(fd_table[fde->fd] != fde) {
+        FATAL("fd_table out of sync [%d]\n", fde->fd);
+    }
+
+    fd_table[fde->fd] = 0;
+
+    if(!(fde->state & FDE_DONT_CLOSE)) {
+        dump_fde(fde, "close");
+        adb_close(fde->fd);
+    }
+}
+
+static void fdevent_plist_enqueue(fdevent *node)
+{
+    fdevent *list = &list_pending;
+
+    node->next = list;
+    node->prev = list->prev;
+    node->prev->next = node;
+    list->prev = node;
+}
+
+static void fdevent_plist_remove(fdevent *node)
+{
+    node->prev->next = node->next;
+    node->next->prev = node->prev;
+    node->next = 0;
+    node->prev = 0;
+}
+
+static fdevent *fdevent_plist_dequeue(void)
+{
+    fdevent *list = &list_pending;
+    fdevent *node = list->next;
+
+    if(node == list) return 0;
+
+    list->next = node->next;
+    list->next->prev = list;
+    node->next = 0;
+    node->prev = 0;
+
+    return node;
+}
+
+static void fdevent_call_fdfunc(fdevent* fde)
+{
+    unsigned events = fde->events;
+    fde->events = 0;
+    if(!(fde->state & FDE_PENDING)) return;
+    fde->state &= (~FDE_PENDING);
+    dump_fde(fde, "callback");
+    fde->func(fde->fd, events, fde->arg);
+}
+
+static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
+{
+
+    D("subproc handling on fd=%d ev=%04x\n", fd, ev);
+
+    // Hook oneself back into the fde's suitable for select() on read.
+    if((fd < 0) || (fd >= fd_table_max)) {
+        FATAL("fd %d out of range for fd_table \n", fd);
+    }
+    fdevent *fde = fd_table[fd];
+    fdevent_add(fde, FDE_READ);
+
+    if(ev & FDE_READ){
+      int subproc_fd;
+
+      if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
+          FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
+      }
+      if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
+          D("subproc_fd %d out of range 0, fd_table_max=%d\n",
+            subproc_fd, fd_table_max);
+          return;
+      }
+      fdevent *subproc_fde = fd_table[subproc_fd];
+      if(!subproc_fde) {
+          D("subproc_fd %d cleared from fd_table\n", subproc_fd);
+          return;
+      }
+      if(subproc_fde->fd != subproc_fd) {
+          // Already reallocated?
+          D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
+          return;
+      }
+
+      subproc_fde->force_eof = 1;
+
+      int rcount = 0;
+      ioctl(subproc_fd, FIONREAD, &rcount);
+      D("subproc with fd=%d  has rcount=%d err=%d\n",
+        subproc_fd, rcount, errno);
+
+      if(rcount) {
+        // If there is data left, it will show up in the select().
+        // This works because there is no other thread reading that
+        // data when in this fd_func().
+        return;
+      }
+
+      D("subproc_fde.state=%04x\n", subproc_fde->state);
+      subproc_fde->events |= FDE_READ;
+      if(subproc_fde->state & FDE_PENDING) {
+        return;
+      }
+      subproc_fde->state |= FDE_PENDING;
+      fdevent_call_fdfunc(subproc_fde);
+    }
+}
+
+fdevent *fdevent_create(int fd, fd_func func, void *arg)
+{
+    fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
+    if(fde == 0) return 0;
+    fdevent_install(fde, fd, func, arg);
+    fde->state |= FDE_CREATED;
+    return fde;
+}
+
+void fdevent_destroy(fdevent *fde)
+{
+    if(fde == 0) return;
+    if(!(fde->state & FDE_CREATED)) {
+        FATAL("fde %p not created by fdevent_create()\n", fde);
+    }
+    fdevent_remove(fde);
+}
+
+void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
+{
+    memset(fde, 0, sizeof(fdevent));
+    fde->state = FDE_ACTIVE;
+    fde->fd = fd;
+    fde->force_eof = 0;
+    fde->func = func;
+    fde->arg = arg;
+
+#ifndef HAVE_WINSOCK
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
+    fdevent_register(fde);
+    dump_fde(fde, "connect");
+    fdevent_connect(fde);
+    fde->state |= FDE_ACTIVE;
+}
+
+void fdevent_remove(fdevent *fde)
+{
+    if(fde->state & FDE_PENDING) {
+        fdevent_plist_remove(fde);
+    }
+
+    if(fde->state & FDE_ACTIVE) {
+        fdevent_disconnect(fde);
+        dump_fde(fde, "disconnect");
+        fdevent_unregister(fde);
+    }
+
+    fde->state = 0;
+    fde->events = 0;
+}
+
+
+void fdevent_set(fdevent *fde, unsigned events)
+{
+    events &= FDE_EVENTMASK;
+
+    if((fde->state & FDE_EVENTMASK) == events) return;
+
+    if(fde->state & FDE_ACTIVE) {
+        fdevent_update(fde, events);
+        dump_fde(fde, "update");
+    }
+
+    fde->state = (fde->state & FDE_STATEMASK) | events;
+
+    if(fde->state & FDE_PENDING) {
+            /* if we're pending, make sure
+            ** we don't signal an event that
+            ** is no longer wanted.
+            */
+        fde->events &= (~events);
+        if(fde->events == 0) {
+            fdevent_plist_remove(fde);
+            fde->state &= (~FDE_PENDING);
+        }
+    }
+}
+
+void fdevent_add(fdevent *fde, unsigned events)
+{
+    fdevent_set(
+        fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
+}
+
+void fdevent_del(fdevent *fde, unsigned events)
+{
+    fdevent_set(
+        fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
+}
+
+void fdevent_subproc_setup()
+{
+    int s[2];
+
+    if(adb_socketpair(s)) {
+        FATAL("cannot create shell-exit socket-pair\n");
+    }
+    SHELL_EXIT_NOTIFY_FD = s[0];
+    fdevent *fde;
+    fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
+    if(!fde)
+      FATAL("cannot create fdevent for shell-exit handler\n");
+    fdevent_add(fde, FDE_READ);
+}
+
+void fdevent_loop()
+{
+    fdevent *fde;
+    fdevent_subproc_setup();
+
+    for(;;) {
+        D("--- ---- waiting for events\n");
+
+        fdevent_process();
+
+        while((fde = fdevent_plist_dequeue())) {
+            fdevent_call_fdfunc(fde);
+        }
+    }
+}
diff --git a/src/devtools/adb/fdevent.h b/src/devtools/adb/fdevent.h
new file mode 100755
index 0000000..a0ebe2a
--- /dev/null
+++ b/src/devtools/adb/fdevent.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FDEVENT_H
+#define __FDEVENT_H
+
+#include <stdint.h>  /* for int64_t */
+
+/* events that may be observed */
+#define FDE_READ              0x0001
+#define FDE_WRITE             0x0002
+#define FDE_ERROR             0x0004
+#define FDE_TIMEOUT           0x0008
+
+/* features that may be set (via the events set/add/del interface) */
+#define FDE_DONT_CLOSE        0x0080
+
+typedef struct fdevent fdevent;
+
+typedef void (*fd_func)(int fd, unsigned events, void *userdata);
+
+/* Allocate and initialize a new fdevent object
+ * Note: use FD_TIMER as 'fd' to create a fd-less object
+ * (used to implement timers).
+*/
+fdevent *fdevent_create(int fd, fd_func func, void *arg);
+
+/* Uninitialize and deallocate an fdevent object that was
+** created by fdevent_create()
+*/
+void fdevent_destroy(fdevent *fde);
+
+/* Initialize an fdevent object that was externally allocated
+*/
+void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
+
+/* Uninitialize an fdevent object that was initialized by
+** fdevent_install()
+*/
+void fdevent_remove(fdevent *item);
+
+/* Change which events should cause notifications
+*/
+void fdevent_set(fdevent *fde, unsigned events);
+void fdevent_add(fdevent *fde, unsigned events);
+void fdevent_del(fdevent *fde, unsigned events);
+
+void fdevent_set_timeout(fdevent *fde, int64_t  timeout_ms);
+
+/* loop forever, handling events.
+*/
+void fdevent_loop();
+
+struct fdevent 
+{
+    fdevent *next;
+    fdevent *prev;
+
+    int fd;
+    int force_eof;
+
+    unsigned short state;
+    unsigned short events;
+
+    fd_func func;
+    void *arg;
+};
+
+
+#endif
diff --git a/src/devtools/adb/file_sync_client.c b/src/devtools/adb/file_sync_client.c
new file mode 100755
index 0000000..ad59e81
--- /dev/null
+++ b/src/devtools/adb/file_sync_client.c
@@ -0,0 +1,1035 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <dirent.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <zipfile/zipfile.h>
+#include <utime.h>
+
+#include "sysdeps.h"
+#include "adb.h"
+#include "adb_client.h"
+#include "file_sync_service.h"
+
+
+static unsigned long long total_bytes;
+static long long start_time;
+
+static long long NOW()
+{
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    return ((long long) tv.tv_usec) +
+        1000000LL * ((long long) tv.tv_sec);
+}
+
+static void BEGIN()
+{
+    total_bytes = 0;
+    start_time = NOW();
+}
+
+static void END()
+{
+    long long t = NOW() - start_time;
+    if(total_bytes == 0) return;
+
+    if (t == 0)  /* prevent division by 0 :-) */
+        t = 1000000;
+
+    fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
+            ((total_bytes * 1000000LL) / t) / 1024LL,
+            total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+}
+
+static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)";
+
+static void print_transfer_progress(unsigned long long bytes_current,
+                                    unsigned long long bytes_total) {
+    if (bytes_total == 0) return;
+
+    fprintf(stderr, transfer_progress_format, bytes_current, bytes_total,
+            (int) (bytes_current * 100 / bytes_total));
+
+    if (bytes_current == bytes_total) {
+        fputc('\n', stderr);
+    }
+
+    fflush(stderr);
+}
+
+void sync_quit(int fd)
+{
+    syncmsg msg;
+
+    msg.req.id = ID_QUIT;
+    msg.req.namelen = 0;
+
+    writex(fd, &msg.req, sizeof(msg.req));
+}
+
+typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
+
+int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
+{
+    syncmsg msg;
+    char buf[257];
+    int len;
+
+    len = strlen(path);
+    if(len > 1024) goto fail;
+
+    msg.req.id = ID_LIST;
+    msg.req.namelen = htoll(len);
+
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, path, len)) {
+        goto fail;
+    }
+
+    for(;;) {
+        if(readx(fd, &msg.dent, sizeof(msg.dent))) break;
+        if(msg.dent.id == ID_DONE) return 0;
+        if(msg.dent.id != ID_DENT) break;
+
+        len = ltohl(msg.dent.namelen);
+        if(len > 256) break;
+
+        if(readx(fd, buf, len)) break;
+        buf[len] = 0;
+
+        func(ltohl(msg.dent.mode),
+             ltohl(msg.dent.size),
+             ltohl(msg.dent.time),
+             buf, cookie);
+    }
+
+fail:
+    adb_close(fd);
+    return -1;
+}
+
+typedef struct syncsendbuf syncsendbuf;
+
+struct syncsendbuf {
+    unsigned id;
+    unsigned size;
+    char data[SYNC_DATA_MAX];
+};
+
+static syncsendbuf send_buffer;
+
+int sync_readtime(int fd, const char *path, unsigned int *timestamp,
+                  unsigned int *mode)
+{
+    syncmsg msg;
+    int len = strlen(path);
+
+    msg.req.id = ID_STAT;
+    msg.req.namelen = htoll(len);
+
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, path, len)) {
+        return -1;
+    }
+
+    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
+        return -1;
+    }
+
+    if(msg.stat.id != ID_STAT) {
+        return -1;
+    }
+
+    *timestamp = ltohl(msg.stat.time);
+    *mode = ltohl(msg.stat.mode);
+    return 0;
+}
+
+static int sync_start_readtime(int fd, const char *path)
+{
+    syncmsg msg;
+    int len = strlen(path);
+
+    msg.req.id = ID_STAT;
+    msg.req.namelen = htoll(len);
+
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, path, len)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int sync_finish_readtime(int fd, unsigned int *timestamp,
+                                unsigned int *mode, unsigned int *size)
+{
+    syncmsg msg;
+
+    if(readx(fd, &msg.stat, sizeof(msg.stat)))
+        return -1;
+
+    if(msg.stat.id != ID_STAT)
+        return -1;
+
+    *timestamp = ltohl(msg.stat.time);
+    *mode = ltohl(msg.stat.mode);
+    *size = ltohl(msg.stat.size);
+
+    return 0;
+}
+
+int sync_readmode(int fd, const char *path, unsigned *mode)
+{
+    syncmsg msg;
+    int len = strlen(path);
+
+    msg.req.id = ID_STAT;
+    msg.req.namelen = htoll(len);
+
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, path, len)) {
+        return -1;
+    }
+
+    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
+        return -1;
+    }
+
+    if(msg.stat.id != ID_STAT) {
+        return -1;
+    }
+
+    *mode = ltohl(msg.stat.mode);
+    return 0;
+}
+
+static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
+{
+    int lfd, err = 0;
+    unsigned long long size = 0;
+
+    lfd = adb_open(path, O_RDONLY);
+    if(lfd < 0) {
+        fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
+        return -1;
+    }
+
+    if (show_progress) {
+        // Determine local file size.
+        struct stat st;
+        if (fstat(lfd, &st)) {
+            fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
+            return -1;
+        }
+
+        size = st.st_size;
+    }
+
+    sbuf->id = ID_DATA;
+    for(;;) {
+        int ret;
+
+        ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
+        if(!ret)
+            break;
+
+        if(ret < 0) {
+            if(errno == EINTR)
+                continue;
+            fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
+            break;
+        }
+
+        sbuf->size = htoll(ret);
+        if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
+            err = -1;
+            break;
+        }
+        total_bytes += ret;
+
+        if (show_progress) {
+            print_transfer_progress(total_bytes, size);
+        }
+    }
+
+    adb_close(lfd);
+    return err;
+}
+
+static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
+                             int show_progress)
+{
+    int err = 0;
+    int total = 0;
+
+    sbuf->id = ID_DATA;
+    while (total < size) {
+        int count = size - total;
+        if (count > SYNC_DATA_MAX) {
+            count = SYNC_DATA_MAX;
+        }
+
+        memcpy(sbuf->data, &file_buffer[total], count);
+        sbuf->size = htoll(count);
+        if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
+            err = -1;
+            break;
+        }
+        total += count;
+        total_bytes += count;
+
+        if (show_progress) {
+            print_transfer_progress(total, size);
+        }
+    }
+
+    return err;
+}
+
+#ifdef HAVE_SYMLINKS
+static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
+{
+    int len, ret;
+
+    len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
+    if(len < 0) {
+        fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
+        return -1;
+    }
+    sbuf->data[len] = '\0';
+
+    sbuf->size = htoll(len + 1);
+    sbuf->id = ID_DATA;
+
+    ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
+    if(ret)
+        return -1;
+
+    total_bytes += len + 1;
+
+    return 0;
+}
+#endif
+
+static int sync_send(int fd, const char *lpath, const char *rpath,
+                     unsigned mtime, mode_t mode, int show_progress)
+{
+    syncmsg msg;
+    int len, r;
+    syncsendbuf *sbuf = &send_buffer;
+    char* file_buffer = NULL;
+    int size = 0;
+    char tmp[64];
+
+    len = strlen(rpath);
+    if(len > 1024) goto fail;
+
+    snprintf(tmp, sizeof(tmp), ",%d", mode);
+    r = strlen(tmp);
+
+    msg.req.id = ID_SEND;
+    msg.req.namelen = htoll(len + r);
+
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, rpath, len) || writex(fd, tmp, r)) {
+        free(file_buffer);
+        goto fail;
+    }
+
+    if (file_buffer) {
+        write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
+        free(file_buffer);
+    } else if (S_ISREG(mode))
+        write_data_file(fd, lpath, sbuf, show_progress);
+#ifdef HAVE_SYMLINKS
+    else if (S_ISLNK(mode))
+        write_data_link(fd, lpath, sbuf);
+#endif
+    else
+        goto fail;
+
+    msg.data.id = ID_DONE;
+    msg.data.size = htoll(mtime);
+    if(writex(fd, &msg.data, sizeof(msg.data)))
+        goto fail;
+
+    if(readx(fd, &msg.status, sizeof(msg.status)))
+        return -1;
+
+    if(msg.status.id != ID_OKAY) {
+        if(msg.status.id == ID_FAIL) {
+            len = ltohl(msg.status.msglen);
+            if(len > 256) len = 256;
+            if(readx(fd, sbuf->data, len)) {
+                return -1;
+            }
+            sbuf->data[len] = 0;
+        } else
+            strcpy(sbuf->data, "unknown reason");
+
+        fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
+        return -1;
+    }
+
+    return 0;
+
+fail:
+    fprintf(stderr,"protocol failure\n");
+    adb_close(fd);
+    return -1;
+}
+
+static int mkdirs(const char *name)
+{
+    int ret;
+    char *x = (char *)name + 1;
+
+    for(;;) {
+        x = adb_dirstart(x);
+        if(x == 0) return 0;
+        *x = 0;
+        ret = adb_mkdir(name, 0775);
+        *x = OS_PATH_SEPARATOR;
+        if((ret < 0) && (errno != EEXIST)) {
+            return ret;
+        }
+        x++;
+    }
+    return 0;
+}
+
+int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
+{
+    syncmsg msg;
+    int len;
+    int lfd = -1;
+    char *buffer = send_buffer.data;
+    unsigned id;
+    unsigned long long size = 0;
+
+    len = strlen(rpath);
+    if(len > 1024) return -1;
+
+    if (show_progress) {
+        // Determine remote file size.
+        syncmsg stat_msg;
+        stat_msg.req.id = ID_STAT;
+        stat_msg.req.namelen = htoll(len);
+
+        if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
+            writex(fd, rpath, len)) {
+            return -1;
+        }
+
+        if (readx(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
+            return -1;
+        }
+
+        if (stat_msg.stat.id != ID_STAT) return -1;
+
+        size = ltohl(stat_msg.stat.size);
+    }
+
+    msg.req.id = ID_RECV;
+    msg.req.namelen = htoll(len);
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, rpath, len)) {
+        return -1;
+    }
+
+    if(readx(fd, &msg.data, sizeof(msg.data))) {
+        return -1;
+    }
+    id = msg.data.id;
+
+    if((id == ID_DATA) || (id == ID_DONE)) {
+        adb_unlink(lpath);
+        mkdirs(lpath);
+        lfd = adb_creat(lpath, 0644);
+        if(lfd < 0) {
+            fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
+            return -1;
+        }
+        goto handle_data;
+    } else {
+        goto remote_error;
+    }
+
+    for(;;) {
+        if(readx(fd, &msg.data, sizeof(msg.data))) {
+            return -1;
+        }
+        id = msg.data.id;
+
+    handle_data:
+        len = ltohl(msg.data.size);
+        if(id == ID_DONE) break;
+        if(id != ID_DATA) goto remote_error;
+        if(len > SYNC_DATA_MAX) {
+            fprintf(stderr,"data overrun\n");
+            adb_close(lfd);
+            return -1;
+        }
+
+        if(readx(fd, buffer, len)) {
+            adb_close(lfd);
+            return -1;
+        }
+
+        if(writex(lfd, buffer, len)) {
+            fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
+            adb_close(lfd);
+            return -1;
+        }
+
+        total_bytes += len;
+
+        if (show_progress) {
+            print_transfer_progress(total_bytes, size);
+        }
+    }
+
+    adb_close(lfd);
+    return 0;
+
+remote_error:
+    adb_close(lfd);
+    adb_unlink(lpath);
+
+    if(id == ID_FAIL) {
+        len = ltohl(msg.data.size);
+        if(len > 256) len = 256;
+        if(readx(fd, buffer, len)) {
+            return -1;
+        }
+        buffer[len] = 0;
+    } else {
+        memcpy(buffer, &id, 4);
+        buffer[4] = 0;
+//        strcpy(buffer,"unknown reason");
+    }
+    fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
+    return 0;
+}
+
+
+
+/* --- */
+
+
+static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
+                          const char *name, void *cookie)
+{
+    printf("%08x %08x %08x %s\n", mode, size, time, name);
+}
+
+int do_sync_ls(const char *path)
+{
+    int fd = adb_connect("sync:");
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", adb_error());
+        return 1;
+    }
+
+    if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
+        return 1;
+    } else {
+        sync_quit(fd);
+        return 0;
+    }
+}
+
+typedef struct copyinfo copyinfo;
+
+struct copyinfo
+{
+    copyinfo *next;
+    const char *src;
+    const char *dst;
+    unsigned int time;
+    unsigned int mode;
+    unsigned int size;
+    int flag;
+    //char data[0];
+};
+
+copyinfo *mkcopyinfo(const char *spath, const char *dpath,
+                     const char *name, int isdir)
+{
+    int slen = strlen(spath);
+    int dlen = strlen(dpath);
+    int nlen = strlen(name);
+    int ssize = slen + nlen + 2;
+    int dsize = dlen + nlen + 2;
+
+    copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize);
+    if(ci == 0) {
+        fprintf(stderr,"out of memory\n");
+        abort();
+    }
+
+    ci->next = 0;
+    ci->time = 0;
+    ci->mode = 0;
+    ci->size = 0;
+    ci->flag = 0;
+    ci->src = (const char*)(ci + 1);
+    ci->dst = ci->src + ssize;
+    snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
+    snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
+
+//    fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst);
+    return ci;
+}
+
+
+static int local_build_list(copyinfo **filelist,
+                            const char *lpath, const char *rpath)
+{
+    DIR *d;
+    struct dirent *de;
+    struct stat st;
+    copyinfo *dirlist = 0;
+    copyinfo *ci, *next;
+
+//    fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath);
+
+    d = opendir(lpath);
+    if(d == 0) {
+        fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
+        return -1;
+    }
+
+    while((de = readdir(d))) {
+        char stat_path[PATH_MAX];
+        char *name = de->d_name;
+
+        if(name[0] == '.') {
+            if(name[1] == 0) continue;
+            if((name[1] == '.') && (name[2] == 0)) continue;
+        }
+
+        /*
+         * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
+         * always returns DT_UNKNOWN, so we just use stat() for all cases.
+         */
+        if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
+            continue;
+        strcpy(stat_path, lpath);
+        strcat(stat_path, de->d_name);
+
+        if(!lstat(stat_path, &st)) {
+            if (S_ISDIR(st.st_mode)) {
+                ci = mkcopyinfo(lpath, rpath, name, 1);
+                ci->next = dirlist;
+                dirlist = ci;
+            } else {
+                ci = mkcopyinfo(lpath, rpath, name, 0);
+                if(lstat(ci->src, &st)) {
+                    fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
+                    free(ci);
+                    closedir(d);
+                    return -1;
+                }
+                if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+                    fprintf(stderr, "skipping special file '%s'\n", ci->src);
+                    free(ci);
+                } else {
+                    ci->time = st.st_mtime;
+                    ci->mode = st.st_mode;
+                    ci->size = st.st_size;
+                    ci->next = *filelist;
+                    *filelist = ci;
+                }
+            }
+        } else {
+            fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
+        }
+    }
+
+    closedir(d);
+
+    for(ci = dirlist; ci != 0; ci = next) {
+        next = ci->next;
+        local_build_list(filelist, ci->src, ci->dst);
+        free(ci);
+    }
+
+    return 0;
+}
+
+
+static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
+{
+    copyinfo *filelist = 0;
+    copyinfo *ci, *next;
+    int pushed = 0;
+    int skipped = 0;
+
+    if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
+    if(lpath[strlen(lpath) - 1] != '/') {
+        int  tmplen = strlen(lpath)+2;
+        char *tmp = malloc(tmplen);
+        if(tmp == 0) return -1;
+        snprintf(tmp, tmplen, "%s/",lpath);
+        lpath = tmp;
+    }
+    if(rpath[strlen(rpath) - 1] != '/') {
+        int tmplen = strlen(rpath)+2;
+        char *tmp = malloc(tmplen);
+        if(tmp == 0) return -1;
+        snprintf(tmp, tmplen, "%s/",rpath);
+        rpath = tmp;
+    }
+
+    if(local_build_list(&filelist, lpath, rpath)) {
+        return -1;
+    }
+
+    if(checktimestamps){
+        for(ci = filelist; ci != 0; ci = ci->next) {
+            if(sync_start_readtime(fd, ci->dst)) {
+                return 1;
+            }
+        }
+        for(ci = filelist; ci != 0; ci = ci->next) {
+            unsigned int timestamp, mode, size;
+            if(sync_finish_readtime(fd, &timestamp, &mode, &size))
+                return 1;
+            if(size == ci->size) {
+                /* for links, we cannot update the atime/mtime */
+                if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
+                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
+                    ci->flag = 1;
+            }
+        }
+    }
+    for(ci = filelist; ci != 0; ci = next) {
+        next = ci->next;
+        if(ci->flag == 0) {
+            fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
+            if(!listonly &&
+               sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
+                         0 /* no show progress */)) {
+                return 1;
+            }
+            pushed++;
+        } else {
+            skipped++;
+        }
+        free(ci);
+    }
+
+    fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
+            pushed, (pushed == 1) ? "" : "s",
+            skipped, (skipped == 1) ? "" : "s");
+
+    return 0;
+}
+
+
+int do_sync_push(const char *lpath, const char *rpath, int show_progress)
+{
+    struct stat st;
+    unsigned mode;
+    int fd;
+
+    fd = adb_connect("sync:");
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", adb_error());
+        return 1;
+    }
+
+    if(stat(lpath, &st)) {
+        fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
+        sync_quit(fd);
+        return 1;
+    }
+
+    if(S_ISDIR(st.st_mode)) {
+        BEGIN();
+        if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
+            return 1;
+        } else {
+            END();
+            sync_quit(fd);
+        }
+    } else {
+        if(sync_readmode(fd, rpath, &mode)) {
+            return 1;
+        }
+        if((mode != 0) && S_ISDIR(mode)) {
+                /* if we're copying a local file to a remote directory,
+                ** we *really* want to copy to remotedir + "/" + localfilename
+                */
+            const char *name = adb_dirstop(lpath);
+            if(name == 0) {
+                name = lpath;
+            } else {
+                name++;
+            }
+            int  tmplen = strlen(name) + strlen(rpath) + 2;
+            char *tmp = malloc(strlen(name) + strlen(rpath) + 2);
+            if(tmp == 0) return 1;
+            snprintf(tmp, tmplen, "%s/%s", rpath, name);
+            rpath = tmp;
+        }
+        BEGIN();
+        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
+            return 1;
+        } else {
+            END();
+            sync_quit(fd);
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
+
+typedef struct {
+    copyinfo **filelist;
+    copyinfo **dirlist;
+    const char *rpath;
+    const char *lpath;
+} sync_ls_build_list_cb_args;
+
+void
+sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
+                      const char *name, void *cookie)
+{
+    sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
+    copyinfo *ci;
+
+    if (S_ISDIR(mode)) {
+        copyinfo **dirlist = args->dirlist;
+
+        /* Don't try recursing down "." or ".." */
+        if (name[0] == '.') {
+            if (name[1] == '\0') return;
+            if ((name[1] == '.') && (name[2] == '\0')) return;
+        }
+
+        ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
+        ci->next = *dirlist;
+        *dirlist = ci;
+    } else if (S_ISREG(mode) || S_ISLNK(mode)) {
+        copyinfo **filelist = args->filelist;
+
+        ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
+        ci->time = time;
+        ci->mode = mode;
+        ci->size = size;
+        ci->next = *filelist;
+        *filelist = ci;
+    } else {
+        fprintf(stderr, "skipping special file '%s'\n", name);
+    }
+}
+
+static int remote_build_list(int syncfd, copyinfo **filelist,
+                             const char *rpath, const char *lpath)
+{
+    copyinfo *dirlist = NULL;
+    sync_ls_build_list_cb_args args;
+
+    args.filelist = filelist;
+    args.dirlist = &dirlist;
+    args.rpath = rpath;
+    args.lpath = lpath;
+
+    /* Put the files/dirs in rpath on the lists. */
+    if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
+        return 1;
+    }
+
+    /* Recurse into each directory we found. */
+    while (dirlist != NULL) {
+        copyinfo *next = dirlist->next;
+        if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
+            return 1;
+        }
+        free(dirlist);
+        dirlist = next;
+    }
+
+    return 0;
+}
+
+static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode)
+{
+    struct utimbuf times = { time, time };
+    int r1 = utime(lpath, &times);
+
+    /* use umask for permissions */
+    mode_t mask=umask(0000);
+    umask(mask);
+    int r2 = chmod(lpath, mode & ~mask);
+
+    return r1 ? : r2;
+}
+
+static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
+                                 int copy_attrs)
+{
+    copyinfo *filelist = 0;
+    copyinfo *ci, *next;
+    int pulled = 0;
+    int skipped = 0;
+
+    /* Make sure that both directory paths end in a slash. */
+    if (rpath[0] == 0 || lpath[0] == 0) return -1;
+    if (rpath[strlen(rpath) - 1] != '/') {
+        int  tmplen = strlen(rpath) + 2;
+        char *tmp = malloc(tmplen);
+        if (tmp == 0) return -1;
+        snprintf(tmp, tmplen, "%s/", rpath);
+        rpath = tmp;
+    }
+    if (lpath[strlen(lpath) - 1] != '/') {
+        int  tmplen = strlen(lpath) + 2;
+        char *tmp = malloc(tmplen);
+        if (tmp == 0) return -1;
+        snprintf(tmp, tmplen, "%s/", lpath);
+        lpath = tmp;
+    }
+
+    fprintf(stderr, "pull: building file list...\n");
+    /* Recursively build the list of files to copy. */
+    if (remote_build_list(fd, &filelist, rpath, lpath)) {
+        return -1;
+    }
+
+    for (ci = filelist; ci != 0; ci = next) {
+        next = ci->next;
+        if (ci->flag == 0) {
+            fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
+            if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
+                return 1;
+            }
+
+            if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
+               return 1;
+            }
+            pulled++;
+        } else {
+            skipped++;
+        }
+        free(ci);
+    }
+
+    fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
+            pulled, (pulled == 1) ? "" : "s",
+            skipped, (skipped == 1) ? "" : "s");
+
+    return 0;
+}
+
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs)
+{
+    unsigned mode, time;
+    struct stat st;
+
+    int fd;
+
+    fd = adb_connect("sync:");
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", adb_error());
+        return 1;
+    }
+
+    if(sync_readtime(fd, rpath, &time, &mode)) {
+        return 1;
+    }
+    if(mode == 0) {
+        fprintf(stderr,"remote object '%s' does not exist\n", rpath);
+        return 1;
+    }
+
+    if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
+        if(stat(lpath, &st) == 0) {
+            if(S_ISDIR(st.st_mode)) {
+                    /* if we're copying a remote file to a local directory,
+                    ** we *really* want to copy to localdir + "/" + remotefilename
+                    */
+                const char *name = adb_dirstop(rpath);
+                if(name == 0) {
+                    name = rpath;
+                } else {
+                    name++;
+                }
+                int  tmplen = strlen(name) + strlen(lpath) + 2;
+                char *tmp = malloc(tmplen);
+                if(tmp == 0) return 1;
+                snprintf(tmp, tmplen, "%s/%s", lpath, name);
+                lpath = tmp;
+            }
+        }
+        BEGIN();
+        if (sync_recv(fd, rpath, lpath, show_progress)) {
+            return 1;
+        } else {
+            if (copy_attrs && set_time_and_mode(lpath, time, mode))
+                return 1;
+            END();
+            sync_quit(fd);
+            return 0;
+        }
+    } else if(S_ISDIR(mode)) {
+        BEGIN();
+        if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
+            return 1;
+        } else {
+            END();
+            sync_quit(fd);
+            return 0;
+        }
+    } else {
+        fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
+        return 1;
+    }
+}
+
+int do_sync_sync(const char *lpath, const char *rpath, int listonly)
+{
+    fprintf(stderr,"syncing %s...\n",rpath);
+
+    int fd = adb_connect("sync:");
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", adb_error());
+        return 1;
+    }
+
+    BEGIN();
+    if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
+        return 1;
+    } else {
+        END();
+        sync_quit(fd);
+        return 0;
+    }
+}
diff --git a/src/devtools/adb/file_sync_service.c b/src/devtools/adb/file_sync_service.c
new file mode 100755
index 0000000..b2a8bc6
--- /dev/null
+++ b/src/devtools/adb/file_sync_service.c
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <utime.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <private/android_filesystem_config.h>
+
+#ifndef ADB_NON_ANDROID
+#include <selinux/android.h>
+#endif
+#include "sysdeps.h"
+
+#define TRACE_TAG  TRACE_SYNC
+#include "adb.h"
+#include "file_sync_service.h"
+
+/* TODO: use fs_config to configure permissions on /data */
+static bool is_on_system(const char *name) {
+    const char *SYSTEM = "/system/";
+    return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
+}
+
+static bool is_on_vendor(const char *name) {
+    const char *VENDOR = "/vendor/";
+    return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
+}
+
+static int mkdirs(char *name)
+{
+    int ret;
+    char *x = name + 1;
+    uid_t uid = -1;
+    gid_t gid = -1;
+    unsigned int mode = 0775;
+    uint64_t cap = 0;
+
+    if(name[0] != '/') return -1;
+
+    for(;;) {
+        x = adb_dirstart(x);
+        if(x == 0) return 0;
+        *x = 0;
+        if (is_on_system(name) || is_on_vendor(name)) {
+            fs_config(name, 1, &uid, &gid, &mode, &cap);
+        }
+        ret = adb_mkdir(name, mode);
+        if((ret < 0) && (errno != EEXIST)) {
+            D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
+            *x = '/';
+            return ret;
+        } else if(ret == 0) {
+            ret = chown(name, uid, gid);
+            if (ret < 0) {
+                *x = '/';
+                return ret;
+            }
+#ifndef ADB_NON_ANDROID
+            selinux_android_restorecon(name, 0);
+#endif
+        }
+        *x++ = '/';
+    }
+    return 0;
+}
+
+static int do_stat(int s, const char *path)
+{
+    syncmsg msg;
+    struct stat st;
+
+    msg.stat.id = ID_STAT;
+
+    if(lstat(path, &st)) {
+        msg.stat.mode = 0;
+        msg.stat.size = 0;
+        msg.stat.time = 0;
+    } else {
+        msg.stat.mode = htoll(st.st_mode);
+        msg.stat.size = htoll(st.st_size);
+        msg.stat.time = htoll(st.st_mtime);
+    }
+
+    return writex(s, &msg.stat, sizeof(msg.stat));
+}
+
+static int do_list(int s, const char *path)
+{
+    DIR *d;
+    struct dirent *de;
+    struct stat st;
+    syncmsg msg;
+    int len;
+
+    char tmp[1024 + 256 + 1];
+    char *fname;
+
+    len = strlen(path);
+    memcpy(tmp, path, len);
+    tmp[len] = '/';
+    fname = tmp + len + 1;
+
+    msg.dent.id = ID_DENT;
+
+    d = opendir(path);
+    if(d == 0) goto done;
+
+    while((de = readdir(d))) {
+        int len = strlen(de->d_name);
+
+            /* not supposed to be possible, but
+               if it does happen, let's not buffer overrun */
+        if(len > 256) continue;
+
+        strcpy(fname, de->d_name);
+        if(lstat(tmp, &st) == 0) {
+            msg.dent.mode = htoll(st.st_mode);
+            msg.dent.size = htoll(st.st_size);
+            msg.dent.time = htoll(st.st_mtime);
+            msg.dent.namelen = htoll(len);
+
+            if(writex(s, &msg.dent, sizeof(msg.dent)) ||
+               writex(s, de->d_name, len)) {
+                closedir(d);
+                return -1;
+            }
+        }
+    }
+
+    closedir(d);
+
+done:
+    msg.dent.id = ID_DONE;
+    msg.dent.mode = 0;
+    msg.dent.size = 0;
+    msg.dent.time = 0;
+    msg.dent.namelen = 0;
+    return writex(s, &msg.dent, sizeof(msg.dent));
+}
+
+static int fail_message(int s, const char *reason)
+{
+    syncmsg msg;
+    int len = strlen(reason);
+
+    D("sync: failure: %s\n", reason);
+
+    msg.data.id = ID_FAIL;
+    msg.data.size = htoll(len);
+    if(writex(s, &msg.data, sizeof(msg.data)) ||
+       writex(s, reason, len)) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+static int fail_errno(int s)
+{
+    return fail_message(s, strerror(errno));
+}
+
+static int handle_send_file(int s, char *path, uid_t uid,
+        gid_t gid, mode_t mode, char *buffer, bool do_unlink)
+{
+    syncmsg msg;
+    unsigned int timestamp = 0;
+    int fd;
+
+    fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+    if(fd < 0 && errno == ENOENT) {
+        if(mkdirs(path) != 0) {
+            if(fail_errno(s))
+                return -1;
+            fd = -1;
+        } else {
+            fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+        }
+    }
+    if(fd < 0 && errno == EEXIST) {
+        fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
+    }
+    if(fd < 0) {
+        if(fail_errno(s))
+            return -1;
+        fd = -1;
+    } else {
+        if(fchown(fd, uid, gid) != 0) {
+            fail_errno(s);
+            errno = 0;
+        }
+
+        /*
+         * fchown clears the setuid bit - restore it if present.
+         * Ignore the result of calling fchmod. It's not supported
+         * by all filesystems. b/12441485
+         */
+        fchmod(fd, mode);
+    }
+
+    for(;;) {
+        unsigned int len;
+
+        if(readx(s, &msg.data, sizeof(msg.data)))
+            goto fail;
+
+        if(msg.data.id != ID_DATA) {
+            if(msg.data.id == ID_DONE) {
+                timestamp = ltohl(msg.data.size);
+                break;
+            }
+            fail_message(s, "invalid data message");
+            goto fail;
+        }
+        len = ltohl(msg.data.size);
+        if(len > SYNC_DATA_MAX) {
+            fail_message(s, "oversize data message");
+            goto fail;
+        }
+        if(readx(s, buffer, len))
+            goto fail;
+
+        if(fd < 0)
+            continue;
+        if(writex(fd, buffer, len)) {
+            int saved_errno = errno;
+            adb_close(fd);
+            if (do_unlink) adb_unlink(path);
+            fd = -1;
+            errno = saved_errno;
+            if(fail_errno(s)) return -1;
+        }
+    }
+
+    if(fd >= 0) {
+        struct utimbuf u;
+        adb_close(fd);
+#ifndef ADB_NON_ANDROID
+        selinux_android_restorecon(path, 0);
+#endif
+        u.actime = timestamp;
+        u.modtime = timestamp;
+        utime(path, &u);
+
+        msg.status.id = ID_OKAY;
+        msg.status.msglen = 0;
+        if(writex(s, &msg.status, sizeof(msg.status)))
+            return -1;
+    }
+    return 0;
+
+fail:
+    if(fd >= 0)
+        adb_close(fd);
+    if (do_unlink) adb_unlink(path);
+    return -1;
+}
+
+#ifdef HAVE_SYMLINKS
+static int handle_send_link(int s, char *path, char *buffer)
+{
+    syncmsg msg;
+    unsigned int len;
+    int ret;
+
+    if(readx(s, &msg.data, sizeof(msg.data)))
+        return -1;
+
+    if(msg.data.id != ID_DATA) {
+        fail_message(s, "invalid data message: expected ID_DATA");
+        return -1;
+    }
+
+    len = ltohl(msg.data.size);
+    if(len > SYNC_DATA_MAX) {
+        fail_message(s, "oversize data message");
+        return -1;
+    }
+    if(readx(s, buffer, len))
+        return -1;
+
+    ret = symlink(buffer, path);
+    if(ret && errno == ENOENT) {
+        if(mkdirs(path) != 0) {
+            fail_errno(s);
+            return -1;
+        }
+        ret = symlink(buffer, path);
+    }
+    if(ret) {
+        fail_errno(s);
+        return -1;
+    }
+
+    if(readx(s, &msg.data, sizeof(msg.data)))
+        return -1;
+
+    if(msg.data.id == ID_DONE) {
+        msg.status.id = ID_OKAY;
+        msg.status.msglen = 0;
+        if(writex(s, &msg.status, sizeof(msg.status)))
+            return -1;
+    } else {
+        fail_message(s, "invalid data message: expected ID_DONE");
+        return -1;
+    }
+
+    return 0;
+}
+#endif /* HAVE_SYMLINKS */
+
+static int do_send(int s, char *path, char *buffer)
+{
+    char *tmp;
+    unsigned int mode;
+    int is_link, ret;
+    bool do_unlink;
+
+    tmp = strrchr(path,',');
+    if(tmp) {
+        *tmp = 0;
+        errno = 0;
+        mode = strtoul(tmp + 1, NULL, 0);
+#ifndef HAVE_SYMLINKS
+        is_link = 0;
+#else
+        is_link = S_ISLNK((mode_t) mode);
+#endif
+        mode &= 0777;
+    }
+    if(!tmp || errno) {
+        mode = 0644;
+        is_link = 0;
+        do_unlink = true;
+    } else {
+        struct stat st;
+        /* Don't delete files before copying if they are not "regular" */
+        do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
+        if (do_unlink) {
+            adb_unlink(path);
+        }
+    }
+
+#ifdef HAVE_SYMLINKS
+    if(is_link)
+        ret = handle_send_link(s, path, buffer);
+    else {
+#else
+    {
+#endif
+        uid_t uid = -1;
+        gid_t gid = -1;
+        uint64_t cap = 0;
+
+        /* copy user permission bits to "group" and "other" permissions */
+        mode |= ((mode >> 3) & 0070);
+        mode |= ((mode >> 3) & 0007);
+
+        tmp = path;
+        if(*tmp == '/') {
+            tmp++;
+        }
+        if (is_on_system(path) || is_on_vendor(path)) {
+            fs_config(tmp, 0, &uid, &gid, &mode, &cap);
+        }
+        ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
+    }
+
+    return ret;
+}
+
+static int do_recv(int s, const char *path, char *buffer)
+{
+    syncmsg msg;
+    int fd, r;
+
+    fd = adb_open(path, O_RDONLY | O_CLOEXEC);
+    if(fd < 0) {
+        if(fail_errno(s)) return -1;
+        return 0;
+    }
+
+    msg.data.id = ID_DATA;
+    for(;;) {
+        r = adb_read(fd, buffer, SYNC_DATA_MAX);
+        if(r <= 0) {
+            if(r == 0) break;
+            if(errno == EINTR) continue;
+            r = fail_errno(s);
+            adb_close(fd);
+            return r;
+        }
+        msg.data.size = htoll(r);
+        if(writex(s, &msg.data, sizeof(msg.data)) ||
+           writex(s, buffer, r)) {
+            adb_close(fd);
+            return -1;
+        }
+    }
+
+    adb_close(fd);
+
+    msg.data.id = ID_DONE;
+    msg.data.size = 0;
+    if(writex(s, &msg.data, sizeof(msg.data))) {
+        return -1;
+    }
+
+    return 0;
+}
+
+void file_sync_service(int fd, void *cookie)
+{
+    syncmsg msg;
+    char name[1025];
+    unsigned namelen;
+
+    char *buffer = malloc(SYNC_DATA_MAX);
+    if(buffer == 0) goto fail;
+
+    for(;;) {
+        D("sync: waiting for command\n");
+
+        if(readx(fd, &msg.req, sizeof(msg.req))) {
+            fail_message(fd, "command read failure");
+            break;
+        }
+        namelen = ltohl(msg.req.namelen);
+        if(namelen > 1024) {
+            fail_message(fd, "invalid namelen");
+            break;
+        }
+        if(readx(fd, name, namelen)) {
+            fail_message(fd, "filename read failure");
+            break;
+        }
+        name[namelen] = 0;
+
+        msg.req.namelen = 0;
+        D("sync: '%s' '%s'\n", (char*) &msg.req, name);
+
+        switch(msg.req.id) {
+        case ID_STAT:
+            if(do_stat(fd, name)) goto fail;
+            break;
+        case ID_LIST:
+            if(do_list(fd, name)) goto fail;
+            break;
+        case ID_SEND:
+            if(do_send(fd, name, buffer)) goto fail;
+            break;
+        case ID_RECV:
+            if(do_recv(fd, name, buffer)) goto fail;
+            break;
+        case ID_QUIT:
+            goto fail;
+        default:
+            fail_message(fd, "unknown command");
+            goto fail;
+        }
+    }
+
+fail:
+    if(buffer != 0) free(buffer);
+    D("sync: done\n");
+    adb_close(fd);
+}
diff --git a/src/devtools/adb/file_sync_service.h b/src/devtools/adb/file_sync_service.h
new file mode 100755
index 0000000..5dd2e80
--- /dev/null
+++ b/src/devtools/adb/file_sync_service.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _FILE_SYNC_SERVICE_H_
+#define _FILE_SYNC_SERVICE_H_
+
+#ifdef HAVE_BIG_ENDIAN
+static inline unsigned __swap_uint32(unsigned x) 
+{
+    return (((x) & 0xFF000000) >> 24)
+        | (((x) & 0x00FF0000) >> 8)
+        | (((x) & 0x0000FF00) << 8)
+        | (((x) & 0x000000FF) << 24);
+}
+#define htoll(x) __swap_uint32(x)
+#define ltohl(x) __swap_uint32(x)
+#define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24))
+#else
+#define htoll(x) (x)
+#define ltohl(x) (x)
+#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
+#endif
+
+#define ID_STAT MKID('S','T','A','T')
+#define ID_LIST MKID('L','I','S','T')
+#define ID_ULNK MKID('U','L','N','K')
+#define ID_SEND MKID('S','E','N','D')
+#define ID_RECV MKID('R','E','C','V')
+#define ID_DENT MKID('D','E','N','T')
+#define ID_DONE MKID('D','O','N','E')
+#define ID_DATA MKID('D','A','T','A')
+#define ID_OKAY MKID('O','K','A','Y')
+#define ID_FAIL MKID('F','A','I','L')
+#define ID_QUIT MKID('Q','U','I','T')
+
+typedef union {
+    unsigned id;
+    struct {
+        unsigned id;
+        unsigned namelen;
+    } req;
+    struct {
+        unsigned id;
+        unsigned mode;
+        unsigned size;
+        unsigned time;
+    } stat;
+    struct {
+        unsigned id;
+        unsigned mode;
+        unsigned size;
+        unsigned time;
+        unsigned namelen;
+    } dent;
+    struct {
+        unsigned id;
+        unsigned size;
+    } data;
+    struct {
+        unsigned id;
+        unsigned msglen;
+    } status;
+} syncmsg;
+
+
+void file_sync_service(int fd, void *cookie);
+int do_sync_ls(const char *path);
+int do_sync_push(const char *lpath, const char *rpath, int show_progress);
+int do_sync_sync(const char *lpath, const char *rpath, int listonly);
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
+
+#define SYNC_DATA_MAX (64*1024)
+
+#endif
diff --git a/src/devtools/adb/framebuffer_service.c b/src/devtools/adb/framebuffer_service.c
new file mode 100755
index 0000000..1c5cd2f
--- /dev/null
+++ b/src/devtools/adb/framebuffer_service.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "fdevent.h"
+#include "adb.h"
+
+#include <linux/fb.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <cutils/fs.h>
+
+/* TODO:
+** - sync with vsync to avoid tearing
+*/
+/* This version number defines the format of the fbinfo struct.
+   It must match versioning in ddms where this data is consumed. */
+#define DDMS_RAWIMAGE_VERSION 1
+struct fbinfo {
+    unsigned int version;
+    unsigned int bpp;
+    unsigned int size;
+    unsigned int width;
+    unsigned int height;
+    unsigned int red_offset;
+    unsigned int red_length;
+    unsigned int blue_offset;
+    unsigned int blue_length;
+    unsigned int green_offset;
+    unsigned int green_length;
+    unsigned int alpha_offset;
+    unsigned int alpha_length;
+} __attribute__((packed));
+
+void framebuffer_service(int fd, void *cookie)
+{
+    struct fbinfo fbinfo;
+    unsigned int i, bsize;
+    char buf[640];
+    int fd_screencap;
+    int w, h, f;
+    int fds[2];
+
+    if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail;
+
+    pid_t pid = fork();
+    if (pid < 0) goto done;
+
+    if (pid == 0) {
+        dup2(fds[1], STDOUT_FILENO);
+        close(fds[0]);
+        close(fds[1]);
+        const char* command = "screencap";
+        const char *args[2] = {command, NULL};
+        execvp(command, (char**)args);
+        exit(1);
+    }
+
+    fd_screencap = fds[0];
+
+    /* read w, h & format */
+    if(readx(fd_screencap, &w, 4)) goto done;
+    if(readx(fd_screencap, &h, 4)) goto done;
+    if(readx(fd_screencap, &f, 4)) goto done;
+
+    fbinfo.version = DDMS_RAWIMAGE_VERSION;
+    /* see hardware/hardware.h */
+    switch (f) {
+        case 1: /* RGBA_8888 */
+            fbinfo.bpp = 32;
+            fbinfo.size = w * h * 4;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 0;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 16;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 8;
+            break;
+        case 2: /* RGBX_8888 */
+            fbinfo.bpp = 32;
+            fbinfo.size = w * h * 4;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 0;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 16;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 0;
+            break;
+        case 3: /* RGB_888 */
+            fbinfo.bpp = 24;
+            fbinfo.size = w * h * 3;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 0;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 16;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 0;
+            break;
+        case 4: /* RGB_565 */
+            fbinfo.bpp = 16;
+            fbinfo.size = w * h * 2;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 11;
+            fbinfo.red_length = 5;
+            fbinfo.green_offset = 5;
+            fbinfo.green_length = 6;
+            fbinfo.blue_offset = 0;
+            fbinfo.blue_length = 5;
+            fbinfo.alpha_offset = 0;
+            fbinfo.alpha_length = 0;
+            break;
+        case 5: /* BGRA_8888 */
+            fbinfo.bpp = 32;
+            fbinfo.size = w * h * 4;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 16;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 0;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 8;
+           break;
+        default:
+            goto done;
+    }
+
+    /* write header */
+    if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;
+
+    /* write data */
+    for(i = 0; i < fbinfo.size; i += bsize) {
+      bsize = sizeof(buf);
+      if (i + bsize > fbinfo.size)
+        bsize = fbinfo.size - i;
+      if(readx(fd_screencap, buf, bsize)) goto done;
+      if(writex(fd, buf, bsize)) goto done;
+    }
+
+done:
+    TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
+
+    close(fds[0]);
+    close(fds[1]);
+pipefail:
+    close(fd);
+}
diff --git a/src/devtools/adb/get_my_path_darwin.c b/src/devtools/adb/get_my_path_darwin.c
new file mode 100755
index 0000000..ff1396c
--- /dev/null
+++ b/src/devtools/adb/get_my_path_darwin.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#import <Carbon/Carbon.h>
+#include <unistd.h>
+
+void get_my_path(char *s, size_t maxLen)
+{
+    CFBundleRef mainBundle = CFBundleGetMainBundle();
+    CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
+    CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
+    CFRelease(executableURL);
+
+    CFStringGetFileSystemRepresentation(executablePathString, s, maxLen);
+    CFRelease(executablePathString);
+}
+
diff --git a/src/devtools/adb/get_my_path_freebsd.c b/src/devtools/adb/get_my_path_freebsd.c
new file mode 100755
index 0000000..b06ec66
--- /dev/null
+++ b/src/devtools/adb/get_my_path_freebsd.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2009 bsdroid project
+ *               Alexey Tarasov <tarasov@dodologics.com>
+ *
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+
+void
+get_my_path(char *exe, size_t maxLen)
+{
+    char proc[64];
+
+    snprintf(proc, sizeof(proc), "/proc/%d/file", getpid());
+
+    int err = readlink(proc, exe, maxLen - 1);
+
+    exe[err > 0 ? err : 0] = '\0';
+}
+
diff --git a/src/devtools/adb/get_my_path_linux.c b/src/devtools/adb/get_my_path_linux.c
new file mode 100755
index 0000000..179c3dd
--- /dev/null
+++ b/src/devtools/adb/get_my_path_linux.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+
+void get_my_path(char *exe, size_t maxLen)
+{
+    char proc[64];
+    snprintf(proc, sizeof proc, "/proc/%d/exe", getpid());
+    int err = readlink(proc, exe, maxLen - 1);
+    if(err > 0) {
+        exe[err] = '\0';
+    } else {
+        exe[0] = '\0';
+    }
+}
+
diff --git a/src/devtools/adb/get_my_path_windows.c b/src/devtools/adb/get_my_path_windows.c
new file mode 100755
index 0000000..ddf2816
--- /dev/null
+++ b/src/devtools/adb/get_my_path_windows.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits.h>
+#include <assert.h>
+#include <windows.h>
+
+void get_my_path(char *exe, size_t maxLen)
+{
+    char  *r;
+
+    /* XXX: should be GetModuleFileNameA */
+    if (GetModuleFileName(NULL, exe, maxLen) > 0) {
+        r = strrchr(exe, '\\');
+        if (r != NULL)
+            *r = '\0';
+    } else {
+        exe[0] = '\0';
+    }
+}
+
diff --git a/src/devtools/adb/include/android/log.h b/src/devtools/adb/include/android/log.h
new file mode 100755
index 0000000..1c171b7
--- /dev/null
+++ b/src/devtools/adb/include/android/log.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_LOG_H
+#define _ANDROID_LOG_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit) since
+ *   platform release 1.5
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/*
+ * Support routines to send messages to the Android in-kernel log buffer,
+ * which can later be accessed through the 'logcat' utility.
+ *
+ * Each log message must have
+ *   - a priority
+ *   - a log tag
+ *   - some text
+ *
+ * The tag normally corresponds to the component that emits the log message,
+ * and should be reasonably small.
+ *
+ * Log message text may be truncated to less than an implementation-specific
+ * limit (e.g. 1023 characters max).
+ *
+ * Note that a newline character ("\n") will be appended automatically to your
+ * log message, if not already there. It is not possible to send several messages
+ * and have them appear on a single line in logcat.
+ *
+ * PLEASE USE LOGS WITH MODERATION:
+ *
+ *  - Sending log messages eats CPU and slow down your application and the
+ *    system.
+ *
+ *  - The circular log buffer is pretty small (<64KB), sending many messages
+ *    might push off other important log messages from the rest of the system.
+ *
+ *  - In release builds, only send log messages to account for exceptional
+ *    conditions.
+ *
+ * NOTE: These functions MUST be implemented by /system/lib/liblog.so
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Android log priority values, in ascending priority order.
+ */
+typedef enum android_LogPriority {
+    ANDROID_LOG_UNKNOWN = 0,
+    ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
+    ANDROID_LOG_VERBOSE,
+    ANDROID_LOG_DEBUG,
+    ANDROID_LOG_INFO,
+    ANDROID_LOG_WARN,
+    ANDROID_LOG_ERROR,
+    ANDROID_LOG_FATAL,
+    ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
+} android_LogPriority;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_write(int prio, const char *tag, const char *text);
+
+/*
+ * Send a formatted string to the log, used like printf(fmt,...)
+ */
+int __android_log_print(int prio, const char *tag,  const char *fmt, ...)
+#if defined(__GNUC__)
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format(gnu_printf, 3, 4)))
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
+    ;
+
+/*
+ * A variant of __android_log_print() that takes a va_list to list
+ * additional parameters.
+ */
+int __android_log_vprint(int prio, const char *tag,
+                         const char *fmt, va_list ap);
+
+/*
+ * Log an assertion failure and abort the process to have a chance
+ * to inspect it if a debugger is attached. This uses the FATAL priority.
+ */
+void __android_log_assert(const char *cond, const char *tag,
+                          const char *fmt, ...)
+#if defined(__GNUC__)
+    __attribute__ ((noreturn))
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format(gnu_printf, 3, 4)))
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
+    ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ANDROID_LOG_H */
diff --git a/src/devtools/adb/include/cutils/android_reboot.h b/src/devtools/adb/include/cutils/android_reboot.h
new file mode 100755
index 0000000..8c30e8e
--- /dev/null
+++ b/src/devtools/adb/include/cutils/android_reboot.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_ANDROID_REBOOT_H__
+#define __CUTILS_ANDROID_REBOOT_H__
+
+__BEGIN_DECLS
+
+/* Commands */
+#define ANDROID_RB_RESTART  0xDEAD0001
+#define ANDROID_RB_POWEROFF 0xDEAD0002
+#define ANDROID_RB_RESTART2 0xDEAD0003
+
+/* Properties */
+#define ANDROID_RB_PROPERTY "sys.powerctl"
+
+int android_reboot(int cmd, int flags, char *arg);
+
+__END_DECLS
+
+#endif /* __CUTILS_ANDROID_REBOOT_H__ */
diff --git a/src/devtools/adb/include/cutils/fs.h b/src/devtools/adb/include/cutils/fs.h
new file mode 100755
index 0000000..70f0b92
--- /dev/null
+++ b/src/devtools/adb/include/cutils/fs.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_FS_H
+#define __CUTILS_FS_H
+
+#include <sys/types.h>
+#include <unistd.h>
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Ensure that directory exists with given mode and owners.
+ */
+extern int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
+
+/*
+ * Read single plaintext integer from given file, correctly handling files
+ * partially written with fs_write_atomic_int().
+ */
+extern int fs_read_atomic_int(const char* path, int* value);
+
+/*
+ * Write single plaintext integer to given file, creating backup while
+ * in progress.
+ */
+extern int fs_write_atomic_int(const char* path, int value);
+
+/*
+ * Ensure that all directories along given path exist, creating parent
+ * directories as needed.  Validates that given path is absolute and that
+ * it contains no relative "." or ".." paths or symlinks.  Last path segment
+ * is treated as filename and ignored, unless the path ends with "/".
+ */
+extern int fs_mkdirs(const char* path, mode_t mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_FS_H */
diff --git a/src/devtools/adb/include/cutils/list.h b/src/devtools/adb/include/cutils/list.h
new file mode 100755
index 0000000..4ba2cfd
--- /dev/null
+++ b/src/devtools/adb/include/cutils/list.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008-2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CUTILS_LIST_H_
+#define _CUTILS_LIST_H_
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct listnode
+{
+    struct listnode *next;
+    struct listnode *prev;
+};
+
+#define node_to_item(node, container, member) \
+    (container *) (((char*) (node)) - offsetof(container, member))
+
+#define list_declare(name) \
+    struct listnode name = { \
+        .next = &name, \
+        .prev = &name, \
+    }
+
+#define list_for_each(node, list) \
+    for (node = (list)->next; node != (list); node = node->next)
+
+#define list_for_each_reverse(node, list) \
+    for (node = (list)->prev; node != (list); node = node->prev)
+
+#define list_for_each_safe(node, n, list) \
+    for (node = (list)->next, n = node->next; \
+         node != (list); \
+         node = n, n = node->next)
+
+static inline void list_init(struct listnode *node)
+{
+    node->next = node;
+    node->prev = node;
+}
+
+static inline void list_add_tail(struct listnode *head, struct listnode *item)
+{
+    item->next = head;
+    item->prev = head->prev;
+    head->prev->next = item;
+    head->prev = item;
+}
+
+static inline void list_add_head(struct listnode *head, struct listnode *item)
+{
+    item->next = head->next;
+    item->prev = head;
+    head->next->prev = item;
+    head->next = item;
+}
+
+static inline void list_remove(struct listnode *item)
+{
+    item->next->prev = item->prev;
+    item->prev->next = item->next;
+}
+
+#define list_empty(list) ((list) == (list)->next)
+#define list_head(list) ((list)->next)
+#define list_tail(list) ((list)->prev)
+
+#ifdef __cplusplus
+};
+#endif /* __cplusplus */
+
+#endif
diff --git a/src/devtools/adb/include/cutils/misc.h b/src/devtools/adb/include/cutils/misc.h
new file mode 100755
index 0000000..0de505f
--- /dev/null
+++ b/src/devtools/adb/include/cutils/misc.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_MISC_H
+#define __CUTILS_MISC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+        /* Load an entire file into a malloc'd chunk of memory
+         * that is length_of_file + 1 (null terminator).  If
+         * sz is non-zero, return the size of the file via sz.
+         * Returns 0 on failure.
+         */
+extern void *load_file(const char *fn, unsigned *sz);
+
+        /* This is the range of UIDs (and GIDs) that are reserved
+         * for assigning to applications.
+         */
+#define FIRST_APPLICATION_UID 10000
+#define LAST_APPLICATION_UID 99999
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_MISC_H */ 
diff --git a/src/devtools/adb/include/cutils/properties.h b/src/devtools/adb/include/cutils/properties.h
new file mode 100755
index 0000000..20f7f85
--- /dev/null
+++ b/src/devtools/adb/include/cutils/properties.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_PROPERTIES_H
+#define __CUTILS_PROPERTIES_H
+
+#include <sys/cdefs.h>
+#include <stddef.h>
+//#include <sys/system_properties.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef PROP_NAME_MAX
+#define PROP_NAME_MAX 32
+#endif
+#ifndef PROP_VALUE_MAX
+#define PROP_VALUE_MAX 92
+#endif
+
+/* System properties are *small* name value pairs managed by the
+** property service.  If your data doesn't fit in the provided
+** space it is not appropriate for a system property.
+**
+** WARNING: system/bionic/include/sys/system_properties.h also defines
+**          these, but with different names.  (TODO: fix that)
+*/
+#define PROPERTY_KEY_MAX   PROP_NAME_MAX
+#define PROPERTY_VALUE_MAX  PROP_VALUE_MAX
+
+/* property_get: returns the length of the value which will never be
+** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
+** (the length does not include the terminating zero).
+**
+** If the property read fails or returns an empty value, the default
+** value is used (if nonnull).
+*/
+int property_get(const char *key, char *value, const char *default_value);
+
+/* property_get_bool: returns the value of key coerced into a
+** boolean. If the property is not set, then the default value is returned.
+**
+* The following is considered to be true (1):
+**   "1", "true", "y", "yes", "on"
+**
+** The following is considered to be false (0):
+**   "0", "false", "n", "no", "off"
+**
+** The conversion is whitespace-sensitive (e.g. " off" will not be false).
+**
+** If no property with this key is set (or the key is NULL) or the boolean
+** conversion fails, the default value is returned.
+**/
+int8_t property_get_bool(const char *key, int8_t default_value);
+
+/* property_get_int64: returns the value of key truncated and coerced into a
+** int64_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+**   -- 0 prefix is octal
+**   -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int64_t property_get_int64(const char *key, int64_t default_value);
+
+/* property_get_int32: returns the value of key truncated and coerced into an
+** int32_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+**   -- 0 prefix is octal
+**   -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int32_t property_get_int32(const char *key, int32_t default_value);
+
+/* property_set: returns 0 on success, < 0 on failure
+*/
+int property_set(const char *key, const char *value);
+    
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);    
+
+#if defined(__BIONIC_FORTIFY)
+
+extern int __property_get_real(const char *, char *, const char *)
+    __asm__(__USER_LABEL_PREFIX__ "property_get");
+__errordecl(__property_get_too_small_error, "property_get() called with too small of a buffer");
+
+__BIONIC_FORTIFY_INLINE
+int property_get(const char *key, char *value, const char *default_value) {
+    size_t bos = __bos(value);
+    if (bos < PROPERTY_VALUE_MAX) {
+        __property_get_too_small_error();
+    }
+    return __property_get_real(key, value, default_value);
+}
+
+#endif
+
+#ifdef HAVE_SYSTEM_PROPERTY_SERVER
+/*
+ * We have an external property server instead of built-in libc support.
+ * Used by the simulator.
+ */
+#define SYSTEM_PROPERTY_PIPE_NAME       "/tmp/android-sysprop"
+
+enum {
+    kSystemPropertyUnknown = 0,
+    kSystemPropertyGet,
+    kSystemPropertySet,
+    kSystemPropertyList
+};
+#endif /*HAVE_SYSTEM_PROPERTY_SERVER*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/devtools/adb/include/cutils/sockets.h b/src/devtools/adb/include/cutils/sockets.h
new file mode 100755
index 0000000..daf43ec
--- /dev/null
+++ b/src/devtools/adb/include/cutils/sockets.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_SOCKETS_H
+#define __CUTILS_SOCKETS_H
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifdef HAVE_WINSOCK
+#include <winsock2.h>
+typedef int  socklen_t;
+#elif HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#define ANDROID_SOCKET_ENV_PREFIX	"ANDROID_SOCKET_"
+#define ANDROID_SOCKET_DIR		"/dev/socket"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * android_get_control_socket - simple helper function to get the file
+ * descriptor of our init-managed Unix domain socket. `name' is the name of the
+ * socket, as given in init.rc. Returns -1 on error.
+ *
+ * This is inline and not in libcutils proper because we want to use this in
+ * third-party daemons with minimal modification.
+ */
+static inline int android_get_control_socket(const char *name)
+{
+	char key[64] = ANDROID_SOCKET_ENV_PREFIX;
+	const char *val;
+	int fd;
+
+	/* build our environment variable, counting cycles like a wolf ... */
+#if HAVE_STRLCPY
+	strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
+		name,
+		sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
+#else	/* for the host, which may lack the almightly strncpy ... */
+	strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
+		name,
+		sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
+	key[sizeof(key)-1] = '\0';
+#endif
+
+	val = getenv(key);
+	if (!val)
+		return -1;
+
+	errno = 0;
+	fd = strtol(val, NULL, 10);
+	if (errno)
+		return -1;
+
+	return fd;
+}
+
+/*
+ * See also android.os.LocalSocketAddress.Namespace
+ */
+// Linux "abstract" (non-filesystem) namespace
+#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
+// Android "reserved" (/dev/socket) namespace
+#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
+// Normal filesystem namespace
+#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2
+
+extern int socket_loopback_client(int port, int type);
+extern int socket_network_client(const char *host, int port, int type);
+extern int socket_network_client_timeout(const char *host, int port, int type,
+                                         int timeout);
+extern int socket_loopback_server(int port, int type);
+extern int socket_local_server(const char *name, int namespaceId, int type);
+extern int socket_local_server_bind(int s, const char *name, int namespaceId);
+extern int socket_local_client_connect(int fd, 
+        const char *name, int namespaceId, int type);
+extern int socket_local_client(const char *name, int namespaceId, int type);
+extern int socket_inaddr_any_server(int port, int type);
+
+/*
+ * socket_peer_is_trusted - Takes a socket which is presumed to be a
+ * connected local socket (e.g. AF_LOCAL) and returns whether the peer
+ * (the userid that owns the process on the other end of that socket)
+ * is one of the two trusted userids, root or shell.
+ *
+ * Note: This only works as advertised on the Android OS and always
+ * just returns true when called on other operating systems.
+ */
+extern bool socket_peer_is_trusted(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_SOCKETS_H */ 
diff --git a/src/devtools/adb/include/cutils/threads.h b/src/devtools/adb/include/cutils/threads.h
new file mode 100755
index 0000000..acf8f48
--- /dev/null
+++ b/src/devtools/adb/include/cutils/threads.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBS_CUTILS_THREADS_H
+#define _LIBS_CUTILS_THREADS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***********************************************************************/
+/***********************************************************************/
+/*****                                                             *****/
+/*****         local thread storage                                *****/
+/*****                                                             *****/
+/***********************************************************************/
+/***********************************************************************/
+
+#ifdef HAVE_PTHREADS
+
+#include  <pthread.h>
+
+typedef struct {
+    pthread_mutex_t   lock;
+    int               has_tls;
+    pthread_key_t     tls;
+
+} thread_store_t;
+
+#define  THREAD_STORE_INITIALIZER  { PTHREAD_MUTEX_INITIALIZER, 0, 0 }
+
+#elif defined HAVE_WIN32_THREADS
+
+#include <windows.h>
+
+typedef struct {
+    int               lock_init;
+    int               has_tls;
+    DWORD             tls;
+    CRITICAL_SECTION  lock;
+
+} thread_store_t;
+
+#define  THREAD_STORE_INITIALIZER  { 0, 0, 0, {0, 0, 0, 0, 0, 0} }
+
+#else
+#  error  "no thread_store_t implementation for your platform !!"
+#endif
+
+typedef void  (*thread_store_destruct_t)(void*  value);
+
+extern void*  thread_store_get(thread_store_t*  store);
+
+extern void   thread_store_set(thread_store_t*          store, 
+                               void*                    value,
+                               thread_store_destruct_t  destroy);
+
+/***********************************************************************/
+/***********************************************************************/
+/*****                                                             *****/
+/*****         mutexes                                             *****/
+/*****                                                             *****/
+/***********************************************************************/
+/***********************************************************************/
+
+#ifdef HAVE_PTHREADS
+
+typedef pthread_mutex_t   mutex_t;
+
+#define  MUTEX_INITIALIZER  PTHREAD_MUTEX_INITIALIZER
+
+static __inline__ void  mutex_lock(mutex_t*  lock)
+{
+    pthread_mutex_lock(lock);
+}
+static __inline__ void  mutex_unlock(mutex_t*  lock)
+{
+    pthread_mutex_unlock(lock);
+}
+static __inline__ int  mutex_init(mutex_t*  lock)
+{
+    return pthread_mutex_init(lock, NULL);
+}
+static __inline__ void mutex_destroy(mutex_t*  lock)
+{
+    pthread_mutex_destroy(lock);
+}
+#endif
+
+#ifdef HAVE_WIN32_THREADS
+typedef struct { 
+    int                init;
+    CRITICAL_SECTION   lock[1];
+} mutex_t;
+
+#define  MUTEX_INITIALIZER  { 0, {{ NULL, 0, 0, NULL, NULL, 0 }} }
+
+static __inline__ void  mutex_lock(mutex_t*  lock)
+{
+    if (!lock->init) {
+        lock->init = 1;
+        InitializeCriticalSection( lock->lock );
+        lock->init = 2;
+    } else while (lock->init != 2)
+        Sleep(10);
+
+    EnterCriticalSection(lock->lock);
+}
+
+static __inline__ void  mutex_unlock(mutex_t*  lock)
+{
+    LeaveCriticalSection(lock->lock);
+}
+static __inline__ int  mutex_init(mutex_t*  lock)
+{
+    InitializeCriticalSection(lock->lock);
+    lock->init = 2;
+    return 0;
+}
+static __inline__ void  mutex_destroy(mutex_t*  lock)
+{
+    if (lock->init) {
+        lock->init = 0;
+        DeleteCriticalSection(lock->lock); 
+    }
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_CUTILS_THREADS_H */
diff --git a/src/devtools/adb/include/log/log.h b/src/devtools/adb/include/log/log.h
new file mode 100755
index 0000000..ace12d6
--- /dev/null
+++ b/src/devtools/adb/include/log/log.h
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2005-2014 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.
+ */
+
+//
+// C/C++ logging functions.  See the logging documentation for API details.
+//
+// We'd like these to be available from C code (in case we import some from
+// somewhere), so this has a C interface.
+//
+// The output will be correct when the log file is shared between multiple
+// threads and/or multiple processes so long as the operating system
+// supports O_APPEND.  These calls have mutex-protected data structures
+// and so are NOT reentrant.  Do not use LOG in a signal handler.
+//
+#ifndef _LIBS_LOG_LOG_H
+#define _LIBS_LOG_LOG_H
+
+#include <sys/types.h>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <log/logd.h>
+#include <log/uio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Normally we strip ALOGV (VERBOSE messages) from release builds.
+ * You can modify this (for example with "#define LOG_NDEBUG 0"
+ * at the top of your source file) to change that behavior.
+ */
+#ifndef LOG_NDEBUG
+#ifdef NDEBUG
+#define LOG_NDEBUG 1
+#else
+#define LOG_NDEBUG 0
+#endif
+#endif
+
+/*
+ * This is the local tag used for the following simplified
+ * logging macros.  You can change this preprocessor definition
+ * before using the other macros to change the tag.
+ */
+#ifndef LOG_TAG
+#define LOG_TAG NULL
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose log message using the current LOG_TAG.
+ */
+#ifndef ALOGV
+#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0)
+#else
+#define ALOGV(...) __ALOGV(__VA_ARGS__)
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef ALOGV_IF
+#if LOG_NDEBUG
+#define ALOGV_IF(cond, ...)   ((void)0)
+#else
+#define ALOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug log message using the current LOG_TAG.
+ */
+#ifndef ALOGD
+#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGD_IF
+#define ALOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info log message using the current LOG_TAG.
+ */
+#ifndef ALOGI
+#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGI_IF
+#define ALOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning log message using the current LOG_TAG.
+ */
+#ifndef ALOGW
+#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGW_IF
+#define ALOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error log message using the current LOG_TAG.
+ */
+#ifndef ALOGE
+#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGE_IF
+#define ALOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * verbose priority.
+ */
+#ifndef IF_ALOGV
+#if LOG_NDEBUG
+#define IF_ALOGV() if (false)
+#else
+#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
+#endif
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * debug priority.
+ */
+#ifndef IF_ALOGD
+#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * info priority.
+ */
+#ifndef IF_ALOGI
+#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * warn priority.
+ */
+#ifndef IF_ALOGW
+#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * error priority.
+ */
+#ifndef IF_ALOGE
+#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
+#endif
+
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose system log message using the current LOG_TAG.
+ */
+#ifndef SLOGV
+#define __SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0)
+#else
+#define SLOGV(...) __SLOGV(__VA_ARGS__)
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef SLOGV_IF
+#if LOG_NDEBUG
+#define SLOGV_IF(cond, ...)   ((void)0)
+#else
+#define SLOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug system log message using the current LOG_TAG.
+ */
+#ifndef SLOGD
+#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGD_IF
+#define SLOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info system log message using the current LOG_TAG.
+ */
+#ifndef SLOGI
+#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGI_IF
+#define SLOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning system log message using the current LOG_TAG.
+ */
+#ifndef SLOGW
+#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGW_IF
+#define SLOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error system log message using the current LOG_TAG.
+ */
+#ifndef SLOGE
+#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGE_IF
+#define SLOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGV
+#define __RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0)
+#else
+#define RLOGV(...) __RLOGV(__VA_ARGS__)
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef RLOGV_IF
+#if LOG_NDEBUG
+#define RLOGV_IF(cond, ...)   ((void)0)
+#else
+#define RLOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGD
+#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGD_IF
+#define RLOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGI
+#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGI_IF
+#define RLOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGW
+#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGW_IF
+#define RLOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGE
+#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGE_IF
+#define RLOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+
+// ---------------------------------------------------------------------
+
+/*
+ * Log a fatal error.  If the given condition fails, this stops program
+ * execution like a normal assertion, but also generating the given message.
+ * It is NOT stripped from release builds.  Note that the condition test
+ * is -inverted- from the normal assert() semantics.
+ */
+#ifndef LOG_ALWAYS_FATAL_IF
+#define LOG_ALWAYS_FATAL_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+#ifndef LOG_ALWAYS_FATAL
+#define LOG_ALWAYS_FATAL(...) \
+    ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
+#endif
+
+/*
+ * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
+ * are stripped out of release builds.
+ */
+#if LOG_NDEBUG
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) ((void)0)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) ((void)0)
+#endif
+
+#else
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
+#endif
+
+#endif
+
+/*
+ * Assertion that generates a log message when the assertion fails.
+ * Stripped out of release builds.  Uses the current LOG_TAG.
+ */
+#ifndef ALOG_ASSERT
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
+//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Basic log message macro.
+ *
+ * Example:
+ *  ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
+ *
+ * The second argument may be NULL or "" to indicate the "global" tag.
+ */
+#ifndef ALOG
+#define ALOG(priority, tag, ...) \
+    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
+#endif
+
+/*
+ * Log macro that allows you to specify a number for the priority.
+ */
+#ifndef LOG_PRI
+#define LOG_PRI(priority, tag, ...) \
+    android_printLog(priority, tag, __VA_ARGS__)
+#endif
+
+/*
+ * Log macro that allows you to pass in a varargs ("args" is a va_list).
+ */
+#ifndef LOG_PRI_VA
+#define LOG_PRI_VA(priority, tag, fmt, args) \
+    android_vprintLog(priority, NULL, tag, fmt, args)
+#endif
+
+/*
+ * Conditional given a desired logging priority and tag.
+ */
+#ifndef IF_ALOG
+#define IF_ALOG(priority, tag) \
+    if (android_testLog(ANDROID_##priority, tag))
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Event logging.
+ */
+
+/*
+ * Event log entry types.  These must match up with the declarations in
+ * java/android/android/util/EventLog.java.
+ */
+typedef enum {
+    EVENT_TYPE_INT      = 0,
+    EVENT_TYPE_LONG     = 1,
+    EVENT_TYPE_STRING   = 2,
+    EVENT_TYPE_LIST     = 3,
+} AndroidEventLogType;
+#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
+#define typeof_AndroidEventLogType unsigned char
+
+#ifndef LOG_EVENT_INT
+#define LOG_EVENT_INT(_tag, _value) {                                       \
+        int intBuf = _value;                                                \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf,            \
+            sizeof(intBuf));                                                \
+    }
+#endif
+#ifndef LOG_EVENT_LONG
+#define LOG_EVENT_LONG(_tag, _value) {                                      \
+        long long longBuf = _value;                                         \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf,          \
+            sizeof(longBuf));                                               \
+    }
+#endif
+#ifndef LOG_EVENT_STRING
+#define LOG_EVENT_STRING(_tag, _value)                                      \
+        (void) __android_log_bswrite(_tag, _value);
+#endif
+/* TODO: something for LIST */
+
+/*
+ * ===========================================================================
+ *
+ * The stuff in the rest of this file should not be used directly.
+ */
+
+#define android_printLog(prio, tag, fmt...) \
+    __android_log_print(prio, tag, fmt)
+
+#define android_vprintLog(prio, cond, tag, fmt...) \
+    __android_log_vprint(prio, tag, fmt)
+
+/* XXX Macros to work around syntax errors in places where format string
+ * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
+ * (happens only in debug builds).
+ */
+
+/* Returns 2nd arg.  Used to substitute default value if caller's vararg list
+ * is empty.
+ */
+#define __android_second(dummy, second, ...)     second
+
+/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
+ * returns nothing.
+ */
+#define __android_rest(first, ...)               , ## __VA_ARGS__
+
+#define android_printAssert(cond, tag, fmt...) \
+    __android_log_assert(cond, tag, \
+        __android_second(0, ## fmt, NULL) __android_rest(fmt))
+
+#define android_writeLog(prio, tag, text) \
+    __android_log_write(prio, tag, text)
+
+#define android_bWriteLog(tag, payload, len) \
+    __android_log_bwrite(tag, payload, len)
+#define android_btWriteLog(tag, type, payload, len) \
+    __android_log_btwrite(tag, type, payload, len)
+
+// TODO: remove these prototypes and their users
+#define android_testLog(prio, tag) (1)
+#define android_writevLog(vec,num) do{}while(0)
+#define android_write1Log(str,len) do{}while (0)
+#define android_setMinPriority(tag, prio) do{}while(0)
+//#define android_logToCallback(func) do{}while(0)
+#define android_logToFile(tag, file) (0)
+#define android_logToFd(tag, fd) (0)
+
+typedef enum log_id {
+    LOG_ID_MIN = 0,
+
+    LOG_ID_MAIN = 0,
+    LOG_ID_RADIO = 1,
+    LOG_ID_EVENTS = 2,
+    LOG_ID_SYSTEM = 3,
+    LOG_ID_CRASH = 4,
+
+    LOG_ID_MAX
+} log_id_t;
+#define sizeof_log_id_t sizeof(typeof_log_id_t)
+#define typeof_log_id_t unsigned char
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
+#if defined(__GNUC__)
+    __attribute__((__format__(printf, 4, 5)))
+#endif
+    ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_LOG_H */
diff --git a/src/devtools/adb/include/log/log_read.h b/src/devtools/adb/include/log/log_read.h
new file mode 100755
index 0000000..946711a
--- /dev/null
+++ b/src/devtools/adb/include/log/log_read.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2013-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBS_LOG_LOG_READ_H
+#define _LIBS_LOG_LOG_READ_H
+
+#include <stdint.h>
+#include <time.h>
+
+/* struct log_time is a wire-format variant of struct timespec */
+#define NS_PER_SEC 1000000000ULL
+
+#ifdef __cplusplus
+
+// NB: do NOT define a copy constructor. This will result in structure
+// no longer being compatible with pass-by-value which is desired
+// efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
+struct log_time {
+public:
+    uint32_t tv_sec; // good to Feb 5 2106
+    uint32_t tv_nsec;
+
+    static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
+    static const uint32_t tv_nsec_max = 999999999UL;
+
+    log_time(const timespec &T)
+    {
+        tv_sec = T.tv_sec;
+        tv_nsec = T.tv_nsec;
+    }
+    log_time(uint32_t sec, uint32_t nsec)
+    {
+        tv_sec = sec;
+        tv_nsec = nsec;
+    }
+    static const timespec EPOCH;
+    log_time()
+    {
+    }
+    log_time(clockid_t id)
+    {
+        timespec T;
+        clock_gettime(id, &T);
+        tv_sec = T.tv_sec;
+        tv_nsec = T.tv_nsec;
+    }
+    log_time(const char *T)
+    {
+        const uint8_t *c = (const uint8_t *) T;
+        tv_sec = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
+        tv_nsec = c[4] | (c[5] << 8) | (c[6] << 16) | (c[7] << 24);
+    }
+
+    // timespec
+    bool operator== (const timespec &T) const
+    {
+        return (tv_sec == static_cast<uint32_t>(T.tv_sec))
+            && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
+    }
+    bool operator!= (const timespec &T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const timespec &T) const
+    {
+        return (tv_sec < static_cast<uint32_t>(T.tv_sec))
+            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+                && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
+    }
+    bool operator>= (const timespec &T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const timespec &T) const
+    {
+        return (tv_sec > static_cast<uint32_t>(T.tv_sec))
+            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+                && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
+    }
+    bool operator<= (const timespec &T) const
+    {
+        return !(*this > T);
+    }
+    log_time operator-= (const timespec &T);
+    log_time operator- (const timespec &T) const
+    {
+        log_time local(*this);
+        return local -= T;
+    }
+
+    // log_time
+    bool operator== (const log_time &T) const
+    {
+        return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+    }
+    bool operator!= (const log_time &T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const log_time &T) const
+    {
+        return (tv_sec < T.tv_sec)
+            || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+    }
+    bool operator>= (const log_time &T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const log_time &T) const
+    {
+        return (tv_sec > T.tv_sec)
+            || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+    }
+    bool operator<= (const log_time &T) const
+    {
+        return !(*this > T);
+    }
+    log_time operator-= (const log_time &T);
+    log_time operator- (const log_time &T) const
+    {
+        log_time local(*this);
+        return local -= T;
+    }
+
+    uint64_t nsec() const
+    {
+        return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
+    }
+
+    static const char default_format[];
+
+    // Add %#q for the fraction of a second to the standard library functions
+    char *strptime(const char *s, const char *format = default_format);
+} __attribute__((__packed__));
+
+#else
+
+typedef struct log_time {
+    uint32_t tv_sec;
+    uint32_t tv_nsec;
+} __attribute__((__packed__)) log_time;
+
+#endif
+
+#endif /* define _LIBS_LOG_LOG_READ_H */
diff --git a/src/devtools/adb/include/log/logd.h b/src/devtools/adb/include/log/logd.h
new file mode 100755
index 0000000..2e6f220
--- /dev/null
+++ b/src/devtools/adb/include/log/logd.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_CUTILS_LOGD_H
+#define _ANDROID_CUTILS_LOGD_H
+
+/* the stable/frozen log-related definitions have been
+ * moved to this header, which is exposed by the NDK
+ */
+#include <android/log.h>
+
+/* the rest is only used internally by the system */
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/types.h>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <log/uio.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
+int __android_log_btwrite(int32_t tag, char type, const void *payload,
+    size_t len);
+int __android_log_bswrite(int32_t tag, const char *payload);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LOGD_H */
diff --git a/src/devtools/adb/include/log/logger.h b/src/devtools/adb/include/log/logger.h
new file mode 100755
index 0000000..53be1d3
--- /dev/null
+++ b/src/devtools/adb/include/log/logger.h
@@ -0,0 +1,189 @@
+/*
+**
+** Copyright 2007-2014, The Android Open Source Project
+**
+** This file is dual licensed.  It may be redistributed and/or modified
+** under the terms of the Apache 2.0 License OR version 2 of the GNU
+** General Public License.
+*/
+
+#ifndef _LIBS_LOG_LOGGER_H
+#define _LIBS_LOG_LOGGER_H
+
+#include <stdint.h>
+#include <log/log.h>
+#include <log/log_read.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The userspace structure for version 1 of the logger_entry ABI.
+ * This structure is returned to userspace by the kernel logger
+ * driver unless an upgrade to a newer ABI version is requested.
+ */
+struct logger_entry {
+    uint16_t    len;    /* length of the payload */
+    uint16_t    __pad;  /* no matter what, we get 2 bytes of padding */
+    int32_t     pid;    /* generating process's pid */
+    int32_t     tid;    /* generating process's tid */
+    int32_t     sec;    /* seconds since Epoch */
+    int32_t     nsec;   /* nanoseconds */
+    char        msg[0]; /* the entry's payload */
+} __attribute__((__packed__));
+
+/*
+ * The userspace structure for version 2 of the logger_entry ABI.
+ * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
+ * is called with version==2; or used with the user space log daemon.
+ */
+struct logger_entry_v2 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v2) */
+    int32_t     pid;       /* generating process's pid */
+    int32_t     tid;       /* generating process's tid */
+    int32_t     sec;       /* seconds since Epoch */
+    int32_t     nsec;      /* nanoseconds */
+    uint32_t    euid;      /* effective UID of logger */
+    char        msg[0];    /* the entry's payload */
+} __attribute__((__packed__));
+
+struct logger_entry_v3 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v3) */
+    int32_t     pid;       /* generating process's pid */
+    int32_t     tid;       /* generating process's tid */
+    int32_t     sec;       /* seconds since Epoch */
+    int32_t     nsec;      /* nanoseconds */
+    uint32_t    lid;       /* log id of the payload */
+    char        msg[0];    /* the entry's payload */
+} __attribute__((__packed__));
+
+/*
+ * The maximum size of the log entry payload that can be
+ * written to the logger. An attempt to write more than
+ * this amount will result in a truncated log entry.
+ */
+#define LOGGER_ENTRY_MAX_PAYLOAD	4076
+
+/*
+ * The maximum size of a log entry which can be read from the
+ * kernel logger driver. An attempt to read less than this amount
+ * may result in read() returning EINVAL.
+ */
+#define LOGGER_ENTRY_MAX_LEN		(5*1024)
+
+#define NS_PER_SEC 1000000000ULL
+
+struct log_msg {
+    union {
+        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
+        struct logger_entry_v3 entry;
+        struct logger_entry_v3 entry_v3;
+        struct logger_entry_v2 entry_v2;
+        struct logger_entry    entry_v1;
+    } __attribute__((aligned(4)));
+#ifdef __cplusplus
+    /* Matching log_time operators */
+    bool operator== (const log_msg &T) const
+    {
+        return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
+    }
+    bool operator!= (const log_msg &T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const log_msg &T) const
+    {
+        return (entry.sec < T.entry.sec)
+            || ((entry.sec == T.entry.sec)
+             && (entry.nsec < T.entry.nsec));
+    }
+    bool operator>= (const log_msg &T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const log_msg &T) const
+    {
+        return (entry.sec > T.entry.sec)
+            || ((entry.sec == T.entry.sec)
+             && (entry.nsec > T.entry.nsec));
+    }
+    bool operator<= (const log_msg &T) const
+    {
+        return !(*this > T);
+    }
+    uint64_t nsec() const
+    {
+        return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
+    }
+
+    /* packet methods */
+    log_id_t id()
+    {
+        return (log_id_t) entry.lid;
+    }
+    char *msg()
+    {
+        return entry.hdr_size ? (char *) buf + entry.hdr_size : entry_v1.msg;
+    }
+    unsigned int len()
+    {
+        return (entry.hdr_size ? entry.hdr_size : sizeof(entry_v1)) + entry.len;
+    }
+#endif
+};
+
+struct logger;
+
+log_id_t android_logger_get_id(struct logger *logger);
+
+int android_logger_clear(struct logger *logger);
+long android_logger_get_log_size(struct logger *logger);
+int android_logger_set_log_size(struct logger *logger, unsigned long size);
+long android_logger_get_log_readable_size(struct logger *logger);
+int android_logger_get_log_version(struct logger *logger);
+
+struct logger_list;
+
+ssize_t android_logger_get_statistics(struct logger_list *logger_list,
+                                      char *buf, size_t len);
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list,
+                                      char *buf, size_t len);
+int android_logger_set_prune_list(struct logger_list *logger_list,
+                                  char *buf, size_t len);
+
+struct logger_list *android_logger_list_alloc(int mode,
+                                              unsigned int tail,
+                                              pid_t pid);
+struct logger_list *android_logger_list_alloc_time(int mode,
+                                                   log_time start,
+                                                   pid_t pid);
+void android_logger_list_free(struct logger_list *logger_list);
+/* In the purest sense, the following two are orthogonal interfaces */
+int android_logger_list_read(struct logger_list *logger_list,
+                             struct log_msg *log_msg);
+
+/* Multiple log_id_t opens */
+struct logger *android_logger_open(struct logger_list *logger_list,
+                                   log_id_t id);
+#define android_logger_close android_logger_free
+/* Single log_id_t open */
+struct logger_list *android_logger_list_open(log_id_t id,
+                                             int mode,
+                                             unsigned int tail,
+                                             pid_t pid);
+#define android_logger_list_close android_logger_list_free
+
+/*
+ * log_id_t helpers
+ */
+log_id_t android_name_to_log_id(const char *logName);
+const char *android_log_id_to_name(log_id_t log_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_LOGGER_H */
diff --git a/src/devtools/adb/include/log/uio.h b/src/devtools/adb/include/log/uio.h
new file mode 100755
index 0000000..cc9c9ee
--- /dev/null
+++ b/src/devtools/adb/include/log/uio.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007-2014 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.
+ */
+
+//
+// implementation of sys/uio.h for platforms that don't have it (Win32)
+//
+#ifndef _LIBS_CUTILS_UIO_H
+#define _LIBS_CUTILS_UIO_H
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#else
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+#if 0
+struct iovec {
+    void*  iov_base;
+    size_t iov_len;
+};
+#endif
+
+extern int  readv( int  fd, struct iovec*  vecs, int  count );
+extern int  writev( int  fd, const struct iovec*  vecs, int  count );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !HAVE_SYS_UIO_H */
+
+#endif /* _LIBS_UTILS_UIO_H */
+
diff --git a/src/devtools/adb/include/mincrypt/hash-internal.h b/src/devtools/adb/include/mincrypt/hash-internal.h
new file mode 100755
index 0000000..c813b44
--- /dev/null
+++ b/src/devtools/adb/include/mincrypt/hash-internal.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007 The Android Open Source Project
+ *
+ * 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 Google Inc. 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 Google Inc. ``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 Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+struct HASH_CTX;  // forward decl
+
+typedef struct HASH_VTAB {
+  void (* const init)(struct HASH_CTX*);
+  void (* const update)(struct HASH_CTX*, const void*, int);
+  const uint8_t* (* const final)(struct HASH_CTX*);
+  const uint8_t* (* const hash)(const void*, int, uint8_t*);
+  int size;
+} HASH_VTAB;
+
+typedef struct HASH_CTX {
+  const HASH_VTAB * f;
+  uint64_t count;
+  uint8_t buf[64];
+  uint32_t state[8];  // upto SHA2
+} HASH_CTX;
+
+#define HASH_init(ctx) (ctx)->f->init(ctx)
+#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)
+#define HASH_final(ctx) (ctx)->f->final(ctx)
+#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)
+#define HASH_size(ctx) (ctx)->f->size
+
+#ifdef __cplusplus
+}
+#endif  // __cplusplus
+
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
diff --git a/src/devtools/adb/include/mincrypt/rsa.h b/src/devtools/adb/include/mincrypt/rsa.h
new file mode 100755
index 0000000..3d0556b
--- /dev/null
+++ b/src/devtools/adb/include/mincrypt/rsa.h
@@ -0,0 +1,58 @@
+/* rsa.h
+**
+** Copyright 2008, The Android Open Source Project
+**
+** 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 Google Inc. 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 Google Inc. ``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 Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RSANUMBYTES 256           /* 2048 bit key length */
+#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
+
+typedef struct RSAPublicKey {
+    int len;                  /* Length of n[] in number of uint32_t */
+    uint32_t n0inv;           /* -1 / n[0] mod 2^32 */
+    uint32_t n[RSANUMWORDS];  /* modulus as little endian array */
+    uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
+    int exponent;             /* 3 or 65537 */
+} RSAPublicKey;
+
+int RSA_verify(const RSAPublicKey *key,
+               const uint8_t* signature,
+               const int len,
+               const uint8_t* hash,
+               const int hash_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
diff --git a/src/devtools/adb/include/mincrypt/sha.h b/src/devtools/adb/include/mincrypt/sha.h
new file mode 100755
index 0000000..ef60aab
--- /dev/null
+++ b/src/devtools/adb/include/mincrypt/sha.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2005 The Android Open Source Project
+ *
+ * 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 Google Inc. 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 Google Inc. ``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 Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
+
+#include <stdint.h>
+#include "hash-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+typedef HASH_CTX SHA_CTX;
+
+void SHA_init(SHA_CTX* ctx);
+void SHA_update(SHA_CTX* ctx, const void* data, int len);
+const uint8_t* SHA_final(SHA_CTX* ctx);
+
+// Convenience method. Returns digest address.
+// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes.
+const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest);
+
+#define SHA_DIGEST_SIZE 20
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
diff --git a/src/devtools/adb/include/mincrypt/sha256.h b/src/devtools/adb/include/mincrypt/sha256.h
new file mode 100755
index 0000000..3a87c31
--- /dev/null
+++ b/src/devtools/adb/include/mincrypt/sha256.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * 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 Google Inc. 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 Google Inc. ``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 Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
+
+#include <stdint.h>
+#include "hash-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+typedef HASH_CTX SHA256_CTX;
+
+void SHA256_init(SHA256_CTX* ctx);
+void SHA256_update(SHA256_CTX* ctx, const void* data, int len);
+const uint8_t* SHA256_final(SHA256_CTX* ctx);
+
+// Convenience method. Returns digest address.
+const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest);
+
+#define SHA256_DIGEST_SIZE 32
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
diff --git a/src/devtools/adb/include/private/android_filesystem_capability.h b/src/devtools/adb/include/private/android_filesystem_capability.h
new file mode 100755
index 0000000..0505cda
--- /dev/null
+++ b/src/devtools/adb/include/private/android_filesystem_capability.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+/*
+ * Taken from linux/capability.h, with minor modifications
+ */
+
+#ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H
+#define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H
+
+#include <stdint.h>
+
+#define __user
+#define __u32 uint32_t
+#define __le32 uint32_t
+
+#define _LINUX_CAPABILITY_VERSION_1 0x19980330
+#define _LINUX_CAPABILITY_U32S_1 1
+#define _LINUX_CAPABILITY_VERSION_2 0x20071026
+#define _LINUX_CAPABILITY_U32S_2 2
+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+#define _LINUX_CAPABILITY_U32S_3 2
+
+typedef struct __user_cap_header_struct {
+ __u32 version;
+ int pid;
+} __user *cap_user_header_t;
+
+typedef struct __user_cap_data_struct {
+ __u32 effective;
+ __u32 permitted;
+ __u32 inheritable;
+} __user *cap_user_data_t;
+
+#define VFS_CAP_REVISION_MASK 0xFF000000
+#define VFS_CAP_REVISION_SHIFT 24
+#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
+#define VFS_CAP_FLAGS_EFFECTIVE 0x000001
+#define VFS_CAP_REVISION_1 0x01000000
+#define VFS_CAP_U32_1 1
+#define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1))
+#define VFS_CAP_REVISION_2 0x02000000
+#define VFS_CAP_U32_2 2
+#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))
+#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2
+#define VFS_CAP_U32 VFS_CAP_U32_2
+#define VFS_CAP_REVISION VFS_CAP_REVISION_2
+
+struct vfs_cap_data {
+ __le32 magic_etc;
+ struct {
+ __le32 permitted;
+ __le32 inheritable;
+ } data[VFS_CAP_U32];
+};
+
+#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1
+#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1
+#define CAP_CHOWN 0
+#define CAP_DAC_OVERRIDE 1
+#define CAP_DAC_READ_SEARCH 2
+#define CAP_FOWNER 3
+#define CAP_FSETID 4
+#define CAP_KILL 5
+#define CAP_SETGID 6
+#define CAP_SETUID 7
+#define CAP_SETPCAP 8
+#define CAP_LINUX_IMMUTABLE 9
+#define CAP_NET_BIND_SERVICE 10
+#define CAP_NET_BROADCAST 11
+#define CAP_NET_ADMIN 12
+#define CAP_NET_RAW 13
+#define CAP_IPC_LOCK 14
+#define CAP_IPC_OWNER 15
+#define CAP_SYS_MODULE 16
+#define CAP_SYS_RAWIO 17
+#define CAP_SYS_CHROOT 18
+#define CAP_SYS_PTRACE 19
+#define CAP_SYS_PACCT 20
+#define CAP_SYS_ADMIN 21
+#define CAP_SYS_BOOT 22
+#define CAP_SYS_NICE 23
+#define CAP_SYS_RESOURCE 24
+#define CAP_SYS_TIME 25
+#define CAP_SYS_TTY_CONFIG 26
+#define CAP_MKNOD 27
+#define CAP_LEASE 28
+#define CAP_AUDIT_WRITE 29
+#define CAP_AUDIT_CONTROL 30
+#define CAP_SETFCAP 31
+#define CAP_MAC_OVERRIDE 32
+#define CAP_MAC_ADMIN 33
+#define CAP_SYSLOG 34
+#define CAP_WAKE_ALARM 35
+#define CAP_LAST_CAP CAP_WAKE_ALARM
+#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
+#define CAP_TO_INDEX(x) ((x) >> 5)
+#define CAP_TO_MASK(x) (1 << ((x) & 31))
+
+#undef __user
+#undef __u32
+#undef __le32
+
+#endif
diff --git a/src/devtools/adb/include/private/android_filesystem_config.h b/src/devtools/adb/include/private/android_filesystem_config.h
new file mode 100755
index 0000000..b2f91a5
--- /dev/null
+++ b/src/devtools/adb/include/private/android_filesystem_config.h
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+/* This file is used to define the properties of the filesystem
+** images generated by build tools (mkbootfs and mkyaffs2image) and
+** by the device side of adb.
+*/
+
+#ifndef _ANDROID_FILESYSTEM_CONFIG_H_
+#define _ANDROID_FILESYSTEM_CONFIG_H_
+
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+#ifdef HAVE_ANDROID_OS
+#include <linux/capability.h>
+#else
+#include "android_filesystem_capability.h"
+#endif
+
+/* This is the master Users and Groups config for the platform.
+ * DO NOT EVER RENUMBER
+ */
+
+#define AID_ROOT             0  /* traditional unix root user */
+
+#define AID_SYSTEM        1000  /* system server */
+
+#define AID_RADIO         1001  /* telephony subsystem, RIL */
+#define AID_BLUETOOTH     1002  /* bluetooth subsystem */
+#define AID_GRAPHICS      1003  /* graphics devices */
+#define AID_INPUT         1004  /* input devices */
+#define AID_AUDIO         1005  /* audio devices */
+#define AID_CAMERA        1006  /* camera devices */
+#define AID_LOG           1007  /* log devices */
+#define AID_COMPASS       1008  /* compass device */
+#define AID_MOUNT         1009  /* mountd socket */
+#define AID_WIFI          1010  /* wifi subsystem */
+#define AID_ADB           1011  /* android debug bridge (adbd) */
+#define AID_INSTALL       1012  /* group for installing packages */
+#define AID_MEDIA         1013  /* mediaserver process */
+#define AID_DHCP          1014  /* dhcp client */
+#define AID_SDCARD_RW     1015  /* external storage write access */
+#define AID_VPN           1016  /* vpn system */
+#define AID_KEYSTORE      1017  /* keystore subsystem */
+#define AID_USB           1018  /* USB devices */
+#define AID_DRM           1019  /* DRM server */
+#define AID_MDNSR         1020  /* MulticastDNSResponder (service discovery) */
+#define AID_GPS           1021  /* GPS daemon */
+#define AID_UNUSED1       1022  /* deprecated, DO NOT USE */
+#define AID_MEDIA_RW      1023  /* internal media storage write access */
+#define AID_MTP           1024  /* MTP USB driver access */
+#define AID_UNUSED2       1025  /* deprecated, DO NOT USE */
+#define AID_DRMRPC        1026  /* group for drm rpc */
+#define AID_NFC           1027  /* nfc subsystem */
+#define AID_SDCARD_R      1028  /* external storage read access */
+#define AID_CLAT          1029  /* clat part of nat464 */
+#define AID_LOOP_RADIO    1030  /* loop radio devices */
+#define AID_MEDIA_DRM     1031  /* MediaDrm plugins */
+#define AID_PACKAGE_INFO  1032  /* access to installed package details */
+#define AID_SDCARD_PICS   1033  /* external storage photos access */
+#define AID_SDCARD_AV     1034  /* external storage audio/video access */
+#define AID_SDCARD_ALL    1035  /* access all users external storage */
+#define AID_LOGD          1036  /* log daemon */
+#define AID_SHARED_RELRO  1037  /* creator of shared GNU RELRO files */
+
+#define AID_SHELL         2000  /* adb and debug shell user */
+#define AID_CACHE         2001  /* cache access */
+#define AID_DIAG          2002  /* access to diagnostic resources */
+
+/* The range 2900-2999 is reserved for OEM, and must never be
+ * used here */
+#define AID_OEM_RESERVED_START 2900
+#define AID_OEM_RESERVED_END   2999
+
+/* The 3000 series are intended for use as supplemental group id's only.
+ * They indicate special Android capabilities that the kernel is aware of. */
+#define AID_NET_BT_ADMIN  3001  /* bluetooth: create any socket */
+#define AID_NET_BT        3002  /* bluetooth: create sco, rfcomm or l2cap sockets */
+#define AID_INET          3003  /* can create AF_INET and AF_INET6 sockets */
+#define AID_NET_RAW       3004  /* can create raw INET sockets */
+#define AID_NET_ADMIN     3005  /* can configure interfaces and routing tables. */
+#define AID_NET_BW_STATS  3006  /* read bandwidth statistics */
+#define AID_NET_BW_ACCT   3007  /* change bandwidth statistics accounting */
+#define AID_NET_BT_STACK  3008  /* bluetooth: access config files */
+
+#define AID_EVERYBODY     9997  /* shared between all apps in the same profile */
+#define AID_MISC          9998  /* access to misc storage */
+#define AID_NOBODY        9999
+
+#define AID_APP          10000  /* first app user */
+
+#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
+#define AID_ISOLATED_END   99999 /* end of uids for fully isolated sandboxed processes */
+
+#define AID_USER        100000  /* offset for uid ranges for each user */
+
+#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
+#define AID_SHARED_GID_END   59999 /* start of gids for apps in each user to share */
+
+#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
+struct android_id_info {
+    const char *name;
+    unsigned aid;
+};
+
+static const struct android_id_info android_ids[] = {
+    { "root",          AID_ROOT, },
+
+    { "system",        AID_SYSTEM, },
+
+    { "radio",         AID_RADIO, },
+    { "bluetooth",     AID_BLUETOOTH, },
+    { "graphics",      AID_GRAPHICS, },
+    { "input",         AID_INPUT, },
+    { "audio",         AID_AUDIO, },
+    { "camera",        AID_CAMERA, },
+    { "log",           AID_LOG, },
+    { "compass",       AID_COMPASS, },
+    { "mount",         AID_MOUNT, },
+    { "wifi",          AID_WIFI, },
+    { "adb",           AID_ADB, },
+    { "install",       AID_INSTALL, },
+    { "media",         AID_MEDIA, },
+    { "dhcp",          AID_DHCP, },
+    { "sdcard_rw",     AID_SDCARD_RW, },
+    { "vpn",           AID_VPN, },
+    { "keystore",      AID_KEYSTORE, },
+    { "usb",           AID_USB, },
+    { "drm",           AID_DRM, },
+    { "mdnsr",         AID_MDNSR, },
+    { "gps",           AID_GPS, },
+    // AID_UNUSED1
+    { "media_rw",      AID_MEDIA_RW, },
+    { "mtp",           AID_MTP, },
+    // AID_UNUSED2
+    { "drmrpc",        AID_DRMRPC, },
+    { "nfc",           AID_NFC, },
+    { "sdcard_r",      AID_SDCARD_R, },
+    { "clat",          AID_CLAT, },
+    { "loop_radio",    AID_LOOP_RADIO, },
+    { "mediadrm",      AID_MEDIA_DRM, },
+    { "package_info",  AID_PACKAGE_INFO, },
+    { "sdcard_pics",   AID_SDCARD_PICS, },
+    { "sdcard_av",     AID_SDCARD_AV, },
+    { "sdcard_all",    AID_SDCARD_ALL, },
+    { "logd",          AID_LOGD, },
+    { "shared_relro",  AID_SHARED_RELRO, },
+
+    { "shell",         AID_SHELL, },
+    { "cache",         AID_CACHE, },
+    { "diag",          AID_DIAG, },
+
+    { "net_bt_admin",  AID_NET_BT_ADMIN, },
+    { "net_bt",        AID_NET_BT, },
+    { "inet",          AID_INET, },
+    { "net_raw",       AID_NET_RAW, },
+    { "net_admin",     AID_NET_ADMIN, },
+    { "net_bw_stats",  AID_NET_BW_STATS, },
+    { "net_bw_acct",   AID_NET_BW_ACCT, },
+    { "net_bt_stack",  AID_NET_BT_STACK, },
+
+    { "everybody",     AID_EVERYBODY, },
+    { "misc",          AID_MISC, },
+    { "nobody",        AID_NOBODY, },
+};
+
+#define android_id_count \
+    (sizeof(android_ids) / sizeof(android_ids[0]))
+
+struct fs_path_config {
+    unsigned mode;
+    unsigned uid;
+    unsigned gid;
+    uint64_t capabilities;
+    const char *prefix;
+};
+
+/* Rules for directories.
+** These rules are applied based on "first match", so they
+** should start with the most specific path and work their
+** way up to the root.
+*/
+
+static const struct fs_path_config android_dirs[] = {
+    { 00770, AID_SYSTEM, AID_CACHE,  0, "cache" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
+    { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
+    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
+    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local" },
+    { 01771, AID_SYSTEM, AID_MISC,   0, "data/misc" },
+    { 00770, AID_DHCP,   AID_DHCP,   0, "data/misc/dhcp" },
+    { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
+    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
+    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
+    { 00750, AID_ROOT,   AID_SHELL,  0, "sbin" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/bin" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/vendor" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/xbin" },
+    { 00755, AID_ROOT,   AID_ROOT,   0, "system/etc/ppp" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "vendor" },
+    { 00777, AID_ROOT,   AID_ROOT,   0, "sdcard" },
+    { 00755, AID_ROOT,   AID_ROOT,   0, 0 },
+};
+
+/* Rules for files.
+** These rules are applied based on "first match", so they
+** should start with the most specific path and work their
+** way up to the root. Prefixes ending in * denotes wildcard
+** and will allow partial matches.
+*/
+static const struct fs_path_config android_files[] = {
+    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
+    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.trout.rc" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.testmenu" },
+    { 00550, AID_DHCP,      AID_SHELL,     0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
+    { 00444, AID_RADIO,     AID_AUDIO,     0, "system/etc/AudioPara4.csv" },
+    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
+    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
+    { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
+    { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/bin/ping" },
+
+    /* the following file is INTENTIONALLY set-gid and not set-uid.
+     * Do not change. */
+    { 02750, AID_ROOT,      AID_INET,      0, "system/bin/netcfg" },
+
+    /* the following five files are INTENTIONALLY set-uid, but they
+     * are NOT included on user builds. */
+    { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procrank" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/tcpdump" },
+    { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
+
+    /* the following files have enhanced capabilities and ARE included in user builds. */
+    { 00750, AID_ROOT,      AID_SHELL,     (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
+
+    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
+    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
+    { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
+    { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
+};
+
+static inline void fs_config(const char *path, int dir,
+                             unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
+{
+    const struct fs_path_config *pc;
+    int plen;
+
+    if (path[0] == '/') {
+        path++;
+    }
+
+    pc = dir ? android_dirs : android_files;
+    plen = strlen(path);
+    for(; pc->prefix; pc++){
+        int len = strlen(pc->prefix);
+        if (dir) {
+            if(plen < len) continue;
+            if(!strncmp(pc->prefix, path, len)) break;
+            continue;
+        }
+        /* If name ends in * then allow partial matches. */
+        if (pc->prefix[len -1] == '*') {
+            if(!strncmp(pc->prefix, path, len - 1)) break;
+        } else if (plen == len){
+            if(!strncmp(pc->prefix, path, len)) break;
+        }
+    }
+    *uid = pc->uid;
+    *gid = pc->gid;
+    *mode = (*mode & (~07777)) | pc->mode;
+    *capabilities = pc->capabilities;
+
+#if 0
+    fprintf(stderr,"< '%s' '%s' %d %d %o >\n",
+            path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode);
+#endif
+}
+#endif
+#endif
diff --git a/src/devtools/adb/jdwp_service.c b/src/devtools/adb/jdwp_service.c
new file mode 100755
index 0000000..cd62b55
--- /dev/null
+++ b/src/devtools/adb/jdwp_service.c
@@ -0,0 +1,735 @@
+/* implement the "debug-ports" and "track-debug-ports" device services */
+#include "sysdeps.h"
+#define  TRACE_TAG   TRACE_JDWP
+#include "adb.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/* here's how these things work.
+
+   when adbd starts, it creates a unix server socket
+   named @vm-debug-control (@ is a shortcut for "first byte is zero"
+   to use the private namespace instead of the file system)
+
+   when a new JDWP daemon thread starts in a new VM process, it creates
+   a connection to @vm-debug-control to announce its availability.
+
+
+     JDWP thread                             @vm-debug-control
+         |                                         |
+         |------------------------------->         |
+         | hello I'm in process <pid>              |
+         |                                         |
+         |                                         |
+
+    the connection is kept alive. it will be closed automatically if
+    the JDWP process terminates (this allows adbd to detect dead
+    processes).
+
+    adbd thus maintains a list of "active" JDWP processes. it can send
+    its content to clients through the "device:debug-ports" service,
+    or even updates through the "device:track-debug-ports" service.
+
+    when a debugger wants to connect, it simply runs the command
+    equivalent to  "adb forward tcp:<hostport> jdwp:<pid>"
+
+    "jdwp:<pid>" is a new forward destination format used to target
+    a given JDWP process on the device. when sutch a request arrives,
+    adbd does the following:
+
+      - first, it calls socketpair() to create a pair of equivalent
+        sockets.
+
+      - it attaches the first socket in the pair to a local socket
+        which is itself attached to the transport's remote socket:
+
+
+      - it sends the file descriptor of the second socket directly
+        to the JDWP process with the help of sendmsg()
+
+
+     JDWP thread                             @vm-debug-control
+         |                                         |
+         |                  <----------------------|
+         |           OK, try this file descriptor  |
+         |                                         |
+         |                                         |
+
+   then, the JDWP thread uses this new socket descriptor as its
+   pass-through connection to the debugger (and receives the
+   JDWP-Handshake message, answers to it, etc...)
+
+   this gives the following graphics:
+                    ____________________________________
+                   |                                    |
+                   |          ADB Server (host)         |
+                   |                                    |
+        Debugger <---> LocalSocket <----> RemoteSocket  |
+                   |                           ^^       |
+                   |___________________________||_______|
+                                               ||
+                                     Transport ||
+           (TCP for emulator - USB for device) ||
+                                               ||
+                    ___________________________||_______
+                   |                           ||       |
+                   |          ADBD  (device)   ||       |
+                   |                           VV       |
+         JDWP <======> LocalSocket <----> RemoteSocket  |
+                   |                                    |
+                   |____________________________________|
+
+    due to the way adb works, this doesn't need a special socket
+    type or fancy handling of socket termination if either the debugger
+    or the JDWP process closes the connection.
+
+    THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
+    TO HAVE A BETTER IDEA, LET ME KNOW - Digit
+
+**********************************************************************/
+
+/** JDWP PID List Support Code
+ ** for each JDWP process, we record its pid and its connected socket
+ **/
+
+#define  MAX_OUT_FDS   4
+
+#if !ADB_HOST
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+typedef struct JdwpProcess  JdwpProcess;
+struct JdwpProcess {
+    JdwpProcess*  next;
+    JdwpProcess*  prev;
+    int           pid;
+    int           socket;
+    fdevent*      fde;
+
+    char          in_buff[4];  /* input character to read PID */
+    int           in_len;      /* number from JDWP process    */
+
+    int           out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
+    int           out_count;            /* to send to the JDWP process      */
+};
+
+static JdwpProcess  _jdwp_list;
+
+static int
+jdwp_process_list( char*  buffer, int  bufferlen )
+{
+    char*         end  = buffer + bufferlen;
+    char*         p    = buffer;
+    JdwpProcess*  proc = _jdwp_list.next;
+
+    for ( ; proc != &_jdwp_list; proc = proc->next ) {
+        int  len;
+
+        /* skip transient connections */
+        if (proc->pid < 0)
+            continue;
+
+        len = snprintf(p, end-p, "%d\n", proc->pid);
+        if (p + len >= end)
+            break;
+        p += len;
+    }
+    p[0] = 0;
+    return (p - buffer);
+}
+
+
+static int
+jdwp_process_list_msg( char*  buffer, int  bufferlen )
+{
+    char  head[5];
+    int   len = jdwp_process_list( buffer+4, bufferlen-4 );
+    snprintf(head, sizeof head, "%04x", len);
+    memcpy(buffer, head, 4);
+    return len + 4;
+}
+
+
+static void  jdwp_process_list_updated(void);
+
+static void
+jdwp_process_free( JdwpProcess*  proc )
+{
+    if (proc) {
+        int  n;
+
+        proc->prev->next = proc->next;
+        proc->next->prev = proc->prev;
+
+        if (proc->socket >= 0) {
+            adb_shutdown(proc->socket);
+            adb_close(proc->socket);
+            proc->socket = -1;
+        }
+
+        if (proc->fde != NULL) {
+            fdevent_destroy(proc->fde);
+            proc->fde = NULL;
+        }
+        proc->pid = -1;
+
+        for (n = 0; n < proc->out_count; n++) {
+            adb_close(proc->out_fds[n]);
+        }
+        proc->out_count = 0;
+
+        free(proc);
+
+        jdwp_process_list_updated();
+    }
+}
+
+
+static void  jdwp_process_event(int, unsigned, void*);  /* forward */
+
+
+static JdwpProcess*
+jdwp_process_alloc( int  socket )
+{
+    JdwpProcess*  proc = calloc(1,sizeof(*proc));
+
+    if (proc == NULL) {
+        D("not enough memory to create new JDWP process\n");
+        return NULL;
+    }
+
+    proc->socket = socket;
+    proc->pid    = -1;
+    proc->next   = proc;
+    proc->prev   = proc;
+
+    proc->fde = fdevent_create( socket, jdwp_process_event, proc );
+    if (proc->fde == NULL) {
+        D("could not create fdevent for new JDWP process\n" );
+        free(proc);
+        return NULL;
+    }
+
+    proc->fde->state |= FDE_DONT_CLOSE;
+    proc->in_len      = 0;
+    proc->out_count   = 0;
+
+    /* append to list */
+    proc->next = &_jdwp_list;
+    proc->prev = proc->next->prev;
+
+    proc->prev->next = proc;
+    proc->next->prev = proc;
+
+    /* start by waiting for the PID */
+    fdevent_add(proc->fde, FDE_READ);
+
+    return proc;
+}
+
+
+static void
+jdwp_process_event( int  socket, unsigned  events, void*  _proc )
+{
+    JdwpProcess*  proc = _proc;
+
+    if (events & FDE_READ) {
+        if (proc->pid < 0) {
+            /* read the PID as a 4-hexchar string */
+            char*  p    = proc->in_buff + proc->in_len;
+            int    size = 4 - proc->in_len;
+            char   temp[5];
+            while (size > 0) {
+                int  len = recv( socket, p, size, 0 );
+                if (len < 0) {
+                    if (errno == EINTR)
+                        continue;
+                    if (errno == EAGAIN)
+                        return;
+                    /* this can fail here if the JDWP process crashes very fast */
+                    D("weird unknown JDWP process failure: %s\n",
+                      strerror(errno));
+
+                    goto CloseProcess;
+                }
+                if (len == 0) {  /* end of stream ? */
+                    D("weird end-of-stream from unknown JDWP process\n");
+                    goto CloseProcess;
+                }
+                p            += len;
+                proc->in_len += len;
+                size         -= len;
+            }
+            /* we have read 4 characters, now decode the pid */
+            memcpy(temp, proc->in_buff, 4);
+            temp[4] = 0;
+
+            if (sscanf( temp, "%04x", &proc->pid ) != 1) {
+                D("could not decode JDWP %p PID number: '%s'\n", proc, temp);
+                goto CloseProcess;
+            }
+
+            /* all is well, keep reading to detect connection closure */
+            D("Adding pid %d to jdwp process list\n", proc->pid);
+            jdwp_process_list_updated();
+        }
+        else
+        {
+            /* the pid was read, if we get there it's probably because the connection
+             * was closed (e.g. the JDWP process exited or crashed) */
+            char  buf[32];
+
+            for (;;) {
+                int  len = recv(socket, buf, sizeof(buf), 0);
+
+                if (len <= 0) {
+                    if (len < 0 && errno == EINTR)
+                        continue;
+                    if (len < 0 && errno == EAGAIN)
+                        return;
+                    else {
+                        D("terminating JDWP %d connection: %s\n", proc->pid,
+                          strerror(errno));
+                        break;
+                    }
+                }
+                else {
+                    D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n",
+                       proc->pid, len );
+                }
+            }
+
+        CloseProcess:
+            if (proc->pid >= 0)
+                D( "remove pid %d to jdwp process list\n", proc->pid );
+            jdwp_process_free(proc);
+            return;
+        }
+    }
+
+    if (events & FDE_WRITE) {
+        D("trying to write to JDWP pid controli (count=%d first=%d) %d\n",
+          proc->pid, proc->out_count, proc->out_fds[0]);
+        if (proc->out_count > 0) {
+            int  fd = proc->out_fds[0];
+            int  n, ret;
+            struct cmsghdr*  cmsg;
+            struct msghdr    msg;
+            struct iovec     iov;
+            char             dummy = '!';
+            char             buffer[sizeof(struct cmsghdr) + sizeof(int)];
+            int flags;
+
+            iov.iov_base       = &dummy;
+            iov.iov_len        = 1;
+            msg.msg_name       = NULL;
+            msg.msg_namelen    = 0;
+            msg.msg_iov        = &iov;
+            msg.msg_iovlen     = 1;
+            msg.msg_flags      = 0;
+            msg.msg_control    = buffer;
+            msg.msg_controllen = sizeof(buffer);
+
+            cmsg = CMSG_FIRSTHDR(&msg);
+            cmsg->cmsg_len   = msg.msg_controllen;
+            cmsg->cmsg_level = SOL_SOCKET;
+            cmsg->cmsg_type  = SCM_RIGHTS;
+            ((int*)CMSG_DATA(cmsg))[0] = fd;
+
+            flags = fcntl(proc->socket,F_GETFL,0);
+
+            if (flags == -1) {
+                D("failed to get cntl flags for socket %d: %s\n",
+                  proc->pid, strerror(errno));
+                goto CloseProcess;
+
+            }
+
+            if (fcntl(proc->socket, F_SETFL, flags & ~O_NONBLOCK) == -1) {
+                D("failed to remove O_NONBLOCK flag for socket %d: %s\n",
+                  proc->pid, strerror(errno));
+                goto CloseProcess;
+            }
+
+            for (;;) {
+                ret = sendmsg(proc->socket, &msg, 0);
+                if (ret >= 0) {
+                    adb_close(fd);
+                    break;
+                }
+                if (errno == EINTR)
+                    continue;
+                D("sending new file descriptor to JDWP %d failed: %s\n",
+                  proc->pid, strerror(errno));
+                goto CloseProcess;
+            }
+
+            D("sent file descriptor %d to JDWP process %d\n",
+              fd, proc->pid);
+
+            for (n = 1; n < proc->out_count; n++)
+                proc->out_fds[n-1] = proc->out_fds[n];
+
+            if (fcntl(proc->socket, F_SETFL, flags) == -1) {
+                D("failed to set O_NONBLOCK flag for socket %d: %s\n",
+                  proc->pid, strerror(errno));
+                goto CloseProcess;
+            }
+
+            if (--proc->out_count == 0)
+                fdevent_del( proc->fde, FDE_WRITE );
+        }
+    }
+}
+
+
+int
+create_jdwp_connection_fd(int  pid)
+{
+    JdwpProcess*  proc = _jdwp_list.next;
+
+    D("looking for pid %d in JDWP process list\n", pid);
+    for ( ; proc != &_jdwp_list; proc = proc->next ) {
+        if (proc->pid == pid) {
+            goto FoundIt;
+        }
+    }
+    D("search failed !!\n");
+    return -1;
+
+FoundIt:
+    {
+        int  fds[2];
+
+        if (proc->out_count >= MAX_OUT_FDS) {
+            D("%s: too many pending JDWP connection for pid %d\n",
+              __FUNCTION__, pid);
+            return -1;
+        }
+
+        if (adb_socketpair(fds) < 0) {
+            D("%s: socket pair creation failed: %s\n",
+              __FUNCTION__, strerror(errno));
+            return -1;
+        }
+
+        proc->out_fds[ proc->out_count ] = fds[1];
+        if (++proc->out_count == 1)
+            fdevent_add( proc->fde, FDE_WRITE );
+
+        return fds[0];
+    }
+}
+
+/**  VM DEBUG CONTROL SOCKET
+ **
+ **  we do implement a custom asocket to receive the data
+ **/
+
+/* name of the debug control Unix socket */
+#define  JDWP_CONTROL_NAME      "\0jdwp-control"
+#define  JDWP_CONTROL_NAME_LEN  (sizeof(JDWP_CONTROL_NAME)-1)
+
+typedef struct {
+    int       listen_socket;
+    fdevent*  fde;
+
+} JdwpControl;
+
+
+static void
+jdwp_control_event(int  s, unsigned events, void*  user);
+
+
+static int
+jdwp_control_init( JdwpControl*  control,
+                   const char*   sockname,
+                   int           socknamelen )
+{
+    struct sockaddr_un   addr;
+    socklen_t            addrlen;
+    int                  s;
+    int                  maxpath = sizeof(addr.sun_path);
+    int                  pathlen = socknamelen;
+
+    if (pathlen >= maxpath) {
+        D( "vm debug control socket name too long (%d extra chars)\n",
+           pathlen+1-maxpath );
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    memcpy(addr.sun_path, sockname, socknamelen);
+
+    s = socket( AF_UNIX, SOCK_STREAM, 0 );
+    if (s < 0) {
+        D( "could not create vm debug control socket. %d: %s\n",
+           errno, strerror(errno));
+        return -1;
+    }
+
+    addrlen = (pathlen + sizeof(addr.sun_family));
+
+    if (bind(s, (struct sockaddr*)&addr, addrlen) < 0) {
+        D( "could not bind vm debug control socket: %d: %s\n",
+           errno, strerror(errno) );
+        adb_close(s);
+        return -1;
+    }
+
+    if ( listen(s, 4) < 0 ) {
+        D("listen failed in jdwp control socket: %d: %s\n",
+          errno, strerror(errno));
+        adb_close(s);
+        return -1;
+    }
+
+    control->listen_socket = s;
+
+    control->fde = fdevent_create(s, jdwp_control_event, control);
+    if (control->fde == NULL) {
+        D( "could not create fdevent for jdwp control socket\n" );
+        adb_close(s);
+        return -1;
+    }
+
+    /* only wait for incoming connections */
+    fdevent_add(control->fde, FDE_READ);
+    close_on_exec(s);
+
+    D("jdwp control socket started (%d)\n", control->listen_socket);
+    return 0;
+}
+
+
+static void
+jdwp_control_event( int  s, unsigned  events, void*  _control )
+{
+    JdwpControl*  control = (JdwpControl*) _control;
+
+    if (events & FDE_READ) {
+        struct sockaddr   addr;
+        socklen_t         addrlen = sizeof(addr);
+        int               s = -1;
+        JdwpProcess*      proc;
+
+        do {
+            s = adb_socket_accept( control->listen_socket, &addr, &addrlen );
+            if (s < 0) {
+                if (errno == EINTR)
+                    continue;
+                if (errno == ECONNABORTED) {
+                    /* oops, the JDWP process died really quick */
+                    D("oops, the JDWP process died really quick\n");
+                    return;
+                }
+                /* the socket is probably closed ? */
+                D( "weird accept() failed on jdwp control socket: %s\n",
+                   strerror(errno) );
+                return;
+            }
+        }
+        while (s < 0);
+
+        proc = jdwp_process_alloc( s );
+        if (proc == NULL)
+            return;
+    }
+}
+
+
+static JdwpControl   _jdwp_control;
+
+/** "jdwp" local service implementation
+ ** this simply returns the list of known JDWP process pids
+ **/
+
+typedef struct {
+    asocket  socket;
+    int      pass;
+} JdwpSocket;
+
+static void
+jdwp_socket_close( asocket*  s )
+{
+    asocket*  peer = s->peer;
+
+    remove_socket(s);
+
+    if (peer) {
+        peer->peer = NULL;
+        peer->close(peer);
+    }
+    free(s);
+}
+
+static int
+jdwp_socket_enqueue( asocket*  s, apacket*  p )
+{
+    /* you can't write to this asocket */
+    put_apacket(p);
+    s->peer->close(s->peer);
+    return -1;
+}
+
+
+static void
+jdwp_socket_ready( asocket*  s )
+{
+    JdwpSocket*  jdwp = (JdwpSocket*)s;
+    asocket*     peer = jdwp->socket.peer;
+
+   /* on the first call, send the list of pids,
+    * on the second one, close the connection
+    */
+    if (jdwp->pass == 0) {
+        apacket*  p = get_apacket();
+        p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD);
+        peer->enqueue(peer, p);
+        jdwp->pass = 1;
+    }
+    else {
+        peer->close(peer);
+    }
+}
+
+asocket*
+create_jdwp_service_socket( void )
+{
+    JdwpSocket*  s = calloc(sizeof(*s),1);
+
+    if (s == NULL)
+        return NULL;
+
+    install_local_socket(&s->socket);
+
+    s->socket.ready   = jdwp_socket_ready;
+    s->socket.enqueue = jdwp_socket_enqueue;
+    s->socket.close   = jdwp_socket_close;
+    s->pass           = 0;
+
+    return &s->socket;
+}
+
+/** "track-jdwp" local service implementation
+ ** this periodically sends the list of known JDWP process pids
+ ** to the client...
+ **/
+
+typedef struct JdwpTracker  JdwpTracker;
+
+struct JdwpTracker {
+    asocket       socket;
+    JdwpTracker*  next;
+    JdwpTracker*  prev;
+    int           need_update;
+};
+
+static JdwpTracker   _jdwp_trackers_list;
+
+
+static void
+jdwp_process_list_updated(void)
+{
+    char             buffer[1024];
+    int              len;
+    JdwpTracker*  t = _jdwp_trackers_list.next;
+
+    len = jdwp_process_list_msg(buffer, sizeof(buffer));
+
+    for ( ; t != &_jdwp_trackers_list; t = t->next ) {
+        apacket*  p    = get_apacket();
+        asocket*  peer = t->socket.peer;
+        memcpy(p->data, buffer, len);
+        p->len = len;
+        peer->enqueue( peer, p );
+    }
+}
+
+static void
+jdwp_tracker_close( asocket*  s )
+{
+    JdwpTracker*  tracker = (JdwpTracker*) s;
+    asocket*      peer    = s->peer;
+
+    if (peer) {
+        peer->peer = NULL;
+        peer->close(peer);
+    }
+
+    remove_socket(s);
+
+    tracker->prev->next = tracker->next;
+    tracker->next->prev = tracker->prev;
+
+    free(s);
+}
+
+static void
+jdwp_tracker_ready( asocket*  s )
+{
+    JdwpTracker*  t = (JdwpTracker*) s;
+
+    if (t->need_update) {
+        apacket*  p = get_apacket();
+        t->need_update = 0;
+        p->len = jdwp_process_list_msg((char*)p->data, sizeof(p->data));
+        s->peer->enqueue(s->peer, p);
+    }
+}
+
+static int
+jdwp_tracker_enqueue( asocket*  s, apacket*  p )
+{
+    /* you can't write to this socket */
+    put_apacket(p);
+    s->peer->close(s->peer);
+    return -1;
+}
+
+
+asocket*
+create_jdwp_tracker_service_socket( void )
+{
+    JdwpTracker*  t = calloc(sizeof(*t),1);
+
+    if (t == NULL)
+        return NULL;
+
+    t->next = &_jdwp_trackers_list;
+    t->prev = t->next->prev;
+
+    t->next->prev = t;
+    t->prev->next = t;
+
+    install_local_socket(&t->socket);
+
+    t->socket.ready   = jdwp_tracker_ready;
+    t->socket.enqueue = jdwp_tracker_enqueue;
+    t->socket.close   = jdwp_tracker_close;
+    t->need_update    = 1;
+
+    return &t->socket;
+}
+
+
+int
+init_jdwp(void)
+{
+    _jdwp_list.next = &_jdwp_list;
+    _jdwp_list.prev = &_jdwp_list;
+
+    _jdwp_trackers_list.next = &_jdwp_trackers_list;
+    _jdwp_trackers_list.prev = &_jdwp_trackers_list;
+
+    return jdwp_control_init( &_jdwp_control,
+                              JDWP_CONTROL_NAME,
+                              JDWP_CONTROL_NAME_LEN );
+}
+
+#endif /* !ADB_HOST */
+
diff --git a/src/devtools/adb/load_file.c b/src/devtools/adb/load_file.c
new file mode 100755
index 0000000..99f2965
--- /dev/null
+++ b/src/devtools/adb/load_file.c
@@ -0,0 +1,51 @@
+/* libs/cutils/load_file.c
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+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;
+}
diff --git a/src/devtools/adb/logd_write.c b/src/devtools/adb/logd_write.c
new file mode 100755
index 0000000..b2668ce
--- /dev/null
+++ b/src/devtools/adb/logd_write.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2007-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#if (FAKE_LOG_DEVICE == 0)
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+#include <time.h>
+#include <unistd.h>
+
+#ifdef __BIONIC__
+#include <android/set_abort_message.h>
+#endif
+
+#include <log/logd.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+#include <private/android_filesystem_config.h>
+
+#define LOG_BUF_SIZE 1024
+
+#if FAKE_LOG_DEVICE
+/* This will be defined when building for the host. */
+#include "fake_log_device.h"
+#endif
+
+static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
+static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
+#ifdef HAVE_PTHREADS
+static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#ifndef __unused
+#define __unused  __attribute__((__unused__))
+#endif
+
+#if FAKE_LOG_DEVICE
+static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
+#else
+static int logd_fd = -1;
+#endif
+
+/*
+ * This is used by the C++ code to decide if it should write logs through
+ * the C code.  Basically, if /dev/socket/logd is available, we're running in
+ * the simulator rather than a desktop tool and want to use the device.
+ */
+static enum {
+    kLogUninitialized, kLogNotAvailable, kLogAvailable
+} g_log_status = kLogUninitialized;
+int __android_log_dev_available(void)
+{
+    if (g_log_status == kLogUninitialized) {
+        if (access("/dev/socket/logdw", W_OK) == 0)
+            g_log_status = kLogAvailable;
+        else
+            g_log_status = kLogNotAvailable;
+    }
+
+    return (g_log_status == kLogAvailable);
+}
+
+#if !FAKE_LOG_DEVICE
+/* give up, resources too limited */
+static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused,
+                               size_t nr __unused)
+{
+    return -1;
+}
+#endif
+
+/* log_init_lock assumed */
+static int __write_to_log_initialize()
+{
+    int i, ret = 0;
+
+#if FAKE_LOG_DEVICE
+    for (i = 0; i < LOG_ID_MAX; i++) {
+        char buf[sizeof("/dev/log_system")];
+        snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
+        log_fds[i] = fakeLogOpen(buf, O_WRONLY);
+    }
+#else
+    if (logd_fd >= 0) {
+        i = logd_fd;
+        logd_fd = -1;
+        close(i);
+    }
+
+    i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+    if (i < 0) {
+        ret = -errno;
+        write_to_log = __write_to_log_null;
+    } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) {
+        ret = -errno;
+        close(i);
+        i = -1;
+        write_to_log = __write_to_log_null;
+    } else {
+        struct sockaddr_un un;
+        memset(&un, 0, sizeof(struct sockaddr_un));
+        un.sun_family = AF_UNIX;
+        strcpy(un.sun_path, "/dev/socket/logdw");
+
+        if (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) {
+            ret = -errno;
+            close(i);
+            i = -1;
+        }
+    }
+    logd_fd = i;
+#endif
+
+    return ret;
+}
+
+static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+    ssize_t ret;
+#if FAKE_LOG_DEVICE
+    int log_fd;
+
+    if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
+        log_fd = log_fds[(int)log_id];
+    } else {
+        return -EBADF;
+    }
+    do {
+        ret = fakeLogWritev(log_fd, vec, nr);
+        if (ret < 0) {
+            ret = -errno;
+        }
+    } while (ret == -EINTR);
+#else
+    static const unsigned header_length = 3;
+    struct iovec newVec[nr + header_length];
+    typeof_log_id_t log_id_buf;
+    uint16_t tid;
+    struct timespec ts;
+    log_time realtime_ts;
+    size_t i, payload_size;
+    static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
+
+    if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
+        last_uid = getuid();
+    }
+    if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
+        /*
+         * ignore log messages we send to ourself (logd).
+         * Such log messages are often generated by libraries we depend on
+         * which use standard Android logging.
+         */
+        return 0;
+    }
+
+    if (logd_fd < 0) {
+        return -EBADF;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide
+     *      typeof_log_id_t  log_id;
+     *      u16              tid;
+     *      log_time         realtime;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    clock_gettime(CLOCK_REALTIME, &ts);
+    realtime_ts.tv_sec = ts.tv_sec;
+    realtime_ts.tv_nsec = ts.tv_nsec;
+
+    log_id_buf = log_id;
+    tid = gettid();
+
+    newVec[0].iov_base   = (unsigned char *) &log_id_buf;
+    newVec[0].iov_len    = sizeof_log_id_t;
+    newVec[1].iov_base   = (unsigned char *) &tid;
+    newVec[1].iov_len    = sizeof(tid);
+    newVec[2].iov_base   = (unsigned char *) &realtime_ts;
+    newVec[2].iov_len    = sizeof(log_time);
+
+    for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
+        newVec[i].iov_base = vec[i - header_length].iov_base;
+        payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
+
+        if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) {
+            newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD;
+            if (newVec[i].iov_len) {
+                ++i;
+            }
+            break;
+        }
+    }
+
+    /*
+     * The write below could be lost, but will never block.
+     *
+     * ENOTCONN occurs if logd dies.
+     * EAGAIN occurs if logd is overloaded.
+     */
+    ret = writev(logd_fd, newVec, i);
+    if (ret < 0) {
+        ret = -errno;
+        if (ret == -ENOTCONN) {
+#ifdef HAVE_PTHREADS
+            pthread_mutex_lock(&log_init_lock);
+#endif
+            ret = __write_to_log_initialize();
+#ifdef HAVE_PTHREADS
+            pthread_mutex_unlock(&log_init_lock);
+#endif
+
+            if (ret < 0) {
+                return ret;
+            }
+
+            ret = writev(logd_fd, newVec, nr + header_length);
+            if (ret < 0) {
+                ret = -errno;
+            }
+        }
+    }
+
+    if (ret > (ssize_t)(sizeof_log_id_t + sizeof(tid) + sizeof(log_time))) {
+        ret -= sizeof_log_id_t + sizeof(tid) + sizeof(log_time);
+    }
+#endif
+
+    return ret;
+}
+
+#if FAKE_LOG_DEVICE
+static const char *LOG_NAME[LOG_ID_MAX] = {
+    [LOG_ID_MAIN] = "main",
+    [LOG_ID_RADIO] = "radio",
+    [LOG_ID_EVENTS] = "events",
+    [LOG_ID_SYSTEM] = "system",
+    [LOG_ID_CRASH] = "crash"
+};
+
+const char *android_log_id_to_name(log_id_t log_id)
+{
+    if (log_id >= LOG_ID_MAX) {
+        log_id = LOG_ID_MAIN;
+    }
+    return LOG_NAME[log_id];
+}
+#endif
+
+static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+#ifdef HAVE_PTHREADS
+    pthread_mutex_lock(&log_init_lock);
+#endif
+
+    if (write_to_log == __write_to_log_init) {
+        int ret;
+
+        ret = __write_to_log_initialize();
+        if (ret < 0) {
+#ifdef HAVE_PTHREADS
+            pthread_mutex_unlock(&log_init_lock);
+#endif
+            return ret;
+        }
+
+        write_to_log = __write_to_log_kernel;
+    }
+
+#ifdef HAVE_PTHREADS
+    pthread_mutex_unlock(&log_init_lock);
+#endif
+
+    return write_to_log(log_id, vec, nr);
+}
+
+int __android_log_write(int prio, const char *tag, const char *msg)
+{
+    struct iovec vec[3];
+    log_id_t log_id = LOG_ID_MAIN;
+    char tmp_tag[32];
+
+    if (!tag)
+        tag = "";
+
+    /* XXX: This needs to go! */
+    if (!strcmp(tag, "HTC_RIL") ||
+        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
+        !strcmp(tag, "AT") ||
+        !strcmp(tag, "GSM") ||
+        !strcmp(tag, "STK") ||
+        !strcmp(tag, "CDMA") ||
+        !strcmp(tag, "PHONE") ||
+        !strcmp(tag, "SMS")) {
+            log_id = LOG_ID_RADIO;
+            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
+            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+            tag = tmp_tag;
+    }
+
+#if __BIONIC__
+    if (prio == ANDROID_LOG_FATAL) {
+        android_set_abort_message(msg);
+    }
+#endif
+
+    vec[0].iov_base   = (unsigned char *) &prio;
+    vec[0].iov_len    = 1;
+    vec[1].iov_base   = (void *) tag;
+    vec[1].iov_len    = strlen(tag) + 1;
+    vec[2].iov_base   = (void *) msg;
+    vec[2].iov_len    = strlen(msg) + 1;
+
+    return write_to_log(log_id, vec, 3);
+}
+
+int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
+{
+    struct iovec vec[3];
+    char tmp_tag[32];
+
+    if (!tag)
+        tag = "";
+
+    /* XXX: This needs to go! */
+    if ((bufID != LOG_ID_RADIO) &&
+         (!strcmp(tag, "HTC_RIL") ||
+        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
+        !strcmp(tag, "AT") ||
+        !strcmp(tag, "GSM") ||
+        !strcmp(tag, "STK") ||
+        !strcmp(tag, "CDMA") ||
+        !strcmp(tag, "PHONE") ||
+        !strcmp(tag, "SMS"))) {
+            bufID = LOG_ID_RADIO;
+            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
+            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+            tag = tmp_tag;
+    }
+
+    vec[0].iov_base   = (unsigned char *) &prio;
+    vec[0].iov_len    = 1;
+    vec[1].iov_base   = (void *) tag;
+    vec[1].iov_len    = strlen(tag) + 1;
+    vec[2].iov_base   = (void *) msg;
+    vec[2].iov_len    = strlen(msg) + 1;
+
+    return write_to_log(bufID, vec, 3);
+}
+
+int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap)
+{
+    char buf[LOG_BUF_SIZE];
+
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+
+    return __android_log_write(prio, tag, buf);
+}
+
+int __android_log_print(int prio, const char *tag, const char *fmt, ...)
+{
+    va_list ap;
+    char buf[LOG_BUF_SIZE];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+    va_end(ap);
+
+    return __android_log_write(prio, tag, buf);
+}
+
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
+{
+    va_list ap;
+    char buf[LOG_BUF_SIZE];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+    va_end(ap);
+
+    return __android_log_buf_write(bufID, prio, tag, buf);
+}
+
+void __android_log_assert(const char *cond, const char *tag,
+                          const char *fmt, ...)
+{
+    char buf[LOG_BUF_SIZE];
+
+    if (fmt) {
+        va_list ap;
+        va_start(ap, fmt);
+        vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+        va_end(ap);
+    } else {
+        /* Msg not provided, log condition.  N.B. Do not use cond directly as
+         * format string as it could contain spurious '%' syntax (e.g.
+         * "%d" in "blocks%devs == 0").
+         */
+        if (cond)
+            snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
+        else
+            strcpy(buf, "Unspecified assertion failed");
+    }
+
+    __android_log_write(ANDROID_LOG_FATAL, tag, buf);
+    __builtin_trap(); /* trap so we have a chance to debug the situation */
+    /* NOTREACHED */
+}
+
+int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
+{
+    struct iovec vec[2];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = (void*)payload;
+    vec[1].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 2);
+}
+
+/*
+ * Like __android_log_bwrite, but takes the type as well.  Doesn't work
+ * for the general case where we're generating lists of stuff, but very
+ * handy if we just want to dump an integer into the log.
+ */
+int __android_log_btwrite(int32_t tag, char type, const void *payload,
+                          size_t len)
+{
+    struct iovec vec[3];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = (void*)payload;
+    vec[2].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 3);
+}
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+int __android_log_bswrite(int32_t tag, const char *payload)
+{
+    struct iovec vec[4];
+    char type = EVENT_TYPE_STRING;
+    uint32_t len = strlen(payload);
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = &len;
+    vec[2].iov_len = sizeof(len);
+    vec[3].iov_base = (void*)payload;
+    vec[3].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
diff --git a/src/devtools/adb/loghack.h b/src/devtools/adb/loghack.h
new file mode 100755
index 0000000..750cab0
--- /dev/null
+++ b/src/devtools/adb/loghack.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+/**
+ * This is a temporary hack to enable logging from cutils.
+ */
+
+#ifndef _CUTILS_LOGHACK_H
+#define _CUTILS_LOGHACK_H
+
+#ifdef HAVE_ANDROID_OS
+#include <cutils/log.h>
+#else
+#include <stdio.h>
+#define ALOG(level, ...) \
+        ((void)printf("cutils:" level "/" LOG_TAG ": " __VA_ARGS__))
+#define ALOGV(...)   ALOG("V", __VA_ARGS__)
+#define ALOGD(...)   ALOG("D", __VA_ARGS__)
+#define ALOGI(...)   ALOG("I", __VA_ARGS__)
+#define ALOGW(...)   ALOG("W", __VA_ARGS__)
+#define ALOGE(...)   ALOG("E", __VA_ARGS__)
+#define LOG_ALWAYS_FATAL(...)   do { ALOGE(__VA_ARGS__); exit(1); } while (0)
+#endif
+
+#endif // _CUTILS_LOGHACK_H
diff --git a/src/devtools/adb/mutex_list.h b/src/devtools/adb/mutex_list.h
new file mode 100755
index 0000000..ff72751
--- /dev/null
+++ b/src/devtools/adb/mutex_list.h
@@ -0,0 +1,25 @@
+/* the list of mutexes used by adb */
+/* #ifndef __MUTEX_LIST_H
+ * Do not use an include-guard. This file is included once to declare the locks
+ * and once in win32 to actually do the runtime initialization.
+ */
+#ifndef ADB_MUTEX
+#error ADB_MUTEX not defined when including this file
+#endif
+ADB_MUTEX(socket_list_lock)
+ADB_MUTEX(transport_lock)
+#if ADB_HOST
+ADB_MUTEX(local_transports_lock)
+#endif
+ADB_MUTEX(usb_lock)
+
+// Sadly logging to /data/adb/adb-... is not thread safe.
+//  After modifying adb.h::D() to count invocations:
+//   DEBUG(jpa):0:Handling main()
+//   DEBUG(jpa):1:[ usb_init - starting thread ]
+// (Oopsies, no :2:, and matching message is also gone.)
+//   DEBUG(jpa):3:[ usb_thread - opening device ]
+//   DEBUG(jpa):4:jdwp control socket started (10)
+ADB_MUTEX(D_lock)
+
+#undef ADB_MUTEX
diff --git a/src/devtools/adb/properties.c b/src/devtools/adb/properties.c
new file mode 100755
index 0000000..20069b0
--- /dev/null
+++ b/src/devtools/adb/properties.c
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#define LOG_TAG "properties"
+// #define LOG_NDEBUG 0
+#define   TRACE_TAG  TRACE_ADB
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <cutils/sockets.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <cutils/properties.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include "loghack.h"
+
+int8_t property_get_bool(const char *key, int8_t default_value) {
+    if (!key) {
+        return default_value;
+    }
+
+    int8_t result = default_value;
+    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+
+    int len = property_get(key, buf, "");
+    if (len == 1) {
+        char ch = buf[0];
+        if (ch == '0' || ch == 'n') {
+            result = false;
+        } else if (ch == '1' || ch == 'y') {
+            result = true;
+        }
+    } else if (len > 1) {
+         if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+            result = false;
+        } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+            result = true;
+        }
+    }
+
+    return result;
+}
+
+// Convert string property to int (default if fails); return default value if out of bounds
+static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
+        intmax_t default_value) {
+    if (!key) {
+        return default_value;
+    }
+
+    intmax_t result = default_value;
+    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+    char *end = NULL;
+
+    int len = property_get(key, buf, "");
+    if (len > 0) {
+        int tmp = errno;
+        errno = 0;
+
+        // Infer base automatically
+        result = strtoimax(buf, &end, /*base*/0);
+        if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
+            // Over or underflow
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
+        } else if (result < lower_bound || result > upper_bound) {
+            // Out of range of requested bounds
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
+        } else if (end == buf) {
+            // Numeric conversion failed
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
+                    __FUNCTION__, key, default_value);
+        }
+
+        errno = tmp;
+    }
+
+    return result;
+}
+
+int64_t property_get_int64(const char *key, int64_t default_value) {
+    return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
+}
+
+int32_t property_get_int32(const char *key, int32_t default_value) {
+    return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
+}
+
+#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+int property_set(const char *key, const char *value)
+{
+    return __system_property_set(key, value);
+}
+
+int property_get(const char *key, char *value, const char *default_value)
+{
+    int len;
+
+    len = __system_property_get(key, value);
+    if(len > 0) {
+        return len;
+    }
+    if(default_value) {
+        len = strlen(default_value);
+        if (len >= PROPERTY_VALUE_MAX) {
+            len = PROPERTY_VALUE_MAX - 1;
+        }
+        memcpy(value, default_value, len);
+        value[len] = '\0';
+    }
+    return len;
+}
+
+struct property_list_callback_data
+{
+    void (*propfn)(const char *key, const char *value, void *cookie);
+    void *cookie;
+};
+
+static void property_list_callback(const prop_info *pi, void *cookie)
+{
+    char name[PROP_NAME_MAX];
+    char value[PROP_VALUE_MAX];
+    struct property_list_callback_data *data = cookie;
+
+    __system_property_read(pi, name, value);
+    data->propfn(name, value, data->cookie);
+}
+
+int property_list(
+        void (*propfn)(const char *key, const char *value, void *cookie),
+        void *cookie)
+{
+    struct property_list_callback_data data = { propfn, cookie };
+    return __system_property_foreach(property_list_callback, &data);
+}
+
+#elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
+
+/*
+ * The Linux simulator provides a "system property server" that uses IPC
+ * to set/get/list properties.  The file descriptor is shared by all
+ * threads in the process, so we use a mutex to ensure that requests
+ * from multiple threads don't get interleaved.
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <pthread.h>
+
+static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT;
+static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER;
+static int gPropFd = -1;
+
+/*
+ * Connect to the properties server.
+ *
+ * Returns the socket descriptor on success.
+ */
+static int connectToServer(const char* fileName)
+{
+    int sock = -1;
+    int cc;
+
+    struct sockaddr_un addr;
+    
+    sock = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        ALOGW("UNIX domain socket create failed (errno=%d)\n", errno);
+        return -1;
+    }
+
+    /* connect to socket; fails if file doesn't exist */
+    strcpy(addr.sun_path, fileName);    // max 108 bytes
+    addr.sun_family = AF_UNIX;
+    cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
+    if (cc < 0) {
+        // ENOENT means socket file doesn't exist
+        // ECONNREFUSED means socket exists but nobody is listening
+        //ALOGW("AF_UNIX connect failed for '%s': %s\n",
+        //    fileName, strerror(errno));
+        close(sock);
+        return -1;
+    }
+
+    return sock;
+}
+
+/*
+ * Perform one-time initialization.
+ */
+static void init(void)
+{
+    assert(gPropFd == -1);
+
+    gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);
+    if (gPropFd < 0) {
+        //ALOGW("not connected to system property server\n");
+    } else {
+        //ALOGV("Connected to system property server\n");
+    }
+}
+
+int property_get(const char *key, char *value, const char *default_value)
+{
+    char sendBuf[1+PROPERTY_KEY_MAX];
+    char recvBuf[1+PROPERTY_VALUE_MAX];
+    int len = -1;
+
+    //ALOGV("PROPERTY GET [%s]\n", key);
+
+    pthread_once(&gInitOnce, init);
+    if (gPropFd < 0) {
+        /* this mimics the behavior of the device implementation */
+        if (default_value != NULL) {
+            strcpy(value, default_value);
+            len = strlen(value);
+        }
+        return len;
+    }
+
+    if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
+
+    memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
+
+    sendBuf[0] = (char) kSystemPropertyGet;
+    strcpy(sendBuf+1, key);
+
+    pthread_mutex_lock(&gPropertyFdLock);
+    if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    pthread_mutex_unlock(&gPropertyFdLock);
+
+    /* first byte is 0 if value not defined, 1 if found */
+    if (recvBuf[0] == 0) {
+        if (default_value != NULL) {
+            strcpy(value, default_value);
+            len = strlen(value);
+        } else {
+            /*
+             * If the value isn't defined, hand back an empty string and
+             * a zero length, rather than a failure.  This seems wrong,
+             * since you can't tell the difference between "undefined" and
+             * "defined but empty", but it's what the device does.
+             */
+            value[0] = '\0';
+            len = 0;
+        }
+    } else if (recvBuf[0] == 1) {
+        strcpy(value, recvBuf+1);
+        len = strlen(value);
+    } else {
+        ALOGE("Got strange response to property_get request (%d)\n",
+            recvBuf[0]);
+        assert(0);
+        return -1;
+    }
+    //ALOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n",
+    //    recvBuf[0], default_value, len, key, value);
+
+    return len;
+}
+
+
+int property_set(const char *key, const char *value)
+{
+    char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];
+    char recvBuf[1];
+    int result = -1;
+
+    //ALOGV("PROPERTY SET [%s]: [%s]\n", key, value);
+
+    pthread_once(&gInitOnce, init);
+    if (gPropFd < 0)
+        return -1;
+
+    if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
+    if (strlen(value) >= PROPERTY_VALUE_MAX) return -1;
+
+    memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
+
+    sendBuf[0] = (char) kSystemPropertySet;
+    strcpy(sendBuf+1, key);
+    strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);
+
+    pthread_mutex_lock(&gPropertyFdLock);
+    if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    pthread_mutex_unlock(&gPropertyFdLock);
+
+    if (recvBuf[0] != 1)
+        return -1;
+    return 0;
+}
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 
+                  void *cookie)
+{
+    //ALOGV("PROPERTY LIST\n");
+    pthread_once(&gInitOnce, init);
+    if (gPropFd < 0)
+        return -1;
+
+    return 0;
+}
+
+#elif defined(ADB_OVER_PCIE)
+
+/* SUPER-cheesy place-holder implementation for Win32 */
+
+#include <cutils/threads.h>
+
+static mutex_t  env_lock = MUTEX_INITIALIZER;
+
+int property_get(const char *key, char *value, const char *default_value)
+{
+    char ename[PROPERTY_KEY_MAX + 6];
+    char *p;
+    int len;
+    
+    len = strlen(key);
+    if(len >= PROPERTY_KEY_MAX) return -1;
+    memcpy(ename, "PROP_", 5);
+    memcpy(ename + 5, key, len + 1);
+    
+    mutex_lock(&env_lock);
+
+    p = getenv(ename);
+    if(p == 0) p = "";
+    len = strlen(p);
+    if(len >= PROPERTY_VALUE_MAX) {
+        len = PROPERTY_VALUE_MAX - 1;
+    }
+    
+    if((len == 0) && default_value) {
+        len = strlen(default_value);
+        memcpy(value, default_value, len + 1);
+    } else {
+        memcpy(value, p, len);
+        value[len] = 0;
+    }
+
+    mutex_unlock(&env_lock);
+    
+    return len;
+}
+
+
+int property_set(const char *key, const char *value)
+{
+    char ename[PROPERTY_KEY_MAX + 6];
+    char *p;
+    int len;
+    int r;
+
+    if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;
+    
+    len = strlen(key);
+    if(len >= PROPERTY_KEY_MAX) return -1;
+    memcpy(ename, "PROP_", 5);
+    memcpy(ename + 5, key, len + 1);
+
+    mutex_lock(&env_lock);
+#ifdef HAVE_MS_C_RUNTIME
+    {
+        char  temp[256];
+        snprintf( temp, sizeof(temp), "%s=%s", ename, value);
+        putenv(temp);
+        r = 0;
+    }
+#else
+    r = setenv(ename, value, 1);
+#endif
+    mutex_unlock(&env_lock);
+
+    return r;
+}
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
+                  void *cookie)
+{
+    return 0;
+}
+
+#else
+
+/* UCI configuration system implementation for OpenWrt */
+#include <uci.h>
+#include "adb_trace.h"
+
+#define UCI_CONFIG_FILE          "/etc/config/usb"
+
+int property_get(const char *key, char *value, const char *default_value) {
+    if (NULL == key || NULL == value) {
+        return 0;
+    }
+    int retValue = 0;
+    struct uci_context *uciCtx = uci_alloc_context();
+    const char *pValueData = NULL;
+    struct uci_package *pkg = NULL;
+    struct uci_element *e;
+
+    // replace '.' with '_' to avoid uci r/w error
+    char tmp_string[PROPERTY_KEY_MAX];
+    int str_i = 0;
+    strncpy(tmp_string, key, PROPERTY_KEY_MAX - 1);
+    for (str_i = 0; str_i < PROPERTY_KEY_MAX; str_i++) {
+        if (tmp_string[str_i] == '.') {
+            tmp_string[str_i] = '_';
+        }
+    }
+
+
+    if (UCI_OK != uci_load(uciCtx, UCI_CONFIG_FILE, &pkg)) {
+        if (default_value) {
+            int len = strlen(default_value);
+            memcpy(value, default_value, len);
+            value[len] = '\0';
+            retValue = 1;
+        }
+        D("%s(), uci load fail, file: %s\n", __FUNCTION__, UCI_CONFIG_FILE);
+        goto cleanup;
+    }
+
+    uci_foreach_element(&pkg->sections, e) {
+        struct uci_section *s = uci_to_section(e);
+        if (NULL != (pValueData = uci_lookup_option_string(uciCtx, s, tmp_string))) {
+            if (!strncmp(pValueData, ":empty", strlen(":empty"))) {
+                value[0] = '\0';
+            } else {
+                strncpy(value, pValueData, strlen(pValueData));
+            }
+            retValue = 1;
+            D("property_get, %s: %s\n", key, value);
+        }
+    }
+    if (!retValue) {
+        if (default_value) {
+            int len = strlen(default_value);
+            memcpy(value, default_value, len);
+            value[len] = '\0';
+            retValue = 1;
+            D("property_get use default value, %s: %s\n", key, value);
+        }
+    }
+
+    uci_unload(uciCtx, pkg);
+
+cleanup:
+    uci_free_context(uciCtx);
+    uciCtx = NULL;
+    return retValue;
+}
+
+int property_set(const char *key, const char *new_value) {
+
+    if (NULL == key || NULL == new_value) {
+        return 0;
+    }
+    int retValue = 0;
+    int value = 0;
+    struct uci_context *_ctx = uci_alloc_context();
+    struct uci_ptr ptr;
+    struct uci_package *pkg = NULL;
+    memset(&ptr, 0, sizeof(ptr));
+
+    // replace '.' with '_' to avoid uci r/w error
+    char tmp_string[PROPERTY_KEY_MAX];
+    int str_i = 0;
+    strncpy(tmp_string, key, PROPERTY_KEY_MAX - 1);
+    for (str_i = 0; str_i < PROPERTY_KEY_MAX; str_i++) {
+        if (tmp_string[str_i] == '.') {
+            tmp_string[str_i] = '_';
+        }
+    }
+
+    ptr.package = "usb";
+    ptr.section = "adb";
+    ptr.option = tmp_string;
+    if (strlen(new_value) == 0) {
+        ptr.value = ":empty";
+    } else {
+        ptr.value = new_value;
+    }
+    value = uci_set(_ctx, &ptr);
+    if (value == 0) {
+        value = uci_commit(_ctx, &ptr.p, false);
+        if (value == 0) {
+            retValue = 1;
+            D("property_set ok. %s=%s return %d\n", key, new_value, value);
+        } else {
+            D("property_set uci_commit fail %s=%s return %d\n", key, new_value, value);
+        }
+    } else {
+        D("uci_set fail %s=%s return %d\n", key, new_value, value);
+    }
+    uci_unload(_ctx, ptr.p);
+    uci_free_context(_ctx);
+    _ctx = NULL;
+    return retValue;
+}
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
+                  void *cookie)
+{
+    return 0;
+}
+
+#endif
diff --git a/src/devtools/adb/protocol.txt b/src/devtools/adb/protocol.txt
new file mode 100755
index 0000000..c9d3c24
--- /dev/null
+++ b/src/devtools/adb/protocol.txt
@@ -0,0 +1,271 @@
+
+--- a replacement for aproto -------------------------------------------
+
+When it comes down to it, aproto's primary purpose is to forward
+various streams between the host computer and client device (in either
+direction).
+
+This replacement further simplifies the concept, reducing the protocol
+to an extremely straightforward model optimized to accomplish the
+forwarding of these streams and removing additional state or
+complexity.
+
+The host side becomes a simple comms bridge with no "UI", which will 
+be used by either commandline or interactive tools to communicate with 
+a device or emulator that is connected to the bridge.
+
+The protocol is designed to be straightforward and well-defined enough 
+that if it needs to be reimplemented in another environment (Java 
+perhaps), there should not problems ensuring perfect interoperability.
+
+The protocol discards the layering aproto has and should allow the 
+implementation to be much more robust.
+
+
+--- protocol overview and basics ---------------------------------------
+
+The transport layer deals in "messages", which consist of a 24 byte
+header followed (optionally) by a payload.  The header consists of 6
+32 bit words which are sent across the wire in little endian format.
+
+struct message {
+    unsigned command;       /* command identifier constant      */
+    unsigned arg0;          /* first argument                   */
+    unsigned arg1;          /* second argument                  */
+    unsigned data_length;   /* length of payload (0 is allowed) */
+    unsigned data_crc32;    /* crc32 of data payload            */
+    unsigned magic;         /* command ^ 0xffffffff             */
+};
+
+Receipt of an invalid message header, corrupt message payload, or an
+unrecognized command MUST result in the closing of the remote
+connection.  The protocol depends on shared state and any break in the
+message stream will result in state getting out of sync.
+
+The following sections describe the six defined message types in
+detail.  Their format is COMMAND(arg0, arg1, payload) where the payload
+is represented by a quoted string or an empty string if none should be
+sent.
+
+The identifiers "local-id" and "remote-id" are always relative to the
+*sender* of the message, so for a receiver, the meanings are effectively
+reversed.
+
+
+
+--- CONNECT(version, maxdata, "system-identity-string") ----------------
+
+The CONNECT message establishes the presence of a remote system.
+The version is used to ensure protocol compatibility and maxdata
+declares the maximum message body size that the remote system
+is willing to accept.
+
+Currently, version=0x01000000 and maxdata=4096
+
+Both sides send a CONNECT message when the connection between them is
+established.  Until a CONNECT message is received no other messages may
+be sent.  Any messages received before a CONNECT message MUST be ignored.
+
+If a CONNECT message is received with an unknown version or insufficiently
+large maxdata value, the connection with the other side must be closed.
+
+The system identity string should be "<systemtype>:<serialno>:<banner>"
+where systemtype is "bootloader", "device", or "host", serialno is some
+kind of unique ID (or empty), and banner is a human-readable version
+or identifier string.  The banner is used to transmit useful properties.
+
+
+--- AUTH(type, 0, "data") ----------------------------------------------
+
+The AUTH message informs the recipient that authentication is required to
+connect to the sender. If type is TOKEN(1), data is a random token that
+the recipient can sign with a private key. The recipient replies with an
+AUTH packet where type is SIGNATURE(2) and data is the signature. If the
+signature verification succeeds, the sender replies with a CONNECT packet.
+
+If the signature verification fails, the sender replies with a new AUTH
+packet and a new random token, so that the recipient can retry signing
+with a different private key.
+
+Once the recipient has tried all its private keys, it can reply with an
+AUTH packet where type is RSAPUBLICKEY(3) and data is the public key. If
+possible, an on-screen confirmation may be displayed for the user to
+confirm they want to install the public key on the device.
+
+
+--- OPEN(local-id, 0, "destination") -----------------------------------
+
+The OPEN message informs the recipient that the sender has a stream
+identified by local-id that it wishes to connect to the named
+destination in the message payload.  The local-id may not be zero.
+
+The OPEN message MUST result in either a READY message indicating that
+the connection has been established (and identifying the other end) or
+a CLOSE message, indicating failure.  An OPEN message also implies
+a READY message sent at the same time.
+
+Common destination naming conventions include:
+
+* "tcp:<host>:<port>" - host may be omitted to indicate localhost
+* "udp:<host>:<port>" - host may be omitted to indicate localhost
+* "local-dgram:<identifier>"
+* "local-stream:<identifier>"
+* "shell" - local shell service
+* "upload" - service for pushing files across (like aproto's /sync)
+* "fs-bridge" - FUSE protocol filesystem bridge
+
+
+--- READY(local-id, remote-id, "") -------------------------------------
+
+The READY message informs the recipient that the sender's stream
+identified by local-id is ready for write messages and that it is
+connected to the recipient's stream identified by remote-id.
+
+Neither the local-id nor the remote-id may be zero. 
+
+A READY message containing a remote-id which does not map to an open
+stream on the recipient's side is ignored.  The stream may have been
+closed while this message was in-flight.
+
+The local-id is ignored on all but the first READY message (where it
+is used to establish the connection).  Nonetheless, the local-id MUST
+not change on later READY messages sent to the same stream.
+
+
+
+--- WRITE(0, remote-id, "data") ----------------------------------------
+
+The WRITE message sends data to the recipient's stream identified by
+remote-id.  The payload MUST be <= maxdata in length.
+
+A WRITE message containing a remote-id which does not map to an open
+stream on the recipient's side is ignored.  The stream may have been
+closed while this message was in-flight.
+
+A WRITE message may not be sent until a READY message is received.
+Once a WRITE message is sent, an additional WRITE message may not be
+sent until another READY message has been received.  Recipients of
+a WRITE message that is in violation of this requirement will CLOSE
+the connection.
+
+
+--- CLOSE(local-id, remote-id, "") -------------------------------------
+
+The CLOSE message informs recipient that the connection between the
+sender's stream (local-id) and the recipient's stream (remote-id) is
+broken.  The remote-id MUST not be zero, but the local-id MAY be zero
+if this CLOSE indicates a failed OPEN.
+
+A CLOSE message containing a remote-id which does not map to an open
+stream on the recipient's side is ignored.  The stream may have
+already been closed by the recipient while this message was in-flight.
+
+The recipient should not respond to a CLOSE message in any way.  The
+recipient should cancel pending WRITEs or CLOSEs, but this is not a
+requirement, since they will be ignored.
+
+
+--- SYNC(online, sequence, "") -----------------------------------------
+
+The SYNC message is used by the io pump to make sure that stale
+outbound messages are discarded when the connection to the remote side
+is broken.  It is only used internally to the bridge and never valid
+to send across the wire.  
+
+* when the connection to the remote side goes offline, the io pump 
+  sends a SYNC(0, 0) and starts discarding all messages
+* when the connection to the remote side is established, the io pump
+  sends a SYNC(1, token) and continues to discard messages
+* when the io pump receives a matching SYNC(1, token), it once again
+  starts accepting messages to forward to the remote side
+
+
+--- message command constants ------------------------------------------
+
+#define A_SYNC 0x434e5953
+#define A_CNXN 0x4e584e43
+#define A_AUTH 0x48545541
+#define A_OPEN 0x4e45504f
+#define A_OKAY 0x59414b4f
+#define A_CLSE 0x45534c43
+#define A_WRTE 0x45545257
+
+
+
+--- implementation details ---------------------------------------------
+
+The core of the bridge program will use three threads.  One thread
+will be a select/epoll loop to handle io between various inbound and
+outbound connections and the connection to the remote side.
+
+The remote side connection will be implemented as two threads (one for
+reading, one for writing) and a datagram socketpair to provide the
+channel between the main select/epoll thread and the remote connection
+threadpair.  The reason for this is that for usb connections, the
+kernel interface on linux and osx does not allow you to do meaningful
+nonblocking IO.
+
+The endian swapping for the message headers will happen (as needed) in
+the remote connection threadpair and that the rest of the program will
+always treat message header values as native-endian.
+
+The bridge program will be able to have a number of mini-servers
+compiled in.  They will be published under known names (examples
+"shell", "fs-bridge", etc) and upon receiving an OPEN() to such a
+service, the bridge program will create a stream socketpair and spawn
+a thread or subprocess to handle the io.
+
+
+--- simplified / embedded implementation -------------------------------
+
+For limited environments, like the bootloader, it is allowable to
+support a smaller, fixed number of channels using pre-assigned channel
+ID numbers such that only one stream may be connected to a bootloader
+endpoint at any given time.  The protocol remains unchanged, but the
+"embedded" version of it is less dynamic.
+
+The bootloader will support two streams.  A "bootloader:debug" stream,
+which may be opened to get debug messages from the bootloader and a 
+"bootloader:control", stream which will support the set of basic 
+bootloader commands.
+
+Example command stream dialogues:  
+  "flash_kernel,2515049,........\n" "okay\n" 
+  "flash_ramdisk,5038,........\n" "fail,flash write error\n" 
+  "bogus_command......" <CLOSE>
+
+
+--- future expansion ---------------------------------------------------
+
+I plan on providing either a message or a special control stream so that
+the client device could ask the host computer to setup inbound socket
+translations on the fly on behalf of the client device.
+
+
+The initial design does handshaking to provide flow control, with a
+message flow that looks like:
+
+  >OPEN <READY >WRITE <READY >WRITE <READY >WRITE <CLOSE
+
+The far side may choose to issue the READY message as soon as it receives
+a WRITE or it may defer the READY until the write to the local stream
+succeeds.  A future version may want to do some level of windowing where
+multiple WRITEs may be sent without requiring individual READY acks.
+
+------------------------------------------------------------------------
+
+--- smartsockets -------------------------------------------------------
+
+Port 5037 is used for smart sockets which allow a client on the host
+side to request access to a service in the host adb daemon or in the
+remote (device) daemon.  The service is requested by ascii name,
+preceeded by a 4 digit hex length.  Upon successful connection an
+"OKAY" response is sent, otherwise a "FAIL" message is returned.  Once
+connected the client is talking to that (remote or local) service.
+
+client: <hex4> <service-name>
+server: "OKAY"
+
+client: <hex4> <service-name>
+server: "FAIL" <hex4> <reason>
+
diff --git a/src/devtools/adb/remount_service.c b/src/devtools/adb/remount_service.c
new file mode 100755
index 0000000..72d15a1
--- /dev/null
+++ b/src/devtools/adb/remount_service.c
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+#include "sysdeps.h"
+
+#define  TRACE_TAG  TRACE_ADB
+#include "adb.h"
+
+
+static int system_ro = 1;
+static int vendor_ro = 1;
+
+/* Returns the device used to mount a directory in /proc/mounts */
+static char *find_mount(const char *dir)
+{
+    int fd;
+    int res;
+    char *token = NULL;
+    const char delims[] = "\n";
+    char buf[4096];
+
+    fd = unix_open("/proc/mounts", O_RDONLY | O_CLOEXEC);
+    if (fd < 0)
+        return NULL;
+
+    buf[sizeof(buf) - 1] = '\0';
+    adb_read(fd, buf, sizeof(buf) - 1);
+    adb_close(fd);
+
+    token = strtok(buf, delims);
+
+    while (token) {
+        char mount_dev[256];
+        char mount_dir[256];
+        int mount_freq;
+        int mount_passno;
+
+        res = sscanf(token, "%255s %255s %*s %*s %d %d\n",
+                     mount_dev, mount_dir, &mount_freq, &mount_passno);
+        mount_dev[255] = 0;
+        mount_dir[255] = 0;
+        if (res == 4 && (strcmp(dir, mount_dir) == 0))
+            return strdup(mount_dev);
+
+        token = strtok(NULL, delims);
+    }
+    return NULL;
+}
+
+static int hasVendorPartition()
+{
+    struct stat info;
+    if (!lstat("/vendor", &info))
+        if ((info.st_mode & S_IFMT) == S_IFDIR)
+          return true;
+    return false;
+}
+
+/* Init mounts /system as read only, remount to enable writes. */
+static int remount(const char* dir, int* dir_ro)
+{
+    char *dev;
+    int fd;
+    int OFF = 0;
+
+    if (dir_ro == 0) {
+        return 0;
+    }
+
+    dev = find_mount(dir);
+
+    if (!dev)
+        return -1;
+
+    fd = unix_open(dev, O_RDONLY | O_CLOEXEC);
+    if (fd < 0)
+        return -1;
+
+    ioctl(fd, BLKROSET, &OFF);
+    adb_close(fd);
+
+    *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL);
+
+    free(dev);
+
+    return *dir_ro;
+}
+
+static void write_string(int fd, const char* str)
+{
+    writex(fd, str, strlen(str));
+}
+
+void remount_service(int fd, void *cookie)
+{
+    char buffer[200];
+    if (remount("/system", &system_ro)) {
+        snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno));
+        write_string(fd, buffer);
+    }
+
+    if (hasVendorPartition()) {
+        if (remount("/vendor", &vendor_ro)) {
+            snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno));
+            write_string(fd, buffer);
+        }
+    }
+
+    if (!system_ro && (!vendor_ro || !hasVendorPartition()))
+        write_string(fd, "remount succeeded\n");
+    else {
+        write_string(fd, "remount failed\n");
+    }
+
+    adb_close(fd);
+}
+
diff --git a/src/devtools/adb/rsa.c b/src/devtools/adb/rsa.c
new file mode 100755
index 0000000..171c437
--- /dev/null
+++ b/src/devtools/adb/rsa.c
@@ -0,0 +1,310 @@
+/* rsa.c
+**
+** Copyright 2012, The Android Open Source Project
+**
+** 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 Google Inc. 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 Google Inc. ``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 Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
+
+// a[] -= mod
+static void subM(const RSAPublicKey* key,
+                 uint32_t* a) {
+    int64_t A = 0;
+    int i;
+    for (i = 0; i < key->len; ++i) {
+        A += (uint64_t)a[i] - key->n[i];
+        a[i] = (uint32_t)A;
+        A >>= 32;
+    }
+}
+
+// return a[] >= mod
+static int geM(const RSAPublicKey* key,
+               const uint32_t* a) {
+    int i;
+    for (i = key->len; i;) {
+        --i;
+        if (a[i] < key->n[i]) return 0;
+        if (a[i] > key->n[i]) return 1;
+    }
+    return 1;  // equal
+}
+
+// montgomery c[] += a * b[] / R % mod
+static void montMulAdd(const RSAPublicKey* key,
+                       uint32_t* c,
+                       const uint32_t a,
+                       const uint32_t* b) {
+    uint64_t A = (uint64_t)a * b[0] + c[0];
+    uint32_t d0 = (uint32_t)A * key->n0inv;
+    uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
+    int i;
+
+    for (i = 1; i < key->len; ++i) {
+        A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+        B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
+        c[i - 1] = (uint32_t)B;
+    }
+
+    A = (A >> 32) + (B >> 32);
+
+    c[i - 1] = (uint32_t)A;
+
+    if (A >> 32) {
+        subM(key, c);
+    }
+}
+
+// montgomery c[] = a[] * b[] / R % mod
+static void montMul(const RSAPublicKey* key,
+                    uint32_t* c,
+                    const uint32_t* a,
+                    const uint32_t* b) {
+    int i;
+    for (i = 0; i < key->len; ++i) {
+        c[i] = 0;
+    }
+    for (i = 0; i < key->len; ++i) {
+        montMulAdd(key, c, a[i], b);
+    }
+}
+
+// In-place public exponentiation.
+// Input and output big-endian byte array in inout.
+static void modpow(const RSAPublicKey* key,
+                   uint8_t* inout) {
+    uint32_t a[RSANUMWORDS];
+    uint32_t aR[RSANUMWORDS];
+    uint32_t aaR[RSANUMWORDS];
+    uint32_t* aaa = 0;
+    int i;
+
+    // Convert from big endian byte array to little endian word array.
+    for (i = 0; i < key->len; ++i) {
+        uint32_t tmp =
+            (inout[((key->len - 1 - i) * 4) + 0] << 24) |
+            (inout[((key->len - 1 - i) * 4) + 1] << 16) |
+            (inout[((key->len - 1 - i) * 4) + 2] << 8) |
+            (inout[((key->len - 1 - i) * 4) + 3] << 0);
+        a[i] = tmp;
+    }
+
+    if (key->exponent == 65537) {
+        aaa = aaR;  // Re-use location.
+        montMul(key, aR, a, key->rr);  // aR = a * RR / R mod M
+        for (i = 0; i < 16; i += 2) {
+            montMul(key, aaR, aR, aR);  // aaR = aR * aR / R mod M
+            montMul(key, aR, aaR, aaR);  // aR = aaR * aaR / R mod M
+        }
+        montMul(key, aaa, aR, a);  // aaa = aR * a / R mod M
+    } else if (key->exponent == 3) {
+        aaa = aR;  // Re-use location.
+        montMul(key, aR, a, key->rr);  /* aR = a * RR / R mod M   */
+        montMul(key, aaR, aR, aR);     /* aaR = aR * aR / R mod M */
+        montMul(key, aaa, aaR, a);     /* aaa = aaR * a / R mod M */
+    } else {
+        return; // avoid NULL aaa caused exceptions
+    }
+
+    // Make sure aaa < mod; aaa is at most 1x mod too large.
+    if (geM(key, aaa)) {
+        subM(key, aaa);
+    }
+
+    // Convert to bigendian byte array
+    for (i = key->len - 1; i >= 0; --i) {
+        uint32_t tmp = aaa[i];
+        *inout++ = tmp >> 24;
+        *inout++ = tmp >> 16;
+        *inout++ = tmp >> 8;
+        *inout++ = tmp >> 0;
+    }
+}
+
+// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
+// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
+// other flavor which omits the optional parameter entirely). This code does not
+// accept signatures without the optional parameter.
+
+/*
+static const uint8_t sha_padding[RSANUMBYTES] = {
+    0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30,
+    0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
+    0x05, 0x00, 0x04, 0x14,
+
+    // 20 bytes of hash go here.
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+*/
+
+// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above.
+// At the location of the bytes of the hash all 00 are hashed.
+static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
+    0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e,
+    0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68,
+    0x7c, 0xfb, 0xf1, 0x67
+};
+
+/*
+static const uint8_t sha256_padding[RSANUMBYTES] = {
+    0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30,
+    0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
+    0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
+
+    // 32 bytes of hash go here.
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+*/
+
+// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above.
+// At the location of the bytes of the hash all 00 are hashed.
+static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = {
+    0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92,
+    0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e,
+    0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd,
+    0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59,
+};
+
+// Verify a 2048-bit RSA PKCS1.5 signature against an expected hash.
+// Both e=3 and e=65537 are supported.  hash_len may be
+// SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or
+// SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash.  No other
+// values are supported.
+//
+// Returns 1 on successful verification, 0 on failure.
+int RSA_verify(const RSAPublicKey *key,
+               const uint8_t *signature,
+               const int len,
+               const uint8_t *hash,
+               const int hash_len) {
+    uint8_t buf[RSANUMBYTES];
+    int i;
+    const uint8_t* padding_hash;
+
+    if (key->len != RSANUMWORDS) {
+        return 0;  // Wrong key passed in.
+    }
+
+    if (len != sizeof(buf)) {
+        return 0;  // Wrong input length.
+    }
+
+    if (hash_len != SHA_DIGEST_SIZE &&
+        hash_len != SHA256_DIGEST_SIZE) {
+        return 0;  // Unsupported hash.
+    }
+
+    if (key->exponent != 3 && key->exponent != 65537) {
+        return 0;  // Unsupported exponent.
+    }
+
+    for (i = 0; i < len; ++i) {  // Copy input to local workspace.
+        buf[i] = signature[i];
+    }
+
+    modpow(key, buf);  // In-place exponentiation.
+
+    // Xor sha portion, so it all becomes 00 iff equal.
+    for (i = len - hash_len; i < len; ++i) {
+        buf[i] ^= *hash++;
+    }
+
+    // Hash resulting buf, in-place.
+    switch (hash_len) {
+        case SHA_DIGEST_SIZE:
+            padding_hash = kExpectedPadShaRsa2048;
+            SHA_hash(buf, len, buf);
+            break;
+        case SHA256_DIGEST_SIZE:
+            padding_hash = kExpectedPadSha256Rsa2048;
+            SHA256_hash(buf, len, buf);
+            break;
+        default:
+            return 0;
+    }
+
+    // Compare against expected hash value.
+    for (i = 0; i < hash_len; ++i) {
+        if (buf[i] != padding_hash[i]) {
+            return 0;
+        }
+    }
+
+    return 1;  // All checked out OK.
+}
diff --git a/src/devtools/adb/services.c b/src/devtools/adb/services.c
new file mode 100755
index 0000000..1360782
--- /dev/null
+++ b/src/devtools/adb/services.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/reboot.h>
+#include <sys/syscall.h>
+
+#include "sysdeps.h"
+
+#define  TRACE_TAG  TRACE_SERVICES
+#include "adb.h"
+#include "file_sync_service.h"
+
+#if ADB_HOST
+#  ifndef HAVE_WINSOCK
+#    include <netinet/in.h>
+#    include <netdb.h>
+#    include <sys/ioctl.h>
+#  endif
+#else
+#  include <cutils/android_reboot.h>
+#  include <cutils/properties.h>
+#endif
+
+typedef struct stinfo stinfo;
+
+struct stinfo {
+    void (*func)(int fd, void *cookie);
+    int fd;
+    void *cookie;
+};
+
+
+void *service_bootstrap_func(void *x)
+{
+    stinfo *sti = x;
+    sti->func(sti->fd, sti->cookie);
+    free(sti);
+    return 0;
+}
+
+#if !ADB_HOST
+
+void restart_root_service(int fd, void *cookie)
+{
+    char buf[100];
+
+    if (getuid() == 0) {
+        snprintf(buf, sizeof(buf), "adbd is already running as root\n");
+        writex(fd, buf, strlen(buf));
+        adb_close(fd);
+    } else {
+#ifndef ADB_NON_ANDROID
+        char value[PROPERTY_VALUE_MAX];
+        property_get("ro.debuggable", value, "");
+        if (strcmp(value, "1") != 0) {
+            snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
+            writex(fd, buf, strlen(buf));
+            adb_close(fd);
+            return;
+        }
+#endif /* !ADB_NON_ANDROID */
+
+        property_set("service.adb.root", "1");
+        snprintf(buf, sizeof(buf), "restarting adbd as root\n");
+        writex(fd, buf, strlen(buf));
+        adb_close(fd);
+    }
+}
+
+void restart_tcp_service(int fd, void *cookie)
+{
+    char buf[100];
+    char value[PROPERTY_VALUE_MAX];
+    int port = (int) (uintptr_t) cookie;
+
+    if (port <= 0) {
+        snprintf(buf, sizeof(buf), "invalid port\n");
+        writex(fd, buf, strlen(buf));
+        adb_close(fd);
+        return;
+    }
+
+    snprintf(value, sizeof(value), "%d", port);
+    property_set("service.adb.tcp.port", value);
+    snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
+    writex(fd, buf, strlen(buf));
+    adb_close(fd);
+}
+
+void restart_usb_service(int fd, void *cookie)
+{
+    char buf[100];
+
+    property_set("service.adb.tcp.port", "0");
+    snprintf(buf, sizeof(buf), "restarting in USB mode\n");
+    writex(fd, buf, strlen(buf));
+    adb_close(fd);
+}
+
+void restart_adbd_service(int fd, void *cookie)
+{
+    char buf[100];
+
+    snprintf(buf, sizeof(buf), "restarting service\n");
+    writex(fd, buf, strlen(buf));
+    adb_close(fd);
+}
+
+void reboot_service(int fd, void *arg)
+{
+    char buf[100];
+    char property_val[PROPERTY_VALUE_MAX];
+    int ret;
+    const char *param = (const char *)arg;
+    int cmd;
+
+     sync();
+
+    if (!param || strlen(param) == 0)
+        cmd = LINUX_REBOOT_CMD_RESTART;
+    else
+        cmd = LINUX_REBOOT_CMD_RESTART2;
+    syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, param);
+
+#if 0
+    ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg);
+    if (ret >= (int) sizeof(property_val)) {
+        snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
+        writex(fd, buf, strlen(buf));
+        goto cleanup;
+    }
+
+    ret = property_set(ANDROID_RB_PROPERTY, property_val);
+    if (ret < 0) {
+        snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret);
+        writex(fd, buf, strlen(buf));
+        goto cleanup;
+    }
+    // Don't return early. Give the reboot command time to take effect
+    // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
+    while(1) { pause(); }
+#endif
+cleanup:
+    free(arg);
+    adb_close(fd);
+}
+
+void reverse_service(int fd, void* arg)
+{
+    const char* command = arg;
+
+    if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
+        sendfailmsg(fd, "not a reverse forwarding command");
+    }
+    free(arg);
+    adb_close(fd);
+}
+
+#endif
+
+static int create_service_thread(void (*func)(int, void *), void *cookie)
+{
+    stinfo *sti;
+    adb_thread_t t;
+    int s[2];
+
+    if(adb_socketpair(s)) {
+        printf("cannot create service socket pair\n");
+        return -1;
+    }
+
+    sti = malloc(sizeof(stinfo));
+    if(sti == 0) fatal("cannot allocate stinfo");
+    sti->func = func;
+    sti->cookie = cookie;
+    sti->fd = s[1];
+
+    if(adb_thread_create( &t, service_bootstrap_func, sti)){
+        free(sti);
+        adb_close(s[0]);
+        adb_close(s[1]);
+        printf("cannot create service thread\n");
+        return -1;
+    }
+
+    D("service thread started, %d:%d\n",s[0], s[1]);
+    return s[0];
+}
+
+#if !ADB_HOST
+
+static void init_subproc_child()
+{
+    setsid();
+
+    // Set OOM score adjustment to prevent killing
+    int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
+    if (fd >= 0) {
+        adb_write(fd, "0", 1);
+        adb_close(fd);
+    } else {
+       D("adb: unable to update oom_score_adj\n");
+    }
+}
+
+static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+    D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
+#if defined(_WIN32)
+    fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    return -1;
+#else
+    int ptm;
+
+    ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY);
+    if(ptm < 0){
+        printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
+        return -1;
+    }
+
+    char devname[64];
+    if(grantpt(ptm) || unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname)) != 0) {
+        printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
+        adb_close(ptm);
+        return -1;
+    }
+
+    *pid = fork();
+    if(*pid < 0) {
+        printf("- fork failed: %s -\n", strerror(errno));
+        adb_close(ptm);
+        return -1;
+    }
+
+    if (*pid == 0) {
+        init_subproc_child();
+
+        int pts = unix_open(devname, O_RDWR | O_CLOEXEC);
+        if (pts < 0) {
+            fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
+            exit(-1);
+        }
+
+        dup2(pts, STDIN_FILENO);
+        dup2(pts, STDOUT_FILENO);
+        dup2(pts, STDERR_FILENO);
+
+        adb_close(pts);
+        adb_close(ptm);
+
+        execl(cmd, cmd, arg0, arg1, NULL);
+        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
+                cmd, strerror(errno), errno);
+        exit(-1);
+    } else {
+        return ptm;
+    }
+#endif /* !defined(_WIN32) */
+}
+
+static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+    D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
+#if defined(_WIN32)
+    fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    return -1;
+#else
+
+    // 0 is parent socket, 1 is child socket
+    int sv[2];
+    if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
+        printf("[ cannot create socket pair - %s ]\n", strerror(errno));
+        return -1;
+    }
+
+    *pid = fork();
+    if (*pid < 0) {
+        printf("- fork failed: %s -\n", strerror(errno));
+        adb_close(sv[0]);
+        adb_close(sv[1]);
+        return -1;
+    }
+
+    if (*pid == 0) {
+        adb_close(sv[0]);
+        init_subproc_child();
+
+        dup2(sv[1], STDIN_FILENO);
+        dup2(sv[1], STDOUT_FILENO);
+        dup2(sv[1], STDERR_FILENO);
+
+        adb_close(sv[1]);
+
+        execl(cmd, cmd, arg0, arg1, NULL);
+        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
+                cmd, strerror(errno), errno);
+        exit(-1);
+    } else {
+        adb_close(sv[1]);
+        return sv[0];
+    }
+#endif /* !defined(_WIN32) */
+}
+#endif  /* !ABD_HOST */
+
+#if ADB_HOST || ADB_NON_ANDROID
+#define SHELL_COMMAND "/bin/sh"
+#else
+#define SHELL_COMMAND "/system/bin/sh"
+#endif
+
+#if !ADB_HOST
+static void subproc_waiter_service(int fd, void *cookie)
+{
+    pid_t pid = (pid_t) (uintptr_t) cookie;
+
+    D("entered. fd=%d of pid=%d\n", fd, pid);
+    for (;;) {
+        int status;
+        pid_t p = waitpid(pid, &status, 0);
+        if (p == pid) {
+            D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
+            if (WIFSIGNALED(status)) {
+                D("*** Killed by signal %d\n", WTERMSIG(status));
+                break;
+            } else if (!WIFEXITED(status)) {
+                D("*** Didn't exit!!. status %d\n", status);
+                break;
+            } else if (WEXITSTATUS(status) >= 0) {
+                D("*** Exit code %d\n", WEXITSTATUS(status));
+                break;
+            }
+         }
+    }
+    D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
+    if (SHELL_EXIT_NOTIFY_FD >=0) {
+      int res;
+      res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
+      D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
+        SHELL_EXIT_NOTIFY_FD, pid, res, errno);
+    }
+}
+
+static int create_subproc_thread(const char *name, const subproc_mode mode)
+{
+    stinfo *sti;
+    adb_thread_t t;
+    int ret_fd;
+    pid_t pid = -1;
+
+    const char *arg0, *arg1;
+    if (name == 0 || *name == 0) {
+        arg0 = "-"; arg1 = 0;
+    } else {
+        arg0 = "-c"; arg1 = name;
+    }
+
+    switch (mode) {
+    case SUBPROC_PTY:
+        ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);
+        break;
+    case SUBPROC_RAW:
+        ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
+        break;
+    default:
+        fprintf(stderr, "invalid subproc_mode %d\n", mode);
+        return -1;
+    }
+    D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
+
+    sti = malloc(sizeof(stinfo));
+    if(sti == 0) fatal("cannot allocate stinfo");
+    sti->func = subproc_waiter_service;
+    sti->cookie = (void*) (uintptr_t) pid;
+    sti->fd = ret_fd;
+
+    if (adb_thread_create(&t, service_bootstrap_func, sti)) {
+        free(sti);
+        adb_close(ret_fd);
+        fprintf(stderr, "cannot create service thread\n");
+        return -1;
+    }
+
+    D("service thread started, fd=%d pid=%d\n", ret_fd, pid);
+    return ret_fd;
+}
+#endif
+
+int service_to_fd(const char *name)
+{
+    int ret = -1;
+
+    if(!strncmp(name, "tcp:", 4)) {
+        int port = atoi(name + 4);
+        name = strchr(name + 4, ':');
+        if(name == 0) {
+            ret = socket_loopback_client(port, SOCK_STREAM);
+            if (ret >= 0)
+                disable_tcp_nagle(ret);
+        } else {
+#if ADB_HOST
+            ret = socket_network_client(name + 1, port, SOCK_STREAM);
+#else
+            return -1;
+#endif
+        }
+#ifndef HAVE_WINSOCK   /* winsock doesn't implement unix domain sockets */
+    } else if(!strncmp(name, "local:", 6)) {
+        ret = socket_local_client(name + 6,
+                ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+    } else if(!strncmp(name, "localreserved:", 14)) {
+        ret = socket_local_client(name + 14,
+                ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+    } else if(!strncmp(name, "localabstract:", 14)) {
+        ret = socket_local_client(name + 14,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+    } else if(!strncmp(name, "localfilesystem:", 16)) {
+        ret = socket_local_client(name + 16,
+                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
+#endif
+#if !ADB_HOST
+    } else if(!strncmp("dev:", name, 4)) {
+        ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
+    } else if(!strncmp(name, "framebuffer:", 12)) {
+        ret = create_service_thread(framebuffer_service, 0);
+    } else if (!strncmp(name, "jdwp:", 5)) {
+        ret = create_jdwp_connection_fd(atoi(name+5));
+    } else if(!HOST && !strncmp(name, "shell:", 6)) {
+        ret = create_subproc_thread(name + 6, SUBPROC_PTY);
+    } else if(!HOST && !strncmp(name, "exec:", 5)) {
+        ret = create_subproc_thread(name + 5, SUBPROC_RAW);
+    } else if(!strncmp(name, "sync:", 5)) {
+        ret = create_service_thread(file_sync_service, NULL);
+    } else if(!strncmp(name, "remount:", 8)) {
+        ret = create_service_thread(remount_service, NULL);
+    } else if(!strncmp(name, "reboot:", 7)) {
+        void* arg = strdup(name + 7);
+        if (arg == NULL) return -1;
+        ret = create_service_thread(reboot_service, arg);
+    } else if(!strncmp(name, "root:", 5)) {
+        ret = create_service_thread(restart_root_service, NULL);
+    } else if(!strncmp(name, "backup:", 7)) {
+        char* arg = strdup(name + 7);
+        if (arg == NULL) return -1;
+        char* c = arg;
+        for (; *c != '\0'; c++) {
+            if (*c == ':')
+                *c = ' ';
+        }
+        char* cmd;
+        if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) {
+            ret = create_subproc_thread(cmd, SUBPROC_RAW);
+            free(cmd);
+        }
+        free(arg);
+    } else if(!strncmp(name, "restore:", 8)) {
+        ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
+    } else if(!strncmp(name, "tcpip:", 6)) {
+        int port;
+        if (sscanf(name + 6, "%d", &port) == 0) {
+            port = 0;
+        }
+        ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port);
+    } else if(!strncmp(name, "usb:", 4)) {
+        ret = create_service_thread(restart_usb_service, NULL);
+    } else if(!strncmp(name, "reconnect:", 10)) {
+        ret = create_service_thread(restart_adbd_service, NULL);
+    } else if (!strncmp(name, "reverse:", 8)) {
+        char* cookie = strdup(name + 8);
+        if (cookie == NULL) {
+            ret = -1;
+        } else {
+            ret = create_service_thread(reverse_service, cookie);
+            if (ret < 0) {
+                free(cookie);
+            }
+        }
+#endif
+    }
+    if (ret >= 0) {
+        close_on_exec(ret);
+    }
+    return ret;
+}
+
+#if ADB_HOST
+struct state_info {
+    transport_type transport;
+    char* serial;
+    int state;
+};
+
+static void wait_for_state(int fd, void* cookie)
+{
+    struct state_info* sinfo = cookie;
+    char* err = "unknown error";
+
+    D("wait_for_state %d\n", sinfo->state);
+
+    atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
+    if(t != 0) {
+        writex(fd, "OKAY", 4);
+    } else {
+        sendfailmsg(fd, err);
+    }
+
+    if (sinfo->serial)
+        free(sinfo->serial);
+    free(sinfo);
+    adb_close(fd);
+    D("wait_for_state is done\n");
+}
+
+static void connect_device(char* host, char* buffer, int buffer_size)
+{
+    int port, fd;
+    char* portstr = strchr(host, ':');
+    char hostbuf[100];
+    char serial[100];
+    int ret;
+
+    strncpy(hostbuf, host, sizeof(hostbuf) - 1);
+    if (portstr) {
+        if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
+            snprintf(buffer, buffer_size, "bad host name %s", host);
+            return;
+        }
+        // zero terminate the host at the point we found the colon
+        hostbuf[portstr - host] = 0;
+        if (sscanf(portstr + 1, "%d", &port) == 0) {
+            snprintf(buffer, buffer_size, "bad port number %s", portstr);
+            return;
+        }
+    } else {
+        port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+    }
+
+    snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
+
+    fd = socket_network_client_timeout(hostbuf, port, SOCK_STREAM, 10);
+    if (fd < 0) {
+        snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
+        return;
+    }
+
+    D("client: connected on remote on fd %d\n", fd);
+    close_on_exec(fd);
+    disable_tcp_nagle(fd);
+
+    ret = register_socket_transport(fd, serial, port, 0);
+    if (ret < 0) {
+        adb_close(fd);
+        snprintf(buffer, buffer_size, "already connected to %s", serial);
+    } else {
+        snprintf(buffer, buffer_size, "connected to %s", serial);
+    }
+}
+
+void connect_emulator(char* port_spec, char* buffer, int buffer_size)
+{
+    char* port_separator = strchr(port_spec, ',');
+    if (!port_separator) {
+        snprintf(buffer, buffer_size,
+                "unable to parse '%s' as <console port>,<adb port>",
+                port_spec);
+        return;
+    }
+
+    // Zero-terminate console port and make port_separator point to 2nd port.
+    *port_separator++ = 0;
+    int console_port = strtol(port_spec, NULL, 0);
+    int adb_port = strtol(port_separator, NULL, 0);
+    if (!(console_port > 0 && adb_port > 0)) {
+        *(port_separator - 1) = ',';
+        snprintf(buffer, buffer_size,
+                "Invalid port numbers: Expected positive numbers, got '%s'",
+                port_spec);
+        return;
+    }
+
+    /* Check if the emulator is already known.
+     * Note: There's a small but harmless race condition here: An emulator not
+     * present just yet could be registered by another invocation right
+     * after doing this check here. However, local_connect protects
+     * against double-registration too. From here, a better error message
+     * can be produced. In the case of the race condition, the very specific
+     * error message won't be shown, but the data doesn't get corrupted. */
+    atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
+    if (known_emulator != NULL) {
+        snprintf(buffer, buffer_size,
+                "Emulator on port %d already registered.", adb_port);
+        return;
+    }
+
+    /* Check if more emulators can be registered. Similar unproblematic
+     * race condition as above. */
+    int candidate_slot = get_available_local_transport_index();
+    if (candidate_slot < 0) {
+        snprintf(buffer, buffer_size, "Cannot accept more emulators.");
+        return;
+    }
+
+    /* Preconditions met, try to connect to the emulator. */
+    if (!local_connect_arbitrary_ports(console_port, adb_port)) {
+        snprintf(buffer, buffer_size,
+                "Connected to emulator on ports %d,%d", console_port, adb_port);
+    } else {
+        snprintf(buffer, buffer_size,
+                "Could not connect to emulator on ports %d,%d",
+                console_port, adb_port);
+    }
+}
+
+static void connect_service(int fd, void* cookie)
+{
+    char buf[4096];
+    char resp[4096];
+    char *host = cookie;
+
+    if (!strncmp(host, "emu:", 4)) {
+        connect_emulator(host + 4, buf, sizeof(buf));
+    } else {
+        connect_device(host, buf, sizeof(buf));
+    }
+
+    // Send response for emulator and device
+    snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf);
+    writex(fd, resp, strlen(resp));
+    adb_close(fd);
+}
+#endif
+
+#if ADB_HOST
+asocket*  host_service_to_socket(const char*  name, const char *serial)
+{
+    if (!strcmp(name,"track-devices")) {
+        return create_device_tracker();
+    } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
+        struct state_info* sinfo = malloc(sizeof(struct state_info));
+
+        if (serial)
+            sinfo->serial = strdup(serial);
+        else
+            sinfo->serial = NULL;
+
+        name += strlen("wait-for-");
+
+        if (!strncmp(name, "local", strlen("local"))) {
+            sinfo->transport = kTransportLocal;
+            sinfo->state = CS_DEVICE;
+        } else if (!strncmp(name, "usb", strlen("usb"))) {
+            sinfo->transport = kTransportUsb;
+            sinfo->state = CS_DEVICE;
+        } else if (!strncmp(name, "any", strlen("any"))) {
+            sinfo->transport = kTransportAny;
+            sinfo->state = CS_DEVICE;
+        } else {
+            free(sinfo);
+            return NULL;
+        }
+
+        int fd = create_service_thread(wait_for_state, sinfo);
+        return create_local_socket(fd);
+    } else if (!strncmp(name, "connect:", 8)) {
+        const char *host = name + 8;
+        int fd = create_service_thread(connect_service, (void *)host);
+        return create_local_socket(fd);
+    }
+    return NULL;
+}
+#endif /* ADB_HOST */
diff --git a/src/devtools/adb/sha.c b/src/devtools/adb/sha.c
new file mode 100755
index 0000000..5bef32e
--- /dev/null
+++ b/src/devtools/adb/sha.c
@@ -0,0 +1,155 @@
+/* sha.c
+**
+** Copyright 2013, The Android Open Source Project
+**
+** 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 Google Inc. 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 Google Inc. ``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 Google Inc. 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.
+*/
+
+// Optimized for minimal code size.
+
+#include "mincrypt/sha.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+static void SHA1_Transform(SHA_CTX* ctx) {
+    uint32_t W[80];
+    uint32_t A, B, C, D, E;
+    uint8_t* p = ctx->buf;
+    int t;
+
+    for(t = 0; t < 16; ++t) {
+        uint32_t tmp =  *p++ << 24;
+        tmp |= *p++ << 16;
+        tmp |= *p++ << 8;
+        tmp |= *p++;
+        W[t] = tmp;
+    }
+
+    for(; t < 80; t++) {
+        W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+    }
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+    for(t = 0; t < 80; t++) {
+        uint32_t tmp = rol(5,A) + E + W[t];
+
+        if (t < 20)
+            tmp += (D^(B&(C^D))) + 0x5A827999;
+        else if ( t < 40)
+            tmp += (B^C^D) + 0x6ED9EBA1;
+        else if ( t < 60)
+            tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
+        else
+            tmp += (B^C^D) + 0xCA62C1D6;
+
+        E = D;
+        D = C;
+        C = rol(30,B);
+        B = A;
+        A = tmp;
+    }
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+static const HASH_VTAB SHA_VTAB = {
+    SHA_init,
+    SHA_update,
+    SHA_final,
+    SHA_hash,
+    SHA_DIGEST_SIZE
+};
+
+void SHA_init(SHA_CTX* ctx) {
+    ctx->f = &SHA_VTAB;
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+    ctx->count = 0;
+}
+
+
+void SHA_update(SHA_CTX* ctx, const void* data, int len) {
+    int i = (int) (ctx->count & 63);
+    const uint8_t* p = (const uint8_t*)data;
+
+    ctx->count += len;
+
+    while (len--) {
+        ctx->buf[i++] = *p++;
+        if (i == 64) {
+            SHA1_Transform(ctx);
+            i = 0;
+        }
+    }
+}
+
+
+const uint8_t* SHA_final(SHA_CTX* ctx) {
+    uint8_t *p = ctx->buf;
+    uint64_t cnt = ctx->count * 8;
+    int i;
+
+    SHA_update(ctx, (uint8_t*)"\x80", 1);
+    while ((ctx->count & 63) != 56) {
+        SHA_update(ctx, (uint8_t*)"\0", 1);
+    }
+    for (i = 0; i < 8; ++i) {
+        uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
+        SHA_update(ctx, &tmp, 1);
+    }
+
+    for (i = 0; i < 5; i++) {
+        uint32_t tmp = ctx->state[i];
+        *p++ = tmp >> 24;
+        *p++ = tmp >> 16;
+        *p++ = tmp >> 8;
+        *p++ = tmp >> 0;
+    }
+
+    return ctx->buf;
+}
+
+/* Convenience function */
+const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) {
+    SHA_CTX ctx;
+    SHA_init(&ctx);
+    SHA_update(&ctx, data, len);
+    memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);
+    return digest;
+}
diff --git a/src/devtools/adb/sha256.c b/src/devtools/adb/sha256.c
new file mode 100755
index 0000000..eb6e308
--- /dev/null
+++ b/src/devtools/adb/sha256.c
@@ -0,0 +1,184 @@
+/* sha256.c
+**
+** Copyright 2013, The Android Open Source Project
+**
+** 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 Google Inc. 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 Google Inc. ``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 Google Inc. 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.
+*/
+
+// Optimized for minimal code size.
+
+#include "mincrypt/sha256.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
+#define shr(value, bits) ((value) >> (bits))
+
+static const uint32_t K[64] = {
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
+
+static void SHA256_Transform(SHA256_CTX* ctx) {
+    uint32_t W[64];
+    uint32_t A, B, C, D, E, F, G, H;
+    uint8_t* p = ctx->buf;
+    int t;
+
+    for(t = 0; t < 16; ++t) {
+        uint32_t tmp =  *p++ << 24;
+        tmp |= *p++ << 16;
+        tmp |= *p++ << 8;
+        tmp |= *p++;
+        W[t] = tmp;
+    }
+
+    for(; t < 64; t++) {
+        uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3);
+        uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10);
+        W[t] = W[t-16] + s0 + W[t-7] + s1;
+    }
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+    F = ctx->state[5];
+    G = ctx->state[6];
+    H = ctx->state[7];
+
+    for(t = 0; t < 64; t++) {
+        uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22);
+        uint32_t maj = (A & B) ^ (A & C) ^ (B & C);
+        uint32_t t2 = s0 + maj;
+        uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25);
+        uint32_t ch = (E & F) ^ ((~E) & G);
+        uint32_t t1 = H + s1 + ch + K[t] + W[t];
+
+        H = G;
+        G = F;
+        F = E;
+        E = D + t1;
+        D = C;
+        C = B;
+        B = A;
+        A = t1 + t2;
+    }
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+    ctx->state[5] += F;
+    ctx->state[6] += G;
+    ctx->state[7] += H;
+}
+
+static const HASH_VTAB SHA256_VTAB = {
+    SHA256_init,
+    SHA256_update,
+    SHA256_final,
+    SHA256_hash,
+    SHA256_DIGEST_SIZE
+};
+
+void SHA256_init(SHA256_CTX* ctx) {
+    ctx->f = &SHA256_VTAB;
+    ctx->state[0] = 0x6a09e667;
+    ctx->state[1] = 0xbb67ae85;
+    ctx->state[2] = 0x3c6ef372;
+    ctx->state[3] = 0xa54ff53a;
+    ctx->state[4] = 0x510e527f;
+    ctx->state[5] = 0x9b05688c;
+    ctx->state[6] = 0x1f83d9ab;
+    ctx->state[7] = 0x5be0cd19;
+    ctx->count = 0;
+}
+
+
+void SHA256_update(SHA256_CTX* ctx, const void* data, int len) {
+    int i = (int) (ctx->count & 63);
+    const uint8_t* p = (const uint8_t*)data;
+
+    ctx->count += len;
+
+    while (len--) {
+        ctx->buf[i++] = *p++;
+        if (i == 64) {
+            SHA256_Transform(ctx);
+            i = 0;
+        }
+    }
+}
+
+
+const uint8_t* SHA256_final(SHA256_CTX* ctx) {
+    uint8_t *p = ctx->buf;
+    uint64_t cnt = ctx->count * 8;
+    int i;
+
+    SHA256_update(ctx, (uint8_t*)"\x80", 1);
+    while ((ctx->count & 63) != 56) {
+        SHA256_update(ctx, (uint8_t*)"\0", 1);
+    }
+    for (i = 0; i < 8; ++i) {
+        uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
+        SHA256_update(ctx, &tmp, 1);
+    }
+
+    for (i = 0; i < 8; i++) {
+        uint32_t tmp = ctx->state[i];
+        *p++ = tmp >> 24;
+        *p++ = tmp >> 16;
+        *p++ = tmp >> 8;
+        *p++ = tmp >> 0;
+    }
+
+    return ctx->buf;
+}
+
+/* Convenience function */
+const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) {
+    SHA256_CTX ctx;
+    SHA256_init(&ctx);
+    SHA256_update(&ctx, data, len);
+    memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
+    return digest;
+}
diff --git a/src/devtools/adb/socket_inaddr_any_server.c b/src/devtools/adb/socket_inaddr_any_server.c
new file mode 100755
index 0000000..6c849de
--- /dev/null
+++ b/src/devtools/adb/socket_inaddr_any_server.c
@@ -0,0 +1,68 @@
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HAVE_WINSOCK
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#endif
+
+#include <cutils/sockets.h>
+
+#define LISTEN_BACKLOG 4
+
+/* open listen() port on any interface */
+int socket_inaddr_any_server(int port, int type)
+{
+    struct sockaddr_in addr;
+    int s, n;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+    s = socket(AF_INET, type, 0);
+    if(s < 0) return -1;
+
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+
+        if (ret < 0) {
+            close(s);
+            return -1; 
+        }
+    }
+
+    return s;
+}
diff --git a/src/devtools/adb/socket_local.h b/src/devtools/adb/socket_local.h
new file mode 100755
index 0000000..45b9856
--- /dev/null
+++ b/src/devtools/adb/socket_local.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SOCKET_LOCAL_H
+#define __SOCKET_LOCAL_H
+
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/" 
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+
+/*
+ * Set up a given sockaddr_un, to have it refer to the given
+ * name in the given namespace. The namespace must be one
+ * of <code>ANDROID_SOCKET_NAMESPACE_ABSTRACT</code>,
+ * <code>ANDROID_SOCKET_NAMESPACE_RESERVED</code>, or
+ * <code>ANDROID_SOCKET_NAMESPACE_FILESYSTEM</code>. Upon success,
+ * the pointed at sockaddr_un is filled in and the pointed at
+ * socklen_t is set to indicate the final length. This function
+ * will fail if the namespace is invalid (not one of the indicated
+ * constants) or if the name is too long.
+ * 
+ * @return 0 on success or -1 on failure
+ */ 
+int socket_make_sockaddr_un(const char *name, int namespaceId, 
+        struct sockaddr_un *p_addr, socklen_t *alen);
+
+#endif
diff --git a/src/devtools/adb/socket_local_client.c b/src/devtools/adb/socket_local_client.c
new file mode 100755
index 0000000..ddcc2da
--- /dev/null
+++ b/src/devtools/adb/socket_local_client.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+
+#ifdef HAVE_WINSOCK
+
+int socket_local_client(const char *name, int namespaceId, int type)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+#else /* !HAVE_WINSOCK */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+
+#include "socket_local.h"
+
+#define UNUSED __attribute__((unused))
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+int socket_make_sockaddr_un(const char *name, int namespaceId, 
+        struct sockaddr_un *p_addr, socklen_t *alen)
+{
+    memset (p_addr, 0, sizeof (*p_addr));
+    size_t namelen;
+
+    switch (namespaceId) {
+        case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+            namelen  = strlen(name);
+
+            // Test with length +1 for the *initial* '\0'.
+            if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+                goto error;
+            }
+
+            /*
+             * Note: The path in this case is *not* supposed to be
+             * '\0'-terminated. ("man 7 unix" for the gory details.)
+             */
+            
+            p_addr->sun_path[0] = 0;
+            memcpy(p_addr->sun_path + 1, name, namelen);
+#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+            /* this OS doesn't have the Linux abstract namespace */
+
+            namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+            /* unix_path_max appears to be missing on linux */
+            if (namelen > sizeof(*p_addr) 
+                    - offsetof(struct sockaddr_un, sun_path) - 1) {
+                goto error;
+            }
+
+            strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+            strcat(p_addr->sun_path, name);
+#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+        break;
+
+        case ANDROID_SOCKET_NAMESPACE_RESERVED:
+            namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+            /* unix_path_max appears to be missing on linux */
+            if (namelen > sizeof(*p_addr) 
+                    - offsetof(struct sockaddr_un, sun_path) - 1) {
+                goto error;
+            }
+
+            strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+            strcat(p_addr->sun_path, name);
+        break;
+
+        case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+            namelen = strlen(name);
+            /* unix_path_max appears to be missing on linux */
+            if (namelen > sizeof(*p_addr) 
+                    - offsetof(struct sockaddr_un, sun_path) - 1) {
+                goto error;
+            }
+
+            strcpy(p_addr->sun_path, name);
+        break;
+        default:
+            // invalid namespace id
+            return -1;
+    }
+
+    p_addr->sun_family = AF_LOCAL;
+    *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+    return 0;
+error:
+    return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ * 
+ * Used by AndroidSocketImpl
+ */
+int socket_local_client_connect(int fd, const char *name, int namespaceId, 
+        int type UNUSED)
+{
+    struct sockaddr_un addr;
+    socklen_t alen;
+    int err;
+
+    err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+    if (err < 0) {
+        goto error;
+    }
+
+    if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
+        goto error;
+    }
+
+    return fd;
+
+error:
+    return -1;
+}
+
+/** 
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+int socket_local_client(const char *name, int namespaceId, int type)
+{
+    int s;
+
+    s = socket(AF_LOCAL, type, 0);
+    if(s < 0) return -1;
+
+    if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+}
+
+#endif /* !HAVE_WINSOCK */
diff --git a/src/devtools/adb/socket_local_server.c b/src/devtools/adb/socket_local_server.c
new file mode 100755
index 0000000..7628fe4
--- /dev/null
+++ b/src/devtools/adb/socket_local_server.c
@@ -0,0 +1,126 @@
+/* libs/cutils/socket_local_server.c
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include <cutils/sockets.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+
+#ifdef HAVE_WINSOCK
+
+int socket_local_server(const char *name, int namespaceId, int type)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+#else /* !HAVE_WINSOCK */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "socket_local.h"
+
+#define LISTEN_BACKLOG 4
+
+/* Only the bottom bits are really the socket type; there are flags too. */
+#define SOCK_TYPE_MASK 0xf
+
+/**
+ * Binds a pre-created socket(AF_LOCAL) 's' to 'name'
+ * returns 's' on success, -1 on fail
+ *
+ * Does not call listen()
+ */
+int socket_local_server_bind(int s, const char *name, int namespaceId)
+{
+    struct sockaddr_un addr;
+    socklen_t alen;
+    int n;
+    int err;
+
+    err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+    if (err < 0) {
+        return -1;
+    }
+
+    /* basically: if this is a filesystem path, unlink first */
+#ifndef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+    if (1) {
+#else
+    if (namespaceId == ANDROID_SOCKET_NAMESPACE_RESERVED
+        || namespaceId == ANDROID_SOCKET_NAMESPACE_FILESYSTEM) {
+#endif
+        /*ignore ENOENT*/
+        unlink(addr.sun_path);
+    }
+
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, alen) < 0) {
+        return -1;
+    }
+
+    return s;
+
+}
+
+
+/** Open a server-side UNIX domain datagram socket in the Linux non-filesystem 
+ *  namespace
+ *
+ *  Returns fd on success, -1 on fail
+ */
+
+int socket_local_server(const char *name, int namespace, int type)
+{
+    int err;
+    int s;
+    
+    s = socket(AF_LOCAL, type, 0);
+    if (s < 0) return -1;
+
+    err = socket_local_server_bind(s, name, namespace);
+
+    if (err < 0) {
+        close(s);
+        return -1;
+    }
+
+    if ((type & SOCK_TYPE_MASK) == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+
+        if (ret < 0) {
+            close(s);
+            return -1;
+        }
+    }
+
+    return s;
+}
+
+#endif /* !HAVE_WINSOCK */
diff --git a/src/devtools/adb/socket_loopback_client.c b/src/devtools/adb/socket_loopback_client.c
new file mode 100755
index 0000000..9aed7b7
--- /dev/null
+++ b/src/devtools/adb/socket_loopback_client.c
@@ -0,0 +1,57 @@
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HAVE_WINSOCK
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#endif
+
+#include <cutils/sockets.h>
+
+/* Connect to port on the loopback IP interface. type is
+ * SOCK_STREAM or SOCK_DGRAM. 
+ * return is a file descriptor or -1 on error
+ */
+int socket_loopback_client(int port, int type)
+{
+    struct sockaddr_in addr;
+    int s;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    s = socket(AF_INET, type, 0);
+    if(s < 0) return -1;
+
+    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+
+}
+
diff --git a/src/devtools/adb/socket_loopback_server.c b/src/devtools/adb/socket_loopback_server.c
new file mode 100755
index 0000000..71afce7
--- /dev/null
+++ b/src/devtools/adb/socket_loopback_server.c
@@ -0,0 +1,69 @@
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LISTEN_BACKLOG 4
+
+#ifndef HAVE_WINSOCK
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#endif
+
+#include <cutils/sockets.h>
+
+/* open listen() port on loopback interface */
+int socket_loopback_server(int port, int type)
+{
+    struct sockaddr_in addr;
+    int s, n;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    s = socket(AF_INET, type, 0);
+    if(s < 0) return -1;
+
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+
+        if (ret < 0) {
+            close(s);
+            return -1; 
+        }
+    }
+
+    return s;
+}
+
diff --git a/src/devtools/adb/socket_network_client.c b/src/devtools/adb/socket_network_client.c
new file mode 100755
index 0000000..4826033
--- /dev/null
+++ b/src/devtools/adb/socket_network_client.c
@@ -0,0 +1,126 @@
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <cutils/sockets.h>
+
+/* Connect to port on the IP interface. type is
+ * SOCK_STREAM or SOCK_DGRAM. 
+ * return is a file descriptor or -1 on error
+ */
+int socket_network_client(const char *host, int port, int type)
+{
+    return socket_network_client_timeout(host, port, type, 0);
+}
+
+/* Connect to port on the IP interface. type is SOCK_STREAM or SOCK_DGRAM.
+ * timeout in seconds return is a file descriptor or -1 on error
+ */
+int socket_network_client_timeout(const char *host, int port, int type, int timeout)
+{
+    struct hostent *hp;
+    struct sockaddr_in addr;
+    socklen_t alen;
+    int s;
+    int flags = 0, error = 0, ret = 0;
+    fd_set rset, wset;
+    socklen_t len = sizeof(error);
+    struct timeval ts;
+
+    ts.tv_sec = timeout;
+    ts.tv_usec = 0;
+
+    hp = gethostbyname(host);
+    if (hp == 0) return -1;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = hp->h_addrtype;
+    addr.sin_port = htons(port);
+    memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
+
+    s = socket(hp->h_addrtype, type, 0);
+    if (s < 0) return -1;
+
+    if ((flags = fcntl(s, F_GETFL, 0)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if ((ret = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) {
+        if (errno != EINPROGRESS) {
+            close(s);
+            return -1;
+        }
+    }
+
+    if (ret == 0)
+        goto done;
+
+    FD_ZERO(&rset);
+    FD_SET(s, &rset);
+    wset = rset;
+
+    if ((ret = select(s + 1, &rset, &wset, NULL, (timeout) ? &ts : NULL)) < 0) {
+        close(s);
+        return -1;
+    }
+    if (ret == 0) {   // we had a timeout
+        errno = ETIMEDOUT;
+        close(s);
+        return -1;
+    }
+
+    if (FD_ISSET(s, &rset) || FD_ISSET(s, &wset)) {
+        if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+            close(s);
+            return -1;
+        }
+    } else {
+        close(s);
+        return -1;
+    }
+
+    if (error) {  // check if we had a socket error
+        errno = error;
+        close(s);
+        return -1;
+    }
+
+done:
+    if (fcntl(s, F_SETFL, flags) < 0) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+}
diff --git a/src/devtools/adb/sockets.c b/src/devtools/adb/sockets.c
new file mode 100755
index 0000000..3c2773c
--- /dev/null
+++ b/src/devtools/adb/sockets.c
@@ -0,0 +1,918 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sysdeps.h"
+
+#if !ADB_HOST
+#include <cutils/properties.h>
+#endif
+
+#define  TRACE_TAG  TRACE_SOCKETS
+#include "adb.h"
+
+ADB_MUTEX_DEFINE( socket_list_lock );
+
+static void local_socket_close_locked(asocket *s);
+
+int sendfailmsg(int fd, const char *reason)
+{
+    char buf[9];
+    int len;
+    len = strlen(reason);
+    if(len > 0xffff) len = 0xffff;
+    snprintf(buf, sizeof buf, "FAIL%04x", len);
+    if(writex(fd, buf, 8)) return -1;
+    return writex(fd, reason, len);
+}
+
+//extern int online;
+
+static unsigned local_socket_next_id = 1;
+
+static asocket local_socket_list = {
+    .next = &local_socket_list,
+    .prev = &local_socket_list,
+};
+
+/* the the list of currently closing local sockets.
+** these have no peer anymore, but still packets to
+** write to their fd.
+*/
+static asocket local_socket_closing_list = {
+    .next = &local_socket_closing_list,
+    .prev = &local_socket_closing_list,
+};
+
+// Parse the global list of sockets to find one with id |local_id|.
+// If |peer_id| is not 0, also check that it is connected to a peer
+// with id |peer_id|. Returns an asocket handle on success, NULL on failure.
+asocket *find_local_socket(unsigned local_id, unsigned peer_id)
+{
+    asocket *s;
+    asocket *result = NULL;
+
+    adb_mutex_lock(&socket_list_lock);
+    for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+        if (s->id != local_id)
+            continue;
+        if (peer_id == 0 || (s->peer && s->peer->id == peer_id)) {
+            result = s;
+        }
+        break;
+    }
+    adb_mutex_unlock(&socket_list_lock);
+
+    return result;
+}
+
+static void
+insert_local_socket(asocket*  s, asocket*  list)
+{
+    s->next       = list;
+    s->prev       = s->next->prev;
+    s->prev->next = s;
+    s->next->prev = s;
+}
+
+
+void install_local_socket(asocket *s)
+{
+    adb_mutex_lock(&socket_list_lock);
+
+    s->id = local_socket_next_id++;
+
+    // Socket ids should never be 0.
+    if (local_socket_next_id == 0)
+      local_socket_next_id = 1;
+
+    insert_local_socket(s, &local_socket_list);
+
+    adb_mutex_unlock(&socket_list_lock);
+}
+
+void remove_socket(asocket *s)
+{
+    // socket_list_lock should already be held
+    if (s->prev && s->next)
+    {
+        s->prev->next = s->next;
+        s->next->prev = s->prev;
+        s->next = 0;
+        s->prev = 0;
+        s->id = 0;
+    }
+}
+
+void close_all_sockets(atransport *t)
+{
+    asocket *s;
+
+        /* this is a little gross, but since s->close() *will* modify
+        ** the list out from under you, your options are limited.
+        */
+    adb_mutex_lock(&socket_list_lock);
+restart:
+    for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
+        if(s->transport == t || (s->peer && s->peer->transport == t)) {
+            local_socket_close_locked(s);
+            goto restart;
+        }
+    }
+    adb_mutex_unlock(&socket_list_lock);
+}
+
+static int local_socket_enqueue(asocket *s, apacket *p)
+{
+    D("LS(%d): enqueue %d\n", s->id, p->len);
+
+    p->ptr = p->data;
+
+        /* if there is already data queue'd, we will receive
+        ** events when it's time to write.  just add this to
+        ** the tail
+        */
+    if(s->pkt_first) {
+        goto enqueue;
+    }
+
+        /* write as much as we can, until we
+        ** would block or there is an error/eof
+        */
+    while(p->len > 0) {
+        int r = adb_write(s->fd, p->ptr, p->len);
+        if(r > 0) {
+            p->len -= r;
+            p->ptr += r;
+            continue;
+        }
+        if((r == 0) || (errno != EAGAIN)) {
+            D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) );
+            s->close(s);
+            return 1; /* not ready (error) */
+        } else {
+            break;
+        }
+    }
+
+    if(p->len == 0) {
+        put_apacket(p);
+        return 0; /* ready for more data */
+    }
+
+enqueue:
+    p->next = 0;
+    if(s->pkt_first) {
+        s->pkt_last->next = p;
+    } else {
+        s->pkt_first = p;
+    }
+    s->pkt_last = p;
+
+        /* make sure we are notified when we can drain the queue */
+    fdevent_add(&s->fde, FDE_WRITE);
+
+    return 1; /* not ready (backlog) */
+}
+
+static void local_socket_ready(asocket *s)
+{
+        /* far side is ready for data, pay attention to
+           readable events */
+    fdevent_add(&s->fde, FDE_READ);
+//    D("LS(%d): ready()\n", s->id);
+}
+
+static void local_socket_close(asocket *s)
+{
+    adb_mutex_lock(&socket_list_lock);
+    local_socket_close_locked(s);
+    adb_mutex_unlock(&socket_list_lock);
+}
+
+// be sure to hold the socket list lock when calling this
+static void local_socket_destroy(asocket  *s)
+{
+    apacket *p, *n;
+    int exit_on_close = s->exit_on_close;
+
+    D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd);
+
+        /* IMPORTANT: the remove closes the fd
+        ** that belongs to this socket
+        */
+    fdevent_remove(&s->fde);
+
+        /* dispose of any unwritten data */
+    for(p = s->pkt_first; p; p = n) {
+        D("LS(%d): discarding %d bytes\n", s->id, p->len);
+        n = p->next;
+        put_apacket(p);
+    }
+    remove_socket(s);
+    free(s);
+
+    if (exit_on_close) {
+        D("local_socket_destroy: exiting\n");
+        exit(1);
+    }
+}
+
+
+static void local_socket_close_locked(asocket *s)
+{
+    D("entered. LS(%d) fd=%d\n", s->id, s->fd);
+    if(s->peer) {
+        D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
+          s->id, s->peer->id, s->peer->fd);
+        /* Note: it's important to call shutdown before disconnecting from
+         * the peer, this ensures that remote sockets can still get the id
+         * of the local socket they're connected to, to send a CLOSE()
+         * protocol event. */
+        if (s->peer->shutdown)
+          s->peer->shutdown(s->peer);
+        s->peer->peer = 0;
+        // tweak to avoid deadlock
+        if (s->peer->close == local_socket_close) {
+            local_socket_close_locked(s->peer);
+        } else {
+            s->peer->close(s->peer);
+        }
+        s->peer = 0;
+    }
+
+        /* If we are already closing, or if there are no
+        ** pending packets, destroy immediately
+        */
+    if (s->closing || s->pkt_first == NULL) {
+        int   id = s->id;
+        local_socket_destroy(s);
+        D("LS(%d): closed\n", id);
+        return;
+    }
+
+        /* otherwise, put on the closing list
+        */
+    D("LS(%d): closing\n", s->id);
+    s->closing = 1;
+    fdevent_del(&s->fde, FDE_READ);
+    remove_socket(s);
+    D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd);
+    insert_local_socket(s, &local_socket_closing_list);
+}
+
+static void local_socket_event_func(int fd, unsigned ev, void *_s)
+{
+    asocket *s = _s;
+
+    D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
+
+    /* put the FDE_WRITE processing before the FDE_READ
+    ** in order to simplify the code.
+    */
+    if(ev & FDE_WRITE){
+        apacket *p;
+
+        while((p = s->pkt_first) != 0) {
+            while(p->len > 0) {
+                int r = adb_write(fd, p->ptr, p->len);
+                if(r > 0) {
+                    p->ptr += r;
+                    p->len -= r;
+                    continue;
+                }
+                if(r < 0) {
+                    /* returning here is ok because FDE_READ will
+                    ** be processed in the next iteration loop
+                    */
+                    if(errno == EAGAIN) return;
+                    if(errno == EINTR) continue;
+                }
+                D(" closing after write because r=%d and errno is %d\n", r, errno);
+                s->close(s);
+                return;
+            }
+
+            if(p->len == 0) {
+                s->pkt_first = p->next;
+                if(s->pkt_first == 0) s->pkt_last = 0;
+                put_apacket(p);
+            }
+        }
+
+            /* if we sent the last packet of a closing socket,
+            ** we can now destroy it.
+            */
+        if (s->closing) {
+            D(" closing because 'closing' is set after write\n");
+            s->close(s);
+            return;
+        }
+
+            /* no more packets queued, so we can ignore
+            ** writable events again and tell our peer
+            ** to resume writing
+            */
+        fdevent_del(&s->fde, FDE_WRITE);
+        s->peer->ready(s->peer);
+    }
+
+
+    if(ev & FDE_READ){
+        apacket *p = get_apacket();
+        unsigned char *x = p->data;
+        size_t avail = MAX_PAYLOAD;
+        int r;
+        int is_eof = 0;
+
+        while(avail > 0) {
+            r = adb_read(fd, x, avail);
+            D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n", s->id, s->fd, r, r<0?errno:0, avail);
+            if(r > 0) {
+                avail -= r;
+                x += r;
+                continue;
+            }
+            if(r < 0) {
+                if(errno == EAGAIN) break;
+                if(errno == EINTR) continue;
+            }
+
+                /* r = 0 or unhandled error */
+            is_eof = 1;
+            break;
+        }
+        D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
+          s->id, s->fd, r, is_eof, s->fde.force_eof);
+        if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
+            put_apacket(p);
+        } else {
+            p->len = MAX_PAYLOAD - avail;
+
+            r = s->peer->enqueue(s->peer, p);
+            D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
+
+            if(r < 0) {
+                    /* error return means they closed us as a side-effect
+                    ** and we must return immediately.
+                    **
+                    ** note that if we still have buffered packets, the
+                    ** socket will be placed on the closing socket list.
+                    ** this handler function will be called again
+                    ** to process FDE_WRITE events.
+                    */
+                return;
+            }
+
+            if(r > 0) {
+                    /* if the remote cannot accept further events,
+                    ** we disable notification of READs.  They'll
+                    ** be enabled again when we get a call to ready()
+                    */
+                fdevent_del(&s->fde, FDE_READ);
+            }
+        }
+        /* Don't allow a forced eof if data is still there */
+        if((s->fde.force_eof && !r) || is_eof) {
+            D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof);
+            s->close(s);
+        }
+    }
+
+    if(ev & FDE_ERROR){
+            /* this should be caught be the next read or write
+            ** catching it here means we may skip the last few
+            ** bytes of readable data.
+            */
+//        s->close(s);
+        D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
+
+        return;
+    }
+}
+
+asocket *create_local_socket(int fd)
+{
+    asocket *s = calloc(1, sizeof(asocket));
+    if (s == NULL) fatal("cannot allocate socket");
+    s->fd = fd;
+    s->enqueue = local_socket_enqueue;
+    s->ready = local_socket_ready;
+    s->shutdown = NULL;
+    s->close = local_socket_close;
+    install_local_socket(s);
+
+    fdevent_install(&s->fde, fd, local_socket_event_func, s);
+/*    fdevent_add(&s->fde, FDE_ERROR); */
+    //fprintf(stderr, "Created local socket in create_local_socket \n");
+    D("LS(%d): created (fd=%d)\n", s->id, s->fd);
+    return s;
+}
+
+asocket *create_local_service_socket(const char *name)
+{
+    asocket *s;
+    int fd;
+#if !ADB_HOST
+    char debug[PROPERTY_VALUE_MAX];
+#endif
+
+#if !ADB_HOST
+    if (!strcmp(name,"jdwp")) {
+        return create_jdwp_service_socket();
+    }
+    if (!strcmp(name,"track-jdwp")) {
+        return create_jdwp_tracker_service_socket();
+    }
+#endif
+    fd = service_to_fd(name);
+    if(fd < 0) return 0;
+
+    s = create_local_socket(fd);
+    D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
+
+#if !ADB_HOST
+    if (!strncmp(name, "root:", 5))
+        property_get("ro.debuggable", debug, "");
+
+    if ((!strncmp(name, "root:", 5) && getuid() != 0
+        && strcmp(debug, "1") == 0)
+        || !strncmp(name, "usb:", 4)
+        || !strncmp(name, "tcpip:", 6)
+	|| !strncmp(name, "reconnect:", 10)) {
+        D("LS(%d): enabling exit_on_close\n", s->id);
+        s->exit_on_close = 1;
+    }
+#endif
+
+    return s;
+}
+
+#if ADB_HOST
+static asocket *create_host_service_socket(const char *name, const char* serial)
+{
+    asocket *s;
+
+    s = host_service_to_socket(name, serial);
+
+    if (s != NULL) {
+        D("LS(%d) bound to '%s'\n", s->id, name);
+        return s;
+    }
+
+    return s;
+}
+#endif /* ADB_HOST */
+
+/* a Remote socket is used to send/receive data to/from a given transport object
+** it needs to be closed when the transport is forcibly destroyed by the user
+*/
+typedef struct aremotesocket {
+    asocket      socket;
+    adisconnect  disconnect;
+} aremotesocket;
+
+static int remote_socket_enqueue(asocket *s, apacket *p)
+{
+    D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
+      s->id, s->fd, s->peer->fd);
+    p->msg.command = A_WRTE;
+    p->msg.arg0 = s->peer->id;
+    p->msg.arg1 = s->id;
+    p->msg.data_length = p->len;
+    send_packet(p, s->transport);
+    return 1;
+}
+
+static void remote_socket_ready(asocket *s)
+{
+    D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n",
+      s->id, s->fd, s->peer->fd);
+    apacket *p = get_apacket();
+    p->msg.command = A_OKAY;
+    p->msg.arg0 = s->peer->id;
+    p->msg.arg1 = s->id;
+    send_packet(p, s->transport);
+}
+
+static void remote_socket_shutdown(asocket *s)
+{
+    D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d\n",
+      s->id, s->fd, s->peer?s->peer->fd:-1);
+    apacket *p = get_apacket();
+    p->msg.command = A_CLSE;
+    if(s->peer) {
+        p->msg.arg0 = s->peer->id;
+    }
+    p->msg.arg1 = s->id;
+    send_packet(p, s->transport);
+}
+
+static void remote_socket_close(asocket *s)
+{
+    if (s->peer) {
+        s->peer->peer = 0;
+        D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n",
+          s->id, s->peer->id, s->peer->fd);
+        s->peer->close(s->peer);
+    }
+    D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
+      s->id, s->fd, s->peer?s->peer->fd:-1);
+    D("RS(%d): closed\n", s->id);
+    remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
+    free(s);
+}
+
+static void remote_socket_disconnect(void*  _s, atransport*  t)
+{
+    asocket*  s    = _s;
+    asocket*  peer = s->peer;
+
+    D("remote_socket_disconnect RS(%d)\n", s->id);
+    if (peer) {
+        peer->peer = NULL;
+        peer->close(peer);
+    }
+    remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
+    free(s);
+}
+
+/* Create an asocket to exchange packets with a remote service through transport
+  |t|. Where |id| is the socket id of the corresponding service on the other
+   side of the transport (it is allocated by the remote side and _cannot_ be 0).
+   Returns a new non-NULL asocket handle. */
+asocket *create_remote_socket(unsigned id, atransport *t)
+{
+    asocket* s;
+    adisconnect* dis;
+
+    if (id == 0) fatal("invalid remote socket id (0)");
+    s = calloc(1, sizeof(aremotesocket));
+    dis = &((aremotesocket*)s)->disconnect;
+
+    if (s == NULL) fatal("cannot allocate socket");
+    s->id = id;
+    s->enqueue = remote_socket_enqueue;
+    s->ready = remote_socket_ready;
+    s->shutdown = remote_socket_shutdown;
+    s->close = remote_socket_close;
+    s->transport = t;
+
+    dis->func   = remote_socket_disconnect;
+    dis->opaque = s;
+    add_transport_disconnect( t, dis );
+    D("RS(%d): created\n", s->id);
+    return s;
+}
+
+void connect_to_remote(asocket *s, const char *destination)
+{
+    D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd);
+    apacket *p = get_apacket();
+    int len = strlen(destination) + 1;
+
+    if(len > (MAX_PAYLOAD-1)) {
+        fatal("destination oversized");
+    }
+
+    D("LS(%d): connect('%s')\n", s->id, destination);
+    p->msg.command = A_OPEN;
+    p->msg.arg0 = s->id;
+    p->msg.data_length = len;
+    strcpy((char*) p->data, destination);
+    send_packet(p, s->transport);
+}
+
+
+/* this is used by magic sockets to rig local sockets to
+   send the go-ahead message when they connect */
+static void local_socket_ready_notify(asocket *s)
+{
+    s->ready = local_socket_ready;
+    s->shutdown = NULL;
+    s->close = local_socket_close;
+    adb_write(s->fd, "OKAY", 4);
+    s->ready(s);
+}
+
+/* this is used by magic sockets to rig local sockets to
+   send the failure message if they are closed before
+   connected (to avoid closing them without a status message) */
+static void local_socket_close_notify(asocket *s)
+{
+    s->ready = local_socket_ready;
+    s->shutdown = NULL;
+    s->close = local_socket_close;
+    sendfailmsg(s->fd, "closed");
+    s->close(s);
+}
+
+unsigned unhex(unsigned char *s, int len)
+{
+    unsigned n = 0, c;
+
+    while(len-- > 0) {
+        switch((c = *s++)) {
+        case '0': case '1': case '2':
+        case '3': case '4': case '5':
+        case '6': case '7': case '8':
+        case '9':
+            c -= '0';
+            break;
+        case 'a': case 'b': case 'c':
+        case 'd': case 'e': case 'f':
+            c = c - 'a' + 10;
+            break;
+        case 'A': case 'B': case 'C':
+        case 'D': case 'E': case 'F':
+            c = c - 'A' + 10;
+            break;
+        default:
+            return 0xffffffff;
+        }
+
+        n = (n << 4) | c;
+    }
+
+    return n;
+}
+
+#define PREFIX(str) { str, sizeof(str) - 1 }
+static const struct prefix_struct {
+    const char *str;
+    const size_t len;
+} prefixes[] = {
+    PREFIX("usb:"),
+    PREFIX("product:"),
+    PREFIX("model:"),
+    PREFIX("device:"),
+};
+static const int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0]));
+
+/* skip_host_serial return the position in a string
+   skipping over the 'serial' parameter in the ADB protocol,
+   where parameter string may be a host:port string containing
+   the protocol delimiter (colon). */
+char *skip_host_serial(char *service) {
+    char *first_colon, *serial_end;
+    int i;
+
+    for (i = 0; i < num_prefixes; i++) {
+        if (!strncmp(service, prefixes[i].str, prefixes[i].len))
+            return strchr(service + prefixes[i].len, ':');
+    }
+
+    first_colon = strchr(service, ':');
+    if (!first_colon) {
+        /* No colon in service string. */
+        return NULL;
+    }
+    serial_end = first_colon;
+    if (isdigit(serial_end[1])) {
+        serial_end++;
+        while ((*serial_end) && isdigit(*serial_end)) {
+            serial_end++;
+        }
+        if ((*serial_end) != ':') {
+            // Something other than numbers was found, reset the end.
+            serial_end = first_colon;
+        }
+    }
+    return serial_end;
+}
+
+static int smart_socket_enqueue(asocket *s, apacket *p)
+{
+    unsigned len;
+#if ADB_HOST
+    char *service = NULL;
+    char* serial = NULL;
+    transport_type ttype = kTransportAny;
+#endif
+
+    D("SS(%d): enqueue %d\n", s->id, p->len);
+
+    if(s->pkt_first == 0) {
+        s->pkt_first = p;
+        s->pkt_last = p;
+    } else {
+        if((s->pkt_first->len + p->len) > MAX_PAYLOAD) {
+            D("SS(%d): overflow\n", s->id);
+            put_apacket(p);
+            goto fail;
+        }
+
+        memcpy(s->pkt_first->data + s->pkt_first->len,
+               p->data, p->len);
+        s->pkt_first->len += p->len;
+        put_apacket(p);
+
+        p = s->pkt_first;
+    }
+
+        /* don't bother if we can't decode the length */
+    if(p->len < 4) return 0;
+
+    len = unhex(p->data, 4);
+    if((len < 1) ||  (len > 1024)) {
+        D("SS(%d): bad size (%d)\n", s->id, len);
+        goto fail;
+    }
+
+    D("SS(%d): len is %d\n", s->id, len );
+        /* can't do anything until we have the full header */
+    if((len + 4) > p->len) {
+        D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len);
+        return 0;
+    }
+
+    p->data[len + 4] = 0;
+
+    D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4));
+
+#if ADB_HOST
+    service = (char *)p->data + 4;
+    if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
+        char* serial_end;
+        service += strlen("host-serial:");
+
+        // serial number should follow "host:" and could be a host:port string.
+        serial_end = skip_host_serial(service);
+        if (serial_end) {
+            *serial_end = 0; // terminate string
+            serial = service;
+            service = serial_end + 1;
+        }
+    } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
+        ttype = kTransportUsb;
+        service += strlen("host-usb:");
+    } else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
+        ttype = kTransportLocal;
+        service += strlen("host-local:");
+    } else if (!strncmp(service, "host:", strlen("host:"))) {
+        ttype = kTransportAny;
+        service += strlen("host:");
+    } else {
+        service = NULL;
+    }
+
+    if (service) {
+        asocket *s2;
+
+            /* some requests are handled immediately -- in that
+            ** case the handle_host_request() routine has sent
+            ** the OKAY or FAIL message and all we have to do
+            ** is clean up.
+            */
+        if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
+                /* XXX fail message? */
+            D( "SS(%d): handled host service '%s'\n", s->id, service );
+            goto fail;
+        }
+        if (!strncmp(service, "transport", strlen("transport"))) {
+            D( "SS(%d): okay transport\n", s->id );
+            p->len = 0;
+            return 0;
+        }
+
+            /* try to find a local service with this name.
+            ** if no such service exists, we'll fail out
+            ** and tear down here.
+            */
+        s2 = create_host_service_socket(service, serial);
+        if(s2 == 0) {
+            D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
+            sendfailmsg(s->peer->fd, "unknown host service");
+            goto fail;
+        }
+
+            /* we've connected to a local host service,
+            ** so we make our peer back into a regular
+            ** local socket and bind it to the new local
+            ** service socket, acknowledge the successful
+            ** connection, and close this smart socket now
+            ** that its work is done.
+            */
+        adb_write(s->peer->fd, "OKAY", 4);
+
+        s->peer->ready = local_socket_ready;
+        s->peer->shutdown = NULL;
+        s->peer->close = local_socket_close;
+        s->peer->peer = s2;
+        s2->peer = s->peer;
+        s->peer = 0;
+        D( "SS(%d): okay\n", s->id );
+        s->close(s);
+
+            /* initial state is "ready" */
+        s2->ready(s2);
+        return 0;
+    }
+#else /* !ADB_HOST */
+    if (s->transport == NULL) {
+        char* error_string = "unknown failure";
+        s->transport = acquire_one_transport (CS_ANY,
+                kTransportAny, NULL, &error_string);
+
+        if (s->transport == NULL) {
+            sendfailmsg(s->peer->fd, error_string);
+            goto fail;
+        }
+    }
+#endif
+
+    if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
+           /* if there's no remote we fail the connection
+            ** right here and terminate it
+            */
+        sendfailmsg(s->peer->fd, "device offline (x)");
+        goto fail;
+    }
+
+
+        /* instrument our peer to pass the success or fail
+        ** message back once it connects or closes, then
+        ** detach from it, request the connection, and
+        ** tear down
+        */
+    s->peer->ready = local_socket_ready_notify;
+    s->peer->shutdown = NULL;
+    s->peer->close = local_socket_close_notify;
+    s->peer->peer = 0;
+        /* give him our transport and upref it */
+    s->peer->transport = s->transport;
+
+    connect_to_remote(s->peer, (char*) (p->data + 4));
+    s->peer = 0;
+    s->close(s);
+    return 1;
+
+fail:
+        /* we're going to close our peer as a side-effect, so
+        ** return -1 to signal that state to the local socket
+        ** who is enqueueing against us
+        */
+    s->close(s);
+    return -1;
+}
+
+static void smart_socket_ready(asocket *s)
+{
+    D("SS(%d): ready\n", s->id);
+}
+
+static void smart_socket_close(asocket *s)
+{
+    D("SS(%d): closed\n", s->id);
+    if(s->pkt_first){
+        put_apacket(s->pkt_first);
+    }
+    if(s->peer) {
+        s->peer->peer = 0;
+        s->peer->close(s->peer);
+        s->peer = 0;
+    }
+    free(s);
+}
+
+static asocket *create_smart_socket(void)
+{
+    D("Creating smart socket \n");
+    asocket *s = calloc(1, sizeof(asocket));
+    if (s == NULL) fatal("cannot allocate socket");
+    s->enqueue = smart_socket_enqueue;
+    s->ready = smart_socket_ready;
+    s->shutdown = NULL;
+    s->close = smart_socket_close;
+
+    D("SS(%d)\n", s->id);
+    return s;
+}
+
+void connect_to_smartsocket(asocket *s)
+{
+    D("Connecting to smart socket \n");
+    asocket *ss = create_smart_socket();
+    s->peer = ss;
+    ss->peer = s;
+    s->ready(s);
+}
diff --git a/src/devtools/adb/sysdeps.h b/src/devtools/adb/sysdeps.h
new file mode 100755
index 0000000..cc1f839
--- /dev/null
+++ b/src/devtools/adb/sysdeps.h
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+/* this file contains system-dependent definitions used by ADB
+ * they're related to threads, sockets and file descriptors
+ */
+#ifndef _ADB_SYSDEPS_H
+#define _ADB_SYSDEPS_H
+
+#ifdef __CYGWIN__
+#  undef _WIN32
+#endif
+
+#ifdef _WIN32
+
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#include <process.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+#include <direct.h>
+
+#define OS_PATH_SEPARATOR '\\'
+#define OS_PATH_SEPARATOR_STR "\\"
+#define ENV_PATH_SEPARATOR_STR ";"
+
+typedef CRITICAL_SECTION          adb_mutex_t;
+
+#define  ADB_MUTEX_DEFINE(x)     adb_mutex_t   x
+
+/* declare all mutexes */
+/* For win32, adb_sysdeps_init() will do the mutex runtime initialization. */
+#define  ADB_MUTEX(x)   extern adb_mutex_t  x;
+#include "mutex_list.h"
+
+extern void  adb_sysdeps_init(void);
+
+static __inline__ void adb_mutex_lock( adb_mutex_t*  lock )
+{
+    EnterCriticalSection( lock );
+}
+
+static __inline__ void  adb_mutex_unlock( adb_mutex_t*  lock )
+{
+    LeaveCriticalSection( lock );
+}
+
+typedef struct { unsigned  tid; }  adb_thread_t;
+
+typedef  void*  (*adb_thread_func_t)(void*  arg);
+
+typedef  void (*win_thread_func_t)(void*  arg);
+
+static __inline__ int  adb_thread_create( adb_thread_t  *thread, adb_thread_func_t  func, void*  arg)
+{
+    thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
+    if (thread->tid == (unsigned)-1L) {
+        return -1;
+    }
+    return 0;
+}
+
+static __inline__ void  close_on_exec(int  fd)
+{
+    /* nothing really */
+}
+
+extern void  disable_tcp_nagle(int  fd);
+
+#define  lstat    stat   /* no symlinks on Win32 */
+
+#define  S_ISLNK(m)   0   /* no symlinks on Win32 */
+
+static __inline__  int    adb_unlink(const char*  path)
+{
+    int  rc = unlink(path);
+
+    if (rc == -1 && errno == EACCES) {
+        /* unlink returns EACCES when the file is read-only, so we first */
+        /* try to make it writable, then unlink again...                  */
+        rc = chmod(path, _S_IREAD|_S_IWRITE );
+        if (rc == 0)
+            rc = unlink(path);
+    }
+    return rc;
+}
+#undef  unlink
+#define unlink  ___xxx_unlink
+
+static __inline__ int  adb_mkdir(const char*  path, int mode)
+{
+	return _mkdir(path);
+}
+#undef   mkdir
+#define  mkdir  ___xxx_mkdir
+
+extern int  adb_open(const char*  path, int  options);
+extern int  adb_creat(const char*  path, int  mode);
+extern int  adb_read(int  fd, void* buf, int len);
+extern int  adb_write(int  fd, const void*  buf, int  len);
+extern int  adb_lseek(int  fd, int  pos, int  where);
+extern int  adb_shutdown(int  fd);
+extern int  adb_close(int  fd);
+
+static __inline__ int  unix_close(int fd)
+{
+    return close(fd);
+}
+#undef   close
+#define  close   ____xxx_close
+
+static __inline__  int  unix_read(int  fd, void*  buf, size_t  len)
+{
+    return read(fd, buf, len);
+}
+#undef   read
+#define  read  ___xxx_read
+
+static __inline__  int  unix_write(int  fd, const void*  buf, size_t  len)
+{
+    return write(fd, buf, len);
+}
+#undef   write
+#define  write  ___xxx_write
+
+static __inline__ int  adb_open_mode(const char* path, int options, int mode)
+{
+    return adb_open(path, options);
+}
+
+static __inline__ int  unix_open(const char*  path, int options,...)
+{
+    if ((options & O_CREAT) == 0)
+    {
+        return  open(path, options);
+    }
+    else
+    {
+        int      mode;
+        va_list  args;
+        va_start( args, options );
+        mode = va_arg( args, int );
+        va_end( args );
+        return open(path, options, mode);
+    }
+}
+#define  open    ___xxx_unix_open
+
+
+/* normally provided by <cutils/misc.h> */
+extern void*  load_file(const char*  pathname, unsigned*  psize);
+
+/* normally provided by <cutils/sockets.h> */
+extern int socket_loopback_client(int port, int type);
+extern int socket_network_client(const char *host, int port, int type);
+extern int socket_network_client_timeout(const char *host, int port, int type,
+                                         int timeout);
+extern int socket_loopback_server(int port, int type);
+extern int socket_inaddr_any_server(int port, int type);
+
+/* normally provided by "fdevent.h" */
+
+#define FDE_READ              0x0001
+#define FDE_WRITE             0x0002
+#define FDE_ERROR             0x0004
+#define FDE_DONT_CLOSE        0x0080
+
+typedef struct fdevent fdevent;
+
+typedef void (*fd_func)(int fd, unsigned events, void *userdata);
+
+fdevent *fdevent_create(int fd, fd_func func, void *arg);
+void     fdevent_destroy(fdevent *fde);
+void     fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
+void     fdevent_remove(fdevent *item);
+void     fdevent_set(fdevent *fde, unsigned events);
+void     fdevent_add(fdevent *fde, unsigned events);
+void     fdevent_del(fdevent *fde, unsigned events);
+void     fdevent_loop();
+
+struct fdevent {
+    fdevent *next;
+    fdevent *prev;
+
+    int fd;
+    int force_eof;
+
+    unsigned short state;
+    unsigned short events;
+
+    fd_func func;
+    void *arg;
+};
+
+static __inline__ void  adb_sleep_ms( int  mseconds )
+{
+    Sleep( mseconds );
+}
+
+extern int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen);
+
+#undef   accept
+#define  accept  ___xxx_accept
+
+static __inline__  int  adb_socket_setbufsize( int   fd, int  bufsize )
+{
+    int opt = bufsize;
+    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt));
+}
+
+extern int  adb_socketpair( int  sv[2] );
+
+static __inline__  char*  adb_dirstart( const char*  path )
+{
+    char*  p  = strchr(path, '/');
+    char*  p2 = strchr(path, '\\');
+
+    if ( !p )
+        p = p2;
+    else if ( p2 && p2 > p )
+        p = p2;
+
+    return p;
+}
+
+static __inline__  char*  adb_dirstop( const char*  path )
+{
+    char*  p  = strrchr(path, '/');
+    char*  p2 = strrchr(path, '\\');
+
+    if ( !p )
+        p = p2;
+    else if ( p2 && p2 > p )
+        p = p2;
+
+    return p;
+}
+
+static __inline__  int  adb_is_absolute_host_path( const char*  path )
+{
+    return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
+}
+
+extern char*  adb_strtok_r(char *str, const char *delim, char **saveptr);
+
+#else /* !_WIN32 a.k.a. Unix */
+
+#include "fdevent.h"
+#include <cutils/sockets.h>
+#include <cutils/misc.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
+#define OS_PATH_SEPARATOR '/'
+#define OS_PATH_SEPARATOR_STR "/"
+#define ENV_PATH_SEPARATOR_STR ":"
+
+typedef  pthread_mutex_t          adb_mutex_t;
+
+#define  ADB_MUTEX_INITIALIZER    PTHREAD_MUTEX_INITIALIZER
+#define  adb_mutex_init           pthread_mutex_init
+#define  adb_mutex_lock           pthread_mutex_lock
+#define  adb_mutex_unlock         pthread_mutex_unlock
+#define  adb_mutex_destroy        pthread_mutex_destroy
+
+#define  ADB_MUTEX_DEFINE(m)      adb_mutex_t   m = PTHREAD_MUTEX_INITIALIZER
+
+#define  adb_cond_t               pthread_cond_t
+#define  adb_cond_init            pthread_cond_init
+#define  adb_cond_wait            pthread_cond_wait
+#define  adb_cond_broadcast       pthread_cond_broadcast
+#define  adb_cond_signal          pthread_cond_signal
+#define  adb_cond_destroy         pthread_cond_destroy
+
+/* declare all mutexes */
+#define  ADB_MUTEX(x)   extern adb_mutex_t  x;
+#include "mutex_list.h"
+
+static __inline__ void  close_on_exec(int  fd)
+{
+    fcntl( fd, F_SETFD, FD_CLOEXEC );
+}
+
+static __inline__ int  unix_open(const char*  path, int options,...)
+{
+    if ((options & O_CREAT) == 0)
+    {
+        return  TEMP_FAILURE_RETRY( open(path, options) );
+    }
+    else
+    {
+        int      mode;
+        va_list  args;
+        va_start( args, options );
+        mode = va_arg( args, int );
+        va_end( args );
+        return TEMP_FAILURE_RETRY( open( path, options, mode ) );
+    }
+}
+
+static __inline__ int  adb_open_mode( const char*  pathname, int  options, int  mode )
+{
+    return TEMP_FAILURE_RETRY( open( pathname, options, mode ) );
+}
+
+
+static __inline__ int  adb_open( const char*  pathname, int  options )
+{
+    int  fd = TEMP_FAILURE_RETRY( open( pathname, options ) );
+    if (fd < 0)
+        return -1;
+    close_on_exec( fd );
+    return fd;
+}
+#undef   open
+#define  open    ___xxx_open
+
+static __inline__ int  adb_shutdown(int fd)
+{
+    return shutdown(fd, SHUT_RDWR);
+}
+#undef   shutdown
+#define  shutdown   ____xxx_shutdown
+
+static __inline__ int  adb_close(int fd)
+{
+    return close(fd);
+}
+#undef   close
+#define  close   ____xxx_close
+
+
+static __inline__  int  adb_read(int  fd, void*  buf, size_t  len)
+{
+    return TEMP_FAILURE_RETRY( read( fd, buf, len ) );
+}
+
+#undef   read
+#define  read  ___xxx_read
+
+static __inline__  int  adb_write(int  fd, const void*  buf, size_t  len)
+{
+    return TEMP_FAILURE_RETRY( write( fd, buf, len ) );
+}
+#undef   write
+#define  write  ___xxx_write
+
+static __inline__ int   adb_lseek(int  fd, int  pos, int  where)
+{
+    return lseek(fd, pos, where);
+}
+#undef   lseek
+#define  lseek   ___xxx_lseek
+
+static __inline__  int    adb_unlink(const char*  path)
+{
+    return  unlink(path);
+}
+#undef  unlink
+#define unlink  ___xxx_unlink
+
+static __inline__  int  adb_creat(const char*  path, int  mode)
+{
+    int  fd = TEMP_FAILURE_RETRY( creat( path, mode ) );
+
+    if ( fd < 0 )
+        return -1;
+
+    close_on_exec(fd);
+    return fd;
+}
+#undef   creat
+#define  creat  ___xxx_creat
+
+static __inline__ int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
+{
+    int fd;
+
+    fd = TEMP_FAILURE_RETRY( accept( serverfd, addr, addrlen ) );
+    if (fd >= 0)
+        close_on_exec(fd);
+
+    return fd;
+}
+
+#undef   accept
+#define  accept  ___xxx_accept
+
+#define  unix_read   adb_read
+#define  unix_write  adb_write
+#define  unix_close  adb_close
+
+typedef  pthread_t                 adb_thread_t;
+
+typedef void*  (*adb_thread_func_t)( void*  arg );
+
+static __inline__ int  adb_thread_create( adb_thread_t  *pthread, adb_thread_func_t  start, void*  arg )
+{
+    pthread_attr_t   attr;
+
+    pthread_attr_init (&attr);
+    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+
+    return pthread_create( pthread, &attr, start, arg );
+}
+
+static __inline__  int  adb_socket_setbufsize( int   fd, int  bufsize )
+{
+    int opt = bufsize;
+    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
+}
+
+static __inline__ void  disable_tcp_nagle(int fd)
+{
+    int  on = 1;
+    setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
+}
+
+
+static __inline__ int  unix_socketpair( int  d, int  type, int  protocol, int sv[2] )
+{
+    return socketpair( d, type, protocol, sv );
+}
+
+static __inline__ int  adb_socketpair( int  sv[2] )
+{
+    int  rc;
+
+    rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
+    if (rc < 0)
+        return -1;
+
+    close_on_exec( sv[0] );
+    close_on_exec( sv[1] );
+    return 0;
+}
+
+#undef   socketpair
+#define  socketpair   ___xxx_socketpair
+
+static __inline__ void  adb_sleep_ms( int  mseconds )
+{
+    usleep( mseconds*1000 );
+}
+
+static __inline__ int  adb_mkdir(const char*  path, int mode)
+{
+    return mkdir(path, mode);
+}
+#undef   mkdir
+#define  mkdir  ___xxx_mkdir
+
+static __inline__ void  adb_sysdeps_init(void)
+{
+}
+
+static __inline__ char*  adb_dirstart(const char*  path)
+{
+    return strchr(path, '/');
+}
+
+static __inline__ char*  adb_dirstop(const char*  path)
+{
+    return strrchr(path, '/');
+}
+
+static __inline__  int  adb_is_absolute_host_path( const char*  path )
+{
+    return path[0] == '/';
+}
+
+static __inline__ char*  adb_strtok_r(char *str, const char *delim, char **saveptr)
+{
+    return strtok_r(str, delim, saveptr);
+}
+#undef   strtok_r
+#define  strtok_r  ___xxx_strtok_r
+
+#endif /* !_WIN32 */
+
+#endif /* _ADB_SYSDEPS_H */
diff --git a/src/devtools/adb/sysdeps_win32.c b/src/devtools/adb/sysdeps_win32.c
new file mode 100755
index 0000000..b082c6d
--- /dev/null
+++ b/src/devtools/adb/sysdeps_win32.c
@@ -0,0 +1,2227 @@
+#include "sysdeps.h"
+#include <winsock2.h>
+#include <windows.h>
+#include <stdio.h>
+#include <errno.h>
+#define  TRACE_TAG  TRACE_SYSDEPS
+#include "adb.h"
+
+extern void fatal(const char *fmt, ...);
+
+#define assert(cond)  do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****      replaces libs/cutils/load_file.c                          *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+void *load_file(const char *fn, unsigned *_sz)
+{
+    HANDLE    file;
+    char     *data;
+    DWORD     file_size;
+
+    file = CreateFile( fn,
+                       GENERIC_READ,
+                       FILE_SHARE_READ,
+                       NULL,
+                       OPEN_EXISTING,
+                       0,
+                       NULL );
+
+    if (file == INVALID_HANDLE_VALUE)
+        return NULL;
+
+    file_size = GetFileSize( file, NULL );
+    data      = NULL;
+
+    if (file_size > 0) {
+        data = (char*) malloc( file_size + 1 );
+        if (data == NULL) {
+            D("load_file: could not allocate %ld bytes\n", file_size );
+            file_size = 0;
+        } else {
+            DWORD  out_bytes;
+
+            if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) ||
+                 out_bytes != file_size )
+            {
+                D("load_file: could not read %ld bytes from '%s'\n", file_size, fn);
+                free(data);
+                data      = NULL;
+                file_size = 0;
+            }
+        }
+    }
+    CloseHandle( file );
+
+    *_sz = (unsigned) file_size;
+    return  data;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    common file descriptor handling                             *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+typedef const struct FHClassRec_*   FHClass;
+
+typedef struct FHRec_*          FH;
+
+typedef struct EventHookRec_*  EventHook;
+
+typedef struct FHClassRec_
+{
+    void (*_fh_init) ( FH  f );
+    int  (*_fh_close)( FH  f );
+    int  (*_fh_lseek)( FH  f, int  pos, int  origin );
+    int  (*_fh_read) ( FH  f, void*  buf, int  len );
+    int  (*_fh_write)( FH  f, const void*  buf, int  len );
+    void (*_fh_hook) ( FH  f, int  events, EventHook  hook );
+
+} FHClassRec;
+
+/* used to emulate unix-domain socket pairs */
+typedef struct SocketPairRec_*  SocketPair;
+
+typedef struct FHRec_
+{
+    FHClass    clazz;
+    int        used;
+    int        eof;
+    union {
+        HANDLE      handle;
+        SOCKET      socket;
+        SocketPair  pair;
+    } u;
+
+    HANDLE    event;
+    int       mask;
+
+    char  name[32];
+
+} FHRec;
+
+#define  fh_handle  u.handle
+#define  fh_socket  u.socket
+#define  fh_pair    u.pair
+
+#define  WIN32_FH_BASE    100
+
+#define  WIN32_MAX_FHS    128
+
+static adb_mutex_t   _win32_lock;
+static  FHRec        _win32_fhs[ WIN32_MAX_FHS ];
+static  int          _win32_fh_count;
+
+static FH
+_fh_from_int( int   fd )
+{
+    FH  f;
+
+    fd -= WIN32_FH_BASE;
+
+    if (fd < 0 || fd >= _win32_fh_count) {
+        D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
+        errno = EBADF;
+        return NULL;
+    }
+
+    f = &_win32_fhs[fd];
+
+    if (f->used == 0) {
+        D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
+        errno = EBADF;
+        return NULL;
+    }
+
+    return f;
+}
+
+
+static int
+_fh_to_int( FH  f )
+{
+    if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS)
+        return (int)(f - _win32_fhs) + WIN32_FH_BASE;
+
+    return -1;
+}
+
+static FH
+_fh_alloc( FHClass  clazz )
+{
+    int  nn;
+    FH   f = NULL;
+
+    adb_mutex_lock( &_win32_lock );
+
+    if (_win32_fh_count < WIN32_MAX_FHS) {
+        f = &_win32_fhs[ _win32_fh_count++ ];
+        goto Exit;
+    }
+
+    for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
+        if ( _win32_fhs[nn].clazz == NULL) {
+            f = &_win32_fhs[nn];
+            goto Exit;
+        }
+    }
+    D( "_fh_alloc: no more free file descriptors\n" );
+Exit:
+    if (f) {
+        f->clazz = clazz;
+        f->used  = 1;
+        f->eof   = 0;
+        clazz->_fh_init(f);
+    }
+    adb_mutex_unlock( &_win32_lock );
+    return f;
+}
+
+
+static int
+_fh_close( FH   f )
+{
+    if ( f->used ) {
+        f->clazz->_fh_close( f );
+        f->used = 0;
+        f->eof  = 0;
+        f->clazz = NULL;
+    }
+    return 0;
+}
+
+/* forward definitions */
+static const FHClassRec   _fh_file_class;
+static const FHClassRec   _fh_socket_class;
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    file-based descriptor handling                              *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+static void
+_fh_file_init( FH  f )
+{
+    f->fh_handle = INVALID_HANDLE_VALUE;
+}
+
+static int
+_fh_file_close( FH  f )
+{
+    CloseHandle( f->fh_handle );
+    f->fh_handle = INVALID_HANDLE_VALUE;
+    return 0;
+}
+
+static int
+_fh_file_read( FH  f,  void*  buf, int   len )
+{
+    DWORD  read_bytes;
+
+    if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
+        D( "adb_read: could not read %d bytes from %s\n", len, f->name );
+        errno = EIO;
+        return -1;
+    } else if (read_bytes < (DWORD)len) {
+        f->eof = 1;
+    }
+    return (int)read_bytes;
+}
+
+static int
+_fh_file_write( FH  f,  const void*  buf, int   len )
+{
+    DWORD  wrote_bytes;
+
+    if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
+        D( "adb_file_write: could not write %d bytes from %s\n", len, f->name );
+        errno = EIO;
+        return -1;
+    } else if (wrote_bytes < (DWORD)len) {
+        f->eof = 1;
+    }
+    return  (int)wrote_bytes;
+}
+
+static int
+_fh_file_lseek( FH  f, int  pos, int  origin )
+{
+    DWORD  method;
+    DWORD  result;
+
+    switch (origin)
+    {
+        case SEEK_SET:  method = FILE_BEGIN; break;
+        case SEEK_CUR:  method = FILE_CURRENT; break;
+        case SEEK_END:  method = FILE_END; break;
+        default:
+            errno = EINVAL;
+            return -1;
+    }
+
+    result = SetFilePointer( f->fh_handle, pos, NULL, method );
+    if (result == INVALID_SET_FILE_POINTER) {
+        errno = EIO;
+        return -1;
+    } else {
+        f->eof = 0;
+    }
+    return (int)result;
+}
+
+static void  _fh_file_hook( FH  f, int  event, EventHook  eventhook );  /* forward */
+
+static const FHClassRec  _fh_file_class =
+{
+    _fh_file_init,
+    _fh_file_close,
+    _fh_file_lseek,
+    _fh_file_read,
+    _fh_file_write,
+    _fh_file_hook
+};
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    file-based descriptor handling                              *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+int  adb_open(const char*  path, int  options)
+{
+    FH  f;
+
+    DWORD  desiredAccess       = 0;
+    DWORD  shareMode           = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+    switch (options) {
+        case O_RDONLY:
+            desiredAccess = GENERIC_READ;
+            break;
+        case O_WRONLY:
+            desiredAccess = GENERIC_WRITE;
+            break;
+        case O_RDWR:
+            desiredAccess = GENERIC_READ | GENERIC_WRITE;
+            break;
+        default:
+            D("adb_open: invalid options (0x%0x)\n", options);
+            errno = EINVAL;
+            return -1;
+    }
+
+    f = _fh_alloc( &_fh_file_class );
+    if ( !f ) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    f->fh_handle = CreateFile( path, desiredAccess, shareMode, NULL, OPEN_EXISTING,
+                               0, NULL );
+
+    if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+        _fh_close(f);
+        D( "adb_open: could not open '%s':", path );
+        switch (GetLastError()) {
+            case ERROR_FILE_NOT_FOUND:
+                D( "file not found\n" );
+                errno = ENOENT;
+                return -1;
+
+            case ERROR_PATH_NOT_FOUND:
+                D( "path not found\n" );
+                errno = ENOTDIR;
+                return -1;
+
+            default:
+                D( "unknown error\n" );
+                errno = ENOENT;
+                return -1;
+        }
+    }
+
+    snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
+    D( "adb_open: '%s' => fd %d\n", path, _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+/* ignore mode on Win32 */
+int  adb_creat(const char*  path, int  mode)
+{
+    FH  f;
+
+    f = _fh_alloc( &_fh_file_class );
+    if ( !f ) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    f->fh_handle = CreateFile( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+                               NULL );
+
+    if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+        _fh_close(f);
+        D( "adb_creat: could not open '%s':", path );
+        switch (GetLastError()) {
+            case ERROR_FILE_NOT_FOUND:
+                D( "file not found\n" );
+                errno = ENOENT;
+                return -1;
+
+            case ERROR_PATH_NOT_FOUND:
+                D( "path not found\n" );
+                errno = ENOTDIR;
+                return -1;
+
+            default:
+                D( "unknown error\n" );
+                errno = ENOENT;
+                return -1;
+        }
+    }
+    snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
+    D( "adb_creat: '%s' => fd %d\n", path, _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+
+int  adb_read(int  fd, void* buf, int len)
+{
+    FH     f = _fh_from_int(fd);
+
+    if (f == NULL) {
+        return -1;
+    }
+
+    return f->clazz->_fh_read( f, buf, len );
+}
+
+
+int  adb_write(int  fd, const void*  buf, int  len)
+{
+    FH     f = _fh_from_int(fd);
+
+    if (f == NULL) {
+        return -1;
+    }
+
+    return f->clazz->_fh_write(f, buf, len);
+}
+
+
+int  adb_lseek(int  fd, int  pos, int  where)
+{
+    FH     f = _fh_from_int(fd);
+
+    if (!f) {
+        return -1;
+    }
+
+    return f->clazz->_fh_lseek(f, pos, where);
+}
+
+
+int  adb_shutdown(int  fd)
+{
+    FH   f = _fh_from_int(fd);
+
+    if (!f) {
+        return -1;
+    }
+
+    D( "adb_shutdown: %s\n", f->name);
+    shutdown( f->fh_socket, SD_BOTH );
+    return 0;
+}
+
+
+int  adb_close(int  fd)
+{
+    FH   f = _fh_from_int(fd);
+
+    if (!f) {
+        return -1;
+    }
+
+    D( "adb_close: %s\n", f->name);
+    _fh_close(f);
+    return 0;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    socket-based file descriptors                               *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+static void
+_socket_set_errno( void )
+{
+    switch (WSAGetLastError()) {
+    case 0:              errno = 0; break;
+    case WSAEWOULDBLOCK: errno = EAGAIN; break;
+    case WSAEINTR:       errno = EINTR; break;
+    default:
+        D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() );
+        errno = EINVAL;
+    }
+}
+
+static void
+_fh_socket_init( FH  f )
+{
+    f->fh_socket = INVALID_SOCKET;
+    f->event     = WSACreateEvent();
+    f->mask      = 0;
+}
+
+static int
+_fh_socket_close( FH  f )
+{
+    /* gently tell any peer that we're closing the socket */
+    shutdown( f->fh_socket, SD_BOTH );
+    closesocket( f->fh_socket );
+    f->fh_socket = INVALID_SOCKET;
+    CloseHandle( f->event );
+    f->mask = 0;
+    return 0;
+}
+
+static int
+_fh_socket_lseek( FH  f, int pos, int origin )
+{
+    errno = EPIPE;
+    return -1;
+}
+
+static int
+_fh_socket_read( FH  f, void*  buf, int  len )
+{
+    int  result = recv( f->fh_socket, buf, len, 0 );
+    if (result == SOCKET_ERROR) {
+        _socket_set_errno();
+        result = -1;
+    }
+    return  result;
+}
+
+static int
+_fh_socket_write( FH  f, const void*  buf, int  len )
+{
+    int  result = send( f->fh_socket, buf, len, 0 );
+    if (result == SOCKET_ERROR) {
+        _socket_set_errno();
+        result = -1;
+    }
+    return result;
+}
+
+static void  _fh_socket_hook( FH  f, int  event, EventHook  hook );  /* forward */
+
+static const FHClassRec  _fh_socket_class =
+{
+    _fh_socket_init,
+    _fh_socket_close,
+    _fh_socket_lseek,
+    _fh_socket_read,
+    _fh_socket_write,
+    _fh_socket_hook
+};
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    replacement for libs/cutils/socket_xxxx.c                   *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+#include <winsock2.h>
+
+static int  _winsock_init;
+
+static void
+_cleanup_winsock( void )
+{
+    WSACleanup();
+}
+
+static void
+_init_winsock( void )
+{
+    if (!_winsock_init) {
+        WSADATA  wsaData;
+        int      rc = WSAStartup( MAKEWORD(2,2), &wsaData);
+        if (rc != 0) {
+            fatal( "adb: could not initialize Winsock\n" );
+        }
+        atexit( _cleanup_winsock );
+        _winsock_init = 1;
+    }
+}
+
+int socket_loopback_client(int port, int type)
+{
+    FH  f = _fh_alloc( &_fh_socket_class );
+    struct sockaddr_in addr;
+    SOCKET  s;
+
+    if (!f)
+        return -1;
+
+    if (!_winsock_init)
+        _init_winsock();
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    s = socket(AF_INET, type, 0);
+    if(s == INVALID_SOCKET) {
+        D("socket_loopback_client: could not create socket\n" );
+        _fh_close(f);
+        return -1;
+    }
+
+    f->fh_socket = s;
+    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port );
+        _fh_close(f);
+        return -1;
+    }
+    snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
+    D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+#define LISTEN_BACKLOG 4
+
+int socket_loopback_server(int port, int type)
+{
+    FH   f = _fh_alloc( &_fh_socket_class );
+    struct sockaddr_in addr;
+    SOCKET  s;
+    int  n;
+
+    if (!f) {
+        return -1;
+    }
+
+    if (!_winsock_init)
+        _init_winsock();
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    s = socket(AF_INET, type, 0);
+    if(s == INVALID_SOCKET) return -1;
+
+    f->fh_socket = s;
+
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        _fh_close(f);
+        return -1;
+    }
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+        if (ret < 0) {
+            _fh_close(f);
+            return -1;
+        }
+    }
+    snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
+    D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+
+int socket_network_client(const char *host, int port, int type)
+{
+    FH  f = _fh_alloc( &_fh_socket_class );
+    struct hostent *hp;
+    struct sockaddr_in addr;
+    SOCKET s;
+
+    if (!f)
+        return -1;
+
+    if (!_winsock_init)
+        _init_winsock();
+
+    hp = gethostbyname(host);
+    if(hp == 0) {
+        _fh_close(f);
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = hp->h_addrtype;
+    addr.sin_port = htons(port);
+    memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
+
+    s = socket(hp->h_addrtype, type, 0);
+    if(s == INVALID_SOCKET) {
+        _fh_close(f);
+        return -1;
+    }
+    f->fh_socket = s;
+
+    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        _fh_close(f);
+        return -1;
+    }
+
+    snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
+    D( "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+
+int socket_network_client_timeout(const char *host, int port, int type, int timeout)
+{
+    // TODO: implement timeouts for Windows.
+    return socket_network_client(host, port, type);
+}
+
+
+int socket_inaddr_any_server(int port, int type)
+{
+    FH  f = _fh_alloc( &_fh_socket_class );
+    struct sockaddr_in addr;
+    SOCKET  s;
+    int n;
+
+    if (!f)
+        return -1;
+
+    if (!_winsock_init)
+        _init_winsock();
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+    s = socket(AF_INET, type, 0);
+    if(s == INVALID_SOCKET) {
+        _fh_close(f);
+        return -1;
+    }
+
+    f->fh_socket = s;
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        _fh_close(f);
+        return -1;
+    }
+
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+        if (ret < 0) {
+            _fh_close(f);
+            return -1;
+        }
+    }
+    snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
+    D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+#undef accept
+int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
+{
+    FH   serverfh = _fh_from_int(serverfd);
+    FH   fh;
+
+    if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
+        D( "adb_socket_accept: invalid fd %d\n", serverfd );
+        return -1;
+    }
+
+    fh = _fh_alloc( &_fh_socket_class );
+    if (!fh) {
+        D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
+        return -1;
+    }
+
+    fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
+    if (fh->fh_socket == INVALID_SOCKET) {
+        _fh_close( fh );
+        D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
+        return -1;
+    }
+
+    snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
+    D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
+    return  _fh_to_int(fh);
+}
+
+
+void  disable_tcp_nagle(int fd)
+{
+    FH   fh = _fh_from_int(fd);
+    int  on = 1;
+
+    if ( !fh || fh->clazz != &_fh_socket_class )
+        return;
+
+    setsockopt( fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on) );
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    emulated socketpairs                                       *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+/* we implement socketpairs directly in use space for the following reasons:
+ *   - it avoids copying data from/to the Nt kernel
+ *   - it allows us to implement fdevent hooks easily and cheaply, something
+ *     that is not possible with standard Win32 pipes !!
+ *
+ * basically, we use two circular buffers, each one corresponding to a given
+ * direction.
+ *
+ * each buffer is implemented as two regions:
+ *
+ *   region A which is (a_start,a_end)
+ *   region B which is (0, b_end)  with b_end <= a_start
+ *
+ * an empty buffer has:  a_start = a_end = b_end = 0
+ *
+ * a_start is the pointer where we start reading data
+ * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE,
+ * then you start writing at b_end
+ *
+ * the buffer is full when  b_end == a_start && a_end == BUFFER_SIZE
+ *
+ * there is room when b_end < a_start || a_end < BUFER_SIZE
+ *
+ * when reading, a_start is incremented, it a_start meets a_end, then
+ * we do:  a_start = 0, a_end = b_end, b_end = 0, and keep going on..
+ */
+
+#define  BIP_BUFFER_SIZE   4096
+
+#if 0
+#include <stdio.h>
+#  define  BIPD(x)      D x
+#  define  BIPDUMP   bip_dump_hex
+
+static void  bip_dump_hex( const unsigned char*  ptr, size_t  len )
+{
+    int  nn, len2 = len;
+
+    if (len2 > 8) len2 = 8;
+
+    for (nn = 0; nn < len2; nn++)
+        printf("%02x", ptr[nn]);
+    printf("  ");
+
+    for (nn = 0; nn < len2; nn++) {
+        int  c = ptr[nn];
+        if (c < 32 || c > 127)
+            c = '.';
+        printf("%c", c);
+    }
+    printf("\n");
+    fflush(stdout);
+}
+
+#else
+#  define  BIPD(x)        do {} while (0)
+#  define  BIPDUMP(p,l)   BIPD(p)
+#endif
+
+typedef struct BipBufferRec_
+{
+    int                a_start;
+    int                a_end;
+    int                b_end;
+    int                fdin;
+    int                fdout;
+    int                closed;
+    int                can_write;  /* boolean */
+    HANDLE             evt_write;  /* event signaled when one can write to a buffer  */
+    int                can_read;   /* boolean */
+    HANDLE             evt_read;   /* event signaled when one can read from a buffer */
+    CRITICAL_SECTION  lock;
+    unsigned char      buff[ BIP_BUFFER_SIZE ];
+
+} BipBufferRec, *BipBuffer;
+
+static void
+bip_buffer_init( BipBuffer  buffer )
+{
+    D( "bit_buffer_init %p\n", buffer );
+    buffer->a_start   = 0;
+    buffer->a_end     = 0;
+    buffer->b_end     = 0;
+    buffer->can_write = 1;
+    buffer->can_read  = 0;
+    buffer->fdin      = 0;
+    buffer->fdout     = 0;
+    buffer->closed    = 0;
+    buffer->evt_write = CreateEvent( NULL, TRUE, TRUE, NULL );
+    buffer->evt_read  = CreateEvent( NULL, TRUE, FALSE, NULL );
+    InitializeCriticalSection( &buffer->lock );
+}
+
+static void
+bip_buffer_close( BipBuffer  bip )
+{
+    bip->closed = 1;
+
+    if (!bip->can_read) {
+        SetEvent( bip->evt_read );
+    }
+    if (!bip->can_write) {
+        SetEvent( bip->evt_write );
+    }
+}
+
+static void
+bip_buffer_done( BipBuffer  bip )
+{
+    BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout ));
+    CloseHandle( bip->evt_read );
+    CloseHandle( bip->evt_write );
+    DeleteCriticalSection( &bip->lock );
+}
+
+static int
+bip_buffer_write( BipBuffer  bip, const void* src, int  len )
+{
+    int  avail, count = 0;
+
+    if (len <= 0)
+        return 0;
+
+    BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
+    BIPDUMP( src, len );
+
+    EnterCriticalSection( &bip->lock );
+
+    while (!bip->can_write) {
+        int  ret;
+        LeaveCriticalSection( &bip->lock );
+
+        if (bip->closed) {
+            errno = EPIPE;
+            return -1;
+        }
+        /* spinlocking here is probably unfair, but let's live with it */
+        ret = WaitForSingleObject( bip->evt_write, INFINITE );
+        if (ret != WAIT_OBJECT_0) {  /* buffer probably closed */
+            D( "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError() );
+            return 0;
+        }
+        if (bip->closed) {
+            errno = EPIPE;
+            return -1;
+        }
+        EnterCriticalSection( &bip->lock );
+    }
+
+    BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
+
+    avail = BIP_BUFFER_SIZE - bip->a_end;
+    if (avail > 0)
+    {
+        /* we can append to region A */
+        if (avail > len)
+            avail = len;
+
+        memcpy( bip->buff + bip->a_end, src, avail );
+        src   = (const char *)src + avail;
+        count += avail;
+        len   -= avail;
+
+        bip->a_end += avail;
+        if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
+            bip->can_write = 0;
+            ResetEvent( bip->evt_write );
+            goto Exit;
+        }
+    }
+
+    if (len == 0)
+        goto Exit;
+
+    avail = bip->a_start - bip->b_end;
+    assert( avail > 0 );  /* since can_write is TRUE */
+
+    if (avail > len)
+        avail = len;
+
+    memcpy( bip->buff + bip->b_end, src, avail );
+    count += avail;
+    bip->b_end += avail;
+
+    if (bip->b_end == bip->a_start) {
+        bip->can_write = 0;
+        ResetEvent( bip->evt_write );
+    }
+
+Exit:
+    assert( count > 0 );
+
+    if ( !bip->can_read ) {
+        bip->can_read = 1;
+        SetEvent( bip->evt_read );
+    }
+
+    BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
+            bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
+    LeaveCriticalSection( &bip->lock );
+
+    return count;
+ }
+
+static int
+bip_buffer_read( BipBuffer  bip, void*  dst, int  len )
+{
+    int  avail, count = 0;
+
+    if (len <= 0)
+        return 0;
+
+    BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
+
+    EnterCriticalSection( &bip->lock );
+    while ( !bip->can_read )
+    {
+#if 0
+        LeaveCriticalSection( &bip->lock );
+        errno = EAGAIN;
+        return -1;
+#else
+        int  ret;
+        LeaveCriticalSection( &bip->lock );
+
+        if (bip->closed) {
+            errno = EPIPE;
+            return -1;
+        }
+
+        ret = WaitForSingleObject( bip->evt_read, INFINITE );
+        if (ret != WAIT_OBJECT_0) { /* probably closed buffer */
+            D( "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
+            return 0;
+        }
+        if (bip->closed) {
+            errno = EPIPE;
+            return -1;
+        }
+        EnterCriticalSection( &bip->lock );
+#endif
+    }
+
+    BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
+
+    avail = bip->a_end - bip->a_start;
+    assert( avail > 0 );  /* since can_read is TRUE */
+
+    if (avail > len)
+        avail = len;
+
+    memcpy( dst, bip->buff + bip->a_start, avail );
+    dst   = (char *)dst + avail;
+    count += avail;
+    len   -= avail;
+
+    bip->a_start += avail;
+    if (bip->a_start < bip->a_end)
+        goto Exit;
+
+    bip->a_start = 0;
+    bip->a_end   = bip->b_end;
+    bip->b_end   = 0;
+
+    avail = bip->a_end;
+    if (avail > 0) {
+        if (avail > len)
+            avail = len;
+        memcpy( dst, bip->buff, avail );
+        count += avail;
+        bip->a_start += avail;
+
+        if ( bip->a_start < bip->a_end )
+            goto Exit;
+
+        bip->a_start = bip->a_end = 0;
+    }
+
+    bip->can_read = 0;
+    ResetEvent( bip->evt_read );
+
+Exit:
+    assert( count > 0 );
+
+    if (!bip->can_write ) {
+        bip->can_write = 1;
+        SetEvent( bip->evt_write );
+    }
+
+    BIPDUMP( (const unsigned char*)dst - count, count );
+    BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
+            bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
+    LeaveCriticalSection( &bip->lock );
+
+    return count;
+}
+
+typedef struct SocketPairRec_
+{
+    BipBufferRec  a2b_bip;
+    BipBufferRec  b2a_bip;
+    FH            a_fd;
+    int           used;
+
+} SocketPairRec;
+
+void _fh_socketpair_init( FH  f )
+{
+    f->fh_pair = NULL;
+}
+
+static int
+_fh_socketpair_close( FH  f )
+{
+    if ( f->fh_pair ) {
+        SocketPair  pair = f->fh_pair;
+
+        if ( f == pair->a_fd ) {
+            pair->a_fd = NULL;
+        }
+
+        bip_buffer_close( &pair->b2a_bip );
+        bip_buffer_close( &pair->a2b_bip );
+
+        if ( --pair->used == 0 ) {
+            bip_buffer_done( &pair->b2a_bip );
+            bip_buffer_done( &pair->a2b_bip );
+            free( pair );
+        }
+        f->fh_pair = NULL;
+    }
+    return 0;
+}
+
+static int
+_fh_socketpair_lseek( FH  f, int pos, int  origin )
+{
+    errno = ESPIPE;
+    return -1;
+}
+
+static int
+_fh_socketpair_read( FH  f, void* buf, int  len )
+{
+    SocketPair  pair = f->fh_pair;
+    BipBuffer   bip;
+
+    if (!pair)
+        return -1;
+
+    if ( f == pair->a_fd )
+        bip = &pair->b2a_bip;
+    else
+        bip = &pair->a2b_bip;
+
+    return bip_buffer_read( bip, buf, len );
+}
+
+static int
+_fh_socketpair_write( FH  f, const void*  buf, int  len )
+{
+    SocketPair  pair = f->fh_pair;
+    BipBuffer   bip;
+
+    if (!pair)
+        return -1;
+
+    if ( f == pair->a_fd )
+        bip = &pair->a2b_bip;
+    else
+        bip = &pair->b2a_bip;
+
+    return bip_buffer_write( bip, buf, len );
+}
+
+
+static void  _fh_socketpair_hook( FH  f, int  event, EventHook  hook );  /* forward */
+
+static const FHClassRec  _fh_socketpair_class =
+{
+    _fh_socketpair_init,
+    _fh_socketpair_close,
+    _fh_socketpair_lseek,
+    _fh_socketpair_read,
+    _fh_socketpair_write,
+    _fh_socketpair_hook
+};
+
+
+int  adb_socketpair( int  sv[2] )
+{
+    FH          fa, fb;
+    SocketPair  pair;
+
+    fa = _fh_alloc( &_fh_socketpair_class );
+    fb = _fh_alloc( &_fh_socketpair_class );
+
+    if (!fa || !fb)
+        goto Fail;
+
+    pair = malloc( sizeof(*pair) );
+    if (pair == NULL) {
+        D("adb_socketpair: not enough memory to allocate pipes\n" );
+        goto Fail;
+    }
+
+    bip_buffer_init( &pair->a2b_bip );
+    bip_buffer_init( &pair->b2a_bip );
+
+    fa->fh_pair = pair;
+    fb->fh_pair = pair;
+    pair->used  = 2;
+    pair->a_fd  = fa;
+
+    sv[0] = _fh_to_int(fa);
+    sv[1] = _fh_to_int(fb);
+
+    pair->a2b_bip.fdin  = sv[0];
+    pair->a2b_bip.fdout = sv[1];
+    pair->b2a_bip.fdin  = sv[1];
+    pair->b2a_bip.fdout = sv[0];
+
+    snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] );
+    snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
+    D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] );
+    return 0;
+
+Fail:
+    _fh_close(fb);
+    _fh_close(fa);
+    return -1;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    fdevents emulation                                          *****/
+/*****                                                                *****/
+/*****   this is a very simple implementation, we rely on the fact    *****/
+/*****   that ADB doesn't use FDE_ERROR.                              *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+#define FATAL(x...) fatal(__FUNCTION__, x)
+
+#if DEBUG
+static void dump_fde(fdevent *fde, const char *info)
+{
+    fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
+            fde->state & FDE_READ ? 'R' : ' ',
+            fde->state & FDE_WRITE ? 'W' : ' ',
+            fde->state & FDE_ERROR ? 'E' : ' ',
+            info);
+}
+#else
+#define dump_fde(fde, info) do { } while(0)
+#endif
+
+#define FDE_EVENTMASK  0x00ff
+#define FDE_STATEMASK  0xff00
+
+#define FDE_ACTIVE     0x0100
+#define FDE_PENDING    0x0200
+#define FDE_CREATED    0x0400
+
+static void fdevent_plist_enqueue(fdevent *node);
+static void fdevent_plist_remove(fdevent *node);
+static fdevent *fdevent_plist_dequeue(void);
+
+static fdevent list_pending = {
+    .next = &list_pending,
+    .prev = &list_pending,
+};
+
+static fdevent **fd_table = 0;
+static int       fd_table_max = 0;
+
+typedef struct EventLooperRec_*  EventLooper;
+
+typedef struct EventHookRec_
+{
+    EventHook    next;
+    FH           fh;
+    HANDLE       h;
+    int          wanted;   /* wanted event flags */
+    int          ready;    /* ready event flags  */
+    void*        aux;
+    void        (*prepare)( EventHook  hook );
+    int         (*start)  ( EventHook  hook );
+    void        (*stop)   ( EventHook  hook );
+    int         (*check)  ( EventHook  hook );
+    int         (*peek)   ( EventHook  hook );
+} EventHookRec;
+
+static EventHook  _free_hooks;
+
+static EventHook
+event_hook_alloc( FH  fh )
+{
+    EventHook  hook = _free_hooks;
+    if (hook != NULL)
+        _free_hooks = hook->next;
+    else {
+        hook = malloc( sizeof(*hook) );
+        if (hook == NULL)
+            fatal( "could not allocate event hook\n" );
+    }
+    hook->next   = NULL;
+    hook->fh     = fh;
+    hook->wanted = 0;
+    hook->ready  = 0;
+    hook->h      = INVALID_HANDLE_VALUE;
+    hook->aux    = NULL;
+
+    hook->prepare = NULL;
+    hook->start   = NULL;
+    hook->stop    = NULL;
+    hook->check   = NULL;
+    hook->peek    = NULL;
+
+    return hook;
+}
+
+static void
+event_hook_free( EventHook  hook )
+{
+    hook->fh     = NULL;
+    hook->wanted = 0;
+    hook->ready  = 0;
+    hook->next   = _free_hooks;
+    _free_hooks  = hook;
+}
+
+
+static void
+event_hook_signal( EventHook  hook )
+{
+    FH        f   = hook->fh;
+    int       fd  = _fh_to_int(f);
+    fdevent*  fde = fd_table[ fd - WIN32_FH_BASE ];
+
+    if (fde != NULL && fde->fd == fd) {
+        if ((fde->state & FDE_PENDING) == 0) {
+            fde->state |= FDE_PENDING;
+            fdevent_plist_enqueue( fde );
+        }
+        fde->events |= hook->wanted;
+    }
+}
+
+
+#define  MAX_LOOPER_HANDLES  WIN32_MAX_FHS
+
+typedef struct EventLooperRec_
+{
+    EventHook    hooks;
+    HANDLE       htab[ MAX_LOOPER_HANDLES ];
+    int          htab_count;
+
+} EventLooperRec;
+
+static EventHook*
+event_looper_find_p( EventLooper  looper, FH  fh )
+{
+    EventHook  *pnode = &looper->hooks;
+    EventHook   node  = *pnode;
+    for (;;) {
+        if ( node == NULL || node->fh == fh )
+            break;
+        pnode = &node->next;
+        node  = *pnode;
+    }
+    return  pnode;
+}
+
+static void
+event_looper_hook( EventLooper  looper, int  fd, int  events )
+{
+    FH          f = _fh_from_int(fd);
+    EventHook  *pnode;
+    EventHook   node;
+
+    if (f == NULL)  /* invalid arg */ {
+        D("event_looper_hook: invalid fd=%d\n", fd);
+        return;
+    }
+
+    pnode = event_looper_find_p( looper, f );
+    node  = *pnode;
+    if ( node == NULL ) {
+        node       = event_hook_alloc( f );
+        node->next = *pnode;
+        *pnode     = node;
+    }
+
+    if ( (node->wanted & events) != events ) {
+        /* this should update start/stop/check/peek */
+        D("event_looper_hook: call hook for %d (new=%x, old=%x)\n",
+           fd, node->wanted, events);
+        f->clazz->_fh_hook( f, events & ~node->wanted, node );
+        node->wanted |= events;
+    } else {
+        D("event_looper_hook: ignoring events %x for %d wanted=%x)\n",
+           events, fd, node->wanted);
+    }
+}
+
+static void
+event_looper_unhook( EventLooper  looper, int  fd, int  events )
+{
+    FH          fh    = _fh_from_int(fd);
+    EventHook  *pnode = event_looper_find_p( looper, fh );
+    EventHook   node  = *pnode;
+
+    if (node != NULL) {
+        int  events2 = events & node->wanted;
+        if ( events2 == 0 ) {
+            D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd );
+            return;
+        }
+        node->wanted &= ~events2;
+        if (!node->wanted) {
+            *pnode = node->next;
+            event_hook_free( node );
+        }
+    }
+}
+
+/*
+ * A fixer for WaitForMultipleObjects on condition that there are more than 64
+ * handles to wait on.
+ *
+ * In cetain cases DDMS may establish more than 64 connections with ADB. For
+ * instance, this may happen if there are more than 64 processes running on a
+ * device, or there are multiple devices connected (including the emulator) with
+ * the combined number of running processes greater than 64. In this case using
+ * WaitForMultipleObjects to wait on connection events simply wouldn't cut,
+ * because of the API limitations (64 handles max). So, we need to provide a way
+ * to scale WaitForMultipleObjects to accept an arbitrary number of handles. The
+ * easiest (and "Microsoft recommended") way to do that would be dividing the
+ * handle array into chunks with the chunk size less than 64, and fire up as many
+ * waiting threads as there are chunks. Then each thread would wait on a chunk of
+ * handles, and will report back to the caller which handle has been set.
+ * Here is the implementation of that algorithm.
+ */
+
+/* Number of handles to wait on in each wating thread. */
+#define WAIT_ALL_CHUNK_SIZE 63
+
+/* Descriptor for a wating thread */
+typedef struct WaitForAllParam {
+    /* A handle to an event to signal when waiting is over. This handle is shared
+     * accross all the waiting threads, so each waiting thread knows when any
+     * other thread has exited, so it can exit too. */
+    HANDLE          main_event;
+    /* Upon exit from a waiting thread contains the index of the handle that has
+     * been signaled. The index is an absolute index of the signaled handle in
+     * the original array. This pointer is shared accross all the waiting threads
+     * and it's not guaranteed (due to a race condition) that when all the
+     * waiting threads exit, the value contained here would indicate the first
+     * handle that was signaled. This is fine, because the caller cares only
+     * about any handle being signaled. It doesn't care about the order, nor
+     * about the whole list of handles that were signaled. */
+    LONG volatile   *signaled_index;
+    /* Array of handles to wait on in a waiting thread. */
+    HANDLE*         handles;
+    /* Number of handles in 'handles' array to wait on. */
+    int             handles_count;
+    /* Index inside the main array of the first handle in the 'handles' array. */
+    int             first_handle_index;
+    /* Waiting thread handle. */
+    HANDLE          thread;
+} WaitForAllParam;
+
+/* Waiting thread routine. */
+static unsigned __stdcall
+_in_waiter_thread(void*  arg)
+{
+    HANDLE wait_on[WAIT_ALL_CHUNK_SIZE + 1];
+    int res;
+    WaitForAllParam* const param = (WaitForAllParam*)arg;
+
+    /* We have to wait on the main_event in order to be notified when any of the
+     * sibling threads is exiting. */
+    wait_on[0] = param->main_event;
+    /* The rest of the handles go behind the main event handle. */
+    memcpy(wait_on + 1, param->handles, param->handles_count * sizeof(HANDLE));
+
+    res = WaitForMultipleObjects(param->handles_count + 1, wait_on, FALSE, INFINITE);
+    if (res > 0 && res < (param->handles_count + 1)) {
+        /* One of the original handles got signaled. Save its absolute index into
+         * the output variable. */
+        InterlockedCompareExchange(param->signaled_index,
+                                   res - 1L + param->first_handle_index, -1L);
+    }
+
+    /* Notify the caller (and the siblings) that the wait is over. */
+    SetEvent(param->main_event);
+
+    _endthreadex(0);
+    return 0;
+}
+
+/* WaitForMultipeObjects fixer routine.
+ * Param:
+ *  handles Array of handles to wait on.
+ *  handles_count Number of handles in the array.
+ * Return:
+ *  (>= 0 && < handles_count) - Index of the signaled handle in the array, or
+ *  WAIT_FAILED on an error.
+ */
+static int
+_wait_for_all(HANDLE* handles, int handles_count)
+{
+    WaitForAllParam* threads;
+    HANDLE main_event;
+    int chunks, chunk, remains;
+
+    /* This variable is going to be accessed by several threads at the same time,
+     * this is bound to fail randomly when the core is run on multi-core machines.
+     * To solve this, we need to do the following (1 _and_ 2):
+     * 1. Use the "volatile" qualifier to ensure the compiler doesn't optimize
+     *    out the reads/writes in this function unexpectedly.
+     * 2. Ensure correct memory ordering. The "simple" way to do that is to wrap
+     *    all accesses inside a critical section. But we can also use
+     *    InterlockedCompareExchange() which always provide a full memory barrier
+     *    on Win32.
+     */
+    volatile LONG sig_index = -1;
+
+    /* Calculate number of chunks, and allocate thread param array. */
+    chunks = handles_count / WAIT_ALL_CHUNK_SIZE;
+    remains = handles_count % WAIT_ALL_CHUNK_SIZE;
+    threads = (WaitForAllParam*)malloc((chunks + (remains ? 1 : 0)) *
+                                        sizeof(WaitForAllParam));
+    if (threads == NULL) {
+        D("Unable to allocate thread array for %d handles.", handles_count);
+        return (int)WAIT_FAILED;
+    }
+
+    /* Create main event to wait on for all waiting threads. This is a "manualy
+     * reset" event that will remain set once it was set. */
+    main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (main_event == NULL) {
+        D("Unable to create main event. Error: %d", (int)GetLastError());
+        free(threads);
+        return (int)WAIT_FAILED;
+    }
+
+    /*
+     * Initialize waiting thread parameters.
+     */
+
+    for (chunk = 0; chunk < chunks; chunk++) {
+        threads[chunk].main_event = main_event;
+        threads[chunk].signaled_index = &sig_index;
+        threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
+        threads[chunk].handles = handles + threads[chunk].first_handle_index;
+        threads[chunk].handles_count = WAIT_ALL_CHUNK_SIZE;
+    }
+    if (remains) {
+        threads[chunk].main_event = main_event;
+        threads[chunk].signaled_index = &sig_index;
+        threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
+        threads[chunk].handles = handles + threads[chunk].first_handle_index;
+        threads[chunk].handles_count = remains;
+        chunks++;
+    }
+
+    /* Start the waiting threads. */
+    for (chunk = 0; chunk < chunks; chunk++) {
+        /* Note that using adb_thread_create is not appropriate here, since we
+         * need a handle to wait on for thread termination. */
+        threads[chunk].thread = (HANDLE)_beginthreadex(NULL, 0, _in_waiter_thread,
+                                                       &threads[chunk], 0, NULL);
+        if (threads[chunk].thread == NULL) {
+            /* Unable to create a waiter thread. Collapse. */
+            D("Unable to create a waiting thread %d of %d. errno=%d",
+              chunk, chunks, errno);
+            chunks = chunk;
+            SetEvent(main_event);
+            break;
+        }
+    }
+
+    /* Wait on any of the threads to get signaled. */
+    WaitForSingleObject(main_event, INFINITE);
+
+    /* Wait on all the waiting threads to exit. */
+    for (chunk = 0; chunk < chunks; chunk++) {
+        WaitForSingleObject(threads[chunk].thread, INFINITE);
+        CloseHandle(threads[chunk].thread);
+    }
+
+    CloseHandle(main_event);
+    free(threads);
+
+
+    const int ret = (int)InterlockedCompareExchange(&sig_index, -1, -1);
+    return (ret >= 0) ? ret : (int)WAIT_FAILED;
+}
+
+static EventLooperRec  win32_looper;
+
+static void fdevent_init(void)
+{
+    win32_looper.htab_count = 0;
+    win32_looper.hooks      = NULL;
+}
+
+static void fdevent_connect(fdevent *fde)
+{
+    EventLooper  looper = &win32_looper;
+    int          events = fde->state & FDE_EVENTMASK;
+
+    if (events != 0)
+        event_looper_hook( looper, fde->fd, events );
+}
+
+static void fdevent_disconnect(fdevent *fde)
+{
+    EventLooper  looper = &win32_looper;
+    int          events = fde->state & FDE_EVENTMASK;
+
+    if (events != 0)
+        event_looper_unhook( looper, fde->fd, events );
+}
+
+static void fdevent_update(fdevent *fde, unsigned events)
+{
+    EventLooper  looper  = &win32_looper;
+    unsigned     events0 = fde->state & FDE_EVENTMASK;
+
+    if (events != events0) {
+        int  removes = events0 & ~events;
+        int  adds    = events  & ~events0;
+        if (removes) {
+            D("fdevent_update: remove %x from %d\n", removes, fde->fd);
+            event_looper_unhook( looper, fde->fd, removes );
+        }
+        if (adds) {
+            D("fdevent_update: add %x to %d\n", adds, fde->fd);
+            event_looper_hook  ( looper, fde->fd, adds );
+        }
+    }
+}
+
+static void fdevent_process()
+{
+    EventLooper  looper = &win32_looper;
+    EventHook    hook;
+    int          gotone = 0;
+
+    /* if we have at least one ready hook, execute it/them */
+    for (hook = looper->hooks; hook; hook = hook->next) {
+        hook->ready = 0;
+        if (hook->prepare) {
+            hook->prepare(hook);
+            if (hook->ready != 0) {
+                event_hook_signal( hook );
+                gotone = 1;
+            }
+        }
+    }
+
+    /* nothing's ready yet, so wait for something to happen */
+    if (!gotone)
+    {
+        looper->htab_count = 0;
+
+        for (hook = looper->hooks; hook; hook = hook->next)
+        {
+            if (hook->start && !hook->start(hook)) {
+                D( "fdevent_process: error when starting a hook\n" );
+                return;
+            }
+            if (hook->h != INVALID_HANDLE_VALUE) {
+                int  nn;
+
+                for (nn = 0; nn < looper->htab_count; nn++)
+                {
+                    if ( looper->htab[nn] == hook->h )
+                        goto DontAdd;
+                }
+                looper->htab[ looper->htab_count++ ] = hook->h;
+            DontAdd:
+                ;
+            }
+        }
+
+        if (looper->htab_count == 0) {
+            D( "fdevent_process: nothing to wait for !!\n" );
+            return;
+        }
+
+        do
+        {
+            int   wait_ret;
+
+            D( "adb_win32: waiting for %d events\n", looper->htab_count );
+            if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) {
+                D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS.\n", looper->htab_count);
+                wait_ret = _wait_for_all(looper->htab, looper->htab_count);
+            } else {
+                wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE );
+            }
+            if (wait_ret == (int)WAIT_FAILED) {
+                D( "adb_win32: wait failed, error %ld\n", GetLastError() );
+            } else {
+                D( "adb_win32: got one (index %d)\n", wait_ret );
+
+                /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
+                 * like mouse movements. we need to filter these with the "check" function
+                 */
+                if ((unsigned)wait_ret < (unsigned)looper->htab_count)
+                {
+                    for (hook = looper->hooks; hook; hook = hook->next)
+                    {
+                        if ( looper->htab[wait_ret] == hook->h       &&
+                         (!hook->check || hook->check(hook)) )
+                        {
+                            D( "adb_win32: signaling %s for %x\n", hook->fh->name, hook->ready );
+                            event_hook_signal( hook );
+                            gotone = 1;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        while (!gotone);
+
+        for (hook = looper->hooks; hook; hook = hook->next) {
+            if (hook->stop)
+                hook->stop( hook );
+        }
+    }
+
+    for (hook = looper->hooks; hook; hook = hook->next) {
+        if (hook->peek && hook->peek(hook))
+                event_hook_signal( hook );
+    }
+}
+
+
+static void fdevent_register(fdevent *fde)
+{
+    int  fd = fde->fd - WIN32_FH_BASE;
+
+    if(fd < 0) {
+        FATAL("bogus negative fd (%d)\n", fde->fd);
+    }
+
+    if(fd >= fd_table_max) {
+        int oldmax = fd_table_max;
+        if(fde->fd > 32000) {
+            FATAL("bogus huuuuge fd (%d)\n", fde->fd);
+        }
+        if(fd_table_max == 0) {
+            fdevent_init();
+            fd_table_max = 256;
+        }
+        while(fd_table_max <= fd) {
+            fd_table_max *= 2;
+        }
+        fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
+        if(fd_table == 0) {
+            FATAL("could not expand fd_table to %d entries\n", fd_table_max);
+        }
+        memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
+    }
+
+    fd_table[fd] = fde;
+}
+
+static void fdevent_unregister(fdevent *fde)
+{
+    int  fd = fde->fd - WIN32_FH_BASE;
+
+    if((fd < 0) || (fd >= fd_table_max)) {
+        FATAL("fd out of range (%d)\n", fde->fd);
+    }
+
+    if(fd_table[fd] != fde) {
+        FATAL("fd_table out of sync");
+    }
+
+    fd_table[fd] = 0;
+
+    if(!(fde->state & FDE_DONT_CLOSE)) {
+        dump_fde(fde, "close");
+        adb_close(fde->fd);
+    }
+}
+
+static void fdevent_plist_enqueue(fdevent *node)
+{
+    fdevent *list = &list_pending;
+
+    node->next = list;
+    node->prev = list->prev;
+    node->prev->next = node;
+    list->prev = node;
+}
+
+static void fdevent_plist_remove(fdevent *node)
+{
+    node->prev->next = node->next;
+    node->next->prev = node->prev;
+    node->next = 0;
+    node->prev = 0;
+}
+
+static fdevent *fdevent_plist_dequeue(void)
+{
+    fdevent *list = &list_pending;
+    fdevent *node = list->next;
+
+    if(node == list) return 0;
+
+    list->next = node->next;
+    list->next->prev = list;
+    node->next = 0;
+    node->prev = 0;
+
+    return node;
+}
+
+fdevent *fdevent_create(int fd, fd_func func, void *arg)
+{
+    fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
+    if(fde == 0) return 0;
+    fdevent_install(fde, fd, func, arg);
+    fde->state |= FDE_CREATED;
+    return fde;
+}
+
+void fdevent_destroy(fdevent *fde)
+{
+    if(fde == 0) return;
+    if(!(fde->state & FDE_CREATED)) {
+        FATAL("fde %p not created by fdevent_create()\n", fde);
+    }
+    fdevent_remove(fde);
+}
+
+void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
+{
+    memset(fde, 0, sizeof(fdevent));
+    fde->state = FDE_ACTIVE;
+    fde->fd = fd;
+    fde->func = func;
+    fde->arg = arg;
+
+    fdevent_register(fde);
+    dump_fde(fde, "connect");
+    fdevent_connect(fde);
+    fde->state |= FDE_ACTIVE;
+}
+
+void fdevent_remove(fdevent *fde)
+{
+    if(fde->state & FDE_PENDING) {
+        fdevent_plist_remove(fde);
+    }
+
+    if(fde->state & FDE_ACTIVE) {
+        fdevent_disconnect(fde);
+        dump_fde(fde, "disconnect");
+        fdevent_unregister(fde);
+    }
+
+    fde->state = 0;
+    fde->events = 0;
+}
+
+
+void fdevent_set(fdevent *fde, unsigned events)
+{
+    events &= FDE_EVENTMASK;
+
+    if((fde->state & FDE_EVENTMASK) == (int)events) return;
+
+    if(fde->state & FDE_ACTIVE) {
+        fdevent_update(fde, events);
+        dump_fde(fde, "update");
+    }
+
+    fde->state = (fde->state & FDE_STATEMASK) | events;
+
+    if(fde->state & FDE_PENDING) {
+            /* if we're pending, make sure
+            ** we don't signal an event that
+            ** is no longer wanted.
+            */
+        fde->events &= (~events);
+        if(fde->events == 0) {
+            fdevent_plist_remove(fde);
+            fde->state &= (~FDE_PENDING);
+        }
+    }
+}
+
+void fdevent_add(fdevent *fde, unsigned events)
+{
+    fdevent_set(
+        fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
+}
+
+void fdevent_del(fdevent *fde, unsigned events)
+{
+    fdevent_set(
+        fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
+}
+
+void fdevent_loop()
+{
+    fdevent *fde;
+
+    for(;;) {
+#if DEBUG
+        fprintf(stderr,"--- ---- waiting for events\n");
+#endif
+        fdevent_process();
+
+        while((fde = fdevent_plist_dequeue())) {
+            unsigned events = fde->events;
+            fde->events = 0;
+            fde->state &= (~FDE_PENDING);
+            dump_fde(fde, "callback");
+            fde->func(fde->fd, events, fde->arg);
+        }
+    }
+}
+
+/**  FILE EVENT HOOKS
+ **/
+
+static void  _event_file_prepare( EventHook  hook )
+{
+    if (hook->wanted & (FDE_READ|FDE_WRITE)) {
+        /* we can always read/write */
+        hook->ready |= hook->wanted & (FDE_READ|FDE_WRITE);
+    }
+}
+
+static int  _event_file_peek( EventHook  hook )
+{
+    return (hook->wanted & (FDE_READ|FDE_WRITE));
+}
+
+static void  _fh_file_hook( FH  f, int  events, EventHook  hook )
+{
+    hook->h       = f->fh_handle;
+    hook->prepare = _event_file_prepare;
+    hook->peek    = _event_file_peek;
+}
+
+/** SOCKET EVENT HOOKS
+ **/
+
+static void  _event_socket_verify( EventHook  hook, WSANETWORKEVENTS*  evts )
+{
+    if ( evts->lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE) ) {
+        if (hook->wanted & FDE_READ)
+            hook->ready |= FDE_READ;
+        if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR)
+            hook->ready |= FDE_ERROR;
+    }
+    if ( evts->lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE) ) {
+        if (hook->wanted & FDE_WRITE)
+            hook->ready |= FDE_WRITE;
+        if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR)
+            hook->ready |= FDE_ERROR;
+    }
+    if ( evts->lNetworkEvents & FD_OOB ) {
+        if (hook->wanted & FDE_ERROR)
+            hook->ready |= FDE_ERROR;
+    }
+}
+
+static void  _event_socket_prepare( EventHook  hook )
+{
+    WSANETWORKEVENTS  evts;
+
+    /* look if some of the events we want already happened ? */
+    if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts ))
+        _event_socket_verify( hook, &evts );
+}
+
+static int  _socket_wanted_to_flags( int  wanted )
+{
+    int  flags = 0;
+    if (wanted & FDE_READ)
+        flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
+
+    if (wanted & FDE_WRITE)
+        flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
+
+    if (wanted & FDE_ERROR)
+        flags |= FD_OOB;
+
+    return flags;
+}
+
+static int _event_socket_start( EventHook  hook )
+{
+    /* create an event which we're going to wait for */
+    FH    fh    = hook->fh;
+    long  flags = _socket_wanted_to_flags( hook->wanted );
+
+    hook->h = fh->event;
+    if (hook->h == INVALID_HANDLE_VALUE) {
+        D( "_event_socket_start: no event for %s\n", fh->name );
+        return 0;
+    }
+
+    if ( flags != fh->mask ) {
+        D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags );
+        if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) {
+            D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError() );
+            CloseHandle( hook->h );
+            hook->h = INVALID_HANDLE_VALUE;
+            exit(1);
+            return 0;
+        }
+        fh->mask = flags;
+    }
+    return 1;
+}
+
+static void _event_socket_stop( EventHook  hook )
+{
+    hook->h = INVALID_HANDLE_VALUE;
+}
+
+static int  _event_socket_check( EventHook  hook )
+{
+    int               result = 0;
+    FH                fh = hook->fh;
+    WSANETWORKEVENTS  evts;
+
+    if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) {
+        _event_socket_verify( hook, &evts );
+        result = (hook->ready != 0);
+        if (result) {
+            ResetEvent( hook->h );
+        }
+    }
+    D( "_event_socket_check %s returns %d\n", fh->name, result );
+    return  result;
+}
+
+static int  _event_socket_peek( EventHook  hook )
+{
+    WSANETWORKEVENTS  evts;
+    FH                fh = hook->fh;
+
+    /* look if some of the events we want already happened ? */
+    if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) {
+        _event_socket_verify( hook, &evts );
+        if (hook->ready)
+            ResetEvent( hook->h );
+    }
+
+    return hook->ready != 0;
+}
+
+
+
+static void  _fh_socket_hook( FH  f, int  events, EventHook  hook )
+{
+    hook->prepare = _event_socket_prepare;
+    hook->start   = _event_socket_start;
+    hook->stop    = _event_socket_stop;
+    hook->check   = _event_socket_check;
+    hook->peek    = _event_socket_peek;
+
+    _event_socket_start( hook );
+}
+
+/** SOCKETPAIR EVENT HOOKS
+ **/
+
+static void  _event_socketpair_prepare( EventHook  hook )
+{
+    FH          fh   = hook->fh;
+    SocketPair  pair = fh->fh_pair;
+    BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
+    BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
+
+    if (hook->wanted & FDE_READ && rbip->can_read)
+        hook->ready |= FDE_READ;
+
+    if (hook->wanted & FDE_WRITE && wbip->can_write)
+        hook->ready |= FDE_WRITE;
+ }
+
+ static int  _event_socketpair_start( EventHook  hook )
+ {
+    FH          fh   = hook->fh;
+    SocketPair  pair = fh->fh_pair;
+    BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
+    BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
+
+    if (hook->wanted == FDE_READ)
+        hook->h = rbip->evt_read;
+
+    else if (hook->wanted == FDE_WRITE)
+        hook->h = wbip->evt_write;
+
+    else {
+        D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n" );
+        return 0;
+    }
+    D( "_event_socketpair_start: hook %s for %x wanted=%x\n",
+       hook->fh->name, _fh_to_int(fh), hook->wanted);
+    return 1;
+}
+
+static int  _event_socketpair_peek( EventHook  hook )
+{
+    _event_socketpair_prepare( hook );
+    return hook->ready != 0;
+}
+
+static void  _fh_socketpair_hook( FH  fh, int  events, EventHook  hook )
+{
+    hook->prepare = _event_socketpair_prepare;
+    hook->start   = _event_socketpair_start;
+    hook->peek    = _event_socketpair_peek;
+}
+
+
+void
+adb_sysdeps_init( void )
+{
+#define  ADB_MUTEX(x)  InitializeCriticalSection( & x );
+#include "mutex_list.h"
+    InitializeCriticalSection( &_win32_lock );
+}
+
+/* Windows doesn't have strtok_r.  Use the one from bionic. */
+
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ */
+
+char *
+adb_strtok_r(char *s, const char *delim, char **last)
+{
+	char *spanp;
+	int c, sc;
+	char *tok;
+
+
+	if (s == NULL && (s = *last) == NULL)
+		return (NULL);
+
+	/*
+	 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
+	 */
+cont:
+	c = *s++;
+	for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+		if (c == sc)
+			goto cont;
+	}
+
+	if (c == 0) {		/* no non-delimiter characters */
+		*last = NULL;
+		return (NULL);
+	}
+	tok = s - 1;
+
+	/*
+	 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+	 * Note that delim must have one NUL; we stop if we see that, too.
+	 */
+	for (;;) {
+		c = *s++;
+		spanp = (char *)delim;
+		do {
+			if ((sc = *spanp++) == c) {
+				if (c == 0)
+					s = NULL;
+				else
+					s[-1] = 0;
+				*last = s;
+				return (tok);
+			}
+		} while (sc != 0);
+	}
+	/* NOTREACHED */
+}
diff --git a/src/devtools/adb/test_track_devices.c b/src/devtools/adb/test_track_devices.c
new file mode 100755
index 0000000..77b3ad9
--- /dev/null
+++ b/src/devtools/adb/test_track_devices.c
@@ -0,0 +1,97 @@
+/* a simple test program, connects to ADB server, and opens a track-devices session */
+#include <netdb.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <memory.h>
+
+static void
+panic( const char*  msg )
+{
+    fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
+    exit(1);
+}
+
+static int
+unix_write( int  fd, const char*  buf, int  len )
+{
+    int  result = 0;
+    while (len > 0) {
+        int  len2 = write(fd, buf, len);
+        if (len2 < 0) {
+            if (errno == EINTR || errno == EAGAIN)
+                continue;
+            return -1;
+        }
+        result += len2;
+        len -= len2;
+        buf += len2;
+    }
+    return  result;
+}
+
+static int
+unix_read( int  fd, char*  buf, int  len )
+{
+    int  result = 0;
+    while (len > 0) {
+        int  len2 = read(fd, buf, len);
+        if (len2 < 0) {
+            if (errno == EINTR || errno == EAGAIN)
+                continue;
+            return -1;
+        }
+        result += len2;
+        len -= len2;
+        buf += len2;
+    }
+    return  result;
+}
+
+
+int  main( void )
+{
+    int                  ret, s;
+    struct sockaddr_in   server;
+    char                 buffer[1024];
+    const char*          request = "host:track-devices";
+    int                  len;
+
+    memset( &server, 0, sizeof(server) );
+    server.sin_family      = AF_INET;
+    server.sin_port        = htons(5037);
+    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    s = socket( PF_INET, SOCK_STREAM, 0 );
+    ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
+    if (ret < 0) panic( "could not connect to server" );
+
+    /* send the request */
+    len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
+    if (unix_write(s, buffer, len) < 0)
+        panic( "could not send request" );
+
+    /* read the OKAY answer */
+    if (unix_read(s, buffer, 4) != 4)
+        panic( "could not read request" );
+
+    printf( "server answer: %.*s\n", 4, buffer );
+
+    /* now loop */
+    for (;;) {
+        char  head[5] = "0000";
+
+        if (unix_read(s, head, 4) < 0)
+            panic("could not read length");
+
+        if ( sscanf( head, "%04x", &len ) != 1 )
+            panic("could not decode length");
+
+        if (unix_read(s, buffer, len) != len)
+            panic("could not read data");
+
+        printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
+    }
+    close(s);
+}
diff --git a/src/devtools/adb/test_track_jdwp.c b/src/devtools/adb/test_track_jdwp.c
new file mode 100755
index 0000000..8ecc6b8
--- /dev/null
+++ b/src/devtools/adb/test_track_jdwp.c
@@ -0,0 +1,97 @@
+/* a simple test program, connects to ADB server, and opens a track-devices session */
+#include <netdb.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <memory.h>
+
+static void
+panic( const char*  msg )
+{
+    fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
+    exit(1);
+}
+
+static int
+unix_write( int  fd, const char*  buf, int  len )
+{
+    int  result = 0;
+    while (len > 0) {
+        int  len2 = write(fd, buf, len);
+        if (len2 < 0) {
+            if (errno == EINTR || errno == EAGAIN)
+                continue;
+            return -1;
+        }
+        result += len2;
+        len -= len2;
+        buf += len2;
+    }
+    return  result;
+}
+
+static int
+unix_read( int  fd, char*  buf, int  len )
+{
+    int  result = 0;
+    while (len > 0) {
+        int  len2 = read(fd, buf, len);
+        if (len2 < 0) {
+            if (errno == EINTR || errno == EAGAIN)
+                continue;
+            return -1;
+        }
+        result += len2;
+        len -= len2;
+        buf += len2;
+    }
+    return  result;
+}
+
+
+int  main( void )
+{
+    int                  ret, s;
+    struct sockaddr_in   server;
+    char                 buffer[1024];
+    const char*          request = "track-jdwp";
+    int                  len;
+
+    memset( &server, 0, sizeof(server) );
+    server.sin_family      = AF_INET;
+    server.sin_port        = htons(5037);
+    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    s = socket( PF_INET, SOCK_STREAM, 0 );
+    ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
+    if (ret < 0) panic( "could not connect to server" );
+
+    /* send the request */
+    len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
+    if (unix_write(s, buffer, len) < 0)
+        panic( "could not send request" );
+
+    /* read the OKAY answer */
+    if (unix_read(s, buffer, 4) != 4)
+        panic( "could not read request" );
+
+    printf( "server answer: %.*s\n", 4, buffer );
+
+    /* now loop */
+    for (;;) {
+        char  head[5] = "0000";
+
+        if (unix_read(s, head, 4) < 0)
+            panic("could not read length");
+
+        if ( sscanf( head, "%04x", &len ) != 1 )
+            panic("could not decode length");
+
+        if (unix_read(s, buffer, len) != len)
+            panic("could not read data");
+
+        printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
+    }
+    close(s);
+}
diff --git a/src/devtools/adb/thread_utils.c b/src/devtools/adb/thread_utils.c
new file mode 100755
index 0000000..6f4cd3c
--- /dev/null
+++ b/src/devtools/adb/thread_utils.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thread_utils.h"
+
+#if defined(__APPLE__)
+
+#include <sys/syscall.h>
+
+// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
+pid_t gettid() {
+  return syscall(SYS_thread_selfid);
+}
+
+#elif !defined(__BIONIC__)
+
+// glibc doesn't implement or export either gettid or tgkill.
+#include <unistd.h>
+#include <sys/syscall.h>
+
+pid_t gettid() {
+  return syscall(__NR_gettid);
+}
+
+int tgkill(int tgid, int tid, int sig) {
+  return syscall(__NR_tgkill, tgid, tid, sig);
+}
+
+#endif
diff --git a/src/devtools/adb/thread_utils.h b/src/devtools/adb/thread_utils.h
new file mode 100755
index 0000000..ae4c929
--- /dev/null
+++ b/src/devtools/adb/thread_utils.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_THREAD_UTILS_H
+#define _LIBBACKTRACE_THREAD_UTILS_H
+
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+int tgkill(int tgid, int tid, int sig);
+
+pid_t gettid();
+
+__END_DECLS
+
+#endif /* _LIBBACKTRACE_THREAD_UTILS_H */
diff --git a/src/devtools/adb/transport.c b/src/devtools/adb/transport.c
new file mode 100755
index 0000000..dbba5aa
--- /dev/null
+++ b/src/devtools/adb/transport.c
@@ -0,0 +1,1269 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "sysdeps.h"
+
+#define   TRACE_TAG  TRACE_TRANSPORT
+#include "adb.h"
+
+static void transport_unref(atransport *t);
+
+static atransport transport_list = {
+    .next = &transport_list,
+    .prev = &transport_list,
+};
+
+static atransport pending_list = {
+    .next = &pending_list,
+    .prev = &pending_list,
+};
+
+ADB_MUTEX_DEFINE( transport_lock );
+
+#if ADB_TRACE
+#define MAX_DUMP_HEX_LEN 16
+static void  dump_hex( const unsigned char*  ptr, size_t  len )
+{
+    int  nn, len2 = len;
+    // Build a string instead of logging each character.
+    // MAX chars in 2 digit hex, one space, MAX chars, one '\0'.
+    char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer;
+
+    if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN;
+
+    for (nn = 0; nn < len2; nn++) {
+        sprintf(pb, "%02x", ptr[nn]);
+        pb += 2;
+    }
+    sprintf(pb++, " ");
+
+    for (nn = 0; nn < len2; nn++) {
+        int  c = ptr[nn];
+        if (c < 32 || c > 127)
+            c = '.';
+        *pb++ =  c;
+    }
+    *pb++ = '\0';
+    DR("%s\n", buffer);
+}
+#endif
+
+void
+kick_transport(atransport*  t)
+{
+    if (t && !t->kicked)
+    {
+        int  kicked;
+
+        adb_mutex_lock(&transport_lock);
+        kicked = t->kicked;
+        if (!kicked)
+            t->kicked = 1;
+        adb_mutex_unlock(&transport_lock);
+
+        if (!kicked)
+            t->kick(t);
+    }
+}
+
+void
+run_transport_disconnects(atransport*  t)
+{
+    adisconnect*  dis = t->disconnects.next;
+
+    D("%s: run_transport_disconnects\n", t->serial);
+    while (dis != &t->disconnects) {
+        adisconnect*  next = dis->next;
+        dis->func( dis->opaque, t );
+        dis = next;
+    }
+}
+
+#if ADB_TRACE
+static void
+dump_packet(const char* name, const char* func, apacket* p)
+{
+    unsigned  command = p->msg.command;
+    int       len     = p->msg.data_length;
+    char      cmd[9];
+    char      arg0[12], arg1[12];
+    int       n;
+
+    for (n = 0; n < 4; n++) {
+        int  b = (command >> (n*8)) & 255;
+        if (b < 32 || b >= 127)
+            break;
+        cmd[n] = (char)b;
+    }
+    if (n == 4) {
+        cmd[4] = 0;
+    } else {
+        /* There is some non-ASCII name in the command, so dump
+            * the hexadecimal value instead */
+        snprintf(cmd, sizeof cmd, "%08x", command);
+    }
+
+    if (p->msg.arg0 < 256U)
+        snprintf(arg0, sizeof arg0, "%d", p->msg.arg0);
+    else
+        snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0);
+
+    if (p->msg.arg1 < 256U)
+        snprintf(arg1, sizeof arg1, "%d", p->msg.arg1);
+    else
+        snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);
+
+    D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ",
+        name, func, cmd, arg0, arg1, len);
+    dump_hex(p->data, len);
+}
+#endif /* ADB_TRACE */
+
+static int
+read_packet(int  fd, const char* name, apacket** ppacket)
+{
+    char *p = (char*)ppacket;  /* really read a packet address */
+    int   r;
+    int   len = sizeof(*ppacket);
+    char  buff[8];
+    if (!name) {
+        snprintf(buff, sizeof buff, "fd=%d", fd);
+        name = buff;
+    }
+    while(len > 0) {
+        r = adb_read(fd, p, len);
+        if(r > 0) {
+            len -= r;
+            p   += r;
+        } else {
+            D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
+            if((r < 0) && (errno == EINTR)) continue;
+            return -1;
+        }
+    }
+
+#if ADB_TRACE
+    if (ADB_TRACING) {
+        dump_packet(name, "from remote", *ppacket);
+    }
+#endif
+    return 0;
+}
+
+static int
+write_packet(int  fd, const char* name, apacket** ppacket)
+{
+    char *p = (char*) ppacket;  /* we really write the packet address */
+    int r, len = sizeof(ppacket);
+    char buff[8];
+    if (!name) {
+        snprintf(buff, sizeof buff, "fd=%d", fd);
+        name = buff;
+    }
+
+#if ADB_TRACE
+    if (ADB_TRACING) {
+        dump_packet(name, "to remote", *ppacket);
+    }
+#endif
+    len = sizeof(ppacket);
+    while(len > 0) {
+        r = adb_write(fd, p, len);
+        if(r > 0) {
+            len -= r;
+            p += r;
+        } else {
+            D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
+            if((r < 0) && (errno == EINTR)) continue;
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static void transport_socket_events(int fd, unsigned events, void *_t)
+{
+    atransport *t = _t;
+    D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events);
+    if(events & FDE_READ){
+        apacket *p = 0;
+        if(read_packet(fd, t->serial, &p)){
+            D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd);
+        } else {
+            handle_packet(p, (atransport *) _t);
+        }
+    }
+}
+
+void send_packet(apacket *p, atransport *t)
+{
+    unsigned char *x;
+    unsigned sum;
+    unsigned count;
+
+    p->msg.magic = p->msg.command ^ 0xffffffff;
+
+    count = p->msg.data_length;
+    x = (unsigned char *) p->data;
+    sum = 0;
+    while(count-- > 0){
+        sum += *x++;
+    }
+    p->msg.data_check = sum;
+
+    print_packet("send", p);
+
+    if (t == NULL) {
+        D("Transport is null \n");
+        // Zap errno because print_packet() and other stuff have errno effect.
+        errno = 0;
+        fatal_errno("Transport is null");
+    }
+
+    if(write_packet(t->transport_socket, t->serial, &p)){
+        fatal_errno("cannot enqueue packet on transport socket");
+    }
+}
+
+/* The transport is opened by transport_register_func before
+** the input and output threads are started.
+**
+** The output thread issues a SYNC(1, token) message to let
+** the input thread know to start things up.  In the event
+** of transport IO failure, the output thread will post a
+** SYNC(0,0) message to ensure shutdown.
+**
+** The transport will not actually be closed until both
+** threads exit, but the input thread will kick the transport
+** on its way out to disconnect the underlying device.
+*/
+
+static void *output_thread(void *_t)
+{
+    atransport *t = _t;
+    apacket *p;
+
+    D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
+       t->serial, t->fd, t->sync_token + 1);
+    p = get_apacket();
+    p->msg.command = A_SYNC;
+    p->msg.arg0 = 1;
+    p->msg.arg1 = ++(t->sync_token);
+    p->msg.magic = A_SYNC ^ 0xffffffff;
+    if(write_packet(t->fd, t->serial, &p)) {
+        put_apacket(p);
+        D("%s: failed to write SYNC packet\n", t->serial);
+        goto oops;
+    }
+
+    D("%s: data pump started\n", t->serial);
+    for(;;) {
+        p = get_apacket();
+
+        if(t->read_from_remote(p, t) == 0){
+            D("%s: received remote packet, sending to transport\n",
+              t->serial);
+            if(write_packet(t->fd, t->serial, &p)){
+                put_apacket(p);
+                D("%s: failed to write apacket to transport\n", t->serial);
+                goto oops;
+            }
+        } else {
+            D("%s: remote read failed for transport\n", t->serial);
+            put_apacket(p);
+            break;
+        }
+    }
+
+    D("%s: SYNC offline for transport\n", t->serial);
+    p = get_apacket();
+    p->msg.command = A_SYNC;
+    p->msg.arg0 = 0;
+    p->msg.arg1 = 0;
+    p->msg.magic = A_SYNC ^ 0xffffffff;
+    if(write_packet(t->fd, t->serial, &p)) {
+        put_apacket(p);
+        D("%s: failed to write SYNC apacket to transport", t->serial);
+    }
+
+oops:
+    D("%s: transport output thread is exiting\n", t->serial);
+    kick_transport(t);
+    transport_unref(t);
+    return 0;
+}
+
+static void *input_thread(void *_t)
+{
+    atransport *t = _t;
+    apacket *p;
+    int active = 0;
+
+    D("%s: starting transport input thread, reading from fd %d\n",
+       t->serial, t->fd);
+
+    for(;;){
+        if(read_packet(t->fd, t->serial, &p)) {
+            D("%s: failed to read apacket from transport on fd %d\n",
+               t->serial, t->fd );
+            break;
+        }
+        if(p->msg.command == A_SYNC){
+            if(p->msg.arg0 == 0) {
+                D("%s: transport SYNC offline\n", t->serial);
+                put_apacket(p);
+                break;
+            } else {
+                if(p->msg.arg1 == t->sync_token) {
+                    D("%s: transport SYNC online\n", t->serial);
+                    active = 1;
+                } else {
+                    D("%s: transport ignoring SYNC %d != %d\n",
+                      t->serial, p->msg.arg1, t->sync_token);
+                }
+            }
+        } else {
+            if(active) {
+                D("%s: transport got packet, sending to remote\n", t->serial);
+                t->write_to_remote(p, t);
+            } else {
+                D("%s: transport ignoring packet while offline\n", t->serial);
+            }
+        }
+
+        put_apacket(p);
+    }
+
+    // this is necessary to avoid a race condition that occured when a transport closes
+    // while a client socket is still active.
+    close_all_sockets(t);
+
+    D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd);
+    kick_transport(t);
+    transport_unref(t);
+    return 0;
+}
+
+
+static int transport_registration_send = -1;
+static int transport_registration_recv = -1;
+static fdevent transport_registration_fde;
+
+
+#if ADB_HOST
+static int list_transports_msg(char*  buffer, size_t  bufferlen)
+{
+    char  head[5];
+    int   len;
+
+    len = list_transports(buffer+4, bufferlen-4, 0);
+    snprintf(head, sizeof(head), "%04x", len);
+    memcpy(buffer, head, 4);
+    len += 4;
+    return len;
+}
+
+/* this adds support required by the 'track-devices' service.
+ * this is used to send the content of "list_transport" to any
+ * number of client connections that want it through a single
+ * live TCP connection
+ */
+typedef struct device_tracker  device_tracker;
+struct device_tracker {
+    asocket          socket;
+    int              update_needed;
+    device_tracker*  next;
+};
+
+/* linked list of all device trackers */
+static device_tracker*   device_tracker_list;
+
+static void
+device_tracker_remove( device_tracker*  tracker )
+{
+    device_tracker**  pnode = &device_tracker_list;
+    device_tracker*   node  = *pnode;
+
+    adb_mutex_lock( &transport_lock );
+    while (node) {
+        if (node == tracker) {
+            *pnode = node->next;
+            break;
+        }
+        pnode = &node->next;
+        node  = *pnode;
+    }
+    adb_mutex_unlock( &transport_lock );
+}
+
+static void
+device_tracker_close( asocket*  socket )
+{
+    device_tracker*  tracker = (device_tracker*) socket;
+    asocket*         peer    = socket->peer;
+
+    D( "device tracker %p removed\n", tracker);
+    if (peer) {
+        peer->peer = NULL;
+        peer->close(peer);
+    }
+    device_tracker_remove(tracker);
+    free(tracker);
+}
+
+static int
+device_tracker_enqueue( asocket*  socket, apacket*  p )
+{
+    /* you can't read from a device tracker, close immediately */
+    put_apacket(p);
+    device_tracker_close(socket);
+    return -1;
+}
+
+static int
+device_tracker_send( device_tracker*  tracker,
+                     const char*      buffer,
+                     int              len )
+{
+    apacket*  p = get_apacket();
+    asocket*  peer = tracker->socket.peer;
+
+    memcpy(p->data, buffer, len);
+    p->len = len;
+    return peer->enqueue( peer, p );
+}
+
+
+static void
+device_tracker_ready( asocket*  socket )
+{
+    device_tracker*  tracker = (device_tracker*) socket;
+
+    /* we want to send the device list when the tracker connects
+    * for the first time, even if no update occured */
+    if (tracker->update_needed > 0) {
+        char  buffer[1024];
+        int   len;
+
+        tracker->update_needed = 0;
+
+        len = list_transports_msg(buffer, sizeof(buffer));
+        device_tracker_send(tracker, buffer, len);
+    }
+}
+
+
+asocket*
+create_device_tracker(void)
+{
+    device_tracker*  tracker = calloc(1,sizeof(*tracker));
+
+    if(tracker == 0) fatal("cannot allocate device tracker");
+
+    D( "device tracker %p created\n", tracker);
+
+    tracker->socket.enqueue = device_tracker_enqueue;
+    tracker->socket.ready   = device_tracker_ready;
+    tracker->socket.close   = device_tracker_close;
+    tracker->update_needed  = 1;
+
+    tracker->next       = device_tracker_list;
+    device_tracker_list = tracker;
+
+    return &tracker->socket;
+}
+
+
+/* call this function each time the transport list has changed */
+void  update_transports(void)
+{
+    char             buffer[1024];
+    int              len;
+    device_tracker*  tracker;
+
+    len = list_transports_msg(buffer, sizeof(buffer));
+
+    tracker = device_tracker_list;
+    while (tracker != NULL) {
+        device_tracker*  next = tracker->next;
+        /* note: this may destroy the tracker if the connection is closed */
+        device_tracker_send(tracker, buffer, len);
+        tracker = next;
+    }
+}
+#else
+void  update_transports(void)
+{
+    // nothing to do on the device side
+}
+#endif // ADB_HOST
+
+typedef struct tmsg tmsg;
+struct tmsg
+{
+    atransport *transport;
+    int         action;
+};
+
+static int
+transport_read_action(int  fd, struct tmsg*  m)
+{
+    char *p   = (char*)m;
+    int   len = sizeof(*m);
+    int   r;
+
+    while(len > 0) {
+        r = adb_read(fd, p, len);
+        if(r > 0) {
+            len -= r;
+            p   += r;
+        } else {
+            if((r < 0) && (errno == EINTR)) continue;
+            D("transport_read_action: on fd %d, error %d: %s\n",
+              fd, errno, strerror(errno));
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static int
+transport_write_action(int  fd, struct tmsg*  m)
+{
+    char *p   = (char*)m;
+    int   len = sizeof(*m);
+    int   r;
+
+    while(len > 0) {
+        r = adb_write(fd, p, len);
+        if(r > 0) {
+            len -= r;
+            p   += r;
+        } else {
+            if((r < 0) && (errno == EINTR)) continue;
+            D("transport_write_action: on fd %d, error %d: %s\n",
+              fd, errno, strerror(errno));
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static void transport_registration_func(int _fd, unsigned ev, void *data)
+{
+    tmsg m;
+    adb_thread_t output_thread_ptr;
+    adb_thread_t input_thread_ptr;
+    int s[2];
+    atransport *t;
+
+    if(!(ev & FDE_READ)) {
+        return;
+    }
+
+    if(transport_read_action(_fd, &m)) {
+        fatal_errno("cannot read transport registration socket");
+    }
+
+    t = m.transport;
+
+    if(m.action == 0){
+        D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket);
+
+            /* IMPORTANT: the remove closes one half of the
+            ** socket pair.  The close closes the other half.
+            */
+        fdevent_remove(&(t->transport_fde));
+        adb_close(t->fd);
+
+        adb_mutex_lock(&transport_lock);
+        t->next->prev = t->prev;
+        t->prev->next = t->next;
+        adb_mutex_unlock(&transport_lock);
+
+        run_transport_disconnects(t);
+
+        if (t->product)
+            free(t->product);
+        if (t->serial)
+            free(t->serial);
+        if (t->model)
+            free(t->model);
+        if (t->device)
+            free(t->device);
+        if (t->devpath)
+            free(t->devpath);
+
+        memset(t,0xee,sizeof(atransport));
+        free(t);
+
+        update_transports();
+        return;
+    }
+
+    /* don't create transport threads for inaccessible devices */
+    if (t->connection_state != CS_NOPERM) {
+        /* initial references are the two threads */
+        t->ref_count = 2;
+
+        if(adb_socketpair(s)) {
+            fatal_errno("cannot open transport socketpair");
+        }
+
+        D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]);
+
+        t->transport_socket = s[0];
+        t->fd = s[1];
+
+        fdevent_install(&(t->transport_fde),
+                        t->transport_socket,
+                        transport_socket_events,
+                        t);
+
+        fdevent_set(&(t->transport_fde), FDE_READ);
+
+        if(adb_thread_create(&input_thread_ptr, input_thread, t)){
+            fatal_errno("cannot create input thread");
+        }
+
+        if(adb_thread_create(&output_thread_ptr, output_thread, t)){
+            fatal_errno("cannot create output thread");
+        }
+    }
+
+    adb_mutex_lock(&transport_lock);
+    /* remove from pending list */
+    t->next->prev = t->prev;
+    t->prev->next = t->next;
+    /* put us on the master device list */
+    t->next = &transport_list;
+    t->prev = transport_list.prev;
+    t->next->prev = t;
+    t->prev->next = t;
+    adb_mutex_unlock(&transport_lock);
+
+    t->disconnects.next = t->disconnects.prev = &t->disconnects;
+
+    update_transports();
+}
+
+void init_transport_registration(void)
+{
+    int s[2];
+
+    if(adb_socketpair(s)){
+        fatal_errno("cannot open transport registration socketpair");
+    }
+
+    transport_registration_send = s[0];
+    transport_registration_recv = s[1];
+
+    fdevent_install(&transport_registration_fde,
+                    transport_registration_recv,
+                    transport_registration_func,
+                    0);
+
+    fdevent_set(&transport_registration_fde, FDE_READ);
+}
+
+/* the fdevent select pump is single threaded */
+static void register_transport(atransport *transport)
+{
+    tmsg m;
+    m.transport = transport;
+    m.action = 1;
+    D("transport: %s registered\n", transport->serial);
+    if(transport_write_action(transport_registration_send, &m)) {
+        fatal_errno("cannot write transport registration socket\n");
+    }
+}
+
+static void remove_transport(atransport *transport)
+{
+    tmsg m;
+    m.transport = transport;
+    m.action = 0;
+    D("transport: %s removed\n", transport->serial);
+    if(transport_write_action(transport_registration_send, &m)) {
+        fatal_errno("cannot write transport registration socket\n");
+    }
+}
+
+
+static void transport_unref_locked(atransport *t)
+{
+    t->ref_count--;
+    if (t->ref_count == 0) {
+        D("transport: %s unref (kicking and closing)\n", t->serial);
+        if (!t->kicked) {
+            t->kicked = 1;
+            t->kick(t);
+        }
+        t->close(t);
+        remove_transport(t);
+    } else {
+        D("transport: %s unref (count=%d)\n", t->serial, t->ref_count);
+    }
+}
+
+static void transport_unref(atransport *t)
+{
+    if (t) {
+        adb_mutex_lock(&transport_lock);
+        transport_unref_locked(t);
+        adb_mutex_unlock(&transport_lock);
+    }
+}
+
+void add_transport_disconnect(atransport*  t, adisconnect*  dis)
+{
+    adb_mutex_lock(&transport_lock);
+    dis->next       = &t->disconnects;
+    dis->prev       = dis->next->prev;
+    dis->prev->next = dis;
+    dis->next->prev = dis;
+    adb_mutex_unlock(&transport_lock);
+}
+
+void remove_transport_disconnect(atransport*  t, adisconnect*  dis)
+{
+    dis->prev->next = dis->next;
+    dis->next->prev = dis->prev;
+    dis->next = dis->prev = dis;
+}
+
+static int qual_char_is_invalid(char ch)
+{
+    if ('A' <= ch && ch <= 'Z')
+        return 0;
+    if ('a' <= ch && ch <= 'z')
+        return 0;
+    if ('0' <= ch && ch <= '9')
+        return 0;
+    return 1;
+}
+
+static int qual_match(const char *to_test,
+                      const char *prefix, const char *qual, int sanitize_qual)
+{
+    if (!to_test || !*to_test)
+        /* Return true if both the qual and to_test are null strings. */
+        return !qual || !*qual;
+
+    if (!qual)
+        return 0;
+
+    if (prefix) {
+        while (*prefix) {
+            if (*prefix++ != *to_test++)
+                return 0;
+        }
+    }
+
+    while (*qual) {
+        char ch = *qual++;
+        if (sanitize_qual && qual_char_is_invalid(ch))
+            ch = '_';
+        if (ch != *to_test++)
+            return 0;
+    }
+
+    /* Everything matched so far.  Return true if *to_test is a NUL. */
+    return !*to_test;
+}
+
+atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
+{
+    atransport *t;
+    atransport *result = NULL;
+    int ambiguous = 0;
+
+retry:
+    if (error_out)
+        *error_out = "device not found";
+
+    adb_mutex_lock(&transport_lock);
+    for (t = transport_list.next; t != &transport_list; t = t->next) {
+        if (t->connection_state == CS_NOPERM) {
+        if (error_out)
+            *error_out = "insufficient permissions for device";
+            continue;
+        }
+
+        /* check for matching serial number */
+        if (serial) {
+            if ((t->serial && !strcmp(serial, t->serial)) ||
+                (t->devpath && !strcmp(serial, t->devpath)) ||
+                qual_match(serial, "product:", t->product, 0) ||
+                qual_match(serial, "model:", t->model, 1) ||
+                qual_match(serial, "device:", t->device, 0)) {
+                if (result) {
+                    if (error_out)
+                        *error_out = "more than one device";
+                    ambiguous = 1;
+                    result = NULL;
+                    break;
+                }
+                result = t;
+            }
+        } else {
+            if (ttype == kTransportUsb && t->type == kTransportUsb) {
+                if (result) {
+                    if (error_out)
+                        *error_out = "more than one device";
+                    ambiguous = 1;
+                    result = NULL;
+                    break;
+                }
+                result = t;
+            } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
+                if (result) {
+                    if (error_out)
+                        *error_out = "more than one emulator";
+                    ambiguous = 1;
+                    result = NULL;
+                    break;
+                }
+                result = t;
+            } else if (ttype == kTransportAny) {
+                if (result) {
+                    if (error_out)
+                        *error_out = "more than one device and emulator";
+                    ambiguous = 1;
+                    result = NULL;
+                    break;
+                }
+                result = t;
+            }
+        }
+    }
+    adb_mutex_unlock(&transport_lock);
+
+    if (result) {
+        if (result->connection_state == CS_UNAUTHORIZED) {
+            if (error_out)
+                *error_out = "device unauthorized. Please check the confirmation dialog on your device.";
+            result = NULL;
+        }
+
+         /* offline devices are ignored -- they are either being born or dying */
+        if (result && result->connection_state == CS_OFFLINE) {
+            if (error_out)
+                *error_out = "device offline";
+            result = NULL;
+        }
+         /* check for required connection state */
+        if (result && state != CS_ANY && result->connection_state != state) {
+            if (error_out)
+                *error_out = "invalid device state";
+            result = NULL;
+        }
+    }
+
+    if (result) {
+        /* found one that we can take */
+        if (error_out)
+            *error_out = NULL;
+    } else if (state != CS_ANY && (serial || !ambiguous)) {
+        adb_sleep_ms(1000);
+        goto retry;
+    }
+
+    return result;
+}
+
+#if ADB_HOST
+static const char *statename(atransport *t)
+{
+    switch(t->connection_state){
+    case CS_OFFLINE: return "offline";
+    case CS_BOOTLOADER: return "bootloader";
+    case CS_DEVICE: return "device";
+    case CS_HOST: return "host";
+    case CS_RECOVERY: return "recovery";
+    case CS_SIDELOAD: return "sideload";
+    case CS_NOPERM: return "no permissions";
+    case CS_UNAUTHORIZED: return "unauthorized";
+    default: return "unknown";
+    }
+}
+
+static void add_qual(char **buf, size_t *buf_size,
+                     const char *prefix, const char *qual, int sanitize_qual)
+{
+    size_t len;
+    int prefix_len;
+
+    if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual)
+        return;
+
+    len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
+
+    if (sanitize_qual) {
+        char *cp;
+        for (cp = *buf + prefix_len; cp < *buf + len; cp++) {
+            if (qual_char_is_invalid(*cp))
+                *cp = '_';
+        }
+    }
+
+    *buf_size -= len;
+    *buf += len;
+}
+
+static size_t format_transport(atransport *t, char *buf, size_t bufsize,
+                               int long_listing)
+{
+    const char* serial = t->serial;
+    if (!serial || !serial[0])
+        serial = "????????????";
+
+    if (!long_listing) {
+        return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t));
+    } else {
+        size_t len, remaining = bufsize;
+
+        len = snprintf(buf, remaining, "%-22s %s", serial, statename(t));
+        remaining -= len;
+        buf += len;
+
+        add_qual(&buf, &remaining, " ", t->devpath, 0);
+        add_qual(&buf, &remaining, " product:", t->product, 0);
+        add_qual(&buf, &remaining, " model:", t->model, 1);
+        add_qual(&buf, &remaining, " device:", t->device, 0);
+
+        len = snprintf(buf, remaining, "\n");
+        remaining -= len;
+
+        return bufsize - remaining;
+    }
+}
+
+int list_transports(char *buf, size_t  bufsize, int long_listing)
+{
+    char*       p   = buf;
+    char*       end = buf + bufsize;
+    int         len;
+    atransport *t;
+
+        /* XXX OVERRUN PROBLEMS XXX */
+    adb_mutex_lock(&transport_lock);
+    for(t = transport_list.next; t != &transport_list; t = t->next) {
+        len = format_transport(t, p, end - p, long_listing);
+        if (p + len >= end) {
+            /* discard last line if buffer is too short */
+            break;
+        }
+        p += len;
+    }
+    p[0] = 0;
+    adb_mutex_unlock(&transport_lock);
+    return p - buf;
+}
+
+
+/* hack for osx */
+void close_usb_devices()
+{
+    atransport *t;
+
+    adb_mutex_lock(&transport_lock);
+    for(t = transport_list.next; t != &transport_list; t = t->next) {
+        if ( !t->kicked ) {
+            t->kicked = 1;
+            t->kick(t);
+        }
+    }
+    adb_mutex_unlock(&transport_lock);
+}
+#endif // ADB_HOST
+
+int register_socket_transport(int s, const char *serial, int port, int local)
+{
+    atransport *t = calloc(1, sizeof(atransport));
+    atransport *n;
+    char buff[32];
+
+    if (t == 0) {
+        fatal("cannot allocate atransport");
+        return -1;
+    }
+    if (!serial) {
+        snprintf(buff, sizeof buff, "T-%p", t);
+        serial = buff;
+    }
+    D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port);
+    if (init_socket_transport(t, s, port, local) < 0) {
+        free(t);
+        return -1;
+    }
+
+    adb_mutex_lock(&transport_lock);
+    for (n = pending_list.next; n != &pending_list; n = n->next) {
+        if (n->serial && !strcmp(serial, n->serial) && n->sfd == s) {
+            adb_mutex_unlock(&transport_lock);
+            free(t);
+            return -1;
+        }
+    }
+
+    for (n = transport_list.next; n != &transport_list; n = n->next) {
+        if (n->serial && !strcmp(serial, n->serial) && n->sfd == s) {
+            adb_mutex_unlock(&transport_lock);
+            free(t);
+            return -1;
+        }
+    }
+
+    t->next = &pending_list;
+    t->prev = pending_list.prev;
+    t->next->prev = t;
+    t->prev->next = t;
+    t->serial = strdup(serial);
+    adb_mutex_unlock(&transport_lock);
+
+    register_transport(t);
+    return 0;
+}
+
+#if ADB_HOST
+atransport *find_transport(const char *serial)
+{
+    atransport *t;
+
+    adb_mutex_lock(&transport_lock);
+    for(t = transport_list.next; t != &transport_list; t = t->next) {
+        if (t->serial && !strcmp(serial, t->serial)) {
+            break;
+        }
+     }
+    adb_mutex_unlock(&transport_lock);
+
+    if (t != &transport_list)
+        return t;
+    else
+        return 0;
+}
+
+void unregister_transport(atransport *t)
+{
+    adb_mutex_lock(&transport_lock);
+    t->next->prev = t->prev;
+    t->prev->next = t->next;
+    adb_mutex_unlock(&transport_lock);
+
+    kick_transport(t);
+    transport_unref(t);
+}
+
+// unregisters all non-emulator TCP transports
+void unregister_all_tcp_transports()
+{
+    atransport *t, *next;
+    adb_mutex_lock(&transport_lock);
+    for (t = transport_list.next; t != &transport_list; t = next) {
+        next = t->next;
+        if (t->type == kTransportLocal && t->adb_port == 0) {
+            t->next->prev = t->prev;
+            t->prev->next = next;
+            // we cannot call kick_transport when holding transport_lock
+            if (!t->kicked)
+            {
+                t->kicked = 1;
+                t->kick(t);
+            }
+            transport_unref_locked(t);
+        }
+     }
+
+    adb_mutex_unlock(&transport_lock);
+}
+
+#endif
+
+#if (ADB_OVER_PCIE)
+void register_pcie_transport(struct pcie_handle *pcie, const char *devpath, unsigned writeable)
+{
+    atransport *t = calloc(1, sizeof(atransport));
+    if (t == 0) {
+        fatal("cannot allocate atransport");
+        return;
+    }
+    init_pcie_transport(t, pcie, devpath, (writeable ? CS_OFFLINE : CS_NOPERM));
+
+    if(devpath) {
+        t->devpath = strdup(devpath);
+    }
+
+    adb_mutex_lock(&transport_lock);
+    t->next = &pending_list;
+    t->prev = pending_list.prev;
+    t->next->prev = t;
+    t->prev->next = t;
+    adb_mutex_unlock(&transport_lock);
+
+    register_transport(t);
+}
+#else
+void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
+{
+    atransport *t = calloc(1, sizeof(atransport));
+    if (t == 0) {
+        fatal("cannot allocate atransport");
+        return;
+    }
+    D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
+      serial ? serial : "");
+    init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
+    if(serial) {
+        t->serial = strdup(serial);
+    }
+    if(devpath) {
+        t->devpath = strdup(devpath);
+    }
+
+    adb_mutex_lock(&transport_lock);
+    t->next = &pending_list;
+    t->prev = pending_list.prev;
+    t->next->prev = t;
+    t->prev->next = t;
+    adb_mutex_unlock(&transport_lock);
+
+    register_transport(t);
+}
+#endif
+
+/* this should only be used for transports with connection_state == CS_NOPERM */
+void unregister_usb_transport(usb_handle *usb)
+{
+    atransport *t;
+    adb_mutex_lock(&transport_lock);
+    for(t = transport_list.next; t != &transport_list; t = t->next) {
+        if (t->usb == usb && t->connection_state == CS_NOPERM) {
+            t->next->prev = t->prev;
+            t->prev->next = t->next;
+            break;
+        }
+     }
+    adb_mutex_unlock(&transport_lock);
+}
+
+#undef TRACE_TAG
+#define TRACE_TAG  TRACE_RWX
+
+int readx(int fd, void *ptr, size_t len)
+{
+    char *p = ptr;
+    int r;
+#if ADB_TRACE
+    size_t len0 = len;
+#endif
+    D("readx: fd=%d wanted=%zu\n", fd, len);
+    while(len > 0) {
+        r = adb_read(fd, p, len);
+        if(r > 0) {
+            len -= r;
+            p += r;
+        } else {
+            if (r < 0) {
+                D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno));
+                if (errno == EINTR)
+                    continue;
+            } else {
+                D("readx: fd=%d disconnected\n", fd);
+            }
+            return -1;
+        }
+    }
+
+#if ADB_TRACE
+    D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len);
+    dump_hex( ptr, len0 );
+#endif
+    return 0;
+}
+
+int writex(int fd, const void *ptr, size_t len)
+{
+    char *p = (char*) ptr;
+    int r;
+
+#if ADB_TRACE
+    D("writex: fd=%d len=%d: ", fd, (int)len);
+    dump_hex( ptr, len );
+#endif
+    while(len > 0) {
+        r = adb_write(fd, p, len);
+        if(r > 0) {
+            len -= r;
+            p += r;
+        } else {
+            if (r < 0) {
+                D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
+                if (errno == EINTR)
+                    continue;
+                if (errno == EAGAIN) {
+                    adb_sleep_ms(1); // just yield some cpu time
+                    continue;
+                }
+            } else {
+                D("writex: fd=%d disconnected\n", fd);
+            }
+            return -1;
+        }
+    }
+    return 0;
+}
+
+int check_header(apacket *p)
+{
+    if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
+        D("check_header(): invalid magic\n");
+        return -1;
+    }
+
+    if(p->msg.data_length > MAX_PAYLOAD) {
+        D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length);
+        return -1;
+    }
+
+    return 0;
+}
+
+int check_data(apacket *p)
+{
+    unsigned count, sum;
+    unsigned char *x;
+
+    count = p->msg.data_length;
+    x = p->data;
+    sum = 0;
+    while(count-- > 0) {
+        sum += *x++;
+    }
+
+    if(sum != p->msg.data_check) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
diff --git a/src/devtools/adb/transport.h b/src/devtools/adb/transport.h
new file mode 100755
index 0000000..992e052
--- /dev/null
+++ b/src/devtools/adb/transport.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TRANSPORT_H
+#define __TRANSPORT_H
+
+/* convenience wrappers around read/write that will retry on
+** EINTR and/or short read/write.  Returns 0 on success, -1
+** on error or EOF.
+*/
+int readx(int fd, void *ptr, size_t len);
+int writex(int fd, const void *ptr, size_t len);
+#endif   /* __TRANSPORT_H */
diff --git a/src/devtools/adb/transport_local.c b/src/devtools/adb/transport_local.c
new file mode 100755
index 0000000..1f9a1e4
--- /dev/null
+++ b/src/devtools/adb/transport_local.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "sysdeps.h"
+#include <sys/types.h>
+#if !ADB_HOST
+#include <cutils/properties.h>
+#endif
+
+#define  TRACE_TAG  TRACE_TRANSPORT
+#include "adb.h"
+
+#ifdef HAVE_BIG_ENDIAN
+#define H4(x)	(((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
+static inline void fix_endians(apacket *p)
+{
+    p->msg.command     = H4(p->msg.command);
+    p->msg.arg0        = H4(p->msg.arg0);
+    p->msg.arg1        = H4(p->msg.arg1);
+    p->msg.data_length = H4(p->msg.data_length);
+    p->msg.data_check  = H4(p->msg.data_check);
+    p->msg.magic       = H4(p->msg.magic);
+}
+#else
+#define fix_endians(p) do {} while (0)
+#endif
+
+#if ADB_HOST
+/* we keep a list of opened transports. The atransport struct knows to which
+ * local transport it is connected. The list is used to detect when we're
+ * trying to connect twice to a given local transport.
+ */
+#define  ADB_LOCAL_TRANSPORT_MAX  64
+
+ADB_MUTEX_DEFINE( local_transports_lock );
+
+static atransport*  local_transports[ ADB_LOCAL_TRANSPORT_MAX ];
+#endif /* ADB_HOST */
+
+static int remote_read(apacket *p, atransport *t)
+{
+    if(readx(t->sfd, &p->msg, sizeof(amessage))){
+        D("remote local: read terminated (message)\n");
+        return -1;
+    }
+
+    fix_endians(p);
+
+#if 0 && defined HAVE_BIG_ENDIAN
+    D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
+      p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
+#endif
+    if(check_header(p)) {
+        D("bad header: terminated (data)\n");
+        return -1;
+    }
+
+    if(readx(t->sfd, p->data, p->msg.data_length)){
+        D("remote local: terminated (data)\n");
+        return -1;
+    }
+
+    if(check_data(p)) {
+        D("bad data: terminated (data)\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int remote_write(apacket *p, atransport *t)
+{
+    int   length = p->msg.data_length;
+
+    fix_endians(p);
+
+#if 0 && defined HAVE_BIG_ENDIAN
+    D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
+      p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
+#endif
+    if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
+        D("remote local: write terminated\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int local_connect(int port) {
+    return local_connect_arbitrary_ports(port-1, port);
+}
+
+int local_connect_arbitrary_ports(int console_port, int adb_port)
+{
+    char buf[64];
+    int  fd = -1;
+
+#if ADB_HOST
+    const char *host = getenv("ADBHOST");
+    if (host) {
+        fd = socket_network_client(host, adb_port, SOCK_STREAM);
+    }
+#endif
+    if (fd < 0) {
+        fd = socket_loopback_client(adb_port, SOCK_STREAM);
+    }
+
+    if (fd >= 0) {
+        D("client: connected on remote on fd %d\n", fd);
+        close_on_exec(fd);
+        disable_tcp_nagle(fd);
+        snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
+        register_socket_transport(fd, buf, adb_port, 1);
+        return 0;
+    }
+    return -1;
+}
+
+
+static void *client_socket_thread(void *x)
+{
+#if ADB_HOST
+    int  port  = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+    int  count = ADB_LOCAL_TRANSPORT_MAX;
+
+    D("transport: client_socket_thread() starting\n");
+
+    /* try to connect to any number of running emulator instances     */
+    /* this is only done when ADB starts up. later, each new emulator */
+    /* will send a message to ADB to indicate that is is starting up  */
+    for ( ; count > 0; count--, port += 2 ) {
+        (void) local_connect(port);
+    }
+#endif
+    return 0;
+}
+
+static void *server_socket_thread(void * arg)
+{
+    int serverfd, fd;
+    struct sockaddr addr;
+    socklen_t alen;
+    int port = (int) (uintptr_t) arg;
+
+    D("transport: server_socket_thread() starting\n");
+    serverfd = -1;
+    for(;;) {
+        if(serverfd == -1) {
+            serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
+            if(serverfd < 0) {
+                D("server: cannot bind socket yet\n");
+                adb_sleep_ms(1000);
+                continue;
+            }
+            close_on_exec(serverfd);
+        }
+
+        alen = sizeof(addr);
+        D("server: trying to get new connection from %d\n", port);
+        fd = adb_socket_accept(serverfd, &addr, &alen);
+        if(fd >= 0) {
+            D("server: new connection on fd %d\n", fd);
+            close_on_exec(fd);
+            disable_tcp_nagle(fd);
+            register_socket_transport(fd, "host", port, 1);
+        }
+    }
+    D("transport: server_socket_thread() exiting\n");
+    return 0;
+}
+
+/* This is relevant only for ADB daemon running inside the emulator. */
+#if !ADB_HOST && !ADB_NON_ANDROID
+/*
+ * Redefine open and write for qemu_pipe.h that contains inlined references
+ * to those routines. We will redifine them back after qemu_pipe.h inclusion.
+ */
+#undef open
+#undef write
+#define open    adb_open
+#define write   adb_write
+#include <hardware/qemu_pipe.h>
+#undef open
+#undef write
+#define open    ___xxx_open
+#define write   ___xxx_write
+
+/* A worker thread that monitors host connections, and registers a transport for
+ * every new host connection. This thread replaces server_socket_thread on
+ * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD
+ * pipe to communicate with adbd daemon inside the guest. This is done in order
+ * to provide more robust communication channel between ADB host and guest. The
+ * main issue with server_socket_thread approach is that it runs on top of TCP,
+ * and thus is sensitive to network disruptions. For instance, the
+ * ConnectionManager may decide to reset all network connections, in which case
+ * the connection between ADB host and guest will be lost. To make ADB traffic
+ * independent from the network, we use here 'adb' QEMUD service to transfer data
+ * between the host, and the guest. See external/qemu/android/adb-*.* that
+ * implements the emulator's side of the protocol. Another advantage of using
+ * QEMUD approach is that ADB will be up much sooner, since it doesn't depend
+ * anymore on network being set up.
+ * The guest side of the protocol contains the following phases:
+ * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service
+ *   is opened, and it becomes clear whether or not emulator supports that
+ *   protocol.
+ * - Wait for the ADB host to create connection with the guest. This is done by
+ *   sending an 'accept' request to the adb QEMUD service, and waiting on
+ *   response.
+ * - When new ADB host connection is accepted, the connection with adb QEMUD
+ *   service is registered as the transport, and a 'start' request is sent to the
+ *   adb QEMUD service, indicating that the guest is ready to receive messages.
+ *   Note that the guest will ignore messages sent down from the emulator before
+ *   the transport registration is completed. That's why we need to send the
+ *   'start' request after the transport is registered.
+ */
+static void *qemu_socket_thread(void * arg)
+{
+/* 'accept' request to the adb QEMUD service. */
+static const char _accept_req[] = "accept";
+/* 'start' request to the adb QEMUD service. */
+static const char _start_req[]  = "start";
+/* 'ok' reply from the adb QEMUD service. */
+static const char _ok_resp[]    = "ok";
+
+    const int port = (int) (uintptr_t) arg;
+    int res, fd;
+    char tmp[256];
+    char con_name[32];
+
+    D("transport: qemu_socket_thread() starting\n");
+
+    /* adb QEMUD service connection request. */
+    snprintf(con_name, sizeof(con_name), "qemud:adb:%d", port);
+
+    /* Connect to the adb QEMUD service. */
+    fd = qemu_pipe_open(con_name);
+    if (fd < 0) {
+        /* This could be an older version of the emulator, that doesn't
+         * implement adb QEMUD service. Fall back to the old TCP way. */
+        adb_thread_t thr;
+        D("adb service is not available. Falling back to TCP socket.\n");
+        adb_thread_create(&thr, server_socket_thread, arg);
+        return 0;
+    }
+
+    for(;;) {
+        /*
+         * Wait till the host creates a new connection.
+         */
+
+        /* Send the 'accept' request. */
+        res = adb_write(fd, _accept_req, strlen(_accept_req));
+        if ((size_t)res == strlen(_accept_req)) {
+            /* Wait for the response. In the response we expect 'ok' on success,
+             * or 'ko' on failure. */
+            res = adb_read(fd, tmp, sizeof(tmp));
+            if (res != 2 || memcmp(tmp, _ok_resp, 2)) {
+                D("Accepting ADB host connection has failed.\n");
+                adb_close(fd);
+            } else {
+                /* Host is connected. Register the transport, and start the
+                 * exchange. */
+                register_socket_transport(fd, "host", port, 1);
+                adb_write(fd, _start_req, strlen(_start_req));
+            }
+
+            /* Prepare for accepting of the next ADB host connection. */
+            fd = qemu_pipe_open(con_name);
+            if (fd < 0) {
+                D("adb service become unavailable.\n");
+                return 0;
+            }
+        } else {
+            D("Unable to send the '%s' request to ADB service.\n", _accept_req);
+            return 0;
+        }
+    }
+    D("transport: qemu_socket_thread() exiting\n");
+    return 0;
+}
+#endif  // !ADB_HOST
+
+void local_init(int port)
+{
+    adb_thread_t thr;
+    void* (*func)(void *);
+
+    if(HOST) {
+        func = client_socket_thread;
+    } else {
+#if ADB_HOST
+        func = server_socket_thread;
+#elif ADB_NON_ANDROID
+        func = server_socket_thread;
+#else
+        /* For the adbd daemon in the system image we need to distinguish
+         * between the device, and the emulator. */
+        char is_qemu[PROPERTY_VALUE_MAX];
+        property_get("ro.kernel.qemu", is_qemu, "");
+        if (!strcmp(is_qemu, "1")) {
+            /* Running inside the emulator: use QEMUD pipe as the transport. */
+            func = qemu_socket_thread;
+        } else {
+            /* Running inside the device: use TCP socket as the transport. */
+            func = server_socket_thread;
+        }
+#endif // !ADB_HOST
+    }
+
+    D("transport: local %s init\n", HOST ? "client" : "server");
+
+    if(adb_thread_create(&thr, func, (void *) (uintptr_t) port)) {
+        fatal_errno("cannot create local socket %s thread",
+                    HOST ? "client" : "server");
+    }
+}
+
+static void remote_kick(atransport *t)
+{
+    int fd = t->sfd;
+    t->sfd = -1;
+    adb_shutdown(fd);
+    adb_close(fd);
+
+#if ADB_HOST
+    if(HOST) {
+        int  nn;
+        adb_mutex_lock( &local_transports_lock );
+        for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
+            if (local_transports[nn] == t) {
+                local_transports[nn] = NULL;
+                break;
+            }
+        }
+        adb_mutex_unlock( &local_transports_lock );
+    }
+#endif
+}
+
+static void remote_close(atransport *t)
+{
+    adb_close(t->fd);
+}
+
+
+#if ADB_HOST
+/* Only call this function if you already hold local_transports_lock. */
+atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
+{
+    int i;
+    for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
+        if (local_transports[i] && local_transports[i]->adb_port == adb_port) {
+            return local_transports[i];
+        }
+    }
+    return NULL;
+}
+
+atransport* find_emulator_transport_by_adb_port(int adb_port)
+{
+    adb_mutex_lock( &local_transports_lock );
+    atransport* result = find_emulator_transport_by_adb_port_locked(adb_port);
+    adb_mutex_unlock( &local_transports_lock );
+    return result;
+}
+
+/* Only call this function if you already hold local_transports_lock. */
+int get_available_local_transport_index_locked()
+{
+    int i;
+    for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
+        if (local_transports[i] == NULL) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int get_available_local_transport_index()
+{
+    adb_mutex_lock( &local_transports_lock );
+    int result = get_available_local_transport_index_locked();
+    adb_mutex_unlock( &local_transports_lock );
+    return result;
+}
+#endif
+
+int init_socket_transport(atransport *t, int s, int adb_port, int local)
+{
+    int  fail = 0;
+
+    t->kick = remote_kick;
+    t->close = remote_close;
+    t->read_from_remote = remote_read;
+    t->write_to_remote = remote_write;
+    t->sfd = s;
+    t->sync_token = 1;
+    t->connection_state = CS_OFFLINE;
+    t->type = kTransportLocal;
+    t->adb_port = 0;
+
+#if ADB_HOST
+    if (HOST && local) {
+        adb_mutex_lock( &local_transports_lock );
+        {
+            t->adb_port = adb_port;
+            atransport* existing_transport =
+                    find_emulator_transport_by_adb_port_locked(adb_port);
+            int index = get_available_local_transport_index_locked();
+            if (existing_transport != NULL) {
+                D("local transport for port %d already registered (%p)?\n",
+                adb_port, existing_transport);
+                fail = -1;
+            } else if (index < 0) {
+                // Too many emulators.
+                D("cannot register more emulators. Maximum is %d\n",
+                        ADB_LOCAL_TRANSPORT_MAX);
+                fail = -1;
+            } else {
+                local_transports[index] = t;
+            }
+       }
+       adb_mutex_unlock( &local_transports_lock );
+    }
+#endif
+    return fail;
+}
diff --git a/src/devtools/adb/transport_pcie.c b/src/devtools/adb/transport_pcie.c
new file mode 100755
index 0000000..d677587
--- /dev/null
+++ b/src/devtools/adb/transport_pcie.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sysdeps.h>
+#include "transport_pcie.h"
+
+#define  TRACE_TAG  TRACE_TRANSPORT
+#include "adb.h"
+
+#ifdef HAVE_BIG_ENDIAN
+#define H4(x)	(((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
+static inline void fix_endians(apacket *p)
+{
+    p->msg.command     = H4(p->msg.command);
+    p->msg.arg0        = H4(p->msg.arg0);
+    p->msg.arg1        = H4(p->msg.arg1);
+    p->msg.data_length = H4(p->msg.data_length);
+    p->msg.data_check  = H4(p->msg.data_check);
+    p->msg.magic       = H4(p->msg.magic);
+}
+unsigned host_to_le32(unsigned n)
+{
+    return H4(n);
+}
+#else
+#define fix_endians(p) do {} while (0)
+unsigned host_to_le32(unsigned n)
+{
+    return n;
+}
+#endif
+
+static int remote_read(apacket *p, atransport *t)
+{
+	struct pcie_handle *pcie = t->pcie;
+
+	if(unix_read(pcie->fd, &p->msg, sizeof(amessage)) < 0){
+		D("remote pcie: read terminated (message)\n");
+		return -1;
+	}
+
+	fix_endians(p);
+
+	if(check_header(p)) {
+		D("remote pcie: check_header failed\n");
+		return -1;
+	}
+
+	if(p->msg.data_length) {
+		if(unix_read(pcie->fd, p->data, p->msg.data_length) < 0){
+			D("remote pcie: terminated (data)\n");
+			return -1;
+		}
+	}
+
+	if(check_data(p)) {
+		D("remote pcie: check_data failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int remote_write(apacket *p, atransport *t)
+{
+    unsigned size = p->msg.data_length;
+	struct pcie_handle *pcie = t->pcie;
+
+    fix_endians(p);
+
+    if(unix_write(pcie->fd, &p->msg, sizeof(amessage)) < 0) {
+        D("remote pcie: 1 - write terminated\n");
+        return -1;
+    }
+
+    if(p->msg.data_length == 0)
+	return 0;
+
+    if(unix_write(pcie->fd, p->data, size) < 0) {
+        D("remote pcie: 2 - write terminated\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static void remote_close(atransport *t)
+{
+    struct pcie_handle *pcie = t->pcie;
+
+    unix_close(pcie->fd);
+    pcie->fd = -1;
+}
+
+static void remote_kick(atransport *t)
+{
+	struct pcie_handle *pcie = t->pcie;
+
+	if (pcie->kick)
+		pcie->kick(pcie);
+}
+
+void init_pcie_transport(atransport *t, struct pcie_handle *h, const char *devpath, int state)
+{
+    static char *pcie_unknow = "0123456mediatek";
+    D("transport: pcie\n");
+    /* On host side, we need open the file here */
+    if (h->fd < 0)
+	    h->fd = unix_open(devpath, O_RDWR);
+
+    t->close = remote_close;
+    t->kick = remote_kick;
+    t->read_from_remote = remote_read;
+    t->write_to_remote = remote_write;
+    t->sync_token = 1;
+    t->connection_state = state;
+    t->type = kTransportUsb;
+    t->pcie = h;
+
+    /* Device information */
+    t->serial = pcie_unknow;
+    t->device = pcie_unknow;
+    t->product = pcie_unknow;
+
+#if ADB_HOST
+    HOST = 1;
+#else
+    HOST = 0;
+#endif
+}
+
+#if ADB_HOST
+void pcie_host_init(void)
+{
+	struct pcie_handle *pcie;
+
+	pcie = calloc(1, sizeof(*pcie));
+
+	pcie->fd = unix_open(PCIE_ADB_PATH, O_RDWR);
+
+	register_pcie_transport(pcie, PCIE_ADB_PATH, 1);
+}
+
+#else
+/* For ADBD */
+static void *pcie_open_thread(void *x)
+{
+	struct pcie_handle *pcie = (struct pcie_handle *)x;
+	int fd = -1;
+	char *banner = "Start PCIe port\n";
+
+	while (1) {
+		adb_mutex_lock(&pcie->lock);
+		while (pcie->fd != -1)
+			adb_cond_wait(&pcie->notify, &pcie->lock);
+		adb_mutex_unlock(&pcie->lock);
+
+		do {
+			fd = unix_open(PCIE_ADB_PATH, O_RDWR);
+			if (fd < 0) {
+				adb_sleep_ms(1000);
+			}
+		} while (fd < 0);
+
+		pcie->fd = fd;
+		adb_write(fd, banner, strlen(banner));
+
+		/* Get PCIe config information */
+		fd = unix_open(PCIE_INFO_ADB_PATH, O_RDONLY);
+		if (fd > 0) {
+			pcie->info = calloc(1, sizeof(struct pcie_info));
+			if (pcie->info)
+				unix_read(fd, pcie->info, sizeof(pcie->info));
+
+			unix_close(fd);
+		}
+
+		register_pcie_transport(pcie, PCIE_ADB_PATH, 1);
+	}
+
+	// never gets here
+	return 0;
+}
+
+static void pcie_adbd_kick(struct pcie_handle *h)
+{
+	adb_mutex_lock(&h->lock);
+	unix_close(h->fd);
+	h->fd = -1;
+
+	adb_cond_signal(&h->notify);
+	adb_mutex_unlock(&h->lock);
+}
+
+void pcie_init(void)
+{
+    adb_thread_t tid;
+    struct pcie_handle *h;
+
+    h = calloc(1, sizeof(*h));
+
+    h->kick = pcie_adbd_kick;
+    h->fd = -1;
+
+    adb_cond_init(&h->notify, 0);
+    adb_mutex_init(&h->lock, 0);
+
+    D("[ pcie_init - starting thread ]\n");
+    if (adb_thread_create(&tid, pcie_open_thread, h)) {
+        fatal_errno("[ cannot create pcie thread ]\n");
+    }
+}
+#endif
diff --git a/src/devtools/adb/transport_pcie.h b/src/devtools/adb/transport_pcie.h
new file mode 100755
index 0000000..8c33ae0
--- /dev/null
+++ b/src/devtools/adb/transport_pcie.h
@@ -0,0 +1,26 @@
+#ifndef __TRANSPORT_PCIE__H
+#define __TRANSPORT_PCIE__H
+
+#include "fdevent.h"
+#include "adb.h"
+#include "sysdeps.h"
+
+struct pcie_info {
+	unsigned short device;
+	unsigned short vendor;
+	unsigned int class;
+};
+
+struct pcie_handle {
+	int fd;
+	struct pcie_info *info;
+
+	adb_cond_t notify;
+	adb_mutex_t lock;
+
+	int (*write)(struct pcie_handle *h, const void *data, int len);
+	int (*read)(struct pcie_handle *h, void *data, int len);
+	void (*kick)(struct pcie_handle *h);
+};
+
+#endif
diff --git a/src/devtools/adb/transport_usb.c b/src/devtools/adb/transport_usb.c
new file mode 100755
index 0000000..3d19803
--- /dev/null
+++ b/src/devtools/adb/transport_usb.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sysdeps.h>
+
+#define  TRACE_TAG  TRACE_TRANSPORT
+#include "adb.h"
+
+#ifdef HAVE_BIG_ENDIAN
+#define H4(x)	(((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
+static inline void fix_endians(apacket *p)
+{
+    p->msg.command     = H4(p->msg.command);
+    p->msg.arg0        = H4(p->msg.arg0);
+    p->msg.arg1        = H4(p->msg.arg1);
+    p->msg.data_length = H4(p->msg.data_length);
+    p->msg.data_check  = H4(p->msg.data_check);
+    p->msg.magic       = H4(p->msg.magic);
+}
+unsigned host_to_le32(unsigned n)
+{
+    return H4(n);
+}
+#else
+#define fix_endians(p) do {} while (0)
+unsigned host_to_le32(unsigned n)
+{
+    return n;
+}
+#endif
+
+static int remote_read(apacket *p, atransport *t)
+{
+    if(usb_read(t->usb, &p->msg, sizeof(amessage))){
+        D("remote usb: read terminated (message)\n");
+        return -1;
+    }
+
+    fix_endians(p);
+
+    if(check_header(p)) {
+        D("remote usb: check_header failed\n");
+        return -1;
+    }
+
+    if(p->msg.data_length) {
+        if(usb_read(t->usb, p->data, p->msg.data_length)){
+            D("remote usb: terminated (data)\n");
+            return -1;
+        }
+    }
+
+    if(check_data(p)) {
+        D("remote usb: check_data failed\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int remote_write(apacket *p, atransport *t)
+{
+    unsigned size = p->msg.data_length;
+
+    fix_endians(p);
+
+    if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
+        D("remote usb: 1 - write terminated\n");
+        return -1;
+    }
+    if(p->msg.data_length == 0) return 0;
+    if(usb_write(t->usb, &p->data, size)) {
+        D("remote usb: 2 - write terminated\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static void remote_close(atransport *t)
+{
+    usb_close(t->usb);
+    t->usb = 0;
+}
+
+static void remote_kick(atransport *t)
+{
+    usb_kick(t->usb);
+}
+
+void init_usb_transport(atransport *t, usb_handle *h, int state)
+{
+    D("transport: usb\n");
+    t->close = remote_close;
+    t->kick = remote_kick;
+    t->read_from_remote = remote_read;
+    t->write_to_remote = remote_write;
+    t->sync_token = 1;
+    t->connection_state = state;
+    t->type = kTransportUsb;
+    t->usb = h;
+
+#if ADB_HOST
+    HOST = 1;
+#else
+    HOST = 0;
+#endif
+}
+
+#if ADB_HOST
+int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
+{
+    return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
+}
+#endif
diff --git a/src/devtools/adb/usb_libusb.c b/src/devtools/adb/usb_libusb.c
new file mode 100755
index 0000000..06ff5dc
--- /dev/null
+++ b/src/devtools/adb/usb_libusb.c
@@ -0,0 +1,657 @@
+/* 
+ * Copyright (C) 2009 bsdroid project
+ *               Alexey Tarasov <tarasov@dodologics.com>
+ *   
+ * Copyright (C) 2007 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/endian.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <err.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <libusb.h>
+#include "sysdeps.h"
+
+#define   TRACE_TAG  TRACE_USB
+#include "adb.h"
+
+static adb_mutex_t usb_lock = ADB_MUTEX_INITIALIZER;
+static libusb_context *ctx = NULL;
+
+struct usb_handle
+{
+    usb_handle            *prev;
+    usb_handle            *next;
+
+    libusb_device         *dev;
+    libusb_device_handle  *devh;
+    int                   interface;
+    uint8_t               dev_bus;
+    uint8_t               dev_addr;
+	
+    int                   zero_mask;
+    unsigned char         end_point_address[2];
+    char                  serial[128];
+    
+    adb_cond_t            notify;
+    adb_mutex_t           lock;
+};
+
+static struct usb_handle handle_list = {
+        .prev = &handle_list,
+        .next = &handle_list,
+};
+
+void
+usb_cleanup()
+{
+	libusb_exit(ctx);
+}
+
+void
+report_bulk_libusb_error(int r)
+{
+    switch (r) {
+    case LIBUSB_ERROR_TIMEOUT:
+        D("Transfer timeout\n");
+        break;
+
+    case LIBUSB_ERROR_PIPE:
+        D("Control request is not supported\n");
+        break;
+
+    case LIBUSB_ERROR_OVERFLOW:
+        D("Device offered more data\n");
+        break;
+
+    case LIBUSB_ERROR_NO_DEVICE :
+        D("Device was disconnected\n");
+        break;
+
+    default:
+        D("Error %d during transfer\n", r);
+        break;
+    };
+}
+
+static int
+usb_bulk_write(usb_handle *uh, const void *data, int len)
+{
+    int r = 0;
+    int transferred = 0;
+
+    r = libusb_bulk_transfer(uh->devh, uh->end_point_address[1], (void *)data, len,
+                             &transferred, 0);
+   
+    if (r != 0) {
+        D("usb_bulk_write(): ");
+        report_bulk_libusb_error(r);
+        return r;
+    }
+   
+    return (transferred);
+}
+
+static int
+usb_bulk_read(usb_handle *uh, void *data, int len)
+{
+    int r = 0;
+    int transferred = 0;
+
+    r = libusb_bulk_transfer(uh->devh, uh->end_point_address[0], data, len,
+                             &transferred, 0);
+
+    if (r != 0) {
+        D("usb_bulk_read(): ");
+        report_bulk_libusb_error(r);
+        return r;
+    }
+   
+    return (transferred);
+}
+
+int
+usb_write(struct usb_handle *uh, const void *_data, int len)
+{
+    unsigned char *data = (unsigned char*) _data;
+    int n;
+    int need_zero = 0;
+
+    if (uh->zero_mask == 1) {
+        if (!(len & uh->zero_mask)) {
+            need_zero = 1;
+        }
+    }
+
+    D("usb_write(): %p:%d -> transport %p\n", _data, len, uh);
+    
+    while (len > 0) {
+        int xfer = (len > 4096) ? 4096 : len;
+
+        n = usb_bulk_write(uh, data, xfer);
+        
+        if (n != xfer) {
+            D("usb_write(): failed for transport %p (%d bytes left)\n", uh, len);
+            return -1;
+        }
+
+        len -= xfer;
+        data += xfer;
+    }
+
+    if (need_zero){
+        n = usb_bulk_write(uh, _data, 0);
+        
+        if (n < 0) {
+            D("usb_write(): failed to finish operation for transport %p\n", uh);
+        }
+        return n;
+    }
+
+    return 0;
+}
+
+int
+usb_read(struct usb_handle *uh, void *_data, int len)
+{
+    unsigned char *data = (unsigned char*) _data;
+    int n;
+
+    D("usb_read(): %p:%d <- transport %p\n", _data, len, uh);
+    
+    while (len > 0) {
+        int xfer = (len > 4096) ? 4096 : len;
+
+        n = usb_bulk_read(uh, data, xfer);
+        
+        if (n != xfer) {
+            if (n > 0) {
+                data += n;
+                len -= n;
+                continue;
+            }
+            
+            D("usb_read(): failed for transport %p (%d bytes left)\n", uh, len);
+            return -1;
+        }
+
+        len -= xfer;
+        data += xfer;
+    }
+
+    return 0;
+ }
+
+int
+usb_close(struct usb_handle *h)
+{
+    D("usb_close(): closing transport %p\n", h);
+    adb_mutex_lock(&usb_lock);
+    
+    h->next->prev = h->prev;
+    h->prev->next = h->next;
+    h->prev = NULL;
+    h->next = NULL;
+
+    libusb_release_interface(h->devh, h->interface);
+    libusb_close(h->devh);
+    libusb_unref_device(h->dev);
+    
+    adb_mutex_unlock(&usb_lock);
+
+    free(h);
+
+    return (0);
+}
+
+void usb_kick(struct usb_handle *h)
+{
+    D("usb_cick(): kicking transport %p\n", h);
+    
+    adb_mutex_lock(&h->lock);
+    unregister_usb_transport(h);
+    adb_mutex_unlock(&h->lock);
+    
+    h->next->prev = h->prev;
+    h->prev->next = h->next;
+    h->prev = NULL;
+    h->next = NULL;
+
+    libusb_release_interface(h->devh, h->interface);
+    libusb_close(h->devh);
+    libusb_unref_device(h->dev);
+    free(h);
+}
+
+int
+check_usb_interface(libusb_interface *interface,
+                    libusb_device_descriptor *desc,
+                    struct usb_handle *uh)
+{    
+    int e;
+    
+    if (interface->num_altsetting == 0) {
+        D("check_usb_interface(): No interface settings\n");
+        return -1;
+    }
+    
+    libusb_interface_descriptor *idesc = &interface->altsetting[0];
+    
+    if (idesc->bNumEndpoints != 2) {
+        D("check_usb_interface(): Interface have not 2 endpoints, ignoring\n");
+        return -1;
+    }
+
+    for (e = 0; e < idesc->bNumEndpoints; e++) {
+        libusb_endpoint_descriptor *edesc = &idesc->endpoint[e];
+        
+        if (edesc->bmAttributes != LIBUSB_TRANSFER_TYPE_BULK) {
+            D("check_usb_interface(): Endpoint (%u) is not bulk (%u), ignoring\n",
+                    edesc->bmAttributes, LIBUSB_TRANSFER_TYPE_BULK);
+            return -1;
+        }
+        
+        if (edesc->bEndpointAddress & LIBUSB_ENDPOINT_IN)
+            uh->end_point_address[0] = edesc->bEndpointAddress;
+        else
+            uh->end_point_address[1] = edesc->bEndpointAddress;
+        
+            /* aproto 01 needs 0 termination */
+        if (idesc->bInterfaceProtocol == 0x01) {
+            uh->zero_mask = edesc->wMaxPacketSize - 1;
+            D("check_usb_interface(): Forced Android interface protocol v.1\n");
+        }
+    }
+
+    D("check_usb_interface(): Device: %04x:%04x "
+      "iclass: %x, isclass: %x, iproto: %x ep: %x/%x-> ",
+        desc->idVendor, desc->idProduct, idesc->bInterfaceClass,
+	idesc->bInterfaceSubClass, idesc->bInterfaceProtocol,
+	uh->end_point_address[0], uh->end_point_address[1]);
+    
+    if (!is_adb_interface(desc->idVendor, desc->idProduct,
+            idesc->bInterfaceClass, idesc->bInterfaceSubClass,
+            idesc->bInterfaceProtocol))
+    {
+        D("not matches\n");
+        return -1;
+    }
+
+    D("matches\n");
+    return 1;
+}
+
+int
+check_usb_interfaces(libusb_config_descriptor *config,
+                     libusb_device_descriptor *desc, struct usb_handle *uh)
+{  
+    int i;
+    
+    for (i = 0; i < config->bNumInterfaces; ++i) {
+        if (check_usb_interface(&config->interface[i], desc, uh) != -1) {
+            /* found some interface and saved information about it */
+            D("check_usb_interfaces(): Interface %d of %04x:%04x "
+              "matches Android device\n", i, desc->idVendor,
+	      desc->idProduct);
+            
+            return  i;
+        }
+    }
+    
+    return -1;
+}
+
+int
+register_device(struct usb_handle *uh, const char *serial)
+{
+    D("register_device(): Registering %p [%s] as USB transport\n",
+       uh, serial);
+
+    struct usb_handle *usb= NULL;
+
+    usb = calloc(1, sizeof(struct usb_handle));
+    memcpy(usb, uh, sizeof(struct usb_handle));
+    strcpy(usb->serial, uh->serial);
+
+    adb_cond_init(&usb->notify, 0);
+    adb_mutex_init(&usb->lock, 0);
+
+    adb_mutex_lock(&usb_lock);
+    
+    usb->next = &handle_list;
+    usb->prev = handle_list.prev;
+    usb->prev->next = usb;
+    usb->next->prev = usb;
+
+    adb_mutex_unlock(&usb_lock);
+
+    register_usb_transport(usb, serial, NULL, 1); 
+
+    return (1);
+}
+
+int
+already_registered(usb_handle *uh)
+{
+    struct usb_handle *usb= NULL;
+    int exists = 0;
+    
+    adb_mutex_lock(&usb_lock);
+
+    for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+        if ((usb->dev_bus == uh->dev_bus) &&
+            (usb->dev_addr == uh->dev_addr))
+        {
+            exists = 1;
+            break;
+        }
+    }
+
+    adb_mutex_unlock(&usb_lock);
+
+    return exists;
+}
+
+void
+check_device(libusb_device *dev) 
+{
+    struct usb_handle uh;
+    int i = 0;
+    int found = -1;
+    char serial[256] = {0};
+
+    libusb_device_descriptor desc;
+    libusb_config_descriptor *config = NULL;
+    
+    int r = libusb_get_device_descriptor(dev, &desc);
+
+    if (r != LIBUSB_SUCCESS) {
+        D("check_device(): Failed to get device descriptor\n");
+        return;
+    }
+    
+    if ((desc.idVendor == 0) && (desc.idProduct == 0))
+        return;
+    
+    D("check_device(): Probing usb device %04x:%04x\n",
+        desc.idVendor, desc.idProduct);
+    
+    if (!is_adb_interface (desc.idVendor, desc.idProduct,
+                           ADB_CLASS, ADB_SUBCLASS, ADB_PROTOCOL))
+    {
+        D("check_device(): Ignored due unknown vendor id\n");
+        return;
+    }
+    
+    uh.dev_bus = libusb_get_bus_number(dev);
+    uh.dev_addr = libusb_get_device_address(dev);
+    
+    if (already_registered(&uh)) {
+        D("check_device(): Device (bus: %d, address: %d) "
+          "is already registered\n", uh.dev_bus, uh.dev_addr);
+        return;
+    }
+    
+    D("check_device(): Device bus: %d, address: %d\n",
+        uh.dev_bus, uh.dev_addr);
+
+    r = libusb_get_active_config_descriptor(dev, &config);
+    
+    if (r != 0) {
+        if (r == LIBUSB_ERROR_NOT_FOUND) {
+            D("check_device(): Device %4x:%4x is unconfigured\n", 
+                desc.idVendor, desc.idProduct);
+            return;
+        }
+        
+        D("check_device(): Failed to get configuration for %4x:%4x\n",
+            desc.idVendor, desc.idProduct);
+        return;
+    }
+    
+    if (config == NULL) {
+        D("check_device(): Sanity check failed after "
+          "getting active config\n");
+        return;
+    }
+    
+    if (config->interface != NULL) {
+        found = check_usb_interfaces(config, &desc, &uh);
+    }
+    
+    /* not needed anymore */
+    libusb_free_config_descriptor(config);
+    
+    r = libusb_open(dev, &uh.devh);
+    uh.dev = dev;
+
+    if (r != 0) {
+        switch (r) {
+            case LIBUSB_ERROR_NO_MEM:
+                D("check_device(): Memory allocation problem\n");
+                break;
+                
+            case LIBUSB_ERROR_ACCESS:
+                D("check_device(): Permissions problem, "
+                  "current user priveleges are messed up?\n");
+                break;
+                
+            case LIBUSB_ERROR_NO_DEVICE:
+                D("check_device(): Device disconected, bad cable?\n");
+                break;
+            
+            default:
+                D("check_device(): libusb triggered error %d\n", r);
+        }
+        // skip rest
+        found = -1;
+    }
+    
+    if (found >= 0) {
+        D("check_device(): Device matches Android interface\n");
+        // read the device's serial number
+        memset(serial, 0, sizeof(serial));
+        uh.interface = found;
+        
+        r = libusb_claim_interface(uh.devh, uh.interface);
+        
+        if (r < 0) {
+            D("check_device(): Failed to claim interface %d\n",
+                uh.interface);
+
+            goto fail;
+        }
+
+        if (desc.iSerialNumber) {
+            // reading serial
+            uint16_t    buffer[128] = {0};
+            uint16_t    languages[128] = {0};
+            int languageCount = 0;
+
+            memset(languages, 0, sizeof(languages));
+            r = libusb_control_transfer(uh.devh, 
+                LIBUSB_ENDPOINT_IN |  LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
+                LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8,
+		0, (uint8_t *)languages, sizeof(languages), 0);
+
+            if (r <= 0) {
+                D("check_device(): Failed to get languages count\n");
+                goto fail;
+            } 
+            
+            languageCount = (r - 2) / 2;
+            
+            for (i = 1; i <= languageCount; ++i) {
+                memset(buffer, 0, sizeof(buffer));
+
+                r = libusb_control_transfer(uh.devh, 
+                    LIBUSB_ENDPOINT_IN |  LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
+                    LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc.iSerialNumber,
+		    languages[i], (uint8_t *)buffer, sizeof(buffer), 0);
+            
+                if (r > 0) { /* converting serial */
+                    int j = 0;
+                    r /= 2;
+                
+                    for (j = 1; j < r; ++j)
+                        serial[j - 1] = buffer[j];
+                
+                    serial[j - 1] = '\0';
+                    break; /* languagesCount cycle */
+                }
+            }
+            
+            if (register_device(&uh, serial) == 0) {
+                D("check_device(): Failed to register device\n");
+                goto fail_interface;
+            }
+            
+            libusb_ref_device(dev);
+        }
+    }
+    
+    return;
+
+fail_interface:
+    libusb_release_interface(uh.devh, uh.interface);
+
+fail:
+    libusb_close(uh.devh);
+    uh.devh = NULL;
+}
+
+int
+check_device_connected(struct usb_handle *uh)
+{
+    int r = libusb_kernel_driver_active(uh->devh, uh->interface);
+    
+    if (r == LIBUSB_ERROR_NO_DEVICE)
+        return 0;
+    
+    if (r < 0)
+        return -1;
+    
+    return 1;
+}
+
+void
+kick_disconnected()
+{
+    struct usb_handle *usb= NULL;
+    
+    adb_mutex_lock(&usb_lock);
+
+    for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+        
+        if (check_device_connected(usb) == 0) {
+            D("kick_disconnected(): Transport %p is not online anymore\n",
+                usb);
+
+            usb_kick(usb);
+        }
+    }
+    
+    adb_mutex_unlock(&usb_lock);
+}
+
+void
+scan_usb_devices()
+{
+    D("scan_usb_devices(): started\n");
+    
+    libusb_device **devs= NULL;
+    libusb_device *dev= NULL;
+    ssize_t cnt = libusb_get_device_list(ctx, &devs);
+
+    if (cnt < 0) {
+        D("scan_usb_devices(): Failed to get device list (error: %d)\n",
+            cnt);
+
+        return;
+    }
+    
+    int i = 0;
+
+    while ((dev = devs[i++]) != NULL) {
+        check_device(dev);
+    }
+
+    libusb_free_device_list(devs, 1);
+}
+
+void *
+device_poll_thread(void* unused)
+{
+    D("device_poll_thread(): Created USB scan thread\n");
+    
+    for (;;) {
+        sleep(5);
+        kick_disconnected();
+        scan_usb_devices();
+    }
+
+    /* never reaching this point */
+    return (NULL);
+}
+
+static void
+sigalrm_handler(int signo)
+{
+    /* nothing */
+}
+
+void
+usb_init()
+{
+    D("usb_init(): started\n");
+    adb_thread_t        tid;
+    struct sigaction actions;
+
+    int r = libusb_init(&ctx);
+
+    if (r != LIBUSB_SUCCESS) {
+        err(EX_IOERR, "Failed to init libusb\n");
+    }
+
+    memset(&actions, 0, sizeof(actions));
+    
+    sigemptyset(&actions.sa_mask);
+    
+    actions.sa_flags = 0;
+    actions.sa_handler = sigalrm_handler;
+    
+    sigaction(SIGALRM, &actions, NULL);
+
+	/* initial device scan */
+	scan_usb_devices();
+	
+	/* starting USB event polling thread */
+    if (adb_thread_create(&tid, device_poll_thread, NULL)) {
+            err(EX_IOERR, "cannot create USB scan thread\n");
+    }
+    
+    D("usb_init(): finished\n");
+}
+
diff --git a/src/devtools/adb/usb_linux.c b/src/devtools/adb/usb_linux.c
new file mode 100755
index 0000000..f16bdd0
--- /dev/null
+++ b/src/devtools/adb/usb_linux.c
@@ -0,0 +1,715 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <linux/usbdevice_fs.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
+#include <linux/usb/ch9.h>
+#else
+#include <linux/usb_ch9.h>
+#endif
+#include <asm/byteorder.h>
+
+#include "sysdeps.h"
+
+#define   TRACE_TAG  TRACE_USB
+#include "adb.h"
+
+
+/* usb scan debugging is waaaay too verbose */
+#define DBGX(x...)
+
+ADB_MUTEX_DEFINE( usb_lock );
+
+struct usb_handle
+{
+    usb_handle *prev;
+    usb_handle *next;
+
+    char fname[64];
+    int desc;
+    unsigned char ep_in;
+    unsigned char ep_out;
+
+    unsigned zero_mask;
+    unsigned writeable;
+
+    struct usbdevfs_urb urb_in;
+    struct usbdevfs_urb urb_out;
+
+    int urb_in_busy;
+    int urb_out_busy;
+    int dead;
+
+    adb_cond_t notify;
+    adb_mutex_t lock;
+
+    // for garbage collecting disconnected devices
+    int mark;
+
+    // ID of thread currently in REAPURB
+    pthread_t reaper_thread;
+};
+
+static usb_handle handle_list = {
+    .prev = &handle_list,
+    .next = &handle_list,
+};
+
+static int known_device(const char *dev_name)
+{
+    usb_handle *usb;
+
+    adb_mutex_lock(&usb_lock);
+    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
+        if(!strcmp(usb->fname, dev_name)) {
+            // set mark flag to indicate this device is still alive
+            usb->mark = 1;
+            adb_mutex_unlock(&usb_lock);
+            return 1;
+        }
+    }
+    adb_mutex_unlock(&usb_lock);
+    return 0;
+}
+
+static void kick_disconnected_devices()
+{
+    usb_handle *usb;
+
+    adb_mutex_lock(&usb_lock);
+    // kick any devices in the device list that were not found in the device scan
+    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
+        if (usb->mark == 0) {
+            usb_kick(usb);
+        } else {
+            usb->mark = 0;
+        }
+    }
+    adb_mutex_unlock(&usb_lock);
+
+}
+
+static void register_device(const char *dev_name, const char *devpath,
+                            unsigned char ep_in, unsigned char ep_out,
+                            int ifc, int serial_index, unsigned zero_mask);
+
+static inline int badname(const char *name)
+{
+    while(*name) {
+        if(!isdigit(*name++)) return 1;
+    }
+    return 0;
+}
+
+static void find_usb_device(const char *base,
+        void (*register_device_callback)
+                (const char *, const char *, unsigned char, unsigned char, int, int, unsigned))
+{
+    char busname[32], devname[32];
+    unsigned char local_ep_in, local_ep_out;
+    DIR *busdir , *devdir ;
+    struct dirent *de;
+    int fd ;
+
+    busdir = opendir(base);
+    if(busdir == 0) return;
+
+    while((de = readdir(busdir)) != 0) {
+        if(badname(de->d_name)) continue;
+
+        snprintf(busname, sizeof busname, "%s/%s", base, de->d_name);
+        devdir = opendir(busname);
+        if(devdir == 0) continue;
+
+//        DBGX("[ scanning %s ]\n", busname);
+        while((de = readdir(devdir))) {
+            unsigned char devdesc[4096];
+            unsigned char* bufptr = devdesc;
+            unsigned char* bufend;
+            struct usb_device_descriptor* device;
+            struct usb_config_descriptor* config;
+            struct usb_interface_descriptor* interface;
+            struct usb_endpoint_descriptor *ep1, *ep2;
+            unsigned zero_mask = 0;
+            unsigned vid, pid;
+            size_t desclength;
+
+            if(badname(de->d_name)) continue;
+            snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
+
+            if(known_device(devname)) {
+                DBGX("skipping %s\n", devname);
+                continue;
+            }
+
+//            DBGX("[ scanning %s ]\n", devname);
+            if((fd = unix_open(devname, O_RDONLY | O_CLOEXEC)) < 0) {
+                continue;
+            }
+
+            desclength = adb_read(fd, devdesc, sizeof(devdesc));
+            bufend = bufptr + desclength;
+
+                // should have device and configuration descriptors, and atleast two endpoints
+            if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) {
+                D("desclength %zu is too small\n", desclength);
+                adb_close(fd);
+                continue;
+            }
+
+            device = (struct usb_device_descriptor*)bufptr;
+            bufptr += USB_DT_DEVICE_SIZE;
+
+            if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) {
+                adb_close(fd);
+                continue;
+            }
+
+            vid = device->idVendor;
+            pid = device->idProduct;
+            DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid);
+
+                // should have config descriptor next
+            config = (struct usb_config_descriptor *)bufptr;
+            bufptr += USB_DT_CONFIG_SIZE;
+            if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) {
+                D("usb_config_descriptor not found\n");
+                adb_close(fd);
+                continue;
+            }
+
+                // loop through all the descriptors and look for the ADB interface
+            while (bufptr < bufend) {
+                unsigned char length = bufptr[0];
+                unsigned char type = bufptr[1];
+
+                if (type == USB_DT_INTERFACE) {
+                    interface = (struct usb_interface_descriptor *)bufptr;
+                    bufptr += length;
+
+                    if (length != USB_DT_INTERFACE_SIZE) {
+                        D("interface descriptor has wrong size\n");
+                        break;
+                    }
+
+                    DBGX("bInterfaceClass: %d,  bInterfaceSubClass: %d,"
+                         "bInterfaceProtocol: %d, bNumEndpoints: %d\n",
+                         interface->bInterfaceClass, interface->bInterfaceSubClass,
+                         interface->bInterfaceProtocol, interface->bNumEndpoints);
+
+                    if (interface->bNumEndpoints == 2 &&
+                            is_adb_interface(vid, pid, interface->bInterfaceClass,
+                            interface->bInterfaceSubClass, interface->bInterfaceProtocol))  {
+
+                        struct stat st;
+                        char pathbuf[128];
+                        char link[256];
+                        char *devpath = NULL;
+
+                        DBGX("looking for bulk endpoints\n");
+                            // looks like ADB...
+                        ep1 = (struct usb_endpoint_descriptor *)bufptr;
+                        bufptr += USB_DT_ENDPOINT_SIZE;
+                        ep2 = (struct usb_endpoint_descriptor *)bufptr;
+                        bufptr += USB_DT_ENDPOINT_SIZE;
+
+                        if (bufptr > devdesc + desclength ||
+                            ep1->bLength != USB_DT_ENDPOINT_SIZE ||
+                            ep1->bDescriptorType != USB_DT_ENDPOINT ||
+                            ep2->bLength != USB_DT_ENDPOINT_SIZE ||
+                            ep2->bDescriptorType != USB_DT_ENDPOINT) {
+                            D("endpoints not found\n");
+                            break;
+                        }
+
+                            // both endpoints should be bulk
+                        if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK ||
+                            ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) {
+                            D("bulk endpoints not found\n");
+                            continue;
+                        }
+                            /* aproto 01 needs 0 termination */
+                        if(interface->bInterfaceProtocol == 0x01) {
+                            zero_mask = ep1->wMaxPacketSize - 1;
+                        }
+
+                            // we have a match.  now we just need to figure out which is in and which is out.
+                        if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+                            local_ep_in = ep1->bEndpointAddress;
+                            local_ep_out = ep2->bEndpointAddress;
+                        } else {
+                            local_ep_in = ep2->bEndpointAddress;
+                            local_ep_out = ep1->bEndpointAddress;
+                        }
+
+                            // Determine the device path
+                        if (!fstat(fd, &st) && S_ISCHR(st.st_mode)) {
+                            char *slash;
+                            ssize_t link_len;
+                            snprintf(pathbuf, sizeof(pathbuf), "/sys/dev/char/%d:%d",
+                                     major(st.st_rdev), minor(st.st_rdev));
+                            link_len = readlink(pathbuf, link, sizeof(link) - 1);
+                            if (link_len > 0) {
+                                link[link_len] = '\0';
+                                slash = strrchr(link, '/');
+                                if (slash) {
+                                    snprintf(pathbuf, sizeof(pathbuf),
+                                             "usb:%s", slash + 1);
+                                    devpath = pathbuf;
+                                }
+                            }
+                        }
+
+                        register_device_callback(devname, devpath,
+                                local_ep_in, local_ep_out,
+                                interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
+                        break;
+                    }
+                } else {
+                    bufptr += length;
+                }
+            } // end of while
+
+            adb_close(fd);
+        } // end of devdir while
+        closedir(devdir);
+    } //end of busdir while
+    closedir(busdir);
+}
+
+void usb_cleanup()
+{
+}
+
+static int usb_bulk_write(usb_handle *h, const void *data, int len)
+{
+    struct usbdevfs_urb *urb = &h->urb_out;
+    int res;
+    struct timeval tv;
+    struct timespec ts;
+
+    memset(urb, 0, sizeof(*urb));
+    urb->type = USBDEVFS_URB_TYPE_BULK;
+    urb->endpoint = h->ep_out;
+    urb->status = -1;
+    urb->buffer = (void*) data;
+    urb->buffer_length = len;
+
+    D("++ write ++\n");
+
+    adb_mutex_lock(&h->lock);
+    if(h->dead) {
+        res = -1;
+        goto fail;
+    }
+    do {
+        res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
+    } while((res < 0) && (errno == EINTR));
+
+    if(res < 0) {
+        goto fail;
+    }
+
+    res = -1;
+    h->urb_out_busy = 1;
+    for(;;) {
+        /* time out after five seconds */
+        gettimeofday(&tv, NULL);
+        ts.tv_sec = tv.tv_sec + 5;
+        ts.tv_nsec = tv.tv_usec * 1000L;
+        res = pthread_cond_timedwait(&h->notify, &h->lock, &ts);
+        if(res < 0 || h->dead) {
+            break;
+        }
+        if(h->urb_out_busy == 0) {
+            if(urb->status == 0) {
+                res = urb->actual_length;
+            }
+            break;
+        }
+    }
+fail:
+    adb_mutex_unlock(&h->lock);
+    D("-- write --\n");
+    return res;
+}
+
+static int usb_bulk_read(usb_handle *h, void *data, int len)
+{
+    struct usbdevfs_urb *urb = &h->urb_in;
+    struct usbdevfs_urb *out = NULL;
+    int res;
+
+    memset(urb, 0, sizeof(*urb));
+    urb->type = USBDEVFS_URB_TYPE_BULK;
+    urb->endpoint = h->ep_in;
+    urb->status = -1;
+    urb->buffer = data;
+    urb->buffer_length = len;
+
+
+    adb_mutex_lock(&h->lock);
+    if(h->dead) {
+        res = -1;
+        goto fail;
+    }
+    do {
+        res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
+    } while((res < 0) && (errno == EINTR));
+
+    if(res < 0) {
+        goto fail;
+    }
+
+    h->urb_in_busy = 1;
+    for(;;) {
+        D("[ reap urb - wait ]\n");
+        h->reaper_thread = pthread_self();
+        adb_mutex_unlock(&h->lock);
+        res = ioctl(h->desc, USBDEVFS_REAPURB, &out);
+        int saved_errno = errno;
+        adb_mutex_lock(&h->lock);
+        h->reaper_thread = 0;
+        if(h->dead) {
+            res = -1;
+            break;
+        }
+        if(res < 0) {
+            if(saved_errno == EINTR) {
+                continue;
+            }
+            D("[ reap urb - error ]\n");
+            break;
+        }
+        D("[ urb @%p status = %d, actual = %d ]\n",
+            out, out->status, out->actual_length);
+
+        if(out == &h->urb_in) {
+            D("[ reap urb - IN complete ]\n");
+            h->urb_in_busy = 0;
+            if(urb->status == 0) {
+                res = urb->actual_length;
+            } else {
+                res = -1;
+            }
+            break;
+        }
+        if(out == &h->urb_out) {
+            D("[ reap urb - OUT compelete ]\n");
+            h->urb_out_busy = 0;
+            adb_cond_broadcast(&h->notify);
+        }
+    }
+fail:
+    adb_mutex_unlock(&h->lock);
+    return res;
+}
+
+
+int usb_write(usb_handle *h, const void *_data, int len)
+{
+    unsigned char *data = (unsigned char*) _data;
+    int n;
+    int need_zero = 0;
+
+    if(h->zero_mask) {
+            /* if we need 0-markers and our transfer
+            ** is an even multiple of the packet size,
+            ** we make note of it
+            */
+        if(!(len & h->zero_mask)) {
+            need_zero = 1;
+        }
+    }
+
+    while(len > 0) {
+        int xfer = (len > 4096) ? 4096 : len;
+
+        n = usb_bulk_write(h, data, xfer);
+        if(n != xfer) {
+            D("ERROR: n = %d, errno = %d (%s)\n",
+                n, errno, strerror(errno));
+            return -1;
+        }
+
+        len -= xfer;
+        data += xfer;
+    }
+
+    if(need_zero){
+        n = usb_bulk_write(h, _data, 0);
+        return n;
+    }
+
+    return 0;
+}
+
+int usb_read(usb_handle *h, void *_data, int len)
+{
+    unsigned char *data = (unsigned char*) _data;
+    int n;
+
+    D("++ usb_read ++\n");
+    while(len > 0) {
+        int xfer = (len > 4096) ? 4096 : len;
+
+        D("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname);
+        n = usb_bulk_read(h, data, xfer);
+        D("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname);
+        if(n != xfer) {
+            if((errno == ETIMEDOUT) && (h->desc != -1)) {
+                D("[ timeout ]\n");
+                if(n > 0){
+                    data += n;
+                    len -= n;
+                }
+                continue;
+            }
+            D("ERROR: n = %d, errno = %d (%s)\n",
+                n, errno, strerror(errno));
+            return -1;
+        }
+
+        len -= xfer;
+        data += xfer;
+    }
+
+    D("-- usb_read --\n");
+    return 0;
+}
+
+void usb_kick(usb_handle *h)
+{
+    D("[ kicking %p (fd = %d) ]\n", h, h->desc);
+    adb_mutex_lock(&h->lock);
+    if(h->dead == 0) {
+        h->dead = 1;
+
+        if (h->writeable) {
+            /* HACK ALERT!
+            ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
+            ** This is a workaround for that problem.
+            */
+            if (h->reaper_thread) {
+                pthread_kill(h->reaper_thread, SIGALRM);
+            }
+
+            /* cancel any pending transactions
+            ** these will quietly fail if the txns are not active,
+            ** but this ensures that a reader blocked on REAPURB
+            ** will get unblocked
+            */
+            ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
+            ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
+            h->urb_in.status = -ENODEV;
+            h->urb_out.status = -ENODEV;
+            h->urb_in_busy = 0;
+            h->urb_out_busy = 0;
+            adb_cond_broadcast(&h->notify);
+        } else {
+            unregister_usb_transport(h);
+        }
+    }
+    adb_mutex_unlock(&h->lock);
+}
+
+int usb_close(usb_handle *h)
+{
+    D("[ usb close ... ]\n");
+    adb_mutex_lock(&usb_lock);
+    h->next->prev = h->prev;
+    h->prev->next = h->next;
+    h->prev = 0;
+    h->next = 0;
+
+    adb_close(h->desc);
+    D("[ usb closed %p (fd = %d) ]\n", h, h->desc);
+    adb_mutex_unlock(&usb_lock);
+
+    free(h);
+    return 0;
+}
+
+static void register_device(const char *dev_name, const char *devpath,
+                            unsigned char ep_in, unsigned char ep_out,
+                            int interface, int serial_index, unsigned zero_mask)
+{
+    usb_handle* usb = 0;
+    int n = 0;
+    char serial[256];
+
+        /* Since Linux will not reassign the device ID (and dev_name)
+        ** as long as the device is open, we can add to the list here
+        ** once we open it and remove from the list when we're finally
+        ** closed and everything will work out fine.
+        **
+        ** If we have a usb_handle on the list 'o handles with a matching
+        ** name, we have no further work to do.
+        */
+    adb_mutex_lock(&usb_lock);
+    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
+        if(!strcmp(usb->fname, dev_name)) {
+            adb_mutex_unlock(&usb_lock);
+            return;
+        }
+    }
+    adb_mutex_unlock(&usb_lock);
+
+    D("[ usb located new device %s (%d/%d/%d) ]\n",
+        dev_name, ep_in, ep_out, interface);
+    usb = calloc(1, sizeof(usb_handle));
+    strcpy(usb->fname, dev_name);
+    usb->ep_in = ep_in;
+    usb->ep_out = ep_out;
+    usb->zero_mask = zero_mask;
+    usb->writeable = 1;
+
+    adb_cond_init(&usb->notify, 0);
+    adb_mutex_init(&usb->lock, 0);
+    /* initialize mark to 1 so we don't get garbage collected after the device scan */
+    usb->mark = 1;
+    usb->reaper_thread = 0;
+
+    usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC);
+    if(usb->desc < 0) {
+        /* if we fail, see if have read-only access */
+        usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC);
+        if(usb->desc < 0) goto fail;
+        usb->writeable = 0;
+        D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
+    } else {
+        D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
+        n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
+        if(n != 0) goto fail;
+    }
+
+        /* read the device's serial number */
+    serial[0] = 0;
+    memset(serial, 0, sizeof(serial));
+    if (serial_index) {
+        struct usbdevfs_ctrltransfer  ctrl;
+        __u16 buffer[128];
+        __u16 languages[128];
+        int i, result;
+        int languageCount = 0;
+
+        memset(languages, 0, sizeof(languages));
+        memset(&ctrl, 0, sizeof(ctrl));
+
+            // read list of supported languages
+        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
+        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
+        ctrl.wValue = (USB_DT_STRING << 8) | 0;
+        ctrl.wIndex = 0;
+        ctrl.wLength = sizeof(languages);
+        ctrl.data = languages;
+        ctrl.timeout = 1000;
+
+        result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
+        if (result > 0)
+            languageCount = (result - 2) / 2;
+
+        for (i = 1; i <= languageCount; i++) {
+            memset(buffer, 0, sizeof(buffer));
+            memset(&ctrl, 0, sizeof(ctrl));
+
+            ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
+            ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
+            ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
+            ctrl.wIndex = __le16_to_cpu(languages[i]);
+            ctrl.wLength = sizeof(buffer);
+            ctrl.data = buffer;
+            ctrl.timeout = 1000;
+
+            result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
+            if (result > 0) {
+                int i;
+                // skip first word, and copy the rest to the serial string, changing shorts to bytes.
+                result /= 2;
+                for (i = 1; i < result; i++)
+                    serial[i - 1] = __le16_to_cpu(buffer[i]);
+                serial[i - 1] = 0;
+                break;
+            }
+        }
+    }
+
+        /* add to the end of the active handles */
+    adb_mutex_lock(&usb_lock);
+    usb->next = &handle_list;
+    usb->prev = handle_list.prev;
+    usb->prev->next = usb;
+    usb->next->prev = usb;
+    adb_mutex_unlock(&usb_lock);
+
+    register_usb_transport(usb, serial, devpath, usb->writeable);
+    return;
+
+fail:
+    D("[ usb open %s error=%d, err_str = %s]\n",
+        usb->fname,  errno, strerror(errno));
+    if(usb->desc >= 0) {
+        adb_close(usb->desc);
+    }
+    free(usb);
+}
+
+void* device_poll_thread(void* unused)
+{
+    D("Created device thread\n");
+    for(;;) {
+            /* XXX use inotify */
+        find_usb_device("/dev/bus/usb", register_device);
+        kick_disconnected_devices();
+        sleep(1);
+    }
+    return NULL;
+}
+
+static void sigalrm_handler(int signo)
+{
+    // don't need to do anything here
+}
+
+void usb_init()
+{
+    adb_thread_t tid;
+    struct sigaction    actions;
+
+    memset(&actions, 0, sizeof(actions));
+    sigemptyset(&actions.sa_mask);
+    actions.sa_flags = 0;
+    actions.sa_handler = sigalrm_handler;
+    sigaction(SIGALRM,& actions, NULL);
+
+    if(adb_thread_create(&tid, device_poll_thread, NULL)){
+        fatal_errno("cannot create input thread");
+    }
+}
diff --git a/src/devtools/adb/usb_linux_client.c b/src/devtools/adb/usb_linux_client.c
new file mode 100755
index 0000000..2466275
--- /dev/null
+++ b/src/devtools/adb/usb_linux_client.c
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stddef.h>
+#include <sys/epoll.h>
+
+#include "sysdeps.h"
+
+#define   TRACE_TAG  TRACE_USB
+#include "adb.h"
+
+#define MAX_PACKET_SIZE_FS	64
+#define MAX_PACKET_SIZE_HS	512
+#define MAX_PACKET_SIZE_SS	1024
+
+//#define cpu_to_le16(x)  htole16(x)
+//#define cpu_to_le32(x)  htole32(x)
+/*
+ * cpu_to_le16/32 are used when initializing structures, a context where a
+ * function call is not allowed. To solve this, we code cpu_to_le16/32 in a way
+ * that allows them to be used when initializing structures.
+ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x)  (x)
+#define cpu_to_le32(x)  (x)
+#else
+#define cpu_to_le16(x)  ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))
+#define cpu_to_le32(x)  \
+    ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >>  8) | \
+    (((x) & 0x0000ff00u) <<  8) | (((x) & 0x000000ffu) << 24))
+#endif
+
+#define FFS_CONTOL_MAX_EPOLL_EVENT 50
+#define DEBUG   0
+
+struct usb_handle
+{
+    adb_cond_t notify;
+    adb_mutex_t lock;
+
+    int (*write)(usb_handle *h, const void *data, int len);
+    int (*read)(usb_handle *h, void *data, int len);
+    void (*kick)(usb_handle *h);
+
+    // Legacy f_adb
+    int fd;
+
+    // FunctionFS
+    int control;
+    int bulk_out; /* "out" from the host's perspective => source for adbd */
+    int bulk_in;  /* "in" from the host's perspective => sink for adbd */
+    bool ffs_control_thread_created;
+};
+
+static const struct {
+    __le32 magic;
+    __le32 length;
+    __le32 flags;
+    __le32 fs_count;
+    __le32 hs_count;
+    __le32 ss_count;
+    struct {
+        struct usb_interface_descriptor intf;
+        struct usb_endpoint_descriptor_no_audio source;
+        struct usb_endpoint_descriptor_no_audio sink;
+    } __attribute__((packed)) fs_descs, hs_descs;
+    struct {
+        struct usb_interface_descriptor intf;
+        struct usb_endpoint_descriptor_no_audio source;
+        struct usb_ss_ep_comp_descriptor source_comp;
+        struct usb_endpoint_descriptor_no_audio sink;
+        struct usb_ss_ep_comp_descriptor sink_comp;
+    } __attribute__((packed)) ss_descs;
+} __attribute__((packed)) descriptors = {
+    .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+    .length = cpu_to_le32(sizeof(descriptors)),
+    .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC |
+                         FUNCTIONFS_HAS_HS_DESC |
+                         FUNCTIONFS_HAS_SS_DESC),
+    .fs_count = 3,
+    .hs_count = 3,
+    .ss_count = 5,
+    .fs_descs = {
+        .intf = {
+            .bLength = sizeof(descriptors.fs_descs.intf),
+            .bDescriptorType = USB_DT_INTERFACE,
+            .bInterfaceNumber = 0,
+            .bNumEndpoints = 2,
+            .bInterfaceClass = ADB_CLASS,
+            .bInterfaceSubClass = ADB_SUBCLASS,
+            .bInterfaceProtocol = ADB_PROTOCOL,
+            .iInterface = 1, /* first string from the provided table */
+        },
+        .source = {
+            .bLength = sizeof(descriptors.fs_descs.source),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 1 | USB_DIR_OUT,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+        },
+        .sink = {
+            .bLength = sizeof(descriptors.fs_descs.sink),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 2 | USB_DIR_IN,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+        },
+    },
+    .hs_descs = {
+        .intf = {
+            .bLength = sizeof(descriptors.hs_descs.intf),
+            .bDescriptorType = USB_DT_INTERFACE,
+            .bInterfaceNumber = 0,
+            .bNumEndpoints = 2,
+            .bInterfaceClass = ADB_CLASS,
+            .bInterfaceSubClass = ADB_SUBCLASS,
+            .bInterfaceProtocol = ADB_PROTOCOL,
+            .iInterface = 1, /* first string from the provided table */
+        },
+        .source = {
+            .bLength = sizeof(descriptors.hs_descs.source),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 1 | USB_DIR_OUT,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+        },
+        .sink = {
+            .bLength = sizeof(descriptors.hs_descs.sink),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 2 | USB_DIR_IN,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+        },
+    },
+    .ss_descs = {
+        .intf = {
+            .bLength = sizeof(descriptors.ss_descs.intf),
+            .bDescriptorType = USB_DT_INTERFACE,
+            .bInterfaceNumber = 0,
+            .bNumEndpoints = 2,
+            .bInterfaceClass = ADB_CLASS,
+            .bInterfaceSubClass = ADB_SUBCLASS,
+            .bInterfaceProtocol = ADB_PROTOCOL,
+            .iInterface = 1, /* first string from the provided table */
+        },
+        .source = {
+            .bLength = sizeof(descriptors.ss_descs.source),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 1 | USB_DIR_OUT,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+        },
+        .source_comp = {
+            .bLength = sizeof(descriptors.ss_descs.source_comp),
+            .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+        },
+        .sink = {
+            .bLength = sizeof(descriptors.ss_descs.sink),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 2 | USB_DIR_IN,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+        },
+        .sink_comp = {
+            .bLength = sizeof(descriptors.ss_descs.sink_comp),
+            .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+        },
+    },
+};
+
+#define STR_INTERFACE_ "ADB Interface"
+
+static const struct {
+    struct usb_functionfs_strings_head header;
+    struct {
+        __le16 code;
+        const char str1[sizeof(STR_INTERFACE_)];
+    } __attribute__((packed)) lang0;
+} __attribute__((packed)) strings = {
+    .header = {
+        .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
+        .length = cpu_to_le32(sizeof(strings)),
+        .str_count = cpu_to_le32(1),
+        .lang_count = cpu_to_le32(1),
+    },
+    .lang0 = {
+        cpu_to_le16(0x0409), /* en-us */
+        STR_INTERFACE_,
+    },
+};
+
+static void *usb_adb_open_thread(void *x)
+{
+    struct usb_handle *usb = (struct usb_handle *)x;
+    int fd;
+
+    while (1) {
+        // wait until the USB device needs opening
+        adb_mutex_lock(&usb->lock);
+        while (usb->fd != -1)
+            adb_cond_wait(&usb->notify, &usb->lock);
+        adb_mutex_unlock(&usb->lock);
+
+        D("[ usb_thread - opening device ]\n");
+        do {
+            /* XXX use inotify? */
+            fd = unix_open("/dev/android_adb", O_RDWR);
+            if (fd < 0) {
+                // to support older kernels
+                fd = unix_open("/dev/android", O_RDWR);
+            }
+            if (fd < 0) {
+                adb_sleep_ms(1000);
+            }
+        } while (fd < 0);
+        D("[ opening device succeeded ]\n");
+
+        close_on_exec(fd);
+        usb->fd = fd;
+
+        D("[ usb_thread - registering device ]\n");
+        register_usb_transport(usb, 0, 0, 1);
+    }
+
+    // never gets here
+    return 0;
+}
+
+static int usb_adb_write(usb_handle *h, const void *data, int len)
+{
+    int n;
+
+    D("about to write (fd=%d, len=%d)\n", h->fd, len);
+    n = adb_write(h->fd, data, len);
+    if(n != len) {
+        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
+            h->fd, n, errno, strerror(errno));
+        return -1;
+    }
+    D("[ done fd=%d ]\n", h->fd);
+    return 0;
+}
+
+static int usb_adb_read(usb_handle *h, void *data, int len)
+{
+    int n;
+
+    D("about to read (fd=%d, len=%d)\n", h->fd, len);
+    n = adb_read(h->fd, data, len);
+    if(n != len) {
+        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
+            h->fd, n, errno, strerror(errno));
+        return -1;
+    }
+    D("[ done fd=%d ]\n", h->fd);
+    return 0;
+}
+
+static void usb_adb_kick(usb_handle *h)
+{
+    D("usb_kick\n");
+    adb_mutex_lock(&h->lock);
+    adb_close(h->fd);
+    h->fd = -1;
+
+    // notify usb_adb_open_thread that we are disconnected
+    adb_cond_signal(&h->notify);
+    adb_mutex_unlock(&h->lock);
+}
+
+static void usb_adb_init()
+{
+    usb_handle *h;
+    adb_thread_t tid;
+    int fd;
+
+    h = calloc(1, sizeof(usb_handle));
+    if (h == 0) {
+        fatal("cannot allocate usb_handle");
+        return;
+    }
+
+    h->write = usb_adb_write;
+    h->read = usb_adb_read;
+    h->kick = usb_adb_kick;
+    h->bulk_in = -1;
+    h->bulk_out = -1;
+    h->control = -1;
+    h->ffs_control_thread_created = false;
+    h->fd = -1;
+
+    adb_cond_init(&h->notify, 0);
+    adb_mutex_init(&h->lock, 0);
+
+    // Open the file /dev/android_adb_enable to trigger
+    // the enabling of the adb USB function in the kernel.
+    // We never touch this file again - just leave it open
+    // indefinitely so the kernel will know when we are running
+    // and when we are not.
+    fd = unix_open("/dev/android_adb_enable", O_RDWR);
+    if (fd < 0) {
+       D("failed to open /dev/android_adb_enable\n");
+    } else {
+        close_on_exec(fd);
+    }
+
+    D("[ usb_init - starting thread ]\n");
+    if(adb_thread_create(&tid, usb_adb_open_thread, h)){
+        fatal_errno("cannot create usb thread");
+    }
+}
+
+static void *ffs_control_read_msg_thread(void *_h)
+{
+    usb_handle *h = _h;
+    int fd = h->control;
+
+    char buf[MAX_PACKET_SIZE_FS];
+    int size = 0;//event.u.setup.wLength;
+    if (DEBUG) D("FUNCTIONFS_SETUP acking host-to-device control transfer size=%d", size);
+    if (size+1 > MAX_PACKET_SIZE_FS) {
+        D("package size larger than MAX_PACKET_SIZE_FS");
+        return 0;
+    }
+
+    if (DEBUG) D("FUNCTIONFS_SETUP before get host-to-device msg size:%d", size);
+    int rc = adb_read(fd, buf, size);
+    if (DEBUG) D("FUNCTIONFS_SETUP after get host-to-device msg rc:%d", rc);
+    if (rc != size) {
+        D("Read %d bytes when trying to read control request, expected %d", rc, size);
+    }
+    return 0;
+}
+
+static char* ffs_get_event_type_code(int type) {
+    char* code;
+    switch(type) {
+        case FUNCTIONFS_BIND:
+            code = "BIND";
+            break;
+        case FUNCTIONFS_UNBIND:
+            code = "UNBIND";
+            break;
+        case FUNCTIONFS_ENABLE:
+            code = "ENABLE";
+            break;
+        case FUNCTIONFS_DISABLE:
+            code = "DISABLE";
+            break;
+        case FUNCTIONFS_SETUP:
+            code = "SETUP";
+            break;
+        case FUNCTIONFS_SUSPEND:
+            code = "SUSPEND";
+            break;
+        case FUNCTIONFS_RESUME:
+            code = "RESUME";
+            break;
+        default:
+            code = "UNKNOWN";
+            break;
+        }
+    return code;
+}
+
+static void ffs_control_event_handler(usb_handle *h) {
+    int fd = h->control;
+    struct usb_functionfs_event event;
+    int ret = 0;
+
+    if (DEBUG) D("start remote usb read control fd:%d size=%d\n", fd, (int)sizeof(event));
+    ret = adb_read(fd, &event, sizeof(event));
+    if (DEBUG) D("done remote usb read control ret=%d size=%d\n", ret, (int)sizeof(event));
+    if (ret != sizeof(event)) {
+        if (DEBUG) D("remote usb: read size:%d not expect to event size:%d\n", ret, (int)sizeof(event));
+        return;
+    }
+
+    D("event.type: %s\n", ffs_get_event_type_code(event.type));
+
+    switch (event.type) {
+        case FUNCTIONFS_SETUP: {
+            D("received FUNCTIONFS_SETUP");
+            D("bRequestType = %d",(int)(event.u.setup.bRequestType));
+            D("bRequest = %d\n", (int)(event.u.setup.bRequest));
+            D("wValue = %d\n", (int)(event.u.setup.wValue));
+            D("wIndex = %d\n", (int)(event.u.setup.wIndex));
+            D("wLength = %d\n", (int)(event.u.setup.wLength));
+
+            if ((event.u.setup.bRequestType & USB_DIR_IN)) {
+                if (DEBUG) D("FUNCTIONFS_SETUP acking device-to-host control transfer");
+                int rc = adb_write(fd, "", 0);
+                if (rc != 0) {
+                    D("Failed to write empty packet to host");
+                    break;
+                }
+            } else {
+                adb_thread_t ffs_control_read_msg_thread_ptr;
+
+                if(adb_thread_create(&ffs_control_read_msg_thread_ptr, ffs_control_read_msg_thread, h)) {
+                    fatal_errno("cannot create control thread");
+                }
+
+
+                if (DEBUG) D("Wait 100ms before kill read msg thread");
+                adb_sleep_ms(100);
+                int ret = pthread_cancel(ffs_control_read_msg_thread_ptr);
+                D("Done kill the read msg thread ret=%d", ret);
+            }
+        }
+    }
+}
+
+// -1 means failure
+static int epoll_add_fd(int epfd, int fd) {
+    struct epoll_event ev;
+    memset(&ev, 0, sizeof(ev));
+    ev.data.fd = fd;
+    ev.events = EPOLLIN;
+    // don't set the fd to edge trigger
+    // the some event like accept may be lost if two or more clients are connecting to server at the same time
+    // level trigger is preferred to avoid event lost
+    // do not set EPOLLOUT due to it will always trigger when write is available
+    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+        D("epoll_add_fd3() epoll_ctl() failed reason=[%s]%d epfd=%d fd=%d",
+            strerror(errno), errno, epfd, fd);
+        return -1;
+    }
+    return 0;
+}
+
+static void *ffs_control_thread(void *_h)
+{
+    usb_handle *h = _h;
+    int control_fd = h->control;
+    struct epoll_event events[FFS_CONTOL_MAX_EPOLL_EVENT];
+
+    int epfd = epoll_create(FFS_CONTOL_MAX_EPOLL_EVENT);
+    if(epfd == -1) {
+        D("ERR: epoll_create() fail reason=[%s]", strerror(errno));
+        return 0;
+    }
+
+    epoll_add_fd(epfd, control_fd);
+
+    while(1) {
+        int i;
+        int n;
+
+        D("Before ffs control thread epoll_wait");
+        n = epoll_wait(epfd, events, FFS_CONTOL_MAX_EPOLL_EVENT , -1);
+
+        for(i = 0; i < n; i++) {
+            if(events[i].data.fd == control_fd) {
+                if(events[i].events & EPOLLIN) {
+                    if (DEBUG) D("control_fd event triggered");
+                    ffs_control_event_handler(h);
+                }
+            }
+        }
+    }
+}
+
+void ffs_create_control_thread(usb_handle *h) {
+    if (h->control >= 0) {  // only for ffs usb
+        if (!h->ffs_control_thread_created) {
+            adb_thread_t ffs_control_thread_ptr;
+
+            if(adb_thread_create(&ffs_control_thread_ptr, ffs_control_thread, h)){
+                fatal_errno("cannot create ffs_control_thread");
+            } else {
+                h->ffs_control_thread_created = true;
+                if (DEBUG) D("Created ffs_control_thread success");
+            }
+        }
+    }
+}
+
+static void init_functionfs(struct usb_handle *h)
+{
+    ssize_t ret;
+
+    if (h->control < 0) { // might have already done this before
+        D("OPENING %s\n", USB_FFS_ADB_EP0);
+        h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
+        if (h->control < 0) {
+            D("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno);
+            goto err;
+        }
+
+        ret = adb_write(h->control, &descriptors, sizeof(descriptors));
+        if (ret < 0) {
+            D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
+            goto err;
+        }
+
+        ret = adb_write(h->control, &strings, sizeof(strings));
+        if (ret < 0) {
+            D("[ %s: writing strings failed: errno=%d]\n", USB_FFS_ADB_EP0, errno);
+            goto err;
+        }
+    }
+
+    h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR);
+    if (h->bulk_out < 0) {
+        D("[ %s: cannot open bulk-out ep: errno=%d ]\n", USB_FFS_ADB_OUT, errno);
+        goto err;
+    }
+
+    h->bulk_in = adb_open(USB_FFS_ADB_IN, O_RDWR);
+    if (h->bulk_in < 0) {
+        D("[ %s: cannot open bulk-in ep: errno=%d ]\n", USB_FFS_ADB_IN, errno);
+        goto err;
+    }
+
+    ffs_create_control_thread(h);
+    return;
+
+err:
+    if (h->bulk_in > 0) {
+        adb_close(h->bulk_in);
+        h->bulk_in = -1;
+    }
+    if (h->bulk_out > 0) {
+        adb_close(h->bulk_out);
+        h->bulk_out = -1;
+    }
+    if (h->control > 0) {
+        adb_close(h->control);
+        h->control = -1;
+    }
+    return;
+}
+
+static void *usb_ffs_open_thread(void *x)
+{
+    struct usb_handle *usb = (struct usb_handle *)x;
+
+    while (1) {
+        // wait until the USB device needs opening
+        adb_mutex_lock(&usb->lock);
+        while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1)
+            adb_cond_wait(&usb->notify, &usb->lock);
+        adb_mutex_unlock(&usb->lock);
+
+        while (1) {
+            init_functionfs(usb);
+
+            if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0)
+                break;
+
+            adb_sleep_ms(1000);
+        }
+
+        D("[ usb_thread - registering device ]\n");
+        register_usb_transport(usb, 0, 0, 1);
+    }
+
+    // never gets here
+    return 0;
+}
+
+static int bulk_write(int bulk_in, const char *buf, size_t length)
+{
+    size_t count = 0;
+    int ret;
+
+    do {
+        ret = adb_write(bulk_in, buf + count, length - count);
+        if (ret < 0) {
+            if (errno != EINTR)
+                return ret;
+        } else {
+            count += ret;
+        }
+    } while (count < length);
+
+    D("[ bulk_write done fd=%d ]\n", bulk_in);
+    return count;
+}
+
+static int usb_ffs_write(usb_handle *h, const void *data, int len)
+{
+    int n;
+
+    D("about to write (fd=%d, len=%d)\n", h->bulk_in, len);
+    n = bulk_write(h->bulk_in, data, len);
+    if (n != len) {
+        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
+            h->bulk_in, n, errno, strerror(errno));
+        return -1;
+    }
+    D("[ done fd=%d ]\n", h->bulk_in);
+    return 0;
+}
+
+static int bulk_read(int bulk_out, char *buf, size_t length)
+{
+    size_t count = 0;
+    int ret;
+
+    do {
+        ret = adb_read(bulk_out, buf + count, length - count);
+        if (ret < 0) {
+            if (errno != EINTR) {
+                D("[ bulk_read failed fd=%d length=%zu count=%zu ]\n",
+                                           bulk_out, length, count);
+                return ret;
+            }
+        } else {
+            count += ret;
+        }
+    } while (count < length);
+
+    return count;
+}
+
+static int usb_ffs_read(usb_handle *h, void *data, int len)
+{
+    int n;
+
+    D("about to read (fd=%d, len=%d)\n", h->bulk_out, len);
+    n = bulk_read(h->bulk_out, data, len);
+    if (n != len) {
+        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
+            h->bulk_out, n, errno, strerror(errno));
+        return -1;
+    }
+    D("[ done fd=%d ]\n", h->bulk_out);
+    return 0;
+}
+
+static void usb_ffs_kick(usb_handle *h)
+{
+    int err;
+
+    err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT);
+    if (err < 0)
+        D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in, errno);
+
+    err = ioctl(h->bulk_out, FUNCTIONFS_CLEAR_HALT);
+    if (err < 0)
+        D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno);
+
+    adb_mutex_lock(&h->lock);
+
+    // don't close ep0 here, since we may not need to reinitialize it with
+    // the same descriptors again. if however ep1/ep2 fail to re-open in
+    // init_functionfs, only then would we close and open ep0 again.
+    adb_close(h->bulk_out);
+    adb_close(h->bulk_in);
+    h->bulk_out = h->bulk_in = -1;
+
+    // notify usb_ffs_open_thread that we are disconnected
+    adb_cond_signal(&h->notify);
+    adb_mutex_unlock(&h->lock);
+}
+
+static void usb_ffs_init()
+{
+    usb_handle *h;
+    adb_thread_t tid;
+
+    D("[ usb_init - using FunctionFS ]\n");
+
+    h = calloc(1, sizeof(usb_handle));
+    if (h == 0) {
+        fatal("cannot allocate usb_handle");
+        return;
+    }
+
+    h->write = usb_ffs_write;
+    h->read = usb_ffs_read;
+    h->kick = usb_ffs_kick;
+
+    h->control  = -1;
+    h->bulk_out = -1;
+    h->bulk_out = -1;
+    h->ffs_control_thread_created = false;
+
+    adb_cond_init(&h->notify, 0);
+    adb_mutex_init(&h->lock, 0);
+
+    D("[ usb_init - starting thread ]\n");
+    if (adb_thread_create(&tid, usb_ffs_open_thread, h)){
+        fatal_errno("[ cannot create usb thread ]\n");
+    }
+}
+
+void usb_init()
+{
+    if (access(USB_FFS_ADB_EP0, F_OK) == 0)
+        usb_ffs_init();
+    else
+        usb_adb_init();
+}
+
+void usb_cleanup()
+{
+}
+
+int usb_write(usb_handle *h, const void *data, int len)
+{
+    return h->write(h, data, len);
+}
+
+int usb_read(usb_handle *h, void *data, int len)
+{
+    return h->read(h, data, len);
+}
+int usb_close(usb_handle *h)
+{
+    return 0;
+}
+
+void usb_kick(usb_handle *h)
+{
+    h->kick(h);
+}
diff --git a/src/devtools/adb/usb_osx.c b/src/devtools/adb/usb_osx.c
new file mode 100755
index 0000000..ba157f1
--- /dev/null
+++ b/src/devtools/adb/usb_osx.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOMessage.h>
+#include <mach/mach_port.h>
+
+#include "sysdeps.h"
+
+#include <stdio.h>
+
+#define TRACE_TAG   TRACE_USB
+#include "adb.h"
+
+#define  DBG   D
+
+static IONotificationPortRef    notificationPort = 0;
+static io_iterator_t            notificationIterator;
+
+struct usb_handle
+{
+    UInt8                     bulkIn;
+    UInt8                     bulkOut;
+    IOUSBInterfaceInterface   **interface;
+    io_object_t               usbNotification;
+    unsigned int              zero_mask;
+};
+
+static CFRunLoopRef currentRunLoop = 0;
+static pthread_mutex_t start_lock;
+static pthread_cond_t start_cond;
+
+
+static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator);
+static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
+                                   natural_t messageType,
+                                   void *messageArgument);
+static usb_handle* CheckInterface(IOUSBInterfaceInterface **iface,
+                                  UInt16 vendor, UInt16 product);
+
+static int
+InitUSB()
+{
+    CFMutableDictionaryRef  matchingDict;
+    CFRunLoopSourceRef      runLoopSource;
+
+    //* To set up asynchronous notifications, create a notification port and
+    //* add its run loop event source to the program's run loop
+    notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
+    runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
+    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
+
+    //* Create our matching dictionary to find the Android device's
+    //* adb interface
+    //* IOServiceAddMatchingNotification consumes the reference, so we do
+    //* not need to release this
+    matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
+
+    if (!matchingDict) {
+        DBG("ERR: Couldn't create USB matching dictionary.\n");
+        return -1;
+    }
+
+    //* We have to get notifications for all potential candidates and test them
+    //* at connection time because the matching rules don't allow for a
+    //* USB interface class of 0xff for class+subclass+protocol matches
+    //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html
+    IOServiceAddMatchingNotification(
+            notificationPort,
+            kIOFirstMatchNotification,
+            matchingDict,
+            AndroidInterfaceAdded,
+            NULL,
+            &notificationIterator);
+
+    //* Iterate over set of matching interfaces to access already-present
+    //* devices and to arm the notification
+    AndroidInterfaceAdded(NULL, notificationIterator);
+
+    return 0;
+}
+
+static void
+AndroidInterfaceAdded(void *refCon, io_iterator_t iterator)
+{
+    kern_return_t            kr;
+    io_service_t             usbDevice;
+    io_service_t             usbInterface;
+    IOCFPlugInInterface      **plugInInterface = NULL;
+    IOUSBInterfaceInterface220  **iface = NULL;
+    IOUSBDeviceInterface197  **dev = NULL;
+    HRESULT                  result;
+    SInt32                   score;
+    UInt32                   locationId;
+    UInt8                    class, subclass, protocol;
+    UInt16                   vendor;
+    UInt16                   product;
+    UInt8                    serialIndex;
+    char                     serial[256];
+    char                     devpathBuf[64];
+    char                     *devpath = NULL;
+
+    while ((usbInterface = IOIteratorNext(iterator))) {
+        //* Create an intermediate interface plugin
+        kr = IOCreatePlugInInterfaceForService(usbInterface,
+                                               kIOUSBInterfaceUserClientTypeID,
+                                               kIOCFPlugInInterfaceID,
+                                               &plugInInterface, &score);
+        IOObjectRelease(usbInterface);
+        if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
+            DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr);
+            continue;
+        }
+
+        //* This gets us the interface object
+        result = (*plugInInterface)->QueryInterface(plugInInterface,
+                CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)
+                &iface);
+        //* We only needed the plugin to get the interface, so discard it
+        (*plugInInterface)->Release(plugInInterface);
+        if (result || !iface) {
+            DBG("ERR: Couldn't query the interface (%08x)\n", (int) result);
+            continue;
+        }
+
+        kr = (*iface)->GetInterfaceClass(iface, &class);
+        kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
+        kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
+        if(class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
+            // Ignore non-ADB devices.
+            DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", class, subclass, protocol);
+            (*iface)->Release(iface);
+            continue;
+        }
+
+        //* this gets us an ioservice, with which we will find the actual
+        //* device; after getting a plugin, and querying the interface, of
+        //* course.
+        //* Gotta love OS X
+        kr = (*iface)->GetDevice(iface, &usbDevice);
+        if (kIOReturnSuccess != kr || !usbDevice) {
+            DBG("ERR: Couldn't grab device from interface (%08x)\n", kr);
+            continue;
+        }
+
+        plugInInterface = NULL;
+        score = 0;
+        //* create an intermediate device plugin
+        kr = IOCreatePlugInInterfaceForService(usbDevice,
+                                               kIOUSBDeviceUserClientTypeID,
+                                               kIOCFPlugInInterfaceID,
+                                               &plugInInterface, &score);
+        //* only needed this to find the plugin
+        (void)IOObjectRelease(usbDevice);
+        if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
+            DBG("ERR: Unable to create a device plug-in (%08x)\n", kr);
+            continue;
+        }
+
+        result = (*plugInInterface)->QueryInterface(plugInInterface,
+                CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
+        //* only needed this to query the plugin
+        (*plugInInterface)->Release(plugInInterface);
+        if (result || !dev) {
+            DBG("ERR: Couldn't create a device interface (%08x)\n",
+                (int) result);
+            continue;
+        }
+
+        //* Now after all that, we actually have a ref to the device and
+        //* the interface that matched our criteria
+        kr = (*dev)->GetDeviceVendor(dev, &vendor);
+        kr = (*dev)->GetDeviceProduct(dev, &product);
+        kr = (*dev)->GetLocationID(dev, &locationId);
+        if (kr == 0) {
+            snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X",
+	             (unsigned int)locationId);
+            devpath = devpathBuf;
+        }
+        kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
+
+	if (serialIndex > 0) {
+		IOUSBDevRequest req;
+		UInt16          buffer[256];
+		UInt16          languages[128];
+
+		memset(languages, 0, sizeof(languages));
+
+		req.bmRequestType =
+			USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+		req.bRequest = kUSBRqGetDescriptor;
+		req.wValue = (kUSBStringDesc << 8) | 0;
+		req.wIndex = 0;
+		req.pData = languages;
+		req.wLength = sizeof(languages);
+		kr = (*dev)->DeviceRequest(dev, &req);
+
+		if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+
+			int langCount = (req.wLenDone - 2) / 2, lang;
+
+			for (lang = 1; lang <= langCount; lang++) {
+
+                                memset(buffer, 0, sizeof(buffer));
+                                memset(&req, 0, sizeof(req));
+
+				req.bmRequestType =
+					USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+				req.bRequest = kUSBRqGetDescriptor;
+				req.wValue = (kUSBStringDesc << 8) | serialIndex;
+				req.wIndex = languages[lang];
+				req.pData = buffer;
+				req.wLength = sizeof(buffer);
+				kr = (*dev)->DeviceRequest(dev, &req);
+
+				if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+					int i, count;
+
+					// skip first word, and copy the rest to the serial string,
+					// changing shorts to bytes.
+					count = (req.wLenDone - 1) / 2;
+					for (i = 0; i < count; i++)
+						serial[i] = buffer[i + 1];
+					serial[i] = 0;
+                                        break;
+				}
+			}
+		}
+	}
+        (*dev)->Release(dev);
+
+        DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
+            serial);
+
+        usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface,
+                                            vendor, product);
+        if (handle == NULL) {
+            DBG("ERR: Could not find device interface: %08x\n", kr);
+            (*iface)->Release(iface);
+            continue;
+        }
+
+        DBG("AndroidDeviceAdded calling register_usb_transport\n");
+        register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
+
+        // Register for an interest notification of this device being removed.
+        // Pass the reference to our private data as the refCon for the
+        // notification.
+        kr = IOServiceAddInterestNotification(notificationPort,
+                usbInterface,
+                kIOGeneralInterest,
+                AndroidInterfaceNotify,
+                handle,
+                &handle->usbNotification);
+
+        if (kIOReturnSuccess != kr) {
+            DBG("ERR: Unable to create interest notification (%08x)\n", kr);
+        }
+    }
+}
+
+static void
+AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
+{
+    usb_handle *handle = (usb_handle *)refCon;
+
+    if (messageType == kIOMessageServiceIsTerminated) {
+        if (!handle) {
+            DBG("ERR: NULL handle\n");
+            return;
+        }
+        DBG("AndroidInterfaceNotify\n");
+        IOObjectRelease(handle->usbNotification);
+        usb_kick(handle);
+    }
+}
+
+//* TODO: simplify this further since we only register to get ADB interface
+//* subclass+protocol events
+static usb_handle*
+CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product)
+{
+    usb_handle*                 handle = NULL;
+    IOReturn                    kr;
+    UInt8  interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
+    UInt8  endpoint;
+
+
+    //* Now open the interface.  This will cause the pipes associated with
+    //* the endpoints in the interface descriptor to be instantiated
+    kr = (*interface)->USBInterfaceOpen(interface);
+    if (kr != kIOReturnSuccess) {
+        DBG("ERR: Could not open interface: (%08x)\n", kr);
+        return NULL;
+    }
+
+    //* Get the number of endpoints associated with this interface
+    kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
+    if (kr != kIOReturnSuccess) {
+        DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
+        goto err_get_num_ep;
+    }
+
+    //* Get interface class, subclass and protocol
+    if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
+            (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
+            (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
+            DBG("ERR: Unable to get interface class, subclass and protocol\n");
+            goto err_get_interface_class;
+    }
+
+    //* check to make sure interface class, subclass and protocol match ADB
+    //* avoid opening mass storage endpoints
+    if (!is_adb_interface(vendor, product, interfaceClass,
+                interfaceSubClass, interfaceProtocol))
+        goto err_bad_adb_interface;
+
+    handle = calloc(1, sizeof(usb_handle));
+
+    //* Iterate over the endpoints for this interface and find the first
+    //* bulk in/out pipes available.  These will be our read/write pipes.
+    for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
+        UInt8   transferType;
+        UInt16  maxPacketSize;
+        UInt8   interval;
+        UInt8   number;
+        UInt8   direction;
+
+        kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
+                &number, &transferType, &maxPacketSize, &interval);
+
+        if (kIOReturnSuccess == kr) {
+            if (kUSBBulk != transferType)
+                continue;
+
+            if (kUSBIn == direction)
+                handle->bulkIn = endpoint;
+
+            if (kUSBOut == direction)
+                handle->bulkOut = endpoint;
+
+            handle->zero_mask = maxPacketSize - 1;
+        } else {
+            DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
+            goto err_get_pipe_props;
+        }
+    }
+
+    handle->interface = interface;
+    return handle;
+
+err_get_pipe_props:
+    free(handle);
+err_bad_adb_interface:
+err_get_interface_class:
+err_get_num_ep:
+    (*interface)->USBInterfaceClose(interface);
+    return NULL;
+}
+
+
+void* RunLoopThread(void* unused)
+{
+    InitUSB();
+
+    currentRunLoop = CFRunLoopGetCurrent();
+
+    // Signal the parent that we are running
+    adb_mutex_lock(&start_lock);
+    adb_cond_signal(&start_cond);
+    adb_mutex_unlock(&start_lock);
+
+    CFRunLoopRun();
+    currentRunLoop = 0;
+
+    IOObjectRelease(notificationIterator);
+    IONotificationPortDestroy(notificationPort);
+
+    DBG("RunLoopThread done\n");
+    return NULL;    
+}
+
+
+static int initialized = 0;
+void usb_init()
+{
+    if (!initialized)
+    {
+        adb_thread_t    tid;
+
+        adb_mutex_init(&start_lock, NULL);
+        adb_cond_init(&start_cond, NULL);
+
+        if(adb_thread_create(&tid, RunLoopThread, NULL))
+            fatal_errno("cannot create input thread");
+
+        // Wait for initialization to finish
+        adb_mutex_lock(&start_lock);
+        adb_cond_wait(&start_cond, &start_lock);
+        adb_mutex_unlock(&start_lock);
+
+        adb_mutex_destroy(&start_lock);
+        adb_cond_destroy(&start_cond);
+
+        initialized = 1;
+    }
+}
+
+void usb_cleanup()
+{
+    DBG("usb_cleanup\n");
+    close_usb_devices();
+    if (currentRunLoop)
+        CFRunLoopStop(currentRunLoop);
+}
+
+int usb_write(usb_handle *handle, const void *buf, int len)
+{
+    IOReturn    result;
+
+    if (!len)
+        return 0;
+
+    if (!handle)
+        return -1;
+
+    if (NULL == handle->interface) {
+        DBG("ERR: usb_write interface was null\n");
+        return -1;
+    }
+
+    if (0 == handle->bulkOut) {
+        DBG("ERR: bulkOut endpoint not assigned\n");
+        return -1;
+    }
+
+    result =
+        (*handle->interface)->WritePipe(
+                              handle->interface, handle->bulkOut, (void *)buf, len);
+
+    if ((result == 0) && (handle->zero_mask)) {
+        /* we need 0-markers and our transfer */
+        if(!(len & handle->zero_mask)) {
+            result =
+                (*handle->interface)->WritePipe(
+                        handle->interface, handle->bulkOut, (void *)buf, 0);
+        }
+    }
+
+    if (0 == result)
+        return 0;
+
+    DBG("ERR: usb_write failed with status %d\n", result);
+    return -1;
+}
+
+int usb_read(usb_handle *handle, void *buf, int len)
+{
+    IOReturn result;
+    UInt32  numBytes = len;
+
+    if (!len) {
+        return 0;
+    }
+
+    if (!handle) {
+        return -1;
+    }
+
+    if (NULL == handle->interface) {
+        DBG("ERR: usb_read interface was null\n");
+        return -1;
+    }
+
+    if (0 == handle->bulkIn) {
+        DBG("ERR: bulkIn endpoint not assigned\n");
+        return -1;
+    }
+
+    result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
+
+    if (kIOUSBPipeStalled == result) {
+        DBG(" Pipe stalled, clearing stall.\n");
+        (*handle->interface)->ClearPipeStall(handle->interface, handle->bulkIn);
+        result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
+    }
+
+    if (kIOReturnSuccess == result)
+        return 0;
+    else {
+        DBG("ERR: usb_read failed with status %x\n", result);
+    }
+
+    return -1;
+}
+
+int usb_close(usb_handle *handle)
+{
+    return 0;
+}
+
+void usb_kick(usb_handle *handle)
+{
+    /* release the interface */
+    if (!handle)
+        return;
+
+    if (handle->interface)
+    {
+        (*handle->interface)->USBInterfaceClose(handle->interface);
+        (*handle->interface)->Release(handle->interface);
+        handle->interface = 0;
+    }
+}
diff --git a/src/devtools/adb/usb_windows.c b/src/devtools/adb/usb_windows.c
new file mode 100755
index 0000000..b7ad913
--- /dev/null
+++ b/src/devtools/adb/usb_windows.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winsock2.h>
+#include <windows.h>
+#include <winerror.h>
+#include <errno.h>
+#include <usb100.h>
+#include <adb_api.h>
+#include <stdio.h>
+
+#include "sysdeps.h"
+
+#define   TRACE_TAG  TRACE_USB
+#include "adb.h"
+
+/** Structure usb_handle describes our connection to the usb device via
+  AdbWinApi.dll. This structure is returned from usb_open() routine and
+  is expected in each subsequent call that is accessing the device.
+*/
+struct usb_handle {
+  /// Previous entry in the list of opened usb handles
+  usb_handle *prev;
+
+  /// Next entry in the list of opened usb handles
+  usb_handle *next;
+
+  /// Handle to USB interface
+  ADBAPIHANDLE  adb_interface;
+
+  /// Handle to USB read pipe (endpoint)
+  ADBAPIHANDLE  adb_read_pipe;
+
+  /// Handle to USB write pipe (endpoint)
+  ADBAPIHANDLE  adb_write_pipe;
+
+  /// Interface name
+  char*         interface_name;
+
+  /// Mask for determining when to use zero length packets
+  unsigned zero_mask;
+};
+
+/// Class ID assigned to the device by androidusb.sys
+static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
+
+/// List of opened usb handles
+static usb_handle handle_list = {
+  .prev = &handle_list,
+  .next = &handle_list,
+};
+
+/// Locker for the list of opened usb handles
+ADB_MUTEX_DEFINE( usb_lock );
+
+/// Checks if there is opened usb handle in handle_list for this device.
+int known_device(const char* dev_name);
+
+/// Checks if there is opened usb handle in handle_list for this device.
+/// usb_lock mutex must be held before calling this routine.
+int known_device_locked(const char* dev_name);
+
+/// Registers opened usb handle (adds it to handle_list).
+int register_new_device(usb_handle* handle);
+
+/// Checks if interface (device) matches certain criteria
+int recognized_device(usb_handle* handle);
+
+/// Enumerates present and available interfaces (devices), opens new ones and
+/// registers usb transport for them.
+void find_devices();
+
+/// Entry point for thread that polls (every second) for new usb interfaces.
+/// This routine calls find_devices in infinite loop.
+void* device_poll_thread(void* unused);
+
+/// Initializes this module
+void usb_init();
+
+/// Cleans up this module
+void usb_cleanup();
+
+/// Opens usb interface (device) by interface (device) name.
+usb_handle* do_usb_open(const wchar_t* interface_name);
+
+/// Writes data to the opened usb handle
+int usb_write(usb_handle* handle, const void* data, int len);
+
+/// Reads data using the opened usb handle
+int usb_read(usb_handle *handle, void* data, int len);
+
+/// Cleans up opened usb handle
+void usb_cleanup_handle(usb_handle* handle);
+
+/// Cleans up (but don't close) opened usb handle
+void usb_kick(usb_handle* handle);
+
+/// Closes opened usb handle
+int usb_close(usb_handle* handle);
+
+/// Gets interface (device) name for an opened usb handle
+const char *usb_name(usb_handle* handle);
+
+int known_device_locked(const char* dev_name) {
+  usb_handle* usb;
+
+  if (NULL != dev_name) {
+    // Iterate through the list looking for the name match.
+    for(usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+      // In Windows names are not case sensetive!
+      if((NULL != usb->interface_name) &&
+         (0 == stricmp(usb->interface_name, dev_name))) {
+        return 1;
+      }
+    }
+  }
+
+  return 0;
+}
+
+int known_device(const char* dev_name) {
+  int ret = 0;
+
+  if (NULL != dev_name) {
+    adb_mutex_lock(&usb_lock);
+    ret = known_device_locked(dev_name);
+    adb_mutex_unlock(&usb_lock);
+  }
+
+  return ret;
+}
+
+int register_new_device(usb_handle* handle) {
+  if (NULL == handle)
+    return 0;
+
+  adb_mutex_lock(&usb_lock);
+
+  // Check if device is already in the list
+  if (known_device_locked(handle->interface_name)) {
+    adb_mutex_unlock(&usb_lock);
+    return 0;
+  }
+
+  // Not in the list. Add this handle to the list.
+  handle->next = &handle_list;
+  handle->prev = handle_list.prev;
+  handle->prev->next = handle;
+  handle->next->prev = handle;
+
+  adb_mutex_unlock(&usb_lock);
+
+  return 1;
+}
+
+void* device_poll_thread(void* unused) {
+  D("Created device thread\n");
+
+  while(1) {
+    find_devices();
+    adb_sleep_ms(1000);
+  }
+
+  return NULL;
+}
+
+void usb_init() {
+  adb_thread_t tid;
+
+  if(adb_thread_create(&tid, device_poll_thread, NULL)) {
+    fatal_errno("cannot create input thread");
+  }
+}
+
+void usb_cleanup() {
+}
+
+usb_handle* do_usb_open(const wchar_t* interface_name) {
+  // Allocate our handle
+  usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
+  if (NULL == ret)
+    return NULL;
+
+  // Set linkers back to the handle
+  ret->next = ret;
+  ret->prev = ret;
+
+  // Create interface.
+  ret->adb_interface = AdbCreateInterfaceByName(interface_name);
+
+  if (NULL == ret->adb_interface) {
+    free(ret);
+    errno = GetLastError();
+    return NULL;
+  }
+
+  // Open read pipe (endpoint)
+  ret->adb_read_pipe =
+    AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
+                                   AdbOpenAccessTypeReadWrite,
+                                   AdbOpenSharingModeReadWrite);
+  if (NULL != ret->adb_read_pipe) {
+    // Open write pipe (endpoint)
+    ret->adb_write_pipe =
+      AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
+                                      AdbOpenAccessTypeReadWrite,
+                                      AdbOpenSharingModeReadWrite);
+    if (NULL != ret->adb_write_pipe) {
+      // Save interface name
+      unsigned long name_len = 0;
+
+      // First get expected name length
+      AdbGetInterfaceName(ret->adb_interface,
+                          NULL,
+                          &name_len,
+                          true);
+      if (0 != name_len) {
+        ret->interface_name = (char*)malloc(name_len);
+
+        if (NULL != ret->interface_name) {
+          // Now save the name
+          if (AdbGetInterfaceName(ret->adb_interface,
+                                  ret->interface_name,
+                                  &name_len,
+                                  true)) {
+            // We're done at this point
+            return ret;
+          }
+        } else {
+          SetLastError(ERROR_OUTOFMEMORY);
+        }
+      }
+    }
+  }
+
+  // Something went wrong.
+  int saved_errno = GetLastError();
+  usb_cleanup_handle(ret);
+  free(ret);
+  SetLastError(saved_errno);
+
+  return NULL;
+}
+
+int usb_write(usb_handle* handle, const void* data, int len) {
+  unsigned long time_out = 5000;
+  unsigned long written = 0;
+  int ret;
+
+  D("usb_write %d\n", len);
+  if (NULL != handle) {
+    // Perform write
+    ret = AdbWriteEndpointSync(handle->adb_write_pipe,
+                               (void*)data,
+                               (unsigned long)len,
+                               &written,
+                               time_out);
+    int saved_errno = GetLastError();
+
+    if (ret) {
+      // Make sure that we've written what we were asked to write
+      D("usb_write got: %ld, expected: %d\n", written, len);
+      if (written == (unsigned long)len) {
+        if(handle->zero_mask && (len & handle->zero_mask) == 0) {
+          // Send a zero length packet
+          AdbWriteEndpointSync(handle->adb_write_pipe,
+                               (void*)data,
+                               0,
+                               &written,
+                               time_out);
+        }
+        return 0;
+      }
+    } else {
+      // assume ERROR_INVALID_HANDLE indicates we are disconnected
+      if (saved_errno == ERROR_INVALID_HANDLE)
+        usb_kick(handle);
+    }
+    errno = saved_errno;
+  } else {
+    D("usb_write NULL handle\n");
+    SetLastError(ERROR_INVALID_HANDLE);
+  }
+
+  D("usb_write failed: %d\n", errno);
+
+  return -1;
+}
+
+int usb_read(usb_handle *handle, void* data, int len) {
+  unsigned long time_out = 0;
+  unsigned long read = 0;
+  int ret;
+
+  D("usb_read %d\n", len);
+  if (NULL != handle) {
+    while (len > 0) {
+      int xfer = (len > 4096) ? 4096 : len;
+
+      ret = AdbReadEndpointSync(handle->adb_read_pipe,
+                                  data,
+                                  (unsigned long)xfer,
+                                  &read,
+                                  time_out);
+      int saved_errno = GetLastError();
+      D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, saved_errno);
+      if (ret) {
+        data = (char *)data + read;
+        len -= read;
+
+        if (len == 0)
+          return 0;
+      } else {
+        // assume ERROR_INVALID_HANDLE indicates we are disconnected
+        if (saved_errno == ERROR_INVALID_HANDLE)
+          usb_kick(handle);
+        break;
+      }
+      errno = saved_errno;
+    }
+  } else {
+    D("usb_read NULL handle\n");
+    SetLastError(ERROR_INVALID_HANDLE);
+  }
+
+  D("usb_read failed: %d\n", errno);
+
+  return -1;
+}
+
+void usb_cleanup_handle(usb_handle* handle) {
+  if (NULL != handle) {
+    if (NULL != handle->interface_name)
+      free(handle->interface_name);
+    if (NULL != handle->adb_write_pipe)
+      AdbCloseHandle(handle->adb_write_pipe);
+    if (NULL != handle->adb_read_pipe)
+      AdbCloseHandle(handle->adb_read_pipe);
+    if (NULL != handle->adb_interface)
+      AdbCloseHandle(handle->adb_interface);
+
+    handle->interface_name = NULL;
+    handle->adb_write_pipe = NULL;
+    handle->adb_read_pipe = NULL;
+    handle->adb_interface = NULL;
+  }
+}
+
+void usb_kick(usb_handle* handle) {
+  if (NULL != handle) {
+    adb_mutex_lock(&usb_lock);
+
+    usb_cleanup_handle(handle);
+
+    adb_mutex_unlock(&usb_lock);
+  } else {
+    SetLastError(ERROR_INVALID_HANDLE);
+    errno = ERROR_INVALID_HANDLE;
+  }
+}
+
+int usb_close(usb_handle* handle) {
+  D("usb_close\n");
+
+  if (NULL != handle) {
+    // Remove handle from the list
+    adb_mutex_lock(&usb_lock);
+
+    if ((handle->next != handle) && (handle->prev != handle)) {
+      handle->next->prev = handle->prev;
+      handle->prev->next = handle->next;
+      handle->prev = handle;
+      handle->next = handle;
+    }
+
+    adb_mutex_unlock(&usb_lock);
+
+    // Cleanup handle
+    usb_cleanup_handle(handle);
+    free(handle);
+  }
+
+  return 0;
+}
+
+const char *usb_name(usb_handle* handle) {
+  if (NULL == handle) {
+    SetLastError(ERROR_INVALID_HANDLE);
+    errno = ERROR_INVALID_HANDLE;
+    return NULL;
+  }
+
+  return (const char*)handle->interface_name;
+}
+
+int recognized_device(usb_handle* handle) {
+  if (NULL == handle)
+    return 0;
+
+  // Check vendor and product id first
+  USB_DEVICE_DESCRIPTOR device_desc;
+
+  if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
+                                 &device_desc)) {
+    return 0;
+  }
+
+  // Then check interface properties
+  USB_INTERFACE_DESCRIPTOR interf_desc;
+
+  if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
+                                    &interf_desc)) {
+    return 0;
+  }
+
+  // Must have two endpoints
+  if (2 != interf_desc.bNumEndpoints) {
+    return 0;
+  }
+
+  if (is_adb_interface(device_desc.idVendor, device_desc.idProduct,
+      interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass, interf_desc.bInterfaceProtocol)) {
+
+    if(interf_desc.bInterfaceProtocol == 0x01) {
+      AdbEndpointInformation endpoint_info;
+      // assuming zero is a valid bulk endpoint ID
+      if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
+        handle->zero_mask = endpoint_info.max_packet_size - 1;
+      }
+    }
+
+    return 1;
+  }
+
+  return 0;
+}
+
+void find_devices() {
+        usb_handle* handle = NULL;
+  char entry_buffer[2048];
+  char interf_name[2048];
+  AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
+  unsigned long entry_buffer_size = sizeof(entry_buffer);
+  char* copy_name;
+
+  // Enumerate all present and active interfaces.
+  ADBAPIHANDLE enum_handle =
+    AdbEnumInterfaces(usb_class_id, true, true, true);
+
+  if (NULL == enum_handle)
+    return;
+
+  while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
+    // TODO: FIXME - temp hack converting wchar_t into char.
+    // It would be better to change AdbNextInterface so it will return
+    // interface name as single char string.
+    const wchar_t* wchar_name = next_interface->device_name;
+    for(copy_name = interf_name;
+        L'\0' != *wchar_name;
+        wchar_name++, copy_name++) {
+      *copy_name = (char)(*wchar_name);
+    }
+    *copy_name = '\0';
+
+    // Lets see if we already have this device in the list
+    if (!known_device(interf_name)) {
+      // This seems to be a new device. Open it!
+        handle = do_usb_open(next_interface->device_name);
+        if (NULL != handle) {
+        // Lets see if this interface (device) belongs to us
+        if (recognized_device(handle)) {
+          D("adding a new device %s\n", interf_name);
+          char serial_number[512];
+          unsigned long serial_number_len = sizeof(serial_number);
+          if (AdbGetSerialNumber(handle->adb_interface,
+                                serial_number,
+                                &serial_number_len,
+                                true)) {
+            // Lets make sure that we don't duplicate this device
+            if (register_new_device(handle)) {
+              register_usb_transport(handle, serial_number, NULL, 1);
+            } else {
+              D("register_new_device failed for %s\n", interf_name);
+              usb_cleanup_handle(handle);
+              free(handle);
+            }
+          } else {
+            D("cannot get serial number\n");
+            usb_cleanup_handle(handle);
+            free(handle);
+          }
+        } else {
+          usb_cleanup_handle(handle);
+          free(handle);
+        }
+      }
+    }
+
+    entry_buffer_size = sizeof(entry_buffer);
+  }
+
+  AdbCloseHandle(enum_handle);
+}
diff --git a/src/devtools/datool/fbtool.py b/src/devtools/datool/fbtool.py
old mode 100644
new mode 100755
index bbcf36e..61ff980
--- a/src/devtools/datool/fbtool.py
+++ b/src/devtools/datool/fbtool.py
@@ -1,11 +1,13 @@
+# SPDX-License-Identifier:    BSD-3-Clause
+#
+# Copyright (C) MediaTek Inc.
+# Author: Joe Yang <joe.yang@mediatek.com>
+#
+
 #!/usr/bin/env python
-# -*- coding: utf-8 -*
-try:
-    import pyserial as serial
-    import pyserial.tools.list_ports as ser_tools
-except ImportError:
-    import serial
-    import serial.tools.list_ports as ser_tools
+# -*- coding: utf-8 -*-
+import serial
+import serial.tools.list_ports as ser_tools
 import sys, time, struct, logging
 from optparse import OptionParser
 try:
@@ -73,7 +75,7 @@
             try:
                 self.__ser = serial.Serial(comport, 115200)
             except serial.SerialException as e:
-                logging.debug('%s, retry...' %(str(e)))
+                logging.info('%s, retry...' %(str(e)))
             else:
                 logging.info('Got %s' %(comport))
                 return True
@@ -540,7 +542,12 @@
     else:
         logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(levelname)s: %(message)s')
 
-    logging.info('pySerial version: (%s)' %serial.VERSION)
+    if sys.version_info < (3, 0):
+        reload(sys)
+        sys.setdefaultencoding('utf-8')
+
+    logging.info('python version: %s' %sys.version)
+    logging.info('pySerial version: %s' %serial.VERSION)
     if serial.VERSION < '2.6':
         logging.error('pySerial version(%s) is lower than 2.6, please upgrade!' %serial.VERSION)
     logging.info('Use config file: %s' %(config_file))
diff --git a/src/devtools/datool/serial/__init__.py b/src/devtools/datool/serial/__init__.py
new file mode 100755
index 0000000..caa4de1
--- /dev/null
+++ b/src/devtools/datool/serial/__init__.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+#
+# This is a wrapper module for different platform implementations
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2001-2020 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+from __future__ import absolute_import
+
+import sys
+import importlib
+
+from serial.serialutil import *
+#~ SerialBase, SerialException, to_bytes, iterbytes
+
+__version__ = '3.5'
+
+VERSION = __version__
+
+# pylint: disable=wrong-import-position
+if sys.platform == 'cli':
+    from serial.serialcli import Serial
+else:
+    import os
+    # chose an implementation, depending on os
+    if os.name == 'nt':  # sys.platform == 'win32':
+        from serial.serialwin32 import Serial
+    elif os.name == 'posix':
+        from serial.serialposix import Serial, PosixPollSerial, VTIMESerial  # noqa
+    elif os.name == 'java':
+        from serial.serialjava import Serial
+    else:
+        raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name))
+
+
+protocol_handler_packages = [
+    'serial.urlhandler',
+]
+
+
+def serial_for_url(url, *args, **kwargs):
+    """\
+    Get an instance of the Serial class, depending on port/url. The port is not
+    opened when the keyword parameter 'do_not_open' is true, by default it
+    is. All other parameters are directly passed to the __init__ method when
+    the port is instantiated.
+
+    The list of package names that is searched for protocol handlers is kept in
+    ``protocol_handler_packages``.
+
+    e.g. we want to support a URL ``foobar://``. A module
+    ``my_handlers.protocol_foobar`` is provided by the user. Then
+    ``protocol_handler_packages.append("my_handlers")`` would extend the search
+    path so that ``serial_for_url("foobar://"))`` would work.
+    """
+    # check and remove extra parameter to not confuse the Serial class
+    do_open = not kwargs.pop('do_not_open', False)
+    # the default is to use the native implementation
+    klass = Serial
+    try:
+        url_lowercase = url.lower()
+    except AttributeError:
+        # it's not a string, use default
+        pass
+    else:
+        # if it is an URL, try to import the handler module from the list of possible packages
+        if '://' in url_lowercase:
+            protocol = url_lowercase.split('://', 1)[0]
+            module_name = '.protocol_{}'.format(protocol)
+            for package_name in protocol_handler_packages:
+                try:
+                    importlib.import_module(package_name)
+                    handler_module = importlib.import_module(module_name, package_name)
+                except ImportError:
+                    continue
+                else:
+                    if hasattr(handler_module, 'serial_class_for_url'):
+                        url, klass = handler_module.serial_class_for_url(url)
+                    else:
+                        klass = handler_module.Serial
+                    break
+            else:
+                raise ValueError('invalid URL, protocol {!r} not known'.format(protocol))
+    # instantiate and open when desired
+    instance = klass(None, *args, **kwargs)
+    instance.port = url
+    if do_open:
+        instance.open()
+    return instance
diff --git a/src/devtools/datool/serial/__main__.py b/src/devtools/datool/serial/__main__.py
new file mode 100755
index 0000000..9a08ef5
--- /dev/null
+++ b/src/devtools/datool/serial/__main__.py
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier:    BSD-3-Clause
+
+from .tools import miniterm
+
+miniterm.main()
diff --git a/src/devtools/datool/serial/rfc2217.py b/src/devtools/datool/serial/rfc2217.py
new file mode 100755
index 0000000..2ae188e
--- /dev/null
+++ b/src/devtools/datool/serial/rfc2217.py
@@ -0,0 +1,1351 @@
+#! python
+#
+# This module implements a RFC2217 compatible client. RF2217 descibes a
+# protocol to access serial ports over TCP/IP and allows setting the baud rate,
+# modem control lines etc.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+# TODO:
+# - setting control line -> answer is not checked (had problems with one of the
+#   severs). consider implementing a compatibility mode flag to make check
+#   conditional
+# - write timeout not implemented at all
+
+# ###########################################################################
+# observations and issues with servers
+# ===========================================================================
+# sredird V2.2.1
+# - http://www.ibiblio.org/pub/Linux/system/serial/   sredird-2.2.2.tar.gz
+# - does not acknowledge SET_CONTROL (RTS/DTR) correctly, always responding
+#   [105 1] instead of the actual value.
+# - SET_BAUDRATE answer contains 4 extra null bytes -> probably for larger
+#   numbers than 2**32?
+# - To get the signature [COM_PORT_OPTION 0] has to be sent.
+# - run a server: while true; do nc -l -p 7000 -c "sredird debug /dev/ttyUSB0 /var/lock/sredir"; done
+# ===========================================================================
+# telnetcpcd (untested)
+# - http://ftp.wayne.edu/kermit/sredird/telnetcpcd-1.09.tar.gz
+# - To get the signature [COM_PORT_OPTION] w/o data has to be sent.
+# ===========================================================================
+# ser2net
+# - does not negotiate BINARY or COM_PORT_OPTION for his side but at least
+#   acknowledges that the client activates these options
+# - The configuration may be that the server prints a banner. As this client
+#   implementation does a flushInput on connect, this banner is hidden from
+#   the user application.
+# - NOTIFY_MODEMSTATE: the poll interval of the server seems to be one
+#   second.
+# - To get the signature [COM_PORT_OPTION 0] has to be sent.
+# - run a server: run ser2net daemon, in /etc/ser2net.conf:
+#     2000:telnet:0:/dev/ttyS0:9600 remctl banner
+# ###########################################################################
+
+# How to identify ports? pySerial might want to support other protocols in the
+# future, so lets use an URL scheme.
+# for RFC2217 compliant servers we will use this:
+#    rfc2217://<host>:<port>[?option[&option...]]
+#
+# options:
+# - "logging" set log level print diagnostic messages (e.g. "logging=debug")
+# - "ign_set_control": do not look at the answers to SET_CONTROL
+# - "poll_modem": issue NOTIFY_MODEMSTATE requests when CTS/DTR/RI/CD is read.
+#   Without this option it expects that the server sends notifications
+#   automatically on change (which most servers do and is according to the
+#   RFC).
+# the order of the options is not relevant
+
+from __future__ import absolute_import
+
+import logging
+import socket
+import struct
+import threading
+import time
+try:
+    import urlparse
+except ImportError:
+    import urllib.parse as urlparse
+try:
+    import Queue
+except ImportError:
+    import queue as Queue
+
+import serial
+from serial.serialutil import SerialBase, SerialException, to_bytes, \
+    iterbytes, PortNotOpenError, Timeout
+
+# port string is expected to be something like this:
+# rfc2217://host:port
+# host may be an IP or including domain, whatever.
+# port is 0...65535
+
+# map log level names to constants. used in from_url()
+LOGGER_LEVELS = {
+    'debug': logging.DEBUG,
+    'info': logging.INFO,
+    'warning': logging.WARNING,
+    'error': logging.ERROR,
+}
+
+
+# telnet protocol characters
+SE = b'\xf0'    # Subnegotiation End
+NOP = b'\xf1'   # No Operation
+DM = b'\xf2'    # Data Mark
+BRK = b'\xf3'   # Break
+IP = b'\xf4'    # Interrupt process
+AO = b'\xf5'    # Abort output
+AYT = b'\xf6'   # Are You There
+EC = b'\xf7'    # Erase Character
+EL = b'\xf8'    # Erase Line
+GA = b'\xf9'    # Go Ahead
+SB = b'\xfa'    # Subnegotiation Begin
+WILL = b'\xfb'
+WONT = b'\xfc'
+DO = b'\xfd'
+DONT = b'\xfe'
+IAC = b'\xff'   # Interpret As Command
+IAC_DOUBLED = b'\xff\xff'
+
+# selected telnet options
+BINARY = b'\x00'    # 8-bit data path
+ECHO = b'\x01'      # echo
+SGA = b'\x03'       # suppress go ahead
+
+# RFC2217
+COM_PORT_OPTION = b'\x2c'
+
+# Client to Access Server
+SET_BAUDRATE = b'\x01'
+SET_DATASIZE = b'\x02'
+SET_PARITY = b'\x03'
+SET_STOPSIZE = b'\x04'
+SET_CONTROL = b'\x05'
+NOTIFY_LINESTATE = b'\x06'
+NOTIFY_MODEMSTATE = b'\x07'
+FLOWCONTROL_SUSPEND = b'\x08'
+FLOWCONTROL_RESUME = b'\x09'
+SET_LINESTATE_MASK = b'\x0a'
+SET_MODEMSTATE_MASK = b'\x0b'
+PURGE_DATA = b'\x0c'
+
+SERVER_SET_BAUDRATE = b'\x65'
+SERVER_SET_DATASIZE = b'\x66'
+SERVER_SET_PARITY = b'\x67'
+SERVER_SET_STOPSIZE = b'\x68'
+SERVER_SET_CONTROL = b'\x69'
+SERVER_NOTIFY_LINESTATE = b'\x6a'
+SERVER_NOTIFY_MODEMSTATE = b'\x6b'
+SERVER_FLOWCONTROL_SUSPEND = b'\x6c'
+SERVER_FLOWCONTROL_RESUME = b'\x6d'
+SERVER_SET_LINESTATE_MASK = b'\x6e'
+SERVER_SET_MODEMSTATE_MASK = b'\x6f'
+SERVER_PURGE_DATA = b'\x70'
+
+RFC2217_ANSWER_MAP = {
+    SET_BAUDRATE: SERVER_SET_BAUDRATE,
+    SET_DATASIZE: SERVER_SET_DATASIZE,
+    SET_PARITY: SERVER_SET_PARITY,
+    SET_STOPSIZE: SERVER_SET_STOPSIZE,
+    SET_CONTROL: SERVER_SET_CONTROL,
+    NOTIFY_LINESTATE: SERVER_NOTIFY_LINESTATE,
+    NOTIFY_MODEMSTATE: SERVER_NOTIFY_MODEMSTATE,
+    FLOWCONTROL_SUSPEND: SERVER_FLOWCONTROL_SUSPEND,
+    FLOWCONTROL_RESUME: SERVER_FLOWCONTROL_RESUME,
+    SET_LINESTATE_MASK: SERVER_SET_LINESTATE_MASK,
+    SET_MODEMSTATE_MASK: SERVER_SET_MODEMSTATE_MASK,
+    PURGE_DATA: SERVER_PURGE_DATA,
+}
+
+SET_CONTROL_REQ_FLOW_SETTING = b'\x00'        # Request Com Port Flow Control Setting (outbound/both)
+SET_CONTROL_USE_NO_FLOW_CONTROL = b'\x01'     # Use No Flow Control (outbound/both)
+SET_CONTROL_USE_SW_FLOW_CONTROL = b'\x02'     # Use XON/XOFF Flow Control (outbound/both)
+SET_CONTROL_USE_HW_FLOW_CONTROL = b'\x03'     # Use HARDWARE Flow Control (outbound/both)
+SET_CONTROL_REQ_BREAK_STATE = b'\x04'         # Request BREAK State
+SET_CONTROL_BREAK_ON = b'\x05'                # Set BREAK State ON
+SET_CONTROL_BREAK_OFF = b'\x06'               # Set BREAK State OFF
+SET_CONTROL_REQ_DTR = b'\x07'                 # Request DTR Signal State
+SET_CONTROL_DTR_ON = b'\x08'                  # Set DTR Signal State ON
+SET_CONTROL_DTR_OFF = b'\x09'                 # Set DTR Signal State OFF
+SET_CONTROL_REQ_RTS = b'\x0a'                 # Request RTS Signal State
+SET_CONTROL_RTS_ON = b'\x0b'                  # Set RTS Signal State ON
+SET_CONTROL_RTS_OFF = b'\x0c'                 # Set RTS Signal State OFF
+SET_CONTROL_REQ_FLOW_SETTING_IN = b'\x0d'     # Request Com Port Flow Control Setting (inbound)
+SET_CONTROL_USE_NO_FLOW_CONTROL_IN = b'\x0e'  # Use No Flow Control (inbound)
+SET_CONTROL_USE_SW_FLOW_CONTOL_IN = b'\x0f'   # Use XON/XOFF Flow Control (inbound)
+SET_CONTROL_USE_HW_FLOW_CONTOL_IN = b'\x10'   # Use HARDWARE Flow Control (inbound)
+SET_CONTROL_USE_DCD_FLOW_CONTROL = b'\x11'    # Use DCD Flow Control (outbound/both)
+SET_CONTROL_USE_DTR_FLOW_CONTROL = b'\x12'    # Use DTR Flow Control (inbound)
+SET_CONTROL_USE_DSR_FLOW_CONTROL = b'\x13'    # Use DSR Flow Control (outbound/both)
+
+LINESTATE_MASK_TIMEOUT = 128        # Time-out Error
+LINESTATE_MASK_SHIFTREG_EMPTY = 64  # Transfer Shift Register Empty
+LINESTATE_MASK_TRANSREG_EMPTY = 32  # Transfer Holding Register Empty
+LINESTATE_MASK_BREAK_DETECT = 16    # Break-detect Error
+LINESTATE_MASK_FRAMING_ERROR = 8    # Framing Error
+LINESTATE_MASK_PARTIY_ERROR = 4     # Parity Error
+LINESTATE_MASK_OVERRUN_ERROR = 2    # Overrun Error
+LINESTATE_MASK_DATA_READY = 1       # Data Ready
+
+MODEMSTATE_MASK_CD = 128            # Receive Line Signal Detect (also known as Carrier Detect)
+MODEMSTATE_MASK_RI = 64             # Ring Indicator
+MODEMSTATE_MASK_DSR = 32            # Data-Set-Ready Signal State
+MODEMSTATE_MASK_CTS = 16            # Clear-To-Send Signal State
+MODEMSTATE_MASK_CD_CHANGE = 8       # Delta Receive Line Signal Detect
+MODEMSTATE_MASK_RI_CHANGE = 4       # Trailing-edge Ring Detector
+MODEMSTATE_MASK_DSR_CHANGE = 2      # Delta Data-Set-Ready
+MODEMSTATE_MASK_CTS_CHANGE = 1      # Delta Clear-To-Send
+
+PURGE_RECEIVE_BUFFER = b'\x01'      # Purge access server receive data buffer
+PURGE_TRANSMIT_BUFFER = b'\x02'     # Purge access server transmit data buffer
+PURGE_BOTH_BUFFERS = b'\x03'        # Purge both the access server receive data
+                                    # buffer and the access server transmit data buffer
+
+
+RFC2217_PARITY_MAP = {
+    serial.PARITY_NONE: 1,
+    serial.PARITY_ODD: 2,
+    serial.PARITY_EVEN: 3,
+    serial.PARITY_MARK: 4,
+    serial.PARITY_SPACE: 5,
+}
+RFC2217_REVERSE_PARITY_MAP = dict((v, k) for k, v in RFC2217_PARITY_MAP.items())
+
+RFC2217_STOPBIT_MAP = {
+    serial.STOPBITS_ONE: 1,
+    serial.STOPBITS_ONE_POINT_FIVE: 3,
+    serial.STOPBITS_TWO: 2,
+}
+RFC2217_REVERSE_STOPBIT_MAP = dict((v, k) for k, v in RFC2217_STOPBIT_MAP.items())
+
+# Telnet filter states
+M_NORMAL = 0
+M_IAC_SEEN = 1
+M_NEGOTIATE = 2
+
+# TelnetOption and TelnetSubnegotiation states
+REQUESTED = 'REQUESTED'
+ACTIVE = 'ACTIVE'
+INACTIVE = 'INACTIVE'
+REALLY_INACTIVE = 'REALLY_INACTIVE'
+
+
+class TelnetOption(object):
+    """Manage a single telnet option, keeps track of DO/DONT WILL/WONT."""
+
+    def __init__(self, connection, name, option, send_yes, send_no, ack_yes,
+                 ack_no, initial_state, activation_callback=None):
+        """\
+        Initialize option.
+        :param connection: connection used to transmit answers
+        :param name: a readable name for debug outputs
+        :param send_yes: what to send when option is to be enabled.
+        :param send_no: what to send when option is to be disabled.
+        :param ack_yes: what to expect when remote agrees on option.
+        :param ack_no: what to expect when remote disagrees on option.
+        :param initial_state: options initialized with REQUESTED are tried to
+            be enabled on startup. use INACTIVE for all others.
+        """
+        self.connection = connection
+        self.name = name
+        self.option = option
+        self.send_yes = send_yes
+        self.send_no = send_no
+        self.ack_yes = ack_yes
+        self.ack_no = ack_no
+        self.state = initial_state
+        self.active = False
+        self.activation_callback = activation_callback
+
+    def __repr__(self):
+        """String for debug outputs"""
+        return "{o.name}:{o.active}({o.state})".format(o=self)
+
+    def process_incoming(self, command):
+        """\
+        A DO/DONT/WILL/WONT was received for this option, update state and
+        answer when needed.
+        """
+        if command == self.ack_yes:
+            if self.state is REQUESTED:
+                self.state = ACTIVE
+                self.active = True
+                if self.activation_callback is not None:
+                    self.activation_callback()
+            elif self.state is ACTIVE:
+                pass
+            elif self.state is INACTIVE:
+                self.state = ACTIVE
+                self.connection.telnet_send_option(self.send_yes, self.option)
+                self.active = True
+                if self.activation_callback is not None:
+                    self.activation_callback()
+            elif self.state is REALLY_INACTIVE:
+                self.connection.telnet_send_option(self.send_no, self.option)
+            else:
+                raise ValueError('option in illegal state {!r}'.format(self))
+        elif command == self.ack_no:
+            if self.state is REQUESTED:
+                self.state = INACTIVE
+                self.active = False
+            elif self.state is ACTIVE:
+                self.state = INACTIVE
+                self.connection.telnet_send_option(self.send_no, self.option)
+                self.active = False
+            elif self.state is INACTIVE:
+                pass
+            elif self.state is REALLY_INACTIVE:
+                pass
+            else:
+                raise ValueError('option in illegal state {!r}'.format(self))
+
+
+class TelnetSubnegotiation(object):
+    """\
+    A object to handle subnegotiation of options. In this case actually
+    sub-sub options for RFC 2217. It is used to track com port options.
+    """
+
+    def __init__(self, connection, name, option, ack_option=None):
+        if ack_option is None:
+            ack_option = option
+        self.connection = connection
+        self.name = name
+        self.option = option
+        self.value = None
+        self.ack_option = ack_option
+        self.state = INACTIVE
+
+    def __repr__(self):
+        """String for debug outputs."""
+        return "{sn.name}:{sn.state}".format(sn=self)
+
+    def set(self, value):
+        """\
+        Request a change of the value. a request is sent to the server. if
+        the client needs to know if the change is performed he has to check the
+        state of this object.
+        """
+        self.value = value
+        self.state = REQUESTED
+        self.connection.rfc2217_send_subnegotiation(self.option, self.value)
+        if self.connection.logger:
+            self.connection.logger.debug("SB Requesting {} -> {!r}".format(self.name, self.value))
+
+    def is_ready(self):
+        """\
+        Check if answer from server has been received. when server rejects
+        the change, raise a ValueError.
+        """
+        if self.state == REALLY_INACTIVE:
+            raise ValueError("remote rejected value for option {!r}".format(self.name))
+        return self.state == ACTIVE
+    # add property to have a similar interface as TelnetOption
+    active = property(is_ready)
+
+    def wait(self, timeout=3):
+        """\
+        Wait until the subnegotiation has been acknowledged or timeout. It
+        can also throw a value error when the answer from the server does not
+        match the value sent.
+        """
+        timeout_timer = Timeout(timeout)
+        while not timeout_timer.expired():
+            time.sleep(0.05)    # prevent 100% CPU load
+            if self.is_ready():
+                break
+        else:
+            raise SerialException("timeout while waiting for option {!r}".format(self.name))
+
+    def check_answer(self, suboption):
+        """\
+        Check an incoming subnegotiation block. The parameter already has
+        cut off the header like sub option number and com port option value.
+        """
+        if self.value == suboption[:len(self.value)]:
+            self.state = ACTIVE
+        else:
+            # error propagation done in is_ready
+            self.state = REALLY_INACTIVE
+        if self.connection.logger:
+            self.connection.logger.debug("SB Answer {} -> {!r} -> {}".format(self.name, suboption, self.state))
+
+
+class Serial(SerialBase):
+    """Serial port implementation for RFC 2217 remote serial ports."""
+
+    BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+                 9600, 19200, 38400, 57600, 115200)
+
+    def __init__(self, *args, **kwargs):
+        self._thread = None
+        self._socket = None
+        self._linestate = 0
+        self._modemstate = None
+        self._modemstate_timeout = Timeout(-1)
+        self._remote_suspend_flow = False
+        self._write_lock = None
+        self.logger = None
+        self._ignore_set_control_answer = False
+        self._poll_modem_state = False
+        self._network_timeout = 3
+        self._telnet_options = None
+        self._rfc2217_port_settings = None
+        self._rfc2217_options = None
+        self._read_buffer = None
+        super(Serial, self).__init__(*args, **kwargs)  # must be last call in case of auto-open
+
+    def open(self):
+        """\
+        Open port with current settings. This may throw a SerialException
+        if the port cannot be opened.
+        """
+        self.logger = None
+        self._ignore_set_control_answer = False
+        self._poll_modem_state = False
+        self._network_timeout = 3
+        if self._port is None:
+            raise SerialException("Port must be configured before it can be used.")
+        if self.is_open:
+            raise SerialException("Port is already open.")
+        try:
+            self._socket = socket.create_connection(self.from_url(self.portstr), timeout=5)  # XXX good value?
+            self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+        except Exception as msg:
+            self._socket = None
+            raise SerialException("Could not open port {}: {}".format(self.portstr, msg))
+
+        # use a thread save queue as buffer. it also simplifies implementing
+        # the read timeout
+        self._read_buffer = Queue.Queue()
+        # to ensure that user writes does not interfere with internal
+        # telnet/rfc2217 options establish a lock
+        self._write_lock = threading.Lock()
+        # name the following separately so that, below, a check can be easily done
+        mandadory_options = [
+            TelnetOption(self, 'we-BINARY', BINARY, WILL, WONT, DO, DONT, INACTIVE),
+            TelnetOption(self, 'we-RFC2217', COM_PORT_OPTION, WILL, WONT, DO, DONT, REQUESTED),
+        ]
+        # all supported telnet options
+        self._telnet_options = [
+            TelnetOption(self, 'ECHO', ECHO, DO, DONT, WILL, WONT, REQUESTED),
+            TelnetOption(self, 'we-SGA', SGA, WILL, WONT, DO, DONT, REQUESTED),
+            TelnetOption(self, 'they-SGA', SGA, DO, DONT, WILL, WONT, REQUESTED),
+            TelnetOption(self, 'they-BINARY', BINARY, DO, DONT, WILL, WONT, INACTIVE),
+            TelnetOption(self, 'they-RFC2217', COM_PORT_OPTION, DO, DONT, WILL, WONT, REQUESTED),
+        ] + mandadory_options
+        # RFC 2217 specific states
+        # COM port settings
+        self._rfc2217_port_settings = {
+            'baudrate': TelnetSubnegotiation(self, 'baudrate', SET_BAUDRATE, SERVER_SET_BAUDRATE),
+            'datasize': TelnetSubnegotiation(self, 'datasize', SET_DATASIZE, SERVER_SET_DATASIZE),
+            'parity':   TelnetSubnegotiation(self, 'parity',   SET_PARITY,   SERVER_SET_PARITY),
+            'stopsize': TelnetSubnegotiation(self, 'stopsize', SET_STOPSIZE, SERVER_SET_STOPSIZE),
+        }
+        # There are more subnegotiation objects, combine all in one dictionary
+        # for easy access
+        self._rfc2217_options = {
+            'purge':    TelnetSubnegotiation(self, 'purge',    PURGE_DATA,   SERVER_PURGE_DATA),
+            'control':  TelnetSubnegotiation(self, 'control',  SET_CONTROL,  SERVER_SET_CONTROL),
+        }
+        self._rfc2217_options.update(self._rfc2217_port_settings)
+        # cache for line and modem states that the server sends to us
+        self._linestate = 0
+        self._modemstate = None
+        self._modemstate_timeout = Timeout(-1)
+        # RFC 2217 flow control between server and client
+        self._remote_suspend_flow = False
+
+        self.is_open = True
+        self._thread = threading.Thread(target=self._telnet_read_loop)
+        self._thread.setDaemon(True)
+        self._thread.setName('pySerial RFC 2217 reader thread for {}'.format(self._port))
+        self._thread.start()
+
+        try:    # must clean-up if open fails
+            # negotiate Telnet/RFC 2217 -> send initial requests
+            for option in self._telnet_options:
+                if option.state is REQUESTED:
+                    self.telnet_send_option(option.send_yes, option.option)
+            # now wait until important options are negotiated
+            timeout = Timeout(self._network_timeout)
+            while not timeout.expired():
+                time.sleep(0.05)    # prevent 100% CPU load
+                if sum(o.active for o in mandadory_options) == sum(o.state != INACTIVE for o in mandadory_options):
+                    break
+            else:
+                raise SerialException(
+                    "Remote does not seem to support RFC2217 or BINARY mode {!r}".format(mandadory_options))
+            if self.logger:
+                self.logger.info("Negotiated options: {}".format(self._telnet_options))
+
+            # fine, go on, set RFC 2217 specific things
+            self._reconfigure_port()
+            # all things set up get, now a clean start
+            if not self._dsrdtr:
+                self._update_dtr_state()
+            if not self._rtscts:
+                self._update_rts_state()
+            self.reset_input_buffer()
+            self.reset_output_buffer()
+        except:
+            self.close()
+            raise
+
+    def _reconfigure_port(self):
+        """Set communication parameters on opened port."""
+        if self._socket is None:
+            raise SerialException("Can only operate on open ports")
+
+        # if self._timeout != 0 and self._interCharTimeout is not None:
+            # XXX
+
+        if self._write_timeout is not None:
+            raise NotImplementedError('write_timeout is currently not supported')
+            # XXX
+
+        # Setup the connection
+        # to get good performance, all parameter changes are sent first...
+        if not 0 < self._baudrate < 2 ** 32:
+            raise ValueError("invalid baudrate: {!r}".format(self._baudrate))
+        self._rfc2217_port_settings['baudrate'].set(struct.pack(b'!I', self._baudrate))
+        self._rfc2217_port_settings['datasize'].set(struct.pack(b'!B', self._bytesize))
+        self._rfc2217_port_settings['parity'].set(struct.pack(b'!B', RFC2217_PARITY_MAP[self._parity]))
+        self._rfc2217_port_settings['stopsize'].set(struct.pack(b'!B', RFC2217_STOPBIT_MAP[self._stopbits]))
+
+        # and now wait until parameters are active
+        items = self._rfc2217_port_settings.values()
+        if self.logger:
+            self.logger.debug("Negotiating settings: {}".format(items))
+        timeout = Timeout(self._network_timeout)
+        while not timeout.expired():
+            time.sleep(0.05)    # prevent 100% CPU load
+            if sum(o.active for o in items) == len(items):
+                break
+        else:
+            raise SerialException("Remote does not accept parameter change (RFC2217): {!r}".format(items))
+        if self.logger:
+            self.logger.info("Negotiated settings: {}".format(items))
+
+        if self._rtscts and self._xonxoff:
+            raise ValueError('xonxoff and rtscts together are not supported')
+        elif self._rtscts:
+            self.rfc2217_set_control(SET_CONTROL_USE_HW_FLOW_CONTROL)
+        elif self._xonxoff:
+            self.rfc2217_set_control(SET_CONTROL_USE_SW_FLOW_CONTROL)
+        else:
+            self.rfc2217_set_control(SET_CONTROL_USE_NO_FLOW_CONTROL)
+
+    def close(self):
+        """Close port"""
+        self.is_open = False
+        if self._socket:
+            try:
+                self._socket.shutdown(socket.SHUT_RDWR)
+                self._socket.close()
+            except:
+                # ignore errors.
+                pass
+        if self._thread:
+            self._thread.join(7)  # XXX more than socket timeout
+            self._thread = None
+            # in case of quick reconnects, give the server some time
+            time.sleep(0.3)
+        self._socket = None
+
+    def from_url(self, url):
+        """\
+        extract host and port from an URL string, other settings are extracted
+        an stored in instance
+        """
+        parts = urlparse.urlsplit(url)
+        if parts.scheme != "rfc2217":
+            raise SerialException(
+                'expected a string in the form '
+                '"rfc2217://<host>:<port>[?option[&option...]]": '
+                'not starting with rfc2217:// ({!r})'.format(parts.scheme))
+        try:
+            # process options now, directly altering self
+            for option, values in urlparse.parse_qs(parts.query, True).items():
+                if option == 'logging':
+                    logging.basicConfig()   # XXX is that good to call it here?
+                    self.logger = logging.getLogger('pySerial.rfc2217')
+                    self.logger.setLevel(LOGGER_LEVELS[values[0]])
+                    self.logger.debug('enabled logging')
+                elif option == 'ign_set_control':
+                    self._ignore_set_control_answer = True
+                elif option == 'poll_modem':
+                    self._poll_modem_state = True
+                elif option == 'timeout':
+                    self._network_timeout = float(values[0])
+                else:
+                    raise ValueError('unknown option: {!r}'.format(option))
+            if not 0 <= parts.port < 65536:
+                raise ValueError("port not in range 0...65535")
+        except ValueError as e:
+            raise SerialException(
+                'expected a string in the form '
+                '"rfc2217://<host>:<port>[?option[&option...]]": {}'.format(e))
+        return (parts.hostname, parts.port)
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    @property
+    def in_waiting(self):
+        """Return the number of bytes currently in the input buffer."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        return self._read_buffer.qsize()
+
+    def read(self, size=1):
+        """\
+        Read size bytes from the serial port. If a timeout is set it may
+        return less characters as requested. With no timeout it will block
+        until the requested number of bytes is read.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        data = bytearray()
+        try:
+            timeout = Timeout(self._timeout)
+            while len(data) < size:
+                if self._thread is None or not self._thread.is_alive():
+                    raise SerialException('connection failed (reader thread died)')
+                buf = self._read_buffer.get(True, timeout.time_left())
+                if buf is None:
+                    return bytes(data)
+                data += buf
+                if timeout.expired():
+                    break
+        except Queue.Empty:  # -> timeout
+            pass
+        return bytes(data)
+
+    def write(self, data):
+        """\
+        Output the given byte string over the serial port. Can block if the
+        connection is blocked. May raise SerialException if the connection is
+        closed.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        with self._write_lock:
+            try:
+                self._socket.sendall(to_bytes(data).replace(IAC, IAC_DOUBLED))
+            except socket.error as e:
+                raise SerialException("connection failed (socket error): {}".format(e))
+        return len(data)
+
+    def reset_input_buffer(self):
+        """Clear input buffer, discarding all that is in the buffer."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        self.rfc2217_send_purge(PURGE_RECEIVE_BUFFER)
+        # empty read buffer
+        while self._read_buffer.qsize():
+            self._read_buffer.get(False)
+
+    def reset_output_buffer(self):
+        """\
+        Clear output buffer, aborting the current output and
+        discarding all that is in the buffer.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        self.rfc2217_send_purge(PURGE_TRANSMIT_BUFFER)
+
+    def _update_break_state(self):
+        """\
+        Set break: Controls TXD. When active, to transmitting is
+        possible.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('set BREAK to {}'.format('active' if self._break_state else 'inactive'))
+        if self._break_state:
+            self.rfc2217_set_control(SET_CONTROL_BREAK_ON)
+        else:
+            self.rfc2217_set_control(SET_CONTROL_BREAK_OFF)
+
+    def _update_rts_state(self):
+        """Set terminal status line: Request To Send."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('set RTS to {}'.format('active' if self._rts_state else 'inactive'))
+        if self._rts_state:
+            self.rfc2217_set_control(SET_CONTROL_RTS_ON)
+        else:
+            self.rfc2217_set_control(SET_CONTROL_RTS_OFF)
+
+    def _update_dtr_state(self):
+        """Set terminal status line: Data Terminal Ready."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('set DTR to {}'.format('active' if self._dtr_state else 'inactive'))
+        if self._dtr_state:
+            self.rfc2217_set_control(SET_CONTROL_DTR_ON)
+        else:
+            self.rfc2217_set_control(SET_CONTROL_DTR_OFF)
+
+    @property
+    def cts(self):
+        """Read terminal status line: Clear To Send."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        return bool(self.get_modem_state() & MODEMSTATE_MASK_CTS)
+
+    @property
+    def dsr(self):
+        """Read terminal status line: Data Set Ready."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        return bool(self.get_modem_state() & MODEMSTATE_MASK_DSR)
+
+    @property
+    def ri(self):
+        """Read terminal status line: Ring Indicator."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        return bool(self.get_modem_state() & MODEMSTATE_MASK_RI)
+
+    @property
+    def cd(self):
+        """Read terminal status line: Carrier Detect."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        return bool(self.get_modem_state() & MODEMSTATE_MASK_CD)
+
+    # - - - platform specific - - -
+    # None so far
+
+    # - - - RFC2217 specific - - -
+
+    def _telnet_read_loop(self):
+        """Read loop for the socket."""
+        mode = M_NORMAL
+        suboption = None
+        try:
+            while self.is_open:
+                try:
+                    data = self._socket.recv(1024)
+                except socket.timeout:
+                    # just need to get out of recv form time to time to check if
+                    # still alive
+                    continue
+                except socket.error as e:
+                    # connection fails -> terminate loop
+                    if self.logger:
+                        self.logger.debug("socket error in reader thread: {}".format(e))
+                    self._read_buffer.put(None)
+                    break
+                if not data:
+                    self._read_buffer.put(None)
+                    break  # lost connection
+                for byte in iterbytes(data):
+                    if mode == M_NORMAL:
+                        # interpret as command or as data
+                        if byte == IAC:
+                            mode = M_IAC_SEEN
+                        else:
+                            # store data in read buffer or sub option buffer
+                            # depending on state
+                            if suboption is not None:
+                                suboption += byte
+                            else:
+                                self._read_buffer.put(byte)
+                    elif mode == M_IAC_SEEN:
+                        if byte == IAC:
+                            # interpret as command doubled -> insert character
+                            # itself
+                            if suboption is not None:
+                                suboption += IAC
+                            else:
+                                self._read_buffer.put(IAC)
+                            mode = M_NORMAL
+                        elif byte == SB:
+                            # sub option start
+                            suboption = bytearray()
+                            mode = M_NORMAL
+                        elif byte == SE:
+                            # sub option end -> process it now
+                            self._telnet_process_subnegotiation(bytes(suboption))
+                            suboption = None
+                            mode = M_NORMAL
+                        elif byte in (DO, DONT, WILL, WONT):
+                            # negotiation
+                            telnet_command = byte
+                            mode = M_NEGOTIATE
+                        else:
+                            # other telnet commands
+                            self._telnet_process_command(byte)
+                            mode = M_NORMAL
+                    elif mode == M_NEGOTIATE:  # DO, DONT, WILL, WONT was received, option now following
+                        self._telnet_negotiate_option(telnet_command, byte)
+                        mode = M_NORMAL
+        finally:
+            if self.logger:
+                self.logger.debug("read thread terminated")
+
+    # - incoming telnet commands and options
+
+    def _telnet_process_command(self, command):
+        """Process commands other than DO, DONT, WILL, WONT."""
+        # Currently none. RFC2217 only uses negotiation and subnegotiation.
+        if self.logger:
+            self.logger.warning("ignoring Telnet command: {!r}".format(command))
+
+    def _telnet_negotiate_option(self, command, option):
+        """Process incoming DO, DONT, WILL, WONT."""
+        # check our registered telnet options and forward command to them
+        # they know themselves if they have to answer or not
+        known = False
+        for item in self._telnet_options:
+            # can have more than one match! as some options are duplicated for
+            # 'us' and 'them'
+            if item.option == option:
+                item.process_incoming(command)
+                known = True
+        if not known:
+            # handle unknown options
+            # only answer to positive requests and deny them
+            if command == WILL or command == DO:
+                self.telnet_send_option((DONT if command == WILL else WONT), option)
+                if self.logger:
+                    self.logger.warning("rejected Telnet option: {!r}".format(option))
+
+    def _telnet_process_subnegotiation(self, suboption):
+        """Process subnegotiation, the data between IAC SB and IAC SE."""
+        if suboption[0:1] == COM_PORT_OPTION:
+            if suboption[1:2] == SERVER_NOTIFY_LINESTATE and len(suboption) >= 3:
+                self._linestate = ord(suboption[2:3])  # ensure it is a number
+                if self.logger:
+                    self.logger.info("NOTIFY_LINESTATE: {}".format(self._linestate))
+            elif suboption[1:2] == SERVER_NOTIFY_MODEMSTATE and len(suboption) >= 3:
+                self._modemstate = ord(suboption[2:3])  # ensure it is a number
+                if self.logger:
+                    self.logger.info("NOTIFY_MODEMSTATE: {}".format(self._modemstate))
+                # update time when we think that a poll would make sense
+                self._modemstate_timeout.restart(0.3)
+            elif suboption[1:2] == FLOWCONTROL_SUSPEND:
+                self._remote_suspend_flow = True
+            elif suboption[1:2] == FLOWCONTROL_RESUME:
+                self._remote_suspend_flow = False
+            else:
+                for item in self._rfc2217_options.values():
+                    if item.ack_option == suboption[1:2]:
+                        #~ print "processing COM_PORT_OPTION: %r" % list(suboption[1:])
+                        item.check_answer(bytes(suboption[2:]))
+                        break
+                else:
+                    if self.logger:
+                        self.logger.warning("ignoring COM_PORT_OPTION: {!r}".format(suboption))
+        else:
+            if self.logger:
+                self.logger.warning("ignoring subnegotiation: {!r}".format(suboption))
+
+    # - outgoing telnet commands and options
+
+    def _internal_raw_write(self, data):
+        """internal socket write with no data escaping. used to send telnet stuff."""
+        with self._write_lock:
+            self._socket.sendall(data)
+
+    def telnet_send_option(self, action, option):
+        """Send DO, DONT, WILL, WONT."""
+        self._internal_raw_write(IAC + action + option)
+
+    def rfc2217_send_subnegotiation(self, option, value=b''):
+        """Subnegotiation of RFC2217 parameters."""
+        value = value.replace(IAC, IAC_DOUBLED)
+        self._internal_raw_write(IAC + SB + COM_PORT_OPTION + option + value + IAC + SE)
+
+    def rfc2217_send_purge(self, value):
+        """\
+        Send purge request to the remote.
+        (PURGE_RECEIVE_BUFFER / PURGE_TRANSMIT_BUFFER / PURGE_BOTH_BUFFERS)
+        """
+        item = self._rfc2217_options['purge']
+        item.set(value)  # transmit desired purge type
+        item.wait(self._network_timeout)  # wait for acknowledge from the server
+
+    def rfc2217_set_control(self, value):
+        """transmit change of control line to remote"""
+        item = self._rfc2217_options['control']
+        item.set(value)  # transmit desired control type
+        if self._ignore_set_control_answer:
+            # answers are ignored when option is set. compatibility mode for
+            # servers that answer, but not the expected one... (or no answer
+            # at all) i.e. sredird
+            time.sleep(0.1)  # this helps getting the unit tests passed
+        else:
+            item.wait(self._network_timeout)  # wait for acknowledge from the server
+
+    def rfc2217_flow_server_ready(self):
+        """\
+        check if server is ready to receive data. block for some time when
+        not.
+        """
+        #~ if self._remote_suspend_flow:
+        #~     wait---
+
+    def get_modem_state(self):
+        """\
+        get last modem state (cached value. If value is "old", request a new
+        one. This cache helps that we don't issue to many requests when e.g. all
+        status lines, one after the other is queried by the user (CTS, DSR
+        etc.)
+        """
+        # active modem state polling enabled? is the value fresh enough?
+        if self._poll_modem_state and self._modemstate_timeout.expired():
+            if self.logger:
+                self.logger.debug('polling modem state')
+            # when it is older, request an update
+            self.rfc2217_send_subnegotiation(NOTIFY_MODEMSTATE)
+            timeout = Timeout(self._network_timeout)
+            while not timeout.expired():
+                time.sleep(0.05)    # prevent 100% CPU load
+                # when expiration time is updated, it means that there is a new
+                # value
+                if not self._modemstate_timeout.expired():
+                    break
+            else:
+                if self.logger:
+                    self.logger.warning('poll for modem state failed')
+            # even when there is a timeout, do not generate an error just
+            # return the last known value. this way we can support buggy
+            # servers that do not respond to polls, but send automatic
+            # updates.
+        if self._modemstate is not None:
+            if self.logger:
+                self.logger.debug('using cached modem state')
+            return self._modemstate
+        else:
+            # never received a notification from the server
+            raise SerialException("remote sends no NOTIFY_MODEMSTATE")
+
+
+#############################################################################
+# The following is code that helps implementing an RFC 2217 server.
+
+class PortManager(object):
+    """\
+    This class manages the state of Telnet and RFC 2217. It needs a serial
+    instance and a connection to work with. Connection is expected to implement
+    a (thread safe) write function, that writes the string to the network.
+    """
+
+    def __init__(self, serial_port, connection, logger=None):
+        self.serial = serial_port
+        self.connection = connection
+        self.logger = logger
+        self._client_is_rfc2217 = False
+
+        # filter state machine
+        self.mode = M_NORMAL
+        self.suboption = None
+        self.telnet_command = None
+
+        # states for modem/line control events
+        self.modemstate_mask = 255
+        self.last_modemstate = None
+        self.linstate_mask = 0
+
+        # all supported telnet options
+        self._telnet_options = [
+            TelnetOption(self, 'ECHO', ECHO, WILL, WONT, DO, DONT, REQUESTED),
+            TelnetOption(self, 'we-SGA', SGA, WILL, WONT, DO, DONT, REQUESTED),
+            TelnetOption(self, 'they-SGA', SGA, DO, DONT, WILL, WONT, INACTIVE),
+            TelnetOption(self, 'we-BINARY', BINARY, WILL, WONT, DO, DONT, INACTIVE),
+            TelnetOption(self, 'they-BINARY', BINARY, DO, DONT, WILL, WONT, REQUESTED),
+            TelnetOption(self, 'we-RFC2217', COM_PORT_OPTION, WILL, WONT, DO, DONT, REQUESTED, self._client_ok),
+            TelnetOption(self, 'they-RFC2217', COM_PORT_OPTION, DO, DONT, WILL, WONT, INACTIVE, self._client_ok),
+        ]
+
+        # negotiate Telnet/RFC2217 -> send initial requests
+        if self.logger:
+            self.logger.debug("requesting initial Telnet/RFC 2217 options")
+        for option in self._telnet_options:
+            if option.state is REQUESTED:
+                self.telnet_send_option(option.send_yes, option.option)
+        # issue 1st modem state notification
+
+    def _client_ok(self):
+        """\
+        callback of telnet option. It gets called when option is activated.
+        This one here is used to detect when the client agrees on RFC 2217. A
+        flag is set so that other functions like check_modem_lines know if the
+        client is OK.
+        """
+        # The callback is used for we and they so if one party agrees, we're
+        # already happy. it seems not all servers do the negotiation correctly
+        # and i guess there are incorrect clients too.. so be happy if client
+        # answers one or the other positively.
+        self._client_is_rfc2217 = True
+        if self.logger:
+            self.logger.info("client accepts RFC 2217")
+        # this is to ensure that the client gets a notification, even if there
+        # was no change
+        self.check_modem_lines(force_notification=True)
+
+    # - outgoing telnet commands and options
+
+    def telnet_send_option(self, action, option):
+        """Send DO, DONT, WILL, WONT."""
+        self.connection.write(IAC + action + option)
+
+    def rfc2217_send_subnegotiation(self, option, value=b''):
+        """Subnegotiation of RFC 2217 parameters."""
+        value = value.replace(IAC, IAC_DOUBLED)
+        self.connection.write(IAC + SB + COM_PORT_OPTION + option + value + IAC + SE)
+
+    # - check modem lines, needs to be called periodically from user to
+    # establish polling
+
+    def check_modem_lines(self, force_notification=False):
+        """\
+        read control lines from serial port and compare the last value sent to remote.
+        send updates on changes.
+        """
+        modemstate = (
+            (self.serial.cts and MODEMSTATE_MASK_CTS) |
+            (self.serial.dsr and MODEMSTATE_MASK_DSR) |
+            (self.serial.ri and MODEMSTATE_MASK_RI) |
+            (self.serial.cd and MODEMSTATE_MASK_CD))
+        # check what has changed
+        deltas = modemstate ^ (self.last_modemstate or 0)  # when last is None -> 0
+        if deltas & MODEMSTATE_MASK_CTS:
+            modemstate |= MODEMSTATE_MASK_CTS_CHANGE
+        if deltas & MODEMSTATE_MASK_DSR:
+            modemstate |= MODEMSTATE_MASK_DSR_CHANGE
+        if deltas & MODEMSTATE_MASK_RI:
+            modemstate |= MODEMSTATE_MASK_RI_CHANGE
+        if deltas & MODEMSTATE_MASK_CD:
+            modemstate |= MODEMSTATE_MASK_CD_CHANGE
+        # if new state is different and the mask allows this change, send
+        # notification. suppress notifications when client is not rfc2217
+        if modemstate != self.last_modemstate or force_notification:
+            if (self._client_is_rfc2217 and (modemstate & self.modemstate_mask)) or force_notification:
+                self.rfc2217_send_subnegotiation(
+                    SERVER_NOTIFY_MODEMSTATE,
+                    to_bytes([modemstate & self.modemstate_mask]))
+                if self.logger:
+                    self.logger.info("NOTIFY_MODEMSTATE: {}".format(modemstate))
+            # save last state, but forget about deltas.
+            # otherwise it would also notify about changing deltas which is
+            # probably not very useful
+            self.last_modemstate = modemstate & 0xf0
+
+    # - outgoing data escaping
+
+    def escape(self, data):
+        """\
+        This generator function is for the user. All outgoing data has to be
+        properly escaped, so that no IAC character in the data stream messes up
+        the Telnet state machine in the server.
+
+        socket.sendall(escape(data))
+        """
+        for byte in iterbytes(data):
+            if byte == IAC:
+                yield IAC
+                yield IAC
+            else:
+                yield byte
+
+    # - incoming data filter
+
+    def filter(self, data):
+        """\
+        Handle a bunch of incoming bytes. This is a generator. It will yield
+        all characters not of interest for Telnet/RFC 2217.
+
+        The idea is that the reader thread pushes data from the socket through
+        this filter:
+
+        for byte in filter(socket.recv(1024)):
+            # do things like CR/LF conversion/whatever
+            # and write data to the serial port
+            serial.write(byte)
+
+        (socket error handling code left as exercise for the reader)
+        """
+        for byte in iterbytes(data):
+            if self.mode == M_NORMAL:
+                # interpret as command or as data
+                if byte == IAC:
+                    self.mode = M_IAC_SEEN
+                else:
+                    # store data in sub option buffer or pass it to our
+                    # consumer depending on state
+                    if self.suboption is not None:
+                        self.suboption += byte
+                    else:
+                        yield byte
+            elif self.mode == M_IAC_SEEN:
+                if byte == IAC:
+                    # interpret as command doubled -> insert character
+                    # itself
+                    if self.suboption is not None:
+                        self.suboption += byte
+                    else:
+                        yield byte
+                    self.mode = M_NORMAL
+                elif byte == SB:
+                    # sub option start
+                    self.suboption = bytearray()
+                    self.mode = M_NORMAL
+                elif byte == SE:
+                    # sub option end -> process it now
+                    self._telnet_process_subnegotiation(bytes(self.suboption))
+                    self.suboption = None
+                    self.mode = M_NORMAL
+                elif byte in (DO, DONT, WILL, WONT):
+                    # negotiation
+                    self.telnet_command = byte
+                    self.mode = M_NEGOTIATE
+                else:
+                    # other telnet commands
+                    self._telnet_process_command(byte)
+                    self.mode = M_NORMAL
+            elif self.mode == M_NEGOTIATE:  # DO, DONT, WILL, WONT was received, option now following
+                self._telnet_negotiate_option(self.telnet_command, byte)
+                self.mode = M_NORMAL
+
+    # - incoming telnet commands and options
+
+    def _telnet_process_command(self, command):
+        """Process commands other than DO, DONT, WILL, WONT."""
+        # Currently none. RFC2217 only uses negotiation and subnegotiation.
+        if self.logger:
+            self.logger.warning("ignoring Telnet command: {!r}".format(command))
+
+    def _telnet_negotiate_option(self, command, option):
+        """Process incoming DO, DONT, WILL, WONT."""
+        # check our registered telnet options and forward command to them
+        # they know themselves if they have to answer or not
+        known = False
+        for item in self._telnet_options:
+            # can have more than one match! as some options are duplicated for
+            # 'us' and 'them'
+            if item.option == option:
+                item.process_incoming(command)
+                known = True
+        if not known:
+            # handle unknown options
+            # only answer to positive requests and deny them
+            if command == WILL or command == DO:
+                self.telnet_send_option((DONT if command == WILL else WONT), option)
+                if self.logger:
+                    self.logger.warning("rejected Telnet option: {!r}".format(option))
+
+    def _telnet_process_subnegotiation(self, suboption):
+        """Process subnegotiation, the data between IAC SB and IAC SE."""
+        if suboption[0:1] == COM_PORT_OPTION:
+            if self.logger:
+                self.logger.debug('received COM_PORT_OPTION: {!r}'.format(suboption))
+            if suboption[1:2] == SET_BAUDRATE:
+                backup = self.serial.baudrate
+                try:
+                    (baudrate,) = struct.unpack(b"!I", suboption[2:6])
+                    if baudrate != 0:
+                        self.serial.baudrate = baudrate
+                except ValueError as e:
+                    if self.logger:
+                        self.logger.error("failed to set baud rate: {}".format(e))
+                    self.serial.baudrate = backup
+                else:
+                    if self.logger:
+                        self.logger.info("{} baud rate: {}".format('set' if baudrate else 'get', self.serial.baudrate))
+                self.rfc2217_send_subnegotiation(SERVER_SET_BAUDRATE, struct.pack(b"!I", self.serial.baudrate))
+            elif suboption[1:2] == SET_DATASIZE:
+                backup = self.serial.bytesize
+                try:
+                    (datasize,) = struct.unpack(b"!B", suboption[2:3])
+                    if datasize != 0:
+                        self.serial.bytesize = datasize
+                except ValueError as e:
+                    if self.logger:
+                        self.logger.error("failed to set data size: {}".format(e))
+                    self.serial.bytesize = backup
+                else:
+                    if self.logger:
+                        self.logger.info("{} data size: {}".format('set' if datasize else 'get', self.serial.bytesize))
+                self.rfc2217_send_subnegotiation(SERVER_SET_DATASIZE, struct.pack(b"!B", self.serial.bytesize))
+            elif suboption[1:2] == SET_PARITY:
+                backup = self.serial.parity
+                try:
+                    parity = struct.unpack(b"!B", suboption[2:3])[0]
+                    if parity != 0:
+                        self.serial.parity = RFC2217_REVERSE_PARITY_MAP[parity]
+                except ValueError as e:
+                    if self.logger:
+                        self.logger.error("failed to set parity: {}".format(e))
+                    self.serial.parity = backup
+                else:
+                    if self.logger:
+                        self.logger.info("{} parity: {}".format('set' if parity else 'get', self.serial.parity))
+                self.rfc2217_send_subnegotiation(
+                    SERVER_SET_PARITY,
+                    struct.pack(b"!B", RFC2217_PARITY_MAP[self.serial.parity]))
+            elif suboption[1:2] == SET_STOPSIZE:
+                backup = self.serial.stopbits
+                try:
+                    stopbits = struct.unpack(b"!B", suboption[2:3])[0]
+                    if stopbits != 0:
+                        self.serial.stopbits = RFC2217_REVERSE_STOPBIT_MAP[stopbits]
+                except ValueError as e:
+                    if self.logger:
+                        self.logger.error("failed to set stop bits: {}".format(e))
+                    self.serial.stopbits = backup
+                else:
+                    if self.logger:
+                        self.logger.info("{} stop bits: {}".format('set' if stopbits else 'get', self.serial.stopbits))
+                self.rfc2217_send_subnegotiation(
+                    SERVER_SET_STOPSIZE,
+                    struct.pack(b"!B", RFC2217_STOPBIT_MAP[self.serial.stopbits]))
+            elif suboption[1:2] == SET_CONTROL:
+                if suboption[2:3] == SET_CONTROL_REQ_FLOW_SETTING:
+                    if self.serial.xonxoff:
+                        self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_SW_FLOW_CONTROL)
+                    elif self.serial.rtscts:
+                        self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_HW_FLOW_CONTROL)
+                    else:
+                        self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_NO_FLOW_CONTROL)
+                elif suboption[2:3] == SET_CONTROL_USE_NO_FLOW_CONTROL:
+                    self.serial.xonxoff = False
+                    self.serial.rtscts = False
+                    if self.logger:
+                        self.logger.info("changed flow control to None")
+                    self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_NO_FLOW_CONTROL)
+                elif suboption[2:3] == SET_CONTROL_USE_SW_FLOW_CONTROL:
+                    self.serial.xonxoff = True
+                    if self.logger:
+                        self.logger.info("changed flow control to XON/XOFF")
+                    self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_SW_FLOW_CONTROL)
+                elif suboption[2:3] == SET_CONTROL_USE_HW_FLOW_CONTROL:
+                    self.serial.rtscts = True
+                    if self.logger:
+                        self.logger.info("changed flow control to RTS/CTS")
+                    self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_HW_FLOW_CONTROL)
+                elif suboption[2:3] == SET_CONTROL_REQ_BREAK_STATE:
+                    if self.logger:
+                        self.logger.warning("requested break state - not implemented")
+                    pass  # XXX needs cached value
+                elif suboption[2:3] == SET_CONTROL_BREAK_ON:
+                    self.serial.break_condition = True
+                    if self.logger:
+                        self.logger.info("changed BREAK to active")
+                    self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_BREAK_ON)
+                elif suboption[2:3] == SET_CONTROL_BREAK_OFF:
+                    self.serial.break_condition = False
+                    if self.logger:
+                        self.logger.info("changed BREAK to inactive")
+                    self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_BREAK_OFF)
+                elif suboption[2:3] == SET_CONTROL_REQ_DTR:
+                    if self.logger:
+                        self.logger.warning("requested DTR state - not implemented")
+                    pass  # XXX needs cached value
+                elif suboption[2:3] == SET_CONTROL_DTR_ON:
+                    self.serial.dtr = True
+                    if self.logger:
+                        self.logger.info("changed DTR to active")
+                    self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_DTR_ON)
+                elif suboption[2:3] == SET_CONTROL_DTR_OFF:
+                    self.serial.dtr = False
+                    if self.logger:
+                        self.logger.info("changed DTR to inactive")
+                    self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_DTR_OFF)
+                elif suboption[2:3] == SET_CONTROL_REQ_RTS:
+                    if self.logger:
+                        self.logger.warning("requested RTS state - not implemented")
+                    pass  # XXX needs cached value
+                    #~ self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_ON)
+                elif suboption[2:3] == SET_CONTROL_RTS_ON:
+                    self.serial.rts = True
+                    if self.logger:
+                        self.logger.info("changed RTS to active")
+                    self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_ON)
+                elif suboption[2:3] == SET_CONTROL_RTS_OFF:
+                    self.serial.rts = False
+                    if self.logger:
+                        self.logger.info("changed RTS to inactive")
+                    self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_OFF)
+                #~ elif suboption[2:3] == SET_CONTROL_REQ_FLOW_SETTING_IN:
+                #~ elif suboption[2:3] == SET_CONTROL_USE_NO_FLOW_CONTROL_IN:
+                #~ elif suboption[2:3] == SET_CONTROL_USE_SW_FLOW_CONTOL_IN:
+                #~ elif suboption[2:3] == SET_CONTROL_USE_HW_FLOW_CONTOL_IN:
+                #~ elif suboption[2:3] == SET_CONTROL_USE_DCD_FLOW_CONTROL:
+                #~ elif suboption[2:3] == SET_CONTROL_USE_DTR_FLOW_CONTROL:
+                #~ elif suboption[2:3] == SET_CONTROL_USE_DSR_FLOW_CONTROL:
+            elif suboption[1:2] == NOTIFY_LINESTATE:
+                # client polls for current state
+                self.rfc2217_send_subnegotiation(
+                    SERVER_NOTIFY_LINESTATE,
+                    to_bytes([0]))   # sorry, nothing like that implemented
+            elif suboption[1:2] == NOTIFY_MODEMSTATE:
+                if self.logger:
+                    self.logger.info("request for modem state")
+                # client polls for current state
+                self.check_modem_lines(force_notification=True)
+            elif suboption[1:2] == FLOWCONTROL_SUSPEND:
+                if self.logger:
+                    self.logger.info("suspend")
+                self._remote_suspend_flow = True
+            elif suboption[1:2] == FLOWCONTROL_RESUME:
+                if self.logger:
+                    self.logger.info("resume")
+                self._remote_suspend_flow = False
+            elif suboption[1:2] == SET_LINESTATE_MASK:
+                self.linstate_mask = ord(suboption[2:3])  # ensure it is a number
+                if self.logger:
+                    self.logger.info("line state mask: 0x{:02x}".format(self.linstate_mask))
+            elif suboption[1:2] == SET_MODEMSTATE_MASK:
+                self.modemstate_mask = ord(suboption[2:3])  # ensure it is a number
+                if self.logger:
+                    self.logger.info("modem state mask: 0x{:02x}".format(self.modemstate_mask))
+            elif suboption[1:2] == PURGE_DATA:
+                if suboption[2:3] == PURGE_RECEIVE_BUFFER:
+                    self.serial.reset_input_buffer()
+                    if self.logger:
+                        self.logger.info("purge in")
+                    self.rfc2217_send_subnegotiation(SERVER_PURGE_DATA, PURGE_RECEIVE_BUFFER)
+                elif suboption[2:3] == PURGE_TRANSMIT_BUFFER:
+                    self.serial.reset_output_buffer()
+                    if self.logger:
+                        self.logger.info("purge out")
+                    self.rfc2217_send_subnegotiation(SERVER_PURGE_DATA, PURGE_TRANSMIT_BUFFER)
+                elif suboption[2:3] == PURGE_BOTH_BUFFERS:
+                    self.serial.reset_input_buffer()
+                    self.serial.reset_output_buffer()
+                    if self.logger:
+                        self.logger.info("purge both")
+                    self.rfc2217_send_subnegotiation(SERVER_PURGE_DATA, PURGE_BOTH_BUFFERS)
+                else:
+                    if self.logger:
+                        self.logger.error("undefined PURGE_DATA: {!r}".format(list(suboption[2:])))
+            else:
+                if self.logger:
+                    self.logger.error("undefined COM_PORT_OPTION: {!r}".format(list(suboption[1:])))
+        else:
+            if self.logger:
+                self.logger.warning("unknown subnegotiation: {!r}".format(suboption))
+
+
+# simple client test
+if __name__ == '__main__':
+    import sys
+    s = Serial('rfc2217://localhost:7000', 115200)
+    sys.stdout.write('{}\n'.format(s))
+
+    sys.stdout.write("write...\n")
+    s.write(b"hello\n")
+    s.flush()
+    sys.stdout.write("read: {}\n".format(s.read(5)))
+    s.close()
diff --git a/src/devtools/datool/serial/rs485.py b/src/devtools/datool/serial/rs485.py
new file mode 100755
index 0000000..d7aff6f
--- /dev/null
+++ b/src/devtools/datool/serial/rs485.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+
+# RS485 support
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+"""\
+The settings for RS485 are stored in a dedicated object that can be applied to
+serial ports (where supported).
+NOTE: Some implementations may only support a subset of the settings.
+"""
+
+from __future__ import absolute_import
+
+import time
+import serial
+
+
+class RS485Settings(object):
+    def __init__(
+            self,
+            rts_level_for_tx=True,
+            rts_level_for_rx=False,
+            loopback=False,
+            delay_before_tx=None,
+            delay_before_rx=None):
+        self.rts_level_for_tx = rts_level_for_tx
+        self.rts_level_for_rx = rts_level_for_rx
+        self.loopback = loopback
+        self.delay_before_tx = delay_before_tx
+        self.delay_before_rx = delay_before_rx
+
+
+class RS485(serial.Serial):
+    """\
+    A subclass that replaces the write method with one that toggles RTS
+    according to the RS485 settings.
+
+    NOTE: This may work unreliably on some serial ports (control signals not
+          synchronized or delayed compared to data). Using delays may be
+          unreliable (varying times, larger than expected) as the OS may not
+          support very fine grained delays (no smaller than in the order of
+          tens of milliseconds).
+
+    NOTE: Some implementations support this natively. Better performance
+          can be expected when the native version is used.
+
+    NOTE: The loopback property is ignored by this implementation. The actual
+          behavior depends on the used hardware.
+
+    Usage:
+
+        ser = RS485(...)
+        ser.rs485_mode = RS485Settings(...)
+        ser.write(b'hello')
+    """
+
+    def __init__(self, *args, **kwargs):
+        super(RS485, self).__init__(*args, **kwargs)
+        self._alternate_rs485_settings = None
+
+    def write(self, b):
+        """Write to port, controlling RTS before and after transmitting."""
+        if self._alternate_rs485_settings is not None:
+            # apply level for TX and optional delay
+            self.setRTS(self._alternate_rs485_settings.rts_level_for_tx)
+            if self._alternate_rs485_settings.delay_before_tx is not None:
+                time.sleep(self._alternate_rs485_settings.delay_before_tx)
+            # write and wait for data to be written
+            super(RS485, self).write(b)
+            super(RS485, self).flush()
+            # optional delay and apply level for RX
+            if self._alternate_rs485_settings.delay_before_rx is not None:
+                time.sleep(self._alternate_rs485_settings.delay_before_rx)
+            self.setRTS(self._alternate_rs485_settings.rts_level_for_rx)
+        else:
+            super(RS485, self).write(b)
+
+    # redirect where the property stores the settings so that underlying Serial
+    # instance does not see them
+    @property
+    def rs485_mode(self):
+        """\
+        Enable RS485 mode and apply new settings, set to None to disable.
+        See serial.rs485.RS485Settings for more info about the value.
+        """
+        return self._alternate_rs485_settings
+
+    @rs485_mode.setter
+    def rs485_mode(self, rs485_settings):
+        self._alternate_rs485_settings = rs485_settings
diff --git a/src/devtools/datool/serial/serialcli.py b/src/devtools/datool/serial/serialcli.py
new file mode 100755
index 0000000..4614736
--- /dev/null
+++ b/src/devtools/datool/serial/serialcli.py
@@ -0,0 +1,253 @@
+#! python
+#
+# Backend for .NET/Mono (IronPython), .NET >= 2
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2008-2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+from __future__ import absolute_import
+
+import System
+import System.IO.Ports
+from serial.serialutil import *
+
+# must invoke function with byte array, make a helper to convert strings
+# to byte arrays
+sab = System.Array[System.Byte]
+
+
+def as_byte_array(string):
+    return sab([ord(x) for x in string])  # XXX will require adaption when run with a 3.x compatible IronPython
+
+
+class Serial(SerialBase):
+    """Serial port implementation for .NET/Mono."""
+
+    BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+                 9600, 19200, 38400, 57600, 115200)
+
+    def open(self):
+        """\
+        Open port with current settings. This may throw a SerialException
+        if the port cannot be opened.
+        """
+        if self._port is None:
+            raise SerialException("Port must be configured before it can be used.")
+        if self.is_open:
+            raise SerialException("Port is already open.")
+        try:
+            self._port_handle = System.IO.Ports.SerialPort(self.portstr)
+        except Exception as msg:
+            self._port_handle = None
+            raise SerialException("could not open port %s: %s" % (self.portstr, msg))
+
+        # if RTS and/or DTR are not set before open, they default to True
+        if self._rts_state is None:
+            self._rts_state = True
+        if self._dtr_state is None:
+            self._dtr_state = True
+
+        self._reconfigure_port()
+        self._port_handle.Open()
+        self.is_open = True
+        if not self._dsrdtr:
+            self._update_dtr_state()
+        if not self._rtscts:
+            self._update_rts_state()
+        self.reset_input_buffer()
+
+    def _reconfigure_port(self):
+        """Set communication parameters on opened port."""
+        if not self._port_handle:
+            raise SerialException("Can only operate on a valid port handle")
+
+        #~ self._port_handle.ReceivedBytesThreshold = 1
+
+        if self._timeout is None:
+            self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
+        else:
+            self._port_handle.ReadTimeout = int(self._timeout * 1000)
+
+        # if self._timeout != 0 and self._interCharTimeout is not None:
+            # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
+
+        if self._write_timeout is None:
+            self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
+        else:
+            self._port_handle.WriteTimeout = int(self._write_timeout * 1000)
+
+        # Setup the connection info.
+        try:
+            self._port_handle.BaudRate = self._baudrate
+        except IOError as e:
+            # catch errors from illegal baudrate settings
+            raise ValueError(str(e))
+
+        if self._bytesize == FIVEBITS:
+            self._port_handle.DataBits = 5
+        elif self._bytesize == SIXBITS:
+            self._port_handle.DataBits = 6
+        elif self._bytesize == SEVENBITS:
+            self._port_handle.DataBits = 7
+        elif self._bytesize == EIGHTBITS:
+            self._port_handle.DataBits = 8
+        else:
+            raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
+
+        if self._parity == PARITY_NONE:
+            self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None')  # reserved keyword in Py3k
+        elif self._parity == PARITY_EVEN:
+            self._port_handle.Parity = System.IO.Ports.Parity.Even
+        elif self._parity == PARITY_ODD:
+            self._port_handle.Parity = System.IO.Ports.Parity.Odd
+        elif self._parity == PARITY_MARK:
+            self._port_handle.Parity = System.IO.Ports.Parity.Mark
+        elif self._parity == PARITY_SPACE:
+            self._port_handle.Parity = System.IO.Ports.Parity.Space
+        else:
+            raise ValueError("Unsupported parity mode: %r" % self._parity)
+
+        if self._stopbits == STOPBITS_ONE:
+            self._port_handle.StopBits = System.IO.Ports.StopBits.One
+        elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
+            self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive
+        elif self._stopbits == STOPBITS_TWO:
+            self._port_handle.StopBits = System.IO.Ports.StopBits.Two
+        else:
+            raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
+
+        if self._rtscts and self._xonxoff:
+            self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff
+        elif self._rtscts:
+            self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend
+        elif self._xonxoff:
+            self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff
+        else:
+            self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None')   # reserved keyword in Py3k
+
+    #~ def __del__(self):
+        #~ self.close()
+
+    def close(self):
+        """Close port"""
+        if self.is_open:
+            if self._port_handle:
+                try:
+                    self._port_handle.Close()
+                except System.IO.Ports.InvalidOperationException:
+                    # ignore errors. can happen for unplugged USB serial devices
+                    pass
+                self._port_handle = None
+            self.is_open = False
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    @property
+    def in_waiting(self):
+        """Return the number of characters currently in the input buffer."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        return self._port_handle.BytesToRead
+
+    def read(self, size=1):
+        """\
+        Read size bytes from the serial port. If a timeout is set it may
+        return less characters as requested. With no timeout it will block
+        until the requested number of bytes is read.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        # must use single byte reads as this is the only way to read
+        # without applying encodings
+        data = bytearray()
+        while size:
+            try:
+                data.append(self._port_handle.ReadByte())
+            except System.TimeoutException:
+                break
+            else:
+                size -= 1
+        return bytes(data)
+
+    def write(self, data):
+        """Output the given string over the serial port."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        #~ if not isinstance(data, (bytes, bytearray)):
+            #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
+        try:
+            # must call overloaded method with byte array argument
+            # as this is the only one not applying encodings
+            self._port_handle.Write(as_byte_array(data), 0, len(data))
+        except System.TimeoutException:
+            raise SerialTimeoutException('Write timeout')
+        return len(data)
+
+    def reset_input_buffer(self):
+        """Clear input buffer, discarding all that is in the buffer."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        self._port_handle.DiscardInBuffer()
+
+    def reset_output_buffer(self):
+        """\
+        Clear output buffer, aborting the current output and
+        discarding all that is in the buffer.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        self._port_handle.DiscardOutBuffer()
+
+    def _update_break_state(self):
+        """
+        Set break: Controls TXD. When active, to transmitting is possible.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        self._port_handle.BreakState = bool(self._break_state)
+
+    def _update_rts_state(self):
+        """Set terminal status line: Request To Send"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        self._port_handle.RtsEnable = bool(self._rts_state)
+
+    def _update_dtr_state(self):
+        """Set terminal status line: Data Terminal Ready"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        self._port_handle.DtrEnable = bool(self._dtr_state)
+
+    @property
+    def cts(self):
+        """Read terminal status line: Clear To Send"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        return self._port_handle.CtsHolding
+
+    @property
+    def dsr(self):
+        """Read terminal status line: Data Set Ready"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        return self._port_handle.DsrHolding
+
+    @property
+    def ri(self):
+        """Read terminal status line: Ring Indicator"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        #~ return self._port_handle.XXX
+        return False  # XXX an error would be better
+
+    @property
+    def cd(self):
+        """Read terminal status line: Carrier Detect"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        return self._port_handle.CDHolding
+
+    # - - platform specific - - - -
+    # none
diff --git a/src/devtools/datool/serial/serialjava.py b/src/devtools/datool/serial/serialjava.py
new file mode 100755
index 0000000..0789a78
--- /dev/null
+++ b/src/devtools/datool/serial/serialjava.py
@@ -0,0 +1,251 @@
+#!jython
+#
+# Backend Jython with JavaComm
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2002-2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+from __future__ import absolute_import
+
+from serial.serialutil import *
+
+
+def my_import(name):
+    mod = __import__(name)
+    components = name.split('.')
+    for comp in components[1:]:
+        mod = getattr(mod, comp)
+    return mod
+
+
+def detect_java_comm(names):
+    """try given list of modules and return that imports"""
+    for name in names:
+        try:
+            mod = my_import(name)
+            mod.SerialPort
+            return mod
+        except (ImportError, AttributeError):
+            pass
+    raise ImportError("No Java Communications API implementation found")
+
+
+# Java Communications API implementations
+# http://mho.republika.pl/java/comm/
+
+comm = detect_java_comm([
+    'javax.comm',  # Sun/IBM
+    'gnu.io',      # RXTX
+])
+
+
+def device(portnumber):
+    """Turn a port number into a device name"""
+    enum = comm.CommPortIdentifier.getPortIdentifiers()
+    ports = []
+    while enum.hasMoreElements():
+        el = enum.nextElement()
+        if el.getPortType() == comm.CommPortIdentifier.PORT_SERIAL:
+            ports.append(el)
+    return ports[portnumber].getName()
+
+
+class Serial(SerialBase):
+    """\
+    Serial port class, implemented with Java Communications API and
+    thus usable with jython and the appropriate java extension.
+    """
+
+    def open(self):
+        """\
+        Open port with current settings. This may throw a SerialException
+        if the port cannot be opened.
+        """
+        if self._port is None:
+            raise SerialException("Port must be configured before it can be used.")
+        if self.is_open:
+            raise SerialException("Port is already open.")
+        if type(self._port) == type(''):      # strings are taken directly
+            portId = comm.CommPortIdentifier.getPortIdentifier(self._port)
+        else:
+            portId = comm.CommPortIdentifier.getPortIdentifier(device(self._port))     # numbers are transformed to a comport id obj
+        try:
+            self.sPort = portId.open("python serial module", 10)
+        except Exception as msg:
+            self.sPort = None
+            raise SerialException("Could not open port: %s" % msg)
+        self._reconfigurePort()
+        self._instream = self.sPort.getInputStream()
+        self._outstream = self.sPort.getOutputStream()
+        self.is_open = True
+
+    def _reconfigurePort(self):
+        """Set communication parameters on opened port."""
+        if not self.sPort:
+            raise SerialException("Can only operate on a valid port handle")
+
+        self.sPort.enableReceiveTimeout(30)
+        if self._bytesize == FIVEBITS:
+            jdatabits = comm.SerialPort.DATABITS_5
+        elif self._bytesize == SIXBITS:
+            jdatabits = comm.SerialPort.DATABITS_6
+        elif self._bytesize == SEVENBITS:
+            jdatabits = comm.SerialPort.DATABITS_7
+        elif self._bytesize == EIGHTBITS:
+            jdatabits = comm.SerialPort.DATABITS_8
+        else:
+            raise ValueError("unsupported bytesize: %r" % self._bytesize)
+
+        if self._stopbits == STOPBITS_ONE:
+            jstopbits = comm.SerialPort.STOPBITS_1
+        elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
+            jstopbits = comm.SerialPort.STOPBITS_1_5
+        elif self._stopbits == STOPBITS_TWO:
+            jstopbits = comm.SerialPort.STOPBITS_2
+        else:
+            raise ValueError("unsupported number of stopbits: %r" % self._stopbits)
+
+        if self._parity == PARITY_NONE:
+            jparity = comm.SerialPort.PARITY_NONE
+        elif self._parity == PARITY_EVEN:
+            jparity = comm.SerialPort.PARITY_EVEN
+        elif self._parity == PARITY_ODD:
+            jparity = comm.SerialPort.PARITY_ODD
+        elif self._parity == PARITY_MARK:
+            jparity = comm.SerialPort.PARITY_MARK
+        elif self._parity == PARITY_SPACE:
+            jparity = comm.SerialPort.PARITY_SPACE
+        else:
+            raise ValueError("unsupported parity type: %r" % self._parity)
+
+        jflowin = jflowout = 0
+        if self._rtscts:
+            jflowin |= comm.SerialPort.FLOWCONTROL_RTSCTS_IN
+            jflowout |= comm.SerialPort.FLOWCONTROL_RTSCTS_OUT
+        if self._xonxoff:
+            jflowin |= comm.SerialPort.FLOWCONTROL_XONXOFF_IN
+            jflowout |= comm.SerialPort.FLOWCONTROL_XONXOFF_OUT
+
+        self.sPort.setSerialPortParams(self._baudrate, jdatabits, jstopbits, jparity)
+        self.sPort.setFlowControlMode(jflowin | jflowout)
+
+        if self._timeout >= 0:
+            self.sPort.enableReceiveTimeout(int(self._timeout*1000))
+        else:
+            self.sPort.disableReceiveTimeout()
+
+    def close(self):
+        """Close port"""
+        if self.is_open:
+            if self.sPort:
+                self._instream.close()
+                self._outstream.close()
+                self.sPort.close()
+                self.sPort = None
+            self.is_open = False
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    @property
+    def in_waiting(self):
+        """Return the number of characters currently in the input buffer."""
+        if not self.sPort:
+            raise PortNotOpenError()
+        return self._instream.available()
+
+    def read(self, size=1):
+        """\
+        Read size bytes from the serial port. If a timeout is set it may
+        return less characters as requested. With no timeout it will block
+        until the requested number of bytes is read.
+        """
+        if not self.sPort:
+            raise PortNotOpenError()
+        read = bytearray()
+        if size > 0:
+            while len(read) < size:
+                x = self._instream.read()
+                if x == -1:
+                    if self.timeout >= 0:
+                        break
+                else:
+                    read.append(x)
+        return bytes(read)
+
+    def write(self, data):
+        """Output the given string over the serial port."""
+        if not self.sPort:
+            raise PortNotOpenError()
+        if not isinstance(data, (bytes, bytearray)):
+            raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
+        self._outstream.write(data)
+        return len(data)
+
+    def reset_input_buffer(self):
+        """Clear input buffer, discarding all that is in the buffer."""
+        if not self.sPort:
+            raise PortNotOpenError()
+        self._instream.skip(self._instream.available())
+
+    def reset_output_buffer(self):
+        """\
+        Clear output buffer, aborting the current output and
+        discarding all that is in the buffer.
+        """
+        if not self.sPort:
+            raise PortNotOpenError()
+        self._outstream.flush()
+
+    def send_break(self, duration=0.25):
+        """Send break condition. Timed, returns to idle state after given duration."""
+        if not self.sPort:
+            raise PortNotOpenError()
+        self.sPort.sendBreak(duration*1000.0)
+
+    def _update_break_state(self):
+        """Set break: Controls TXD. When active, to transmitting is possible."""
+        if self.fd is None:
+            raise PortNotOpenError()
+        raise SerialException("The _update_break_state function is not implemented in java.")
+
+    def _update_rts_state(self):
+        """Set terminal status line: Request To Send"""
+        if not self.sPort:
+            raise PortNotOpenError()
+        self.sPort.setRTS(self._rts_state)
+
+    def _update_dtr_state(self):
+        """Set terminal status line: Data Terminal Ready"""
+        if not self.sPort:
+            raise PortNotOpenError()
+        self.sPort.setDTR(self._dtr_state)
+
+    @property
+    def cts(self):
+        """Read terminal status line: Clear To Send"""
+        if not self.sPort:
+            raise PortNotOpenError()
+        self.sPort.isCTS()
+
+    @property
+    def dsr(self):
+        """Read terminal status line: Data Set Ready"""
+        if not self.sPort:
+            raise PortNotOpenError()
+        self.sPort.isDSR()
+
+    @property
+    def ri(self):
+        """Read terminal status line: Ring Indicator"""
+        if not self.sPort:
+            raise PortNotOpenError()
+        self.sPort.isRI()
+
+    @property
+    def cd(self):
+        """Read terminal status line: Carrier Detect"""
+        if not self.sPort:
+            raise PortNotOpenError()
+        self.sPort.isCD()
diff --git a/src/devtools/datool/serial/serialposix.py b/src/devtools/datool/serial/serialposix.py
new file mode 100755
index 0000000..7aceb76
--- /dev/null
+++ b/src/devtools/datool/serial/serialposix.py
@@ -0,0 +1,900 @@
+#!/usr/bin/env python
+#
+# backend for serial IO for POSIX compatible systems, like Linux, OSX
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2001-2020 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+#
+# parts based on code from Grant B. Edwards  <grante@visi.com>:
+#  ftp://ftp.visi.com/users/grante/python/PosixSerial.py
+#
+# references: http://www.easysw.com/~mike/serial/serial.html
+
+# Collection of port names (was previously used by number_to_device which was
+# removed.
+# - Linux                   /dev/ttyS%d (confirmed)
+# - cygwin/win32            /dev/com%d (confirmed)
+# - openbsd (OpenBSD)       /dev/cua%02d
+# - bsd*, freebsd*          /dev/cuad%d
+# - darwin (OS X)           /dev/cuad%d
+# - netbsd                  /dev/dty%02d (NetBSD 1.6 testing by Erk)
+# - irix (IRIX)             /dev/ttyf%d (partially tested) names depending on flow control
+# - hp (HP-UX)              /dev/tty%dp0 (not tested)
+# - sunos (Solaris/SunOS)   /dev/tty%c (letters, 'a'..'z') (confirmed)
+# - aix (AIX)               /dev/tty%d
+
+
+from __future__ import absolute_import
+
+# pylint: disable=abstract-method
+import errno
+import fcntl
+import os
+import select
+import struct
+import sys
+import termios
+
+import serial
+from serial.serialutil import SerialBase, SerialException, to_bytes, \
+    PortNotOpenError, SerialTimeoutException, Timeout
+
+
+class PlatformSpecificBase(object):
+    BAUDRATE_CONSTANTS = {}
+
+    def _set_special_baudrate(self, baudrate):
+        raise NotImplementedError('non-standard baudrates are not supported on this platform')
+
+    def _set_rs485_mode(self, rs485_settings):
+        raise NotImplementedError('RS485 not supported on this platform')
+
+    def set_low_latency_mode(self, low_latency_settings):
+        raise NotImplementedError('Low latency not supported on this platform')
+
+    def _update_break_state(self):
+        """\
+        Set break: Controls TXD. When active, no transmitting is possible.
+        """
+        if self._break_state:
+            fcntl.ioctl(self.fd, TIOCSBRK)
+        else:
+            fcntl.ioctl(self.fd, TIOCCBRK)
+    
+
+# some systems support an extra flag to enable the two in POSIX unsupported
+# paritiy settings for MARK and SPACE
+CMSPAR = 0  # default, for unsupported platforms, override below
+
+# try to detect the OS so that a device can be selected...
+# this code block should supply a device() and set_special_baudrate() function
+# for the platform
+plat = sys.platform.lower()
+
+if plat[:5] == 'linux':    # Linux (confirmed)  # noqa
+    import array
+
+    # extra termios flags
+    CMSPAR = 0o10000000000  # Use "stick" (mark/space) parity
+
+    # baudrate ioctls
+    TCGETS2 = 0x802C542A
+    TCSETS2 = 0x402C542B
+    BOTHER = 0o010000
+
+    # RS485 ioctls
+    TIOCGRS485 = 0x542E
+    TIOCSRS485 = 0x542F
+    SER_RS485_ENABLED = 0b00000001
+    SER_RS485_RTS_ON_SEND = 0b00000010
+    SER_RS485_RTS_AFTER_SEND = 0b00000100
+    SER_RS485_RX_DURING_TX = 0b00010000
+
+    class PlatformSpecific(PlatformSpecificBase):
+        BAUDRATE_CONSTANTS = {
+            0:       0o000000,  # hang up
+            50:      0o000001,
+            75:      0o000002,
+            110:     0o000003,
+            134:     0o000004,
+            150:     0o000005,
+            200:     0o000006,
+            300:     0o000007,
+            600:     0o000010,
+            1200:    0o000011,
+            1800:    0o000012,
+            2400:    0o000013,
+            4800:    0o000014,
+            9600:    0o000015,
+            19200:   0o000016,
+            38400:   0o000017,
+            57600:   0o010001,
+            115200:  0o010002,
+            230400:  0o010003,
+            460800:  0o010004,
+            500000:  0o010005,
+            576000:  0o010006,
+            921600:  0o010007,
+            1000000: 0o010010,
+            1152000: 0o010011,
+            1500000: 0o010012,
+            2000000: 0o010013,
+            2500000: 0o010014,
+            3000000: 0o010015,
+            3500000: 0o010016,
+            4000000: 0o010017
+        }
+
+        def set_low_latency_mode(self, low_latency_settings):
+            buf = array.array('i', [0] * 32)
+
+            try:
+                # get serial_struct
+                fcntl.ioctl(self.fd, termios.TIOCGSERIAL, buf)
+
+                # set or unset ASYNC_LOW_LATENCY flag
+                if low_latency_settings:
+                    buf[4] |= 0x2000
+                else:
+                    buf[4] &= ~0x2000
+
+                # set serial_struct
+                fcntl.ioctl(self.fd, termios.TIOCSSERIAL, buf)
+            except IOError as e:
+                raise ValueError('Failed to update ASYNC_LOW_LATENCY flag to {}: {}'.format(low_latency_settings, e))
+
+        def _set_special_baudrate(self, baudrate):
+            # right size is 44 on x86_64, allow for some growth
+            buf = array.array('i', [0] * 64)
+            try:
+                # get serial_struct
+                fcntl.ioctl(self.fd, TCGETS2, buf)
+                # set custom speed
+                buf[2] &= ~termios.CBAUD
+                buf[2] |= BOTHER
+                buf[9] = buf[10] = baudrate
+
+                # set serial_struct
+                fcntl.ioctl(self.fd, TCSETS2, buf)
+            except IOError as e:
+                raise ValueError('Failed to set custom baud rate ({}): {}'.format(baudrate, e))
+
+        def _set_rs485_mode(self, rs485_settings):
+            buf = array.array('i', [0] * 8)  # flags, delaytx, delayrx, padding
+            try:
+                fcntl.ioctl(self.fd, TIOCGRS485, buf)
+                buf[0] |= SER_RS485_ENABLED
+                if rs485_settings is not None:
+                    if rs485_settings.loopback:
+                        buf[0] |= SER_RS485_RX_DURING_TX
+                    else:
+                        buf[0] &= ~SER_RS485_RX_DURING_TX
+                    if rs485_settings.rts_level_for_tx:
+                        buf[0] |= SER_RS485_RTS_ON_SEND
+                    else:
+                        buf[0] &= ~SER_RS485_RTS_ON_SEND
+                    if rs485_settings.rts_level_for_rx:
+                        buf[0] |= SER_RS485_RTS_AFTER_SEND
+                    else:
+                        buf[0] &= ~SER_RS485_RTS_AFTER_SEND
+                    if rs485_settings.delay_before_tx is not None:
+                        buf[1] = int(rs485_settings.delay_before_tx * 1000)
+                    if rs485_settings.delay_before_rx is not None:
+                        buf[2] = int(rs485_settings.delay_before_rx * 1000)
+                else:
+                    buf[0] = 0  # clear SER_RS485_ENABLED
+                fcntl.ioctl(self.fd, TIOCSRS485, buf)
+            except IOError as e:
+                raise ValueError('Failed to set RS485 mode: {}'.format(e))
+
+
+elif plat == 'cygwin':       # cygwin/win32 (confirmed)
+
+    class PlatformSpecific(PlatformSpecificBase):
+        BAUDRATE_CONSTANTS = {
+            128000: 0x01003,
+            256000: 0x01005,
+            500000: 0x01007,
+            576000: 0x01008,
+            921600: 0x01009,
+            1000000: 0x0100a,
+            1152000: 0x0100b,
+            1500000: 0x0100c,
+            2000000: 0x0100d,
+            2500000: 0x0100e,
+            3000000: 0x0100f
+        }
+
+
+elif plat[:6] == 'darwin':   # OS X
+    import array
+    IOSSIOSPEED = 0x80045402  # _IOW('T', 2, speed_t)
+
+    class PlatformSpecific(PlatformSpecificBase):
+        osx_version = os.uname()[2].split('.')
+        TIOCSBRK = 0x2000747B # _IO('t', 123)
+        TIOCCBRK = 0x2000747A # _IO('t', 122)
+
+        # Tiger or above can support arbitrary serial speeds
+        if int(osx_version[0]) >= 8:
+            def _set_special_baudrate(self, baudrate):
+                # use IOKit-specific call to set up high speeds
+                buf = array.array('i', [baudrate])
+                fcntl.ioctl(self.fd, IOSSIOSPEED, buf, 1)
+
+        def _update_break_state(self):
+            """\
+            Set break: Controls TXD. When active, no transmitting is possible.
+            """
+            if self._break_state:
+                fcntl.ioctl(self.fd, PlatformSpecific.TIOCSBRK)
+            else:
+                fcntl.ioctl(self.fd, PlatformSpecific.TIOCCBRK)
+
+elif plat[:3] == 'bsd' or \
+     plat[:7] == 'freebsd' or \
+     plat[:6] == 'netbsd' or \
+     plat[:7] == 'openbsd':
+
+    class ReturnBaudrate(object):
+        def __getitem__(self, key):
+            return key
+
+    class PlatformSpecific(PlatformSpecificBase):
+        # Only tested on FreeBSD:
+        # The baud rate may be passed in as
+        # a literal value.
+        BAUDRATE_CONSTANTS = ReturnBaudrate()
+
+        TIOCSBRK = 0x2000747B # _IO('t', 123)
+        TIOCCBRK = 0x2000747A # _IO('t', 122)
+
+        
+        def _update_break_state(self):
+            """\
+            Set break: Controls TXD. When active, no transmitting is possible.
+            """
+            if self._break_state:
+                fcntl.ioctl(self.fd, PlatformSpecific.TIOCSBRK)
+            else:
+                fcntl.ioctl(self.fd, PlatformSpecific.TIOCCBRK)
+
+else:
+    class PlatformSpecific(PlatformSpecificBase):
+        pass
+
+
+# load some constants for later use.
+# try to use values from termios, use defaults from linux otherwise
+TIOCMGET = getattr(termios, 'TIOCMGET', 0x5415)
+TIOCMBIS = getattr(termios, 'TIOCMBIS', 0x5416)
+TIOCMBIC = getattr(termios, 'TIOCMBIC', 0x5417)
+TIOCMSET = getattr(termios, 'TIOCMSET', 0x5418)
+
+# TIOCM_LE = getattr(termios, 'TIOCM_LE', 0x001)
+TIOCM_DTR = getattr(termios, 'TIOCM_DTR', 0x002)
+TIOCM_RTS = getattr(termios, 'TIOCM_RTS', 0x004)
+# TIOCM_ST = getattr(termios, 'TIOCM_ST', 0x008)
+# TIOCM_SR = getattr(termios, 'TIOCM_SR', 0x010)
+
+TIOCM_CTS = getattr(termios, 'TIOCM_CTS', 0x020)
+TIOCM_CAR = getattr(termios, 'TIOCM_CAR', 0x040)
+TIOCM_RNG = getattr(termios, 'TIOCM_RNG', 0x080)
+TIOCM_DSR = getattr(termios, 'TIOCM_DSR', 0x100)
+TIOCM_CD = getattr(termios, 'TIOCM_CD', TIOCM_CAR)
+TIOCM_RI = getattr(termios, 'TIOCM_RI', TIOCM_RNG)
+# TIOCM_OUT1 = getattr(termios, 'TIOCM_OUT1', 0x2000)
+# TIOCM_OUT2 = getattr(termios, 'TIOCM_OUT2', 0x4000)
+if hasattr(termios, 'TIOCINQ'):
+    TIOCINQ = termios.TIOCINQ
+else:
+    TIOCINQ = getattr(termios, 'FIONREAD', 0x541B)
+TIOCOUTQ = getattr(termios, 'TIOCOUTQ', 0x5411)
+
+TIOCM_zero_str = struct.pack('I', 0)
+TIOCM_RTS_str = struct.pack('I', TIOCM_RTS)
+TIOCM_DTR_str = struct.pack('I', TIOCM_DTR)
+
+TIOCSBRK = getattr(termios, 'TIOCSBRK', 0x5427)
+TIOCCBRK = getattr(termios, 'TIOCCBRK', 0x5428)
+
+
+class Serial(SerialBase, PlatformSpecific):
+    """\
+    Serial port class POSIX implementation. Serial port configuration is
+    done with termios and fcntl. Runs on Linux and many other Un*x like
+    systems.
+    """
+
+    def open(self):
+        """\
+        Open port with current settings. This may throw a SerialException
+        if the port cannot be opened."""
+        if self._port is None:
+            raise SerialException("Port must be configured before it can be used.")
+        if self.is_open:
+            raise SerialException("Port is already open.")
+        self.fd = None
+        # open
+        try:
+            self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
+        except OSError as msg:
+            self.fd = None
+            raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
+        #~ fcntl.fcntl(self.fd, fcntl.F_SETFL, 0)  # set blocking
+
+        self.pipe_abort_read_r, self.pipe_abort_read_w = None, None
+        self.pipe_abort_write_r, self.pipe_abort_write_w = None, None
+
+        try:
+            self._reconfigure_port(force_update=True)
+
+            try:
+                if not self._dsrdtr:
+                    self._update_dtr_state()
+                if not self._rtscts:
+                    self._update_rts_state()
+            except IOError as e:
+                # ignore Invalid argument and Inappropriate ioctl
+                if e.errno not in (errno.EINVAL, errno.ENOTTY):
+                    raise
+
+            self._reset_input_buffer()
+
+            self.pipe_abort_read_r, self.pipe_abort_read_w = os.pipe()
+            self.pipe_abort_write_r, self.pipe_abort_write_w = os.pipe()
+            fcntl.fcntl(self.pipe_abort_read_r, fcntl.F_SETFL, os.O_NONBLOCK)
+            fcntl.fcntl(self.pipe_abort_write_r, fcntl.F_SETFL, os.O_NONBLOCK)
+        except BaseException:
+            try:
+                os.close(self.fd)
+            except Exception:
+                # ignore any exception when closing the port
+                # also to keep original exception that happened when setting up
+                pass
+            self.fd = None
+
+            if self.pipe_abort_read_w is not None:
+                os.close(self.pipe_abort_read_w)
+                self.pipe_abort_read_w = None
+            if self.pipe_abort_read_r is not None:
+                os.close(self.pipe_abort_read_r)
+                self.pipe_abort_read_r = None
+            if self.pipe_abort_write_w is not None:
+                os.close(self.pipe_abort_write_w)
+                self.pipe_abort_write_w = None
+            if self.pipe_abort_write_r is not None:
+                os.close(self.pipe_abort_write_r)
+                self.pipe_abort_write_r = None
+
+            raise
+
+        self.is_open = True
+
+    def _reconfigure_port(self, force_update=False):
+        """Set communication parameters on opened port."""
+        if self.fd is None:
+            raise SerialException("Can only operate on a valid file descriptor")
+
+        # if exclusive lock is requested, create it before we modify anything else
+        if self._exclusive is not None:
+            if self._exclusive:
+                try:
+                    fcntl.flock(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
+                except IOError as msg:
+                    raise SerialException(msg.errno, "Could not exclusively lock port {}: {}".format(self._port, msg))
+            else:
+                fcntl.flock(self.fd, fcntl.LOCK_UN)
+
+        custom_baud = None
+
+        vmin = vtime = 0                # timeout is done via select
+        if self._inter_byte_timeout is not None:
+            vmin = 1
+            vtime = int(self._inter_byte_timeout * 10)
+        try:
+            orig_attr = termios.tcgetattr(self.fd)
+            iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr
+        except termios.error as msg:      # if a port is nonexistent but has a /dev file, it'll fail here
+            raise SerialException("Could not configure port: {}".format(msg))
+        # set up raw mode / no echo / binary
+        cflag |= (termios.CLOCAL | termios.CREAD)
+        lflag &= ~(termios.ICANON | termios.ECHO | termios.ECHOE |
+                   termios.ECHOK | termios.ECHONL |
+                   termios.ISIG | termios.IEXTEN)  # |termios.ECHOPRT
+        for flag in ('ECHOCTL', 'ECHOKE'):  # netbsd workaround for Erk
+            if hasattr(termios, flag):
+                lflag &= ~getattr(termios, flag)
+
+        oflag &= ~(termios.OPOST | termios.ONLCR | termios.OCRNL)
+        iflag &= ~(termios.INLCR | termios.IGNCR | termios.ICRNL | termios.IGNBRK)
+        if hasattr(termios, 'IUCLC'):
+            iflag &= ~termios.IUCLC
+        if hasattr(termios, 'PARMRK'):
+            iflag &= ~termios.PARMRK
+
+        # setup baud rate
+        try:
+            ispeed = ospeed = getattr(termios, 'B{}'.format(self._baudrate))
+        except AttributeError:
+            try:
+                ispeed = ospeed = self.BAUDRATE_CONSTANTS[self._baudrate]
+            except KeyError:
+                #~ raise ValueError('Invalid baud rate: %r' % self._baudrate)
+
+                # See if BOTHER is defined for this platform; if it is, use
+                # this for a speed not defined in the baudrate constants list.
+                try:
+                    ispeed = ospeed = BOTHER
+                except NameError:
+                    # may need custom baud rate, it isn't in our list.
+                    ispeed = ospeed = getattr(termios, 'B38400')
+
+                try:
+                    custom_baud = int(self._baudrate)  # store for later
+                except ValueError:
+                    raise ValueError('Invalid baud rate: {!r}'.format(self._baudrate))
+                else:
+                    if custom_baud < 0:
+                        raise ValueError('Invalid baud rate: {!r}'.format(self._baudrate))
+
+        # setup char len
+        cflag &= ~termios.CSIZE
+        if self._bytesize == 8:
+            cflag |= termios.CS8
+        elif self._bytesize == 7:
+            cflag |= termios.CS7
+        elif self._bytesize == 6:
+            cflag |= termios.CS6
+        elif self._bytesize == 5:
+            cflag |= termios.CS5
+        else:
+            raise ValueError('Invalid char len: {!r}'.format(self._bytesize))
+        # setup stop bits
+        if self._stopbits == serial.STOPBITS_ONE:
+            cflag &= ~(termios.CSTOPB)
+        elif self._stopbits == serial.STOPBITS_ONE_POINT_FIVE:
+            cflag |= (termios.CSTOPB)  # XXX same as TWO.. there is no POSIX support for 1.5
+        elif self._stopbits == serial.STOPBITS_TWO:
+            cflag |= (termios.CSTOPB)
+        else:
+            raise ValueError('Invalid stop bit specification: {!r}'.format(self._stopbits))
+        # setup parity
+        iflag &= ~(termios.INPCK | termios.ISTRIP)
+        if self._parity == serial.PARITY_NONE:
+            cflag &= ~(termios.PARENB | termios.PARODD | CMSPAR)
+        elif self._parity == serial.PARITY_EVEN:
+            cflag &= ~(termios.PARODD | CMSPAR)
+            cflag |= (termios.PARENB)
+        elif self._parity == serial.PARITY_ODD:
+            cflag &= ~CMSPAR
+            cflag |= (termios.PARENB | termios.PARODD)
+        elif self._parity == serial.PARITY_MARK and CMSPAR:
+            cflag |= (termios.PARENB | CMSPAR | termios.PARODD)
+        elif self._parity == serial.PARITY_SPACE and CMSPAR:
+            cflag |= (termios.PARENB | CMSPAR)
+            cflag &= ~(termios.PARODD)
+        else:
+            raise ValueError('Invalid parity: {!r}'.format(self._parity))
+        # setup flow control
+        # xonxoff
+        if hasattr(termios, 'IXANY'):
+            if self._xonxoff:
+                iflag |= (termios.IXON | termios.IXOFF)  # |termios.IXANY)
+            else:
+                iflag &= ~(termios.IXON | termios.IXOFF | termios.IXANY)
+        else:
+            if self._xonxoff:
+                iflag |= (termios.IXON | termios.IXOFF)
+            else:
+                iflag &= ~(termios.IXON | termios.IXOFF)
+        # rtscts
+        if hasattr(termios, 'CRTSCTS'):
+            if self._rtscts:
+                cflag |= (termios.CRTSCTS)
+            else:
+                cflag &= ~(termios.CRTSCTS)
+        elif hasattr(termios, 'CNEW_RTSCTS'):   # try it with alternate constant name
+            if self._rtscts:
+                cflag |= (termios.CNEW_RTSCTS)
+            else:
+                cflag &= ~(termios.CNEW_RTSCTS)
+        # XXX should there be a warning if setting up rtscts (and xonxoff etc) fails??
+
+        # buffer
+        # vmin "minimal number of characters to be read. 0 for non blocking"
+        if vmin < 0 or vmin > 255:
+            raise ValueError('Invalid vmin: {!r}'.format(vmin))
+        cc[termios.VMIN] = vmin
+        # vtime
+        if vtime < 0 or vtime > 255:
+            raise ValueError('Invalid vtime: {!r}'.format(vtime))
+        cc[termios.VTIME] = vtime
+        # activate settings
+        if force_update or [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] != orig_attr:
+            termios.tcsetattr(
+                self.fd,
+                termios.TCSANOW,
+                [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])
+
+        # apply custom baud rate, if any
+        if custom_baud is not None:
+            self._set_special_baudrate(custom_baud)
+
+        if self._rs485_mode is not None:
+            self._set_rs485_mode(self._rs485_mode)
+
+    def close(self):
+        """Close port"""
+        if self.is_open:
+            if self.fd is not None:
+                os.close(self.fd)
+                self.fd = None
+                os.close(self.pipe_abort_read_w)
+                os.close(self.pipe_abort_read_r)
+                os.close(self.pipe_abort_write_w)
+                os.close(self.pipe_abort_write_r)
+                self.pipe_abort_read_r, self.pipe_abort_read_w = None, None
+                self.pipe_abort_write_r, self.pipe_abort_write_w = None, None
+            self.is_open = False
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    @property
+    def in_waiting(self):
+        """Return the number of bytes currently in the input buffer."""
+        #~ s = fcntl.ioctl(self.fd, termios.FIONREAD, TIOCM_zero_str)
+        s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str)
+        return struct.unpack('I', s)[0]
+
+    # select based implementation, proved to work on many systems
+    def read(self, size=1):
+        """\
+        Read size bytes from the serial port. If a timeout is set it may
+        return less characters as requested. With no timeout it will block
+        until the requested number of bytes is read.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        read = bytearray()
+        timeout = Timeout(self._timeout)
+        while len(read) < size:
+            try:
+                ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left())
+                if self.pipe_abort_read_r in ready:
+                    os.read(self.pipe_abort_read_r, 1000)
+                    break
+                # If select was used with a timeout, and the timeout occurs, it
+                # returns with empty lists -> thus abort read operation.
+                # For timeout == 0 (non-blocking operation) also abort when
+                # there is nothing to read.
+                if not ready:
+                    break   # timeout
+                buf = os.read(self.fd, size - len(read))
+            except OSError as e:
+                # this is for Python 3.x where select.error is a subclass of
+                # OSError ignore BlockingIOErrors and EINTR. other errors are shown
+                # https://www.python.org/dev/peps/pep-0475.
+                if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+                    raise SerialException('read failed: {}'.format(e))
+            except select.error as e:
+                # this is for Python 2.x
+                # ignore BlockingIOErrors and EINTR. all errors are shown
+                # see also http://www.python.org/dev/peps/pep-3151/#select
+                if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+                    raise SerialException('read failed: {}'.format(e))
+            else:
+                # read should always return some data as select reported it was
+                # ready to read when we get to this point.
+                if not buf:
+                    # Disconnected devices, at least on Linux, show the
+                    # behavior that they are always ready to read immediately
+                    # but reading returns nothing.
+                    raise SerialException(
+                        'device reports readiness to read but returned no data '
+                        '(device disconnected or multiple access on port?)')
+                read.extend(buf)
+
+            if timeout.expired():
+                break
+        return bytes(read)
+
+    def cancel_read(self):
+        if self.is_open:
+            os.write(self.pipe_abort_read_w, b"x")
+
+    def cancel_write(self):
+        if self.is_open:
+            os.write(self.pipe_abort_write_w, b"x")
+
+    def write(self, data):
+        """Output the given byte string over the serial port."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        d = to_bytes(data)
+        tx_len = length = len(d)
+        timeout = Timeout(self._write_timeout)
+        while tx_len > 0:
+            try:
+                n = os.write(self.fd, d)
+                if timeout.is_non_blocking:
+                    # Zero timeout indicates non-blocking - simply return the
+                    # number of bytes of data actually written
+                    return n
+                elif not timeout.is_infinite:
+                    # when timeout is set, use select to wait for being ready
+                    # with the time left as timeout
+                    if timeout.expired():
+                        raise SerialTimeoutException('Write timeout')
+                    abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], timeout.time_left())
+                    if abort:
+                        os.read(self.pipe_abort_write_r, 1000)
+                        break
+                    if not ready:
+                        raise SerialTimeoutException('Write timeout')
+                else:
+                    assert timeout.time_left() is None
+                    # wait for write operation
+                    abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], None)
+                    if abort:
+                        os.read(self.pipe_abort_write_r, 1)
+                        break
+                    if not ready:
+                        raise SerialException('write failed (select)')
+                d = d[n:]
+                tx_len -= n
+            except SerialException:
+                raise
+            except OSError as e:
+                # this is for Python 3.x where select.error is a subclass of
+                # OSError ignore BlockingIOErrors and EINTR. other errors are shown
+                # https://www.python.org/dev/peps/pep-0475.
+                if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+                    raise SerialException('write failed: {}'.format(e))
+            except select.error as e:
+                # this is for Python 2.x
+                # ignore BlockingIOErrors and EINTR. all errors are shown
+                # see also http://www.python.org/dev/peps/pep-3151/#select
+                if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+                    raise SerialException('write failed: {}'.format(e))
+            if not timeout.is_non_blocking and timeout.expired():
+                raise SerialTimeoutException('Write timeout')
+        return length - len(d)
+
+    def flush(self):
+        """\
+        Flush of file like objects. In this case, wait until all data
+        is written.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        termios.tcdrain(self.fd)
+
+    def _reset_input_buffer(self):
+        """Clear input buffer, discarding all that is in the buffer."""
+        termios.tcflush(self.fd, termios.TCIFLUSH)
+
+    def reset_input_buffer(self):
+        """Clear input buffer, discarding all that is in the buffer."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        self._reset_input_buffer()
+
+    def reset_output_buffer(self):
+        """\
+        Clear output buffer, aborting the current output and discarding all
+        that is in the buffer.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        termios.tcflush(self.fd, termios.TCOFLUSH)
+
+    def send_break(self, duration=0.25):
+        """\
+        Send break condition. Timed, returns to idle state after given
+        duration.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        termios.tcsendbreak(self.fd, int(duration / 0.25))
+
+    def _update_rts_state(self):
+        """Set terminal status line: Request To Send"""
+        if self._rts_state:
+            fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str)
+        else:
+            fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str)
+
+    def _update_dtr_state(self):
+        """Set terminal status line: Data Terminal Ready"""
+        if self._dtr_state:
+            fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str)
+        else:
+            fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str)
+
+    @property
+    def cts(self):
+        """Read terminal status line: Clear To Send"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
+        return struct.unpack('I', s)[0] & TIOCM_CTS != 0
+
+    @property
+    def dsr(self):
+        """Read terminal status line: Data Set Ready"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
+        return struct.unpack('I', s)[0] & TIOCM_DSR != 0
+
+    @property
+    def ri(self):
+        """Read terminal status line: Ring Indicator"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
+        return struct.unpack('I', s)[0] & TIOCM_RI != 0
+
+    @property
+    def cd(self):
+        """Read terminal status line: Carrier Detect"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str)
+        return struct.unpack('I', s)[0] & TIOCM_CD != 0
+
+    # - - platform specific - - - -
+
+    @property
+    def out_waiting(self):
+        """Return the number of bytes currently in the output buffer."""
+        #~ s = fcntl.ioctl(self.fd, termios.FIONREAD, TIOCM_zero_str)
+        s = fcntl.ioctl(self.fd, TIOCOUTQ, TIOCM_zero_str)
+        return struct.unpack('I', s)[0]
+
+    def fileno(self):
+        """\
+        For easier use of the serial port instance with select.
+        WARNING: this function is not portable to different platforms!
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        return self.fd
+
+    def set_input_flow_control(self, enable=True):
+        """\
+        Manually control flow - when software flow control is enabled.
+        This will send XON (true) or XOFF (false) to the other device.
+        WARNING: this function is not portable to different platforms!
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        if enable:
+            termios.tcflow(self.fd, termios.TCION)
+        else:
+            termios.tcflow(self.fd, termios.TCIOFF)
+
+    def set_output_flow_control(self, enable=True):
+        """\
+        Manually control flow of outgoing data - when hardware or software flow
+        control is enabled.
+        WARNING: this function is not portable to different platforms!
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        if enable:
+            termios.tcflow(self.fd, termios.TCOON)
+        else:
+            termios.tcflow(self.fd, termios.TCOOFF)
+
+    def nonblocking(self):
+        """DEPRECATED - has no use"""
+        import warnings
+        warnings.warn("nonblocking() has no effect, already nonblocking", DeprecationWarning)
+
+
+class PosixPollSerial(Serial):
+    """\
+    Poll based read implementation. Not all systems support poll properly.
+    However this one has better handling of errors, such as a device
+    disconnecting while it's in use (e.g. USB-serial unplugged).
+    """
+
+    def read(self, size=1):
+        """\
+        Read size bytes from the serial port. If a timeout is set it may
+        return less characters as requested. With no timeout it will block
+        until the requested number of bytes is read.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        read = bytearray()
+        timeout = Timeout(self._timeout)
+        poll = select.poll()
+        poll.register(self.fd, select.POLLIN | select.POLLERR | select.POLLHUP | select.POLLNVAL)
+        poll.register(self.pipe_abort_read_r, select.POLLIN | select.POLLERR | select.POLLHUP | select.POLLNVAL)
+        if size > 0:
+            while len(read) < size:
+                # print "\tread(): size",size, "have", len(read)    #debug
+                # wait until device becomes ready to read (or something fails)
+                for fd, event in poll.poll(None if timeout.is_infinite else (timeout.time_left() * 1000)):
+                    if fd == self.pipe_abort_read_r:
+                        break
+                    if event & (select.POLLERR | select.POLLHUP | select.POLLNVAL):
+                        raise SerialException('device reports error (poll)')
+                    #  we don't care if it is select.POLLIN or timeout, that's
+                    #  handled below
+                if fd == self.pipe_abort_read_r:
+                    os.read(self.pipe_abort_read_r, 1000)
+                    break
+                buf = os.read(self.fd, size - len(read))
+                read.extend(buf)
+                if timeout.expired() \
+                        or (self._inter_byte_timeout is not None and self._inter_byte_timeout > 0) and not buf:
+                    break   # early abort on timeout
+        return bytes(read)
+
+
+class VTIMESerial(Serial):
+    """\
+    Implement timeout using vtime of tty device instead of using select.
+    This means that no inter character timeout can be specified and that
+    the error handling is degraded.
+
+    Overall timeout is disabled when inter-character timeout is used.
+
+    Note that this implementation does NOT support cancel_read(), it will
+    just ignore that.
+    """
+
+    def _reconfigure_port(self, force_update=True):
+        """Set communication parameters on opened port."""
+        super(VTIMESerial, self)._reconfigure_port()
+        fcntl.fcntl(self.fd, fcntl.F_SETFL, 0)  # clear O_NONBLOCK
+
+        if self._inter_byte_timeout is not None:
+            vmin = 1
+            vtime = int(self._inter_byte_timeout * 10)
+        elif self._timeout is None:
+            vmin = 1
+            vtime = 0
+        else:
+            vmin = 0
+            vtime = int(self._timeout * 10)
+        try:
+            orig_attr = termios.tcgetattr(self.fd)
+            iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr
+        except termios.error as msg:      # if a port is nonexistent but has a /dev file, it'll fail here
+            raise serial.SerialException("Could not configure port: {}".format(msg))
+
+        if vtime < 0 or vtime > 255:
+            raise ValueError('Invalid vtime: {!r}'.format(vtime))
+        cc[termios.VTIME] = vtime
+        cc[termios.VMIN] = vmin
+
+        termios.tcsetattr(
+                self.fd,
+                termios.TCSANOW,
+                [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])
+
+    def read(self, size=1):
+        """\
+        Read size bytes from the serial port. If a timeout is set it may
+        return less characters as requested. With no timeout it will block
+        until the requested number of bytes is read.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        read = bytearray()
+        while len(read) < size:
+            buf = os.read(self.fd, size - len(read))
+            if not buf:
+                break
+            read.extend(buf)
+        return bytes(read)
+
+    # hack to make hasattr return false
+    cancel_read = property()
diff --git a/src/devtools/datool/serial/serialutil.py b/src/devtools/datool/serial/serialutil.py
new file mode 100755
index 0000000..789219e
--- /dev/null
+++ b/src/devtools/datool/serial/serialutil.py
@@ -0,0 +1,697 @@
+#! python
+#
+# Base class and support functions used by various backends.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2001-2020 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+from __future__ import absolute_import
+
+import io
+import time
+
+# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)``
+# isn't returning the contents (very unfortunate). Therefore we need special
+# cases and test for it. Ensure that there is a ``memoryview`` object for older
+# Python versions. This is easier than making every test dependent on its
+# existence.
+try:
+    memoryview
+except (NameError, AttributeError):
+    # implementation does not matter as we do not really use it.
+    # it just must not inherit from something else we might care for.
+    class memoryview(object):   # pylint: disable=redefined-builtin,invalid-name
+        pass
+
+try:
+    unicode
+except (NameError, AttributeError):
+    unicode = str       # for Python 3, pylint: disable=redefined-builtin,invalid-name
+
+try:
+    basestring
+except (NameError, AttributeError):
+    basestring = (str,)    # for Python 3, pylint: disable=redefined-builtin,invalid-name
+
+
+# "for byte in data" fails for python3 as it returns ints instead of bytes
+def iterbytes(b):
+    """Iterate over bytes, returning bytes instead of ints (python3)"""
+    if isinstance(b, memoryview):
+        b = b.tobytes()
+    i = 0
+    while True:
+        a = b[i:i + 1]
+        i += 1
+        if a:
+            yield a
+        else:
+            break
+
+
+# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
+# so a simple ``bytes(sequence)`` doesn't work for all versions
+def to_bytes(seq):
+    """convert a sequence to a bytes type"""
+    if isinstance(seq, bytes):
+        return seq
+    elif isinstance(seq, bytearray):
+        return bytes(seq)
+    elif isinstance(seq, memoryview):
+        return seq.tobytes()
+    elif isinstance(seq, unicode):
+        raise TypeError('unicode strings are not supported, please encode to bytes: {!r}'.format(seq))
+    else:
+        # handle list of integers and bytes (one or more items) for Python 2 and 3
+        return bytes(bytearray(seq))
+
+
+# create control bytes
+XON = to_bytes([17])
+XOFF = to_bytes([19])
+
+CR = to_bytes([13])
+LF = to_bytes([10])
+
+
+PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
+STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
+FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
+
+PARITY_NAMES = {
+    PARITY_NONE: 'None',
+    PARITY_EVEN: 'Even',
+    PARITY_ODD: 'Odd',
+    PARITY_MARK: 'Mark',
+    PARITY_SPACE: 'Space',
+}
+
+
+class SerialException(IOError):
+    """Base class for serial port related exceptions."""
+
+
+class SerialTimeoutException(SerialException):
+    """Write timeouts give an exception"""
+
+
+class PortNotOpenError(SerialException):
+    """Port is not open"""
+    def __init__(self):
+        super(PortNotOpenError, self).__init__('Attempting to use a port that is not open')
+
+
+class Timeout(object):
+    """\
+    Abstraction for timeout operations. Using time.monotonic() if available
+    or time.time() in all other cases.
+
+    The class can also be initialized with 0 or None, in order to support
+    non-blocking and fully blocking I/O operations. The attributes
+    is_non_blocking and is_infinite are set accordingly.
+    """
+    if hasattr(time, 'monotonic'):
+        # Timeout implementation with time.monotonic(). This function is only
+        # supported by Python 3.3 and above. It returns a time in seconds
+        # (float) just as time.time(), but is not affected by system clock
+        # adjustments.
+        TIME = time.monotonic
+    else:
+        # Timeout implementation with time.time(). This is compatible with all
+        # Python versions but has issues if the clock is adjusted while the
+        # timeout is running.
+        TIME = time.time
+
+    def __init__(self, duration):
+        """Initialize a timeout with given duration"""
+        self.is_infinite = (duration is None)
+        self.is_non_blocking = (duration == 0)
+        self.duration = duration
+        if duration is not None:
+            self.target_time = self.TIME() + duration
+        else:
+            self.target_time = None
+
+    def expired(self):
+        """Return a boolean, telling if the timeout has expired"""
+        return self.target_time is not None and self.time_left() <= 0
+
+    def time_left(self):
+        """Return how many seconds are left until the timeout expires"""
+        if self.is_non_blocking:
+            return 0
+        elif self.is_infinite:
+            return None
+        else:
+            delta = self.target_time - self.TIME()
+            if delta > self.duration:
+                # clock jumped, recalculate
+                self.target_time = self.TIME() + self.duration
+                return self.duration
+            else:
+                return max(0, delta)
+
+    def restart(self, duration):
+        """\
+        Restart a timeout, only supported if a timeout was already set up
+        before.
+        """
+        self.duration = duration
+        self.target_time = self.TIME() + duration
+
+
+class SerialBase(io.RawIOBase):
+    """\
+    Serial port base class. Provides __init__ function and properties to
+    get/set port settings.
+    """
+
+    # default values, may be overridden in subclasses that do not support all values
+    BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+                 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
+                 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
+                 3000000, 3500000, 4000000)
+    BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
+    PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
+    STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
+
+    def __init__(self,
+                 port=None,
+                 baudrate=9600,
+                 bytesize=EIGHTBITS,
+                 parity=PARITY_NONE,
+                 stopbits=STOPBITS_ONE,
+                 timeout=None,
+                 xonxoff=False,
+                 rtscts=False,
+                 write_timeout=None,
+                 dsrdtr=False,
+                 inter_byte_timeout=None,
+                 exclusive=None,
+                 **kwargs):
+        """\
+        Initialize comm port object. If a "port" is given, then the port will be
+        opened immediately. Otherwise a Serial port object in closed state
+        is returned.
+        """
+
+        self.is_open = False
+        self.portstr = None
+        self.name = None
+        # correct values are assigned below through properties
+        self._port = None
+        self._baudrate = None
+        self._bytesize = None
+        self._parity = None
+        self._stopbits = None
+        self._timeout = None
+        self._write_timeout = None
+        self._xonxoff = None
+        self._rtscts = None
+        self._dsrdtr = None
+        self._inter_byte_timeout = None
+        self._rs485_mode = None  # disabled by default
+        self._rts_state = True
+        self._dtr_state = True
+        self._break_state = False
+        self._exclusive = None
+
+        # assign values using get/set methods using the properties feature
+        self.port = port
+        self.baudrate = baudrate
+        self.bytesize = bytesize
+        self.parity = parity
+        self.stopbits = stopbits
+        self.timeout = timeout
+        self.write_timeout = write_timeout
+        self.xonxoff = xonxoff
+        self.rtscts = rtscts
+        self.dsrdtr = dsrdtr
+        self.inter_byte_timeout = inter_byte_timeout
+        self.exclusive = exclusive
+
+        # watch for backward compatible kwargs
+        if 'writeTimeout' in kwargs:
+            self.write_timeout = kwargs.pop('writeTimeout')
+        if 'interCharTimeout' in kwargs:
+            self.inter_byte_timeout = kwargs.pop('interCharTimeout')
+        if kwargs:
+            raise ValueError('unexpected keyword arguments: {!r}'.format(kwargs))
+
+        if port is not None:
+            self.open()
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    # to be implemented by subclasses:
+    # def open(self):
+    # def close(self):
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    @property
+    def port(self):
+        """\
+        Get the current port setting. The value that was passed on init or using
+        setPort() is passed back.
+        """
+        return self._port
+
+    @port.setter
+    def port(self, port):
+        """\
+        Change the port.
+        """
+        if port is not None and not isinstance(port, basestring):
+            raise ValueError('"port" must be None or a string, not {}'.format(type(port)))
+        was_open = self.is_open
+        if was_open:
+            self.close()
+        self.portstr = port
+        self._port = port
+        self.name = self.portstr
+        if was_open:
+            self.open()
+
+    @property
+    def baudrate(self):
+        """Get the current baud rate setting."""
+        return self._baudrate
+
+    @baudrate.setter
+    def baudrate(self, baudrate):
+        """\
+        Change baud rate. It raises a ValueError if the port is open and the
+        baud rate is not possible. If the port is closed, then the value is
+        accepted and the exception is raised when the port is opened.
+        """
+        try:
+            b = int(baudrate)
+        except TypeError:
+            raise ValueError("Not a valid baudrate: {!r}".format(baudrate))
+        else:
+            if b < 0:
+                raise ValueError("Not a valid baudrate: {!r}".format(baudrate))
+            self._baudrate = b
+            if self.is_open:
+                self._reconfigure_port()
+
+    @property
+    def bytesize(self):
+        """Get the current byte size setting."""
+        return self._bytesize
+
+    @bytesize.setter
+    def bytesize(self, bytesize):
+        """Change byte size."""
+        if bytesize not in self.BYTESIZES:
+            raise ValueError("Not a valid byte size: {!r}".format(bytesize))
+        self._bytesize = bytesize
+        if self.is_open:
+            self._reconfigure_port()
+
+    @property
+    def exclusive(self):
+        """Get the current exclusive access setting."""
+        return self._exclusive
+
+    @exclusive.setter
+    def exclusive(self, exclusive):
+        """Change the exclusive access setting."""
+        self._exclusive = exclusive
+        if self.is_open:
+            self._reconfigure_port()
+
+    @property
+    def parity(self):
+        """Get the current parity setting."""
+        return self._parity
+
+    @parity.setter
+    def parity(self, parity):
+        """Change parity setting."""
+        if parity not in self.PARITIES:
+            raise ValueError("Not a valid parity: {!r}".format(parity))
+        self._parity = parity
+        if self.is_open:
+            self._reconfigure_port()
+
+    @property
+    def stopbits(self):
+        """Get the current stop bits setting."""
+        return self._stopbits
+
+    @stopbits.setter
+    def stopbits(self, stopbits):
+        """Change stop bits size."""
+        if stopbits not in self.STOPBITS:
+            raise ValueError("Not a valid stop bit size: {!r}".format(stopbits))
+        self._stopbits = stopbits
+        if self.is_open:
+            self._reconfigure_port()
+
+    @property
+    def timeout(self):
+        """Get the current timeout setting."""
+        return self._timeout
+
+    @timeout.setter
+    def timeout(self, timeout):
+        """Change timeout setting."""
+        if timeout is not None:
+            try:
+                timeout + 1     # test if it's a number, will throw a TypeError if not...
+            except TypeError:
+                raise ValueError("Not a valid timeout: {!r}".format(timeout))
+            if timeout < 0:
+                raise ValueError("Not a valid timeout: {!r}".format(timeout))
+        self._timeout = timeout
+        if self.is_open:
+            self._reconfigure_port()
+
+    @property
+    def write_timeout(self):
+        """Get the current timeout setting."""
+        return self._write_timeout
+
+    @write_timeout.setter
+    def write_timeout(self, timeout):
+        """Change timeout setting."""
+        if timeout is not None:
+            if timeout < 0:
+                raise ValueError("Not a valid timeout: {!r}".format(timeout))
+            try:
+                timeout + 1     # test if it's a number, will throw a TypeError if not...
+            except TypeError:
+                raise ValueError("Not a valid timeout: {!r}".format(timeout))
+
+        self._write_timeout = timeout
+        if self.is_open:
+            self._reconfigure_port()
+
+    @property
+    def inter_byte_timeout(self):
+        """Get the current inter-character timeout setting."""
+        return self._inter_byte_timeout
+
+    @inter_byte_timeout.setter
+    def inter_byte_timeout(self, ic_timeout):
+        """Change inter-byte timeout setting."""
+        if ic_timeout is not None:
+            if ic_timeout < 0:
+                raise ValueError("Not a valid timeout: {!r}".format(ic_timeout))
+            try:
+                ic_timeout + 1     # test if it's a number, will throw a TypeError if not...
+            except TypeError:
+                raise ValueError("Not a valid timeout: {!r}".format(ic_timeout))
+
+        self._inter_byte_timeout = ic_timeout
+        if self.is_open:
+            self._reconfigure_port()
+
+    @property
+    def xonxoff(self):
+        """Get the current XON/XOFF setting."""
+        return self._xonxoff
+
+    @xonxoff.setter
+    def xonxoff(self, xonxoff):
+        """Change XON/XOFF setting."""
+        self._xonxoff = xonxoff
+        if self.is_open:
+            self._reconfigure_port()
+
+    @property
+    def rtscts(self):
+        """Get the current RTS/CTS flow control setting."""
+        return self._rtscts
+
+    @rtscts.setter
+    def rtscts(self, rtscts):
+        """Change RTS/CTS flow control setting."""
+        self._rtscts = rtscts
+        if self.is_open:
+            self._reconfigure_port()
+
+    @property
+    def dsrdtr(self):
+        """Get the current DSR/DTR flow control setting."""
+        return self._dsrdtr
+
+    @dsrdtr.setter
+    def dsrdtr(self, dsrdtr=None):
+        """Change DsrDtr flow control setting."""
+        if dsrdtr is None:
+            # if not set, keep backwards compatibility and follow rtscts setting
+            self._dsrdtr = self._rtscts
+        else:
+            # if defined independently, follow its value
+            self._dsrdtr = dsrdtr
+        if self.is_open:
+            self._reconfigure_port()
+
+    @property
+    def rts(self):
+        return self._rts_state
+
+    @rts.setter
+    def rts(self, value):
+        self._rts_state = value
+        if self.is_open:
+            self._update_rts_state()
+
+    @property
+    def dtr(self):
+        return self._dtr_state
+
+    @dtr.setter
+    def dtr(self, value):
+        self._dtr_state = value
+        if self.is_open:
+            self._update_dtr_state()
+
+    @property
+    def break_condition(self):
+        return self._break_state
+
+    @break_condition.setter
+    def break_condition(self, value):
+        self._break_state = value
+        if self.is_open:
+            self._update_break_state()
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+    # functions useful for RS-485 adapters
+
+    @property
+    def rs485_mode(self):
+        """\
+        Enable RS485 mode and apply new settings, set to None to disable.
+        See serial.rs485.RS485Settings for more info about the value.
+        """
+        return self._rs485_mode
+
+    @rs485_mode.setter
+    def rs485_mode(self, rs485_settings):
+        self._rs485_mode = rs485_settings
+        if self.is_open:
+            self._reconfigure_port()
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    _SAVED_SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff',
+                       'dsrdtr', 'rtscts', 'timeout', 'write_timeout',
+                       'inter_byte_timeout')
+
+    def get_settings(self):
+        """\
+        Get current port settings as a dictionary. For use with
+        apply_settings().
+        """
+        return dict([(key, getattr(self, '_' + key)) for key in self._SAVED_SETTINGS])
+
+    def apply_settings(self, d):
+        """\
+        Apply stored settings from a dictionary returned from
+        get_settings(). It's allowed to delete keys from the dictionary. These
+        values will simply left unchanged.
+        """
+        for key in self._SAVED_SETTINGS:
+            if key in d and d[key] != getattr(self, '_' + key):   # check against internal "_" value
+                setattr(self, key, d[key])          # set non "_" value to use properties write function
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    def __repr__(self):
+        """String representation of the current port settings and its state."""
+        return '{name}<id=0x{id:x}, open={p.is_open}>(port={p.portstr!r}, ' \
+               'baudrate={p.baudrate!r}, bytesize={p.bytesize!r}, parity={p.parity!r}, ' \
+               'stopbits={p.stopbits!r}, timeout={p.timeout!r}, xonxoff={p.xonxoff!r}, ' \
+               'rtscts={p.rtscts!r}, dsrdtr={p.dsrdtr!r})'.format(
+                   name=self.__class__.__name__, id=id(self), p=self)
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+    # compatibility with io library
+    # pylint: disable=invalid-name,missing-docstring
+
+    def readable(self):
+        return True
+
+    def writable(self):
+        return True
+
+    def seekable(self):
+        return False
+
+    def readinto(self, b):
+        data = self.read(len(b))
+        n = len(data)
+        try:
+            b[:n] = data
+        except TypeError as err:
+            import array
+            if not isinstance(b, array.array):
+                raise err
+            b[:n] = array.array('b', data)
+        return n
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+    # context manager
+
+    def __enter__(self):
+        if self._port is not None and not self.is_open:
+            self.open()
+        return self
+
+    def __exit__(self, *args, **kwargs):
+        self.close()
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    def send_break(self, duration=0.25):
+        """\
+        Send break condition. Timed, returns to idle state after given
+        duration.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        self.break_condition = True
+        time.sleep(duration)
+        self.break_condition = False
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+    # backwards compatibility / deprecated functions
+
+    def flushInput(self):
+        self.reset_input_buffer()
+
+    def flushOutput(self):
+        self.reset_output_buffer()
+
+    def inWaiting(self):
+        return self.in_waiting
+
+    def sendBreak(self, duration=0.25):
+        self.send_break(duration)
+
+    def setRTS(self, value=1):
+        self.rts = value
+
+    def setDTR(self, value=1):
+        self.dtr = value
+
+    def getCTS(self):
+        return self.cts
+
+    def getDSR(self):
+        return self.dsr
+
+    def getRI(self):
+        return self.ri
+
+    def getCD(self):
+        return self.cd
+
+    def setPort(self, port):
+        self.port = port
+
+    @property
+    def writeTimeout(self):
+        return self.write_timeout
+
+    @writeTimeout.setter
+    def writeTimeout(self, timeout):
+        self.write_timeout = timeout
+
+    @property
+    def interCharTimeout(self):
+        return self.inter_byte_timeout
+
+    @interCharTimeout.setter
+    def interCharTimeout(self, interCharTimeout):
+        self.inter_byte_timeout = interCharTimeout
+
+    def getSettingsDict(self):
+        return self.get_settings()
+
+    def applySettingsDict(self, d):
+        self.apply_settings(d)
+
+    def isOpen(self):
+        return self.is_open
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+    # additional functionality
+
+    def read_all(self):
+        """\
+        Read all bytes currently available in the buffer of the OS.
+        """
+        return self.read(self.in_waiting)
+
+    def read_until(self, expected=LF, size=None):
+        """\
+        Read until an expected sequence is found ('\n' by default), the size
+        is exceeded or until timeout occurs.
+        """
+        lenterm = len(expected)
+        line = bytearray()
+        timeout = Timeout(self._timeout)
+        while True:
+            c = self.read(1)
+            if c:
+                line += c
+                if line[-lenterm:] == expected:
+                    break
+                if size is not None and len(line) >= size:
+                    break
+            else:
+                break
+            if timeout.expired():
+                break
+        return bytes(line)
+
+    def iread_until(self, *args, **kwargs):
+        """\
+        Read lines, implemented as generator. It will raise StopIteration on
+        timeout (empty read).
+        """
+        while True:
+            line = self.read_until(*args, **kwargs)
+            if not line:
+                break
+            yield line
+
+
+#  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+if __name__ == '__main__':
+    import sys
+    s = SerialBase()
+    sys.stdout.write('port name:  {}\n'.format(s.name))
+    sys.stdout.write('baud rates: {}\n'.format(s.BAUDRATES))
+    sys.stdout.write('byte sizes: {}\n'.format(s.BYTESIZES))
+    sys.stdout.write('parities:   {}\n'.format(s.PARITIES))
+    sys.stdout.write('stop bits:  {}\n'.format(s.STOPBITS))
+    sys.stdout.write('{}\n'.format(s))
diff --git a/src/devtools/datool/serial/serialwin32.py b/src/devtools/datool/serial/serialwin32.py
new file mode 100755
index 0000000..e7da929
--- /dev/null
+++ b/src/devtools/datool/serial/serialwin32.py
@@ -0,0 +1,477 @@
+#! python
+#
+# backend for Windows ("win32" incl. 32/64 bit support)
+#
+# (C) 2001-2020 Chris Liechti <cliechti@gmx.net>
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# SPDX-License-Identifier:    BSD-3-Clause
+#
+# Initial patch to use ctypes by Giovanni Bajo <rasky@develer.com>
+
+from __future__ import absolute_import
+
+# pylint: disable=invalid-name,too-few-public-methods
+import ctypes
+import time
+from serial import win32
+
+import serial
+from serial.serialutil import SerialBase, SerialException, to_bytes, PortNotOpenError, SerialTimeoutException
+
+
+class Serial(SerialBase):
+    """Serial port implementation for Win32 based on ctypes."""
+
+    BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+                 9600, 19200, 38400, 57600, 115200)
+
+    def __init__(self, *args, **kwargs):
+        self._port_handle = None
+        self._overlapped_read = None
+        self._overlapped_write = None
+        super(Serial, self).__init__(*args, **kwargs)
+
+    def open(self):
+        """\
+        Open port with current settings. This may throw a SerialException
+        if the port cannot be opened.
+        """
+        if self._port is None:
+            raise SerialException("Port must be configured before it can be used.")
+        if self.is_open:
+            raise SerialException("Port is already open.")
+        # the "\\.\COMx" format is required for devices other than COM1-COM8
+        # not all versions of windows seem to support this properly
+        # so that the first few ports are used with the DOS device name
+        port = self.name
+        try:
+            if port.upper().startswith('COM') and int(port[3:]) > 8:
+                port = '\\\\.\\' + port
+        except ValueError:
+            # for like COMnotanumber
+            pass
+        self._port_handle = win32.CreateFile(
+            port,
+            win32.GENERIC_READ | win32.GENERIC_WRITE,
+            0,  # exclusive access
+            None,  # no security
+            win32.OPEN_EXISTING,
+            win32.FILE_ATTRIBUTE_NORMAL | win32.FILE_FLAG_OVERLAPPED,
+            0)
+        if self._port_handle == win32.INVALID_HANDLE_VALUE:
+            self._port_handle = None    # 'cause __del__ is called anyway
+            raise SerialException("could not open port {!r}: {!r}".format(self.portstr, ctypes.WinError()))
+
+        try:
+            self._overlapped_read = win32.OVERLAPPED()
+            self._overlapped_read.hEvent = win32.CreateEvent(None, 1, 0, None)
+            self._overlapped_write = win32.OVERLAPPED()
+            #~ self._overlapped_write.hEvent = win32.CreateEvent(None, 1, 0, None)
+            self._overlapped_write.hEvent = win32.CreateEvent(None, 0, 0, None)
+
+            # Setup a 4k buffer
+            win32.SetupComm(self._port_handle, 4096, 4096)
+
+            # Save original timeout values:
+            self._orgTimeouts = win32.COMMTIMEOUTS()
+            win32.GetCommTimeouts(self._port_handle, ctypes.byref(self._orgTimeouts))
+
+            self._reconfigure_port()
+
+            # Clear buffers:
+            # Remove anything that was there
+            win32.PurgeComm(
+                self._port_handle,
+                win32.PURGE_TXCLEAR | win32.PURGE_TXABORT |
+                win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
+        except:
+            try:
+                self._close()
+            except:
+                # ignore any exception when closing the port
+                # also to keep original exception that happened when setting up
+                pass
+            self._port_handle = None
+            raise
+        else:
+            self.is_open = True
+
+    def _reconfigure_port(self):
+        """Set communication parameters on opened port."""
+        if not self._port_handle:
+            raise SerialException("Can only operate on a valid port handle")
+
+        # Set Windows timeout values
+        # timeouts is a tuple with the following items:
+        # (ReadIntervalTimeout,ReadTotalTimeoutMultiplier,
+        #  ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier,
+        #  WriteTotalTimeoutConstant)
+        timeouts = win32.COMMTIMEOUTS()
+        if self._timeout is None:
+            pass  # default of all zeros is OK
+        elif self._timeout == 0:
+            timeouts.ReadIntervalTimeout = win32.MAXDWORD
+        else:
+            timeouts.ReadTotalTimeoutConstant = max(int(self._timeout * 1000), 1)
+        if self._timeout != 0 and self._inter_byte_timeout is not None:
+            timeouts.ReadIntervalTimeout = max(int(self._inter_byte_timeout * 1000), 1)
+
+        if self._write_timeout is None:
+            pass
+        elif self._write_timeout == 0:
+            timeouts.WriteTotalTimeoutConstant = win32.MAXDWORD
+        else:
+            timeouts.WriteTotalTimeoutConstant = max(int(self._write_timeout * 1000), 1)
+        win32.SetCommTimeouts(self._port_handle, ctypes.byref(timeouts))
+
+        win32.SetCommMask(self._port_handle, win32.EV_ERR)
+
+        # Setup the connection info.
+        # Get state and modify it:
+        comDCB = win32.DCB()
+        win32.GetCommState(self._port_handle, ctypes.byref(comDCB))
+        comDCB.BaudRate = self._baudrate
+
+        if self._bytesize == serial.FIVEBITS:
+            comDCB.ByteSize = 5
+        elif self._bytesize == serial.SIXBITS:
+            comDCB.ByteSize = 6
+        elif self._bytesize == serial.SEVENBITS:
+            comDCB.ByteSize = 7
+        elif self._bytesize == serial.EIGHTBITS:
+            comDCB.ByteSize = 8
+        else:
+            raise ValueError("Unsupported number of data bits: {!r}".format(self._bytesize))
+
+        if self._parity == serial.PARITY_NONE:
+            comDCB.Parity = win32.NOPARITY
+            comDCB.fParity = 0  # Disable Parity Check
+        elif self._parity == serial.PARITY_EVEN:
+            comDCB.Parity = win32.EVENPARITY
+            comDCB.fParity = 1  # Enable Parity Check
+        elif self._parity == serial.PARITY_ODD:
+            comDCB.Parity = win32.ODDPARITY
+            comDCB.fParity = 1  # Enable Parity Check
+        elif self._parity == serial.PARITY_MARK:
+            comDCB.Parity = win32.MARKPARITY
+            comDCB.fParity = 1  # Enable Parity Check
+        elif self._parity == serial.PARITY_SPACE:
+            comDCB.Parity = win32.SPACEPARITY
+            comDCB.fParity = 1  # Enable Parity Check
+        else:
+            raise ValueError("Unsupported parity mode: {!r}".format(self._parity))
+
+        if self._stopbits == serial.STOPBITS_ONE:
+            comDCB.StopBits = win32.ONESTOPBIT
+        elif self._stopbits == serial.STOPBITS_ONE_POINT_FIVE:
+            comDCB.StopBits = win32.ONE5STOPBITS
+        elif self._stopbits == serial.STOPBITS_TWO:
+            comDCB.StopBits = win32.TWOSTOPBITS
+        else:
+            raise ValueError("Unsupported number of stop bits: {!r}".format(self._stopbits))
+
+        comDCB.fBinary = 1  # Enable Binary Transmission
+        # Char. w/ Parity-Err are replaced with 0xff (if fErrorChar is set to TRUE)
+        if self._rs485_mode is None:
+            if self._rtscts:
+                comDCB.fRtsControl = win32.RTS_CONTROL_HANDSHAKE
+            else:
+                comDCB.fRtsControl = win32.RTS_CONTROL_ENABLE if self._rts_state else win32.RTS_CONTROL_DISABLE
+            comDCB.fOutxCtsFlow = self._rtscts
+        else:
+            # checks for unsupported settings
+            # XXX verify if platform really does not have a setting for those
+            if not self._rs485_mode.rts_level_for_tx:
+                raise ValueError(
+                    'Unsupported value for RS485Settings.rts_level_for_tx: {!r} (only True is allowed)'.format(
+                        self._rs485_mode.rts_level_for_tx,))
+            if self._rs485_mode.rts_level_for_rx:
+                raise ValueError(
+                    'Unsupported value for RS485Settings.rts_level_for_rx: {!r} (only False is allowed)'.format(
+                        self._rs485_mode.rts_level_for_rx,))
+            if self._rs485_mode.delay_before_tx is not None:
+                raise ValueError(
+                    'Unsupported value for RS485Settings.delay_before_tx: {!r} (only None is allowed)'.format(
+                        self._rs485_mode.delay_before_tx,))
+            if self._rs485_mode.delay_before_rx is not None:
+                raise ValueError(
+                    'Unsupported value for RS485Settings.delay_before_rx: {!r} (only None is allowed)'.format(
+                        self._rs485_mode.delay_before_rx,))
+            if self._rs485_mode.loopback:
+                raise ValueError(
+                    'Unsupported value for RS485Settings.loopback: {!r} (only False is allowed)'.format(
+                        self._rs485_mode.loopback,))
+            comDCB.fRtsControl = win32.RTS_CONTROL_TOGGLE
+            comDCB.fOutxCtsFlow = 0
+
+        if self._dsrdtr:
+            comDCB.fDtrControl = win32.DTR_CONTROL_HANDSHAKE
+        else:
+            comDCB.fDtrControl = win32.DTR_CONTROL_ENABLE if self._dtr_state else win32.DTR_CONTROL_DISABLE
+        comDCB.fOutxDsrFlow = self._dsrdtr
+        comDCB.fOutX = self._xonxoff
+        comDCB.fInX = self._xonxoff
+        comDCB.fNull = 0
+        comDCB.fErrorChar = 0
+        comDCB.fAbortOnError = 0
+        comDCB.XonChar = serial.XON
+        comDCB.XoffChar = serial.XOFF
+
+        if not win32.SetCommState(self._port_handle, ctypes.byref(comDCB)):
+            raise SerialException(
+                'Cannot configure port, something went wrong. '
+                'Original message: {!r}'.format(ctypes.WinError()))
+
+    #~ def __del__(self):
+        #~ self.close()
+
+    def _close(self):
+        """internal close port helper"""
+        if self._port_handle is not None:
+            # Restore original timeout values:
+            win32.SetCommTimeouts(self._port_handle, self._orgTimeouts)
+            if self._overlapped_read is not None:
+                self.cancel_read()
+                win32.CloseHandle(self._overlapped_read.hEvent)
+                self._overlapped_read = None
+            if self._overlapped_write is not None:
+                self.cancel_write()
+                win32.CloseHandle(self._overlapped_write.hEvent)
+                self._overlapped_write = None
+            win32.CloseHandle(self._port_handle)
+            self._port_handle = None
+
+    def close(self):
+        """Close port"""
+        if self.is_open:
+            self._close()
+            self.is_open = False
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    @property
+    def in_waiting(self):
+        """Return the number of bytes currently in the input buffer."""
+        flags = win32.DWORD()
+        comstat = win32.COMSTAT()
+        if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)):
+            raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError()))
+        return comstat.cbInQue
+
+    def read(self, size=1):
+        """\
+        Read size bytes from the serial port. If a timeout is set it may
+        return less characters as requested. With no timeout it will block
+        until the requested number of bytes is read.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        if size > 0:
+            win32.ResetEvent(self._overlapped_read.hEvent)
+            flags = win32.DWORD()
+            comstat = win32.COMSTAT()
+            if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)):
+                raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError()))
+            n = min(comstat.cbInQue, size) if self.timeout == 0 else size
+            if n > 0:
+                buf = ctypes.create_string_buffer(n)
+                rc = win32.DWORD()
+                read_ok = win32.ReadFile(
+                    self._port_handle,
+                    buf,
+                    n,
+                    ctypes.byref(rc),
+                    ctypes.byref(self._overlapped_read))
+                if not read_ok and win32.GetLastError() not in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING):
+                    raise SerialException("ReadFile failed ({!r})".format(ctypes.WinError()))
+                result_ok = win32.GetOverlappedResult(
+                    self._port_handle,
+                    ctypes.byref(self._overlapped_read),
+                    ctypes.byref(rc),
+                    True)
+                if not result_ok:
+                    if win32.GetLastError() != win32.ERROR_OPERATION_ABORTED:
+                        raise SerialException("GetOverlappedResult failed ({!r})".format(ctypes.WinError()))
+                read = buf.raw[:rc.value]
+            else:
+                read = bytes()
+        else:
+            read = bytes()
+        return bytes(read)
+
+    def write(self, data):
+        """Output the given byte string over the serial port."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        #~ if not isinstance(data, (bytes, bytearray)):
+            #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
+        # convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview
+        data = to_bytes(data)
+        if data:
+            #~ win32event.ResetEvent(self._overlapped_write.hEvent)
+            n = win32.DWORD()
+            success = win32.WriteFile(self._port_handle, data, len(data), ctypes.byref(n), self._overlapped_write)
+            if self._write_timeout != 0:  # if blocking (None) or w/ write timeout (>0)
+                if not success and win32.GetLastError() not in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING):
+                    raise SerialException("WriteFile failed ({!r})".format(ctypes.WinError()))
+
+                # Wait for the write to complete.
+                #~ win32.WaitForSingleObject(self._overlapped_write.hEvent, win32.INFINITE)
+                win32.GetOverlappedResult(self._port_handle, self._overlapped_write, ctypes.byref(n), True)
+                if win32.GetLastError() == win32.ERROR_OPERATION_ABORTED:
+                    return n.value  # canceled IO is no error
+                if n.value != len(data):
+                    raise SerialTimeoutException('Write timeout')
+                return n.value
+            else:
+                errorcode = win32.ERROR_SUCCESS if success else win32.GetLastError()
+                if errorcode in (win32.ERROR_INVALID_USER_BUFFER, win32.ERROR_NOT_ENOUGH_MEMORY,
+                                 win32.ERROR_OPERATION_ABORTED):
+                    return 0
+                elif errorcode in (win32.ERROR_SUCCESS, win32.ERROR_IO_PENDING):
+                    # no info on true length provided by OS function in async mode
+                    return len(data)
+                else:
+                    raise SerialException("WriteFile failed ({!r})".format(ctypes.WinError()))
+        else:
+            return 0
+
+    def flush(self):
+        """\
+        Flush of file like objects. In this case, wait until all data
+        is written.
+        """
+        while self.out_waiting:
+            time.sleep(0.05)
+        # XXX could also use WaitCommEvent with mask EV_TXEMPTY, but it would
+        # require overlapped IO and it's also only possible to set a single mask
+        # on the port---
+
+    def reset_input_buffer(self):
+        """Clear input buffer, discarding all that is in the buffer."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        win32.PurgeComm(self._port_handle, win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
+
+    def reset_output_buffer(self):
+        """\
+        Clear output buffer, aborting the current output and discarding all
+        that is in the buffer.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        win32.PurgeComm(self._port_handle, win32.PURGE_TXCLEAR | win32.PURGE_TXABORT)
+
+    def _update_break_state(self):
+        """Set break: Controls TXD. When active, to transmitting is possible."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self._break_state:
+            win32.SetCommBreak(self._port_handle)
+        else:
+            win32.ClearCommBreak(self._port_handle)
+
+    def _update_rts_state(self):
+        """Set terminal status line: Request To Send"""
+        if self._rts_state:
+            win32.EscapeCommFunction(self._port_handle, win32.SETRTS)
+        else:
+            win32.EscapeCommFunction(self._port_handle, win32.CLRRTS)
+
+    def _update_dtr_state(self):
+        """Set terminal status line: Data Terminal Ready"""
+        if self._dtr_state:
+            win32.EscapeCommFunction(self._port_handle, win32.SETDTR)
+        else:
+            win32.EscapeCommFunction(self._port_handle, win32.CLRDTR)
+
+    def _GetCommModemStatus(self):
+        if not self.is_open:
+            raise PortNotOpenError()
+        stat = win32.DWORD()
+        win32.GetCommModemStatus(self._port_handle, ctypes.byref(stat))
+        return stat.value
+
+    @property
+    def cts(self):
+        """Read terminal status line: Clear To Send"""
+        return win32.MS_CTS_ON & self._GetCommModemStatus() != 0
+
+    @property
+    def dsr(self):
+        """Read terminal status line: Data Set Ready"""
+        return win32.MS_DSR_ON & self._GetCommModemStatus() != 0
+
+    @property
+    def ri(self):
+        """Read terminal status line: Ring Indicator"""
+        return win32.MS_RING_ON & self._GetCommModemStatus() != 0
+
+    @property
+    def cd(self):
+        """Read terminal status line: Carrier Detect"""
+        return win32.MS_RLSD_ON & self._GetCommModemStatus() != 0
+
+    # - - platform specific - - - -
+
+    def set_buffer_size(self, rx_size=4096, tx_size=None):
+        """\
+        Recommend a buffer size to the driver (device driver can ignore this
+        value). Must be called after the port is opened.
+        """
+        if tx_size is None:
+            tx_size = rx_size
+        win32.SetupComm(self._port_handle, rx_size, tx_size)
+
+    def set_output_flow_control(self, enable=True):
+        """\
+        Manually control flow - when software flow control is enabled.
+        This will do the same as if XON (true) or XOFF (false) are received
+        from the other device and control the transmission accordingly.
+        WARNING: this function is not portable to different platforms!
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        if enable:
+            win32.EscapeCommFunction(self._port_handle, win32.SETXON)
+        else:
+            win32.EscapeCommFunction(self._port_handle, win32.SETXOFF)
+
+    @property
+    def out_waiting(self):
+        """Return how many bytes the in the outgoing buffer"""
+        flags = win32.DWORD()
+        comstat = win32.COMSTAT()
+        if not win32.ClearCommError(self._port_handle, ctypes.byref(flags), ctypes.byref(comstat)):
+            raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError()))
+        return comstat.cbOutQue
+
+    def _cancel_overlapped_io(self, overlapped):
+        """Cancel a blocking read operation, may be called from other thread"""
+        # check if read operation is pending
+        rc = win32.DWORD()
+        err = win32.GetOverlappedResult(
+            self._port_handle,
+            ctypes.byref(overlapped),
+            ctypes.byref(rc),
+            False)
+        if not err and win32.GetLastError() in (win32.ERROR_IO_PENDING, win32.ERROR_IO_INCOMPLETE):
+            # cancel, ignoring any errors (e.g. it may just have finished on its own)
+            win32.CancelIoEx(self._port_handle, overlapped)
+
+    def cancel_read(self):
+        """Cancel a blocking read operation, may be called from other thread"""
+        self._cancel_overlapped_io(self._overlapped_read)
+
+    def cancel_write(self):
+        """Cancel a blocking write operation, may be called from other thread"""
+        self._cancel_overlapped_io(self._overlapped_write)
+
+    @SerialBase.exclusive.setter
+    def exclusive(self, exclusive):
+        """Change the exclusive access setting."""
+        if exclusive is not None and not exclusive:
+            raise ValueError('win32 only supports exclusive access (not: {})'.format(exclusive))
+        else:
+            serial.SerialBase.exclusive.__set__(self, exclusive)
diff --git a/src/devtools/datool/serial/threaded/__init__.py b/src/devtools/datool/serial/threaded/__init__.py
new file mode 100755
index 0000000..b8940b6
--- /dev/null
+++ b/src/devtools/datool/serial/threaded/__init__.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python3
+#
+# Working with threading and pySerial
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2015-2016 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+"""\
+Support threading with serial ports.
+"""
+from __future__ import absolute_import
+
+import serial
+import threading
+
+
+class Protocol(object):
+    """\
+    Protocol as used by the ReaderThread. This base class provides empty
+    implementations of all methods.
+    """
+
+    def connection_made(self, transport):
+        """Called when reader thread is started"""
+
+    def data_received(self, data):
+        """Called with snippets received from the serial port"""
+
+    def connection_lost(self, exc):
+        """\
+        Called when the serial port is closed or the reader loop terminated
+        otherwise.
+        """
+        if isinstance(exc, Exception):
+            raise exc
+
+
+class Packetizer(Protocol):
+    """
+    Read binary packets from serial port. Packets are expected to be terminated
+    with a TERMINATOR byte (null byte by default).
+
+    The class also keeps track of the transport.
+    """
+
+    TERMINATOR = b'\0'
+
+    def __init__(self):
+        self.buffer = bytearray()
+        self.transport = None
+
+    def connection_made(self, transport):
+        """Store transport"""
+        self.transport = transport
+
+    def connection_lost(self, exc):
+        """Forget transport"""
+        self.transport = None
+        super(Packetizer, self).connection_lost(exc)
+
+    def data_received(self, data):
+        """Buffer received data, find TERMINATOR, call handle_packet"""
+        self.buffer.extend(data)
+        while self.TERMINATOR in self.buffer:
+            packet, self.buffer = self.buffer.split(self.TERMINATOR, 1)
+            self.handle_packet(packet)
+
+    def handle_packet(self, packet):
+        """Process packets - to be overridden by subclassing"""
+        raise NotImplementedError('please implement functionality in handle_packet')
+
+
+class FramedPacket(Protocol):
+    """
+    Read binary packets. Packets are expected to have a start and stop marker.
+
+    The class also keeps track of the transport.
+    """
+
+    START = b'('
+    STOP = b')'
+
+    def __init__(self):
+        self.packet = bytearray()
+        self.in_packet = False
+        self.transport = None
+
+    def connection_made(self, transport):
+        """Store transport"""
+        self.transport = transport
+
+    def connection_lost(self, exc):
+        """Forget transport"""
+        self.transport = None
+        self.in_packet = False
+        del self.packet[:]
+        super(FramedPacket, self).connection_lost(exc)
+
+    def data_received(self, data):
+        """Find data enclosed in START/STOP, call handle_packet"""
+        for byte in serial.iterbytes(data):
+            if byte == self.START:
+                self.in_packet = True
+            elif byte == self.STOP:
+                self.in_packet = False
+                self.handle_packet(bytes(self.packet)) # make read-only copy
+                del self.packet[:]
+            elif self.in_packet:
+                self.packet.extend(byte)
+            else:
+                self.handle_out_of_packet_data(byte)
+
+    def handle_packet(self, packet):
+        """Process packets - to be overridden by subclassing"""
+        raise NotImplementedError('please implement functionality in handle_packet')
+
+    def handle_out_of_packet_data(self, data):
+        """Process data that is received outside of packets"""
+        pass
+
+
+class LineReader(Packetizer):
+    """
+    Read and write (Unicode) lines from/to serial port.
+    The encoding is applied.
+    """
+
+    TERMINATOR = b'\r\n'
+    ENCODING = 'utf-8'
+    UNICODE_HANDLING = 'replace'
+
+    def handle_packet(self, packet):
+        self.handle_line(packet.decode(self.ENCODING, self.UNICODE_HANDLING))
+
+    def handle_line(self, line):
+        """Process one line - to be overridden by subclassing"""
+        raise NotImplementedError('please implement functionality in handle_line')
+
+    def write_line(self, text):
+        """
+        Write text to the transport. ``text`` is a Unicode string and the encoding
+        is applied before sending ans also the newline is append.
+        """
+        # + is not the best choice but bytes does not support % or .format in py3 and we want a single write call
+        self.transport.write(text.encode(self.ENCODING, self.UNICODE_HANDLING) + self.TERMINATOR)
+
+
+class ReaderThread(threading.Thread):
+    """\
+    Implement a serial port read loop and dispatch to a Protocol instance (like
+    the asyncio.Protocol) but do it with threads.
+
+    Calls to close() will close the serial port but it is also possible to just
+    stop() this thread and continue the serial port instance otherwise.
+    """
+
+    def __init__(self, serial_instance, protocol_factory):
+        """\
+        Initialize thread.
+
+        Note that the serial_instance' timeout is set to one second!
+        Other settings are not changed.
+        """
+        super(ReaderThread, self).__init__()
+        self.daemon = True
+        self.serial = serial_instance
+        self.protocol_factory = protocol_factory
+        self.alive = True
+        self._lock = threading.Lock()
+        self._connection_made = threading.Event()
+        self.protocol = None
+
+    def stop(self):
+        """Stop the reader thread"""
+        self.alive = False
+        if hasattr(self.serial, 'cancel_read'):
+            self.serial.cancel_read()
+        self.join(2)
+
+    def run(self):
+        """Reader loop"""
+        if not hasattr(self.serial, 'cancel_read'):
+            self.serial.timeout = 1
+        self.protocol = self.protocol_factory()
+        try:
+            self.protocol.connection_made(self)
+        except Exception as e:
+            self.alive = False
+            self.protocol.connection_lost(e)
+            self._connection_made.set()
+            return
+        error = None
+        self._connection_made.set()
+        while self.alive and self.serial.is_open:
+            try:
+                # read all that is there or wait for one byte (blocking)
+                data = self.serial.read(self.serial.in_waiting or 1)
+            except serial.SerialException as e:
+                # probably some I/O problem such as disconnected USB serial
+                # adapters -> exit
+                error = e
+                break
+            else:
+                if data:
+                    # make a separated try-except for called user code
+                    try:
+                        self.protocol.data_received(data)
+                    except Exception as e:
+                        error = e
+                        break
+        self.alive = False
+        self.protocol.connection_lost(error)
+        self.protocol = None
+
+    def write(self, data):
+        """Thread safe writing (uses lock)"""
+        with self._lock:
+            return self.serial.write(data)
+
+    def close(self):
+        """Close the serial port and exit reader thread (uses lock)"""
+        # use the lock to let other threads finish writing
+        with self._lock:
+            # first stop reading, so that closing can be done on idle port
+            self.stop()
+            self.serial.close()
+
+    def connect(self):
+        """
+        Wait until connection is set up and return the transport and protocol
+        instances.
+        """
+        if self.alive:
+            self._connection_made.wait()
+            if not self.alive:
+                raise RuntimeError('connection_lost already called')
+            return (self, self.protocol)
+        else:
+            raise RuntimeError('already stopped')
+
+    # - -  context manager, returns protocol
+
+    def __enter__(self):
+        """\
+        Enter context handler. May raise RuntimeError in case the connection
+        could not be created.
+        """
+        self.start()
+        self._connection_made.wait()
+        if not self.alive:
+            raise RuntimeError('connection_lost already called')
+        return self.protocol
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        """Leave context: close port"""
+        self.close()
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# test
+if __name__ == '__main__':
+    # pylint: disable=wrong-import-position
+    import sys
+    import time
+    import traceback
+
+    #~ PORT = 'spy:///dev/ttyUSB0'
+    PORT = 'loop://'
+
+    class PrintLines(LineReader):
+        def connection_made(self, transport):
+            super(PrintLines, self).connection_made(transport)
+            sys.stdout.write('port opened\n')
+            self.write_line('hello world')
+
+        def handle_line(self, data):
+            sys.stdout.write('line received: {!r}\n'.format(data))
+
+        def connection_lost(self, exc):
+            if exc:
+                traceback.print_exc(exc)
+            sys.stdout.write('port closed\n')
+
+    ser = serial.serial_for_url(PORT, baudrate=115200, timeout=1)
+    with ReaderThread(ser, PrintLines) as protocol:
+        protocol.write_line('hello')
+        time.sleep(2)
+
+    # alternative usage
+    ser = serial.serial_for_url(PORT, baudrate=115200, timeout=1)
+    t = ReaderThread(ser, PrintLines)
+    t.start()
+    transport, protocol = t.connect()
+    protocol.write_line('hello')
+    time.sleep(2)
+    t.close()
diff --git a/src/devtools/datool/serial/tools/__init__.py b/src/devtools/datool/serial/tools/__init__.py
new file mode 100755
index 0000000..aa39021
--- /dev/null
+++ b/src/devtools/datool/serial/tools/__init__.py
@@ -0,0 +1 @@
+# SPDX-License-Identifier:    BSD-3-Clause
\ No newline at end of file
diff --git a/src/devtools/datool/serial/tools/hexlify_codec.py b/src/devtools/datool/serial/tools/hexlify_codec.py
new file mode 100755
index 0000000..bd8f6b0
--- /dev/null
+++ b/src/devtools/datool/serial/tools/hexlify_codec.py
@@ -0,0 +1,126 @@
+#! python
+#
+# This is a codec to create and decode hexdumps with spaces between characters. used by miniterm.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2015-2016 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+"""\
+Python 'hex' Codec - 2-digit hex with spaces content transfer encoding.
+
+Encode and decode may be a bit missleading at first sight...
+
+The textual representation is a hex dump: e.g. "40 41"
+The "encoded" data of this is the binary form, e.g. b"@A"
+
+Therefore decoding is binary to text and thus converting binary data to hex dump.
+
+"""
+
+from __future__ import absolute_import
+
+import codecs
+import serial
+
+
+try:
+    unicode
+except (NameError, AttributeError):
+    unicode = str       # for Python 3, pylint: disable=redefined-builtin,invalid-name
+
+
+HEXDIGITS = '0123456789ABCDEF'
+
+
+# Codec APIs
+
+def hex_encode(data, errors='strict'):
+    """'40 41 42' -> b'@ab'"""
+    return (serial.to_bytes([int(h, 16) for h in data.split()]), len(data))
+
+
+def hex_decode(data, errors='strict'):
+    """b'@ab' -> '40 41 42'"""
+    return (unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data))), len(data))
+
+
+class Codec(codecs.Codec):
+    def encode(self, data, errors='strict'):
+        """'40 41 42' -> b'@ab'"""
+        return serial.to_bytes([int(h, 16) for h in data.split()])
+
+    def decode(self, data, errors='strict'):
+        """b'@ab' -> '40 41 42'"""
+        return unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data)))
+
+
+class IncrementalEncoder(codecs.IncrementalEncoder):
+    """Incremental hex encoder"""
+
+    def __init__(self, errors='strict'):
+        self.errors = errors
+        self.state = 0
+
+    def reset(self):
+        self.state = 0
+
+    def getstate(self):
+        return self.state
+
+    def setstate(self, state):
+        self.state = state
+
+    def encode(self, data, final=False):
+        """\
+        Incremental encode, keep track of digits and emit a byte when a pair
+        of hex digits is found. The space is optional unless the error
+        handling is defined to be 'strict'.
+        """
+        state = self.state
+        encoded = []
+        for c in data.upper():
+            if c in HEXDIGITS:
+                z = HEXDIGITS.index(c)
+                if state:
+                    encoded.append(z + (state & 0xf0))
+                    state = 0
+                else:
+                    state = 0x100 + (z << 4)
+            elif c == ' ':      # allow spaces to separate values
+                if state and self.errors == 'strict':
+                    raise UnicodeError('odd number of hex digits')
+                state = 0
+            else:
+                if self.errors == 'strict':
+                    raise UnicodeError('non-hex digit found: {!r}'.format(c))
+        self.state = state
+        return serial.to_bytes(encoded)
+
+
+class IncrementalDecoder(codecs.IncrementalDecoder):
+    """Incremental decoder"""
+    def decode(self, data, final=False):
+        return unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data)))
+
+
+class StreamWriter(Codec, codecs.StreamWriter):
+    """Combination of hexlify codec and StreamWriter"""
+
+
+class StreamReader(Codec, codecs.StreamReader):
+    """Combination of hexlify codec and StreamReader"""
+
+
+def getregentry():
+    """encodings module API"""
+    return codecs.CodecInfo(
+        name='hexlify',
+        encode=hex_encode,
+        decode=hex_decode,
+        incrementalencoder=IncrementalEncoder,
+        incrementaldecoder=IncrementalDecoder,
+        streamwriter=StreamWriter,
+        streamreader=StreamReader,
+        #~ _is_text_encoding=True,
+    )
diff --git a/src/devtools/datool/serial/tools/list_ports.py b/src/devtools/datool/serial/tools/list_ports.py
new file mode 100755
index 0000000..0d7e3d4
--- /dev/null
+++ b/src/devtools/datool/serial/tools/list_ports.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+#
+# Serial port enumeration. Console tool and backend selection.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2011-2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+"""\
+This module will provide a function called comports that returns an
+iterable (generator or list) that will enumerate available com ports. Note that
+on some systems non-existent ports may be listed.
+
+Additionally a grep function is supplied that can be used to search for ports
+based on their descriptions or hardware ID.
+"""
+
+from __future__ import absolute_import
+
+import sys
+import os
+import re
+
+# chose an implementation, depending on os
+#~ if sys.platform == 'cli':
+#~ else:
+if os.name == 'nt':  # sys.platform == 'win32':
+    from serial.tools.list_ports_windows import comports
+elif os.name == 'posix':
+    from serial.tools.list_ports_posix import comports
+#~ elif os.name == 'java':
+else:
+    raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name))
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+def grep(regexp, include_links=False):
+    """\
+    Search for ports using a regular expression. Port name, description and
+    hardware ID are searched. The function returns an iterable that returns the
+    same tuples as comport() would do.
+    """
+    r = re.compile(regexp, re.I)
+    for info in comports(include_links):
+        port, desc, hwid = info
+        if r.search(port) or r.search(desc) or r.search(hwid):
+            yield info
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def main():
+    import argparse
+
+    parser = argparse.ArgumentParser(description='Serial port enumeration')
+
+    parser.add_argument(
+        'regexp',
+        nargs='?',
+        help='only show ports that match this regex')
+
+    parser.add_argument(
+        '-v', '--verbose',
+        action='store_true',
+        help='show more messages')
+
+    parser.add_argument(
+        '-q', '--quiet',
+        action='store_true',
+        help='suppress all messages')
+
+    parser.add_argument(
+        '-n',
+        type=int,
+        help='only output the N-th entry')
+
+    parser.add_argument(
+        '-s', '--include-links',
+        action='store_true',
+        help='include entries that are symlinks to real devices')
+
+    args = parser.parse_args()
+
+    hits = 0
+    # get iteraror w/ or w/o filter
+    if args.regexp:
+        if not args.quiet:
+            sys.stderr.write("Filtered list with regexp: {!r}\n".format(args.regexp))
+        iterator = sorted(grep(args.regexp, include_links=args.include_links))
+    else:
+        iterator = sorted(comports(include_links=args.include_links))
+    # list them
+    for n, (port, desc, hwid) in enumerate(iterator, 1):
+        if args.n is None or args.n == n:
+            sys.stdout.write("{:20}\n".format(port))
+            if args.verbose:
+                sys.stdout.write("    desc: {}\n".format(desc))
+                sys.stdout.write("    hwid: {}\n".format(hwid))
+        hits += 1
+    if not args.quiet:
+        if hits:
+            sys.stderr.write("{} ports found\n".format(hits))
+        else:
+            sys.stderr.write("no ports found\n")
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# test
+if __name__ == '__main__':
+    main()
diff --git a/src/devtools/datool/serial/tools/list_ports_common.py b/src/devtools/datool/serial/tools/list_ports_common.py
new file mode 100755
index 0000000..617f3dc
--- /dev/null
+++ b/src/devtools/datool/serial/tools/list_ports_common.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+# This is a helper module for the various platform dependent list_port
+# implementations.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+from __future__ import absolute_import
+
+import re
+import glob
+import os
+import os.path
+
+
+def numsplit(text):
+    """\
+    Convert string into a list of texts and numbers in order to support a
+    natural sorting.
+    """
+    result = []
+    for group in re.split(r'(\d+)', text):
+        if group:
+            try:
+                group = int(group)
+            except ValueError:
+                pass
+            result.append(group)
+    return result
+
+
+class ListPortInfo(object):
+    """Info collection base class for serial ports"""
+
+    def __init__(self, device, skip_link_detection=False):
+        self.device = device
+        self.name = os.path.basename(device)
+        self.description = 'n/a'
+        self.hwid = 'n/a'
+        # USB specific data
+        self.vid = None
+        self.pid = None
+        self.serial_number = None
+        self.location = None
+        self.manufacturer = None
+        self.product = None
+        self.interface = None
+        # special handling for links
+        if not skip_link_detection and device is not None and os.path.islink(device):
+            self.hwid = 'LINK={}'.format(os.path.realpath(device))
+
+    def usb_description(self):
+        """return a short string to name the port based on USB info"""
+        if self.interface is not None:
+            return '{} - {}'.format(self.product, self.interface)
+        elif self.product is not None:
+            return self.product
+        else:
+            return self.name
+
+    def usb_info(self):
+        """return a string with USB related information about device"""
+        return 'USB VID:PID={:04X}:{:04X}{}{}'.format(
+            self.vid or 0,
+            self.pid or 0,
+            ' SER={}'.format(self.serial_number) if self.serial_number is not None else '',
+            ' LOCATION={}'.format(self.location) if self.location is not None else '')
+
+    def apply_usb_info(self):
+        """update description and hwid from USB data"""
+        self.description = self.usb_description()
+        self.hwid = self.usb_info()
+
+    def __eq__(self, other):
+        return isinstance(other, ListPortInfo) and self.device == other.device
+
+    def __hash__(self):
+        return hash(self.device)
+
+    def __lt__(self, other):
+        if not isinstance(other, ListPortInfo):
+            raise TypeError('unorderable types: {}() and {}()'.format(
+                type(self).__name__,
+                type(other).__name__))
+        return numsplit(self.device) < numsplit(other.device)
+
+    def __str__(self):
+        return '{} - {}'.format(self.device, self.description)
+
+    def __getitem__(self, index):
+        """Item access: backwards compatible -> (port, desc, hwid)"""
+        if index == 0:
+            return self.device
+        elif index == 1:
+            return self.description
+        elif index == 2:
+            return self.hwid
+        else:
+            raise IndexError('{} > 2'.format(index))
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def list_links(devices):
+    """\
+    search all /dev devices and look for symlinks to known ports already
+    listed in devices.
+    """
+    links = []
+    for device in glob.glob('/dev/*'):
+        if os.path.islink(device) and os.path.realpath(device) in devices:
+            links.append(device)
+    return links
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# test
+if __name__ == '__main__':
+    print(ListPortInfo('dummy'))
diff --git a/src/devtools/datool/serial/tools/list_ports_linux.py b/src/devtools/datool/serial/tools/list_ports_linux.py
new file mode 100755
index 0000000..c8c1cfc
--- /dev/null
+++ b/src/devtools/datool/serial/tools/list_ports_linux.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+#
+# This is a module that gathers a list of serial ports including details on
+# GNU/Linux systems.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2011-2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+from __future__ import absolute_import
+
+import glob
+import os
+from serial.tools import list_ports_common
+
+
+class SysFS(list_ports_common.ListPortInfo):
+    """Wrapper for easy sysfs access and device info"""
+
+    def __init__(self, device):
+        super(SysFS, self).__init__(device)
+        # special handling for links
+        if device is not None and os.path.islink(device):
+            device = os.path.realpath(device)
+            is_link = True
+        else:
+            is_link = False
+        self.usb_device_path = None
+        if os.path.exists('/sys/class/tty/{}/device'.format(self.name)):
+            self.device_path = os.path.realpath('/sys/class/tty/{}/device'.format(self.name))
+            self.subsystem = os.path.basename(os.path.realpath(os.path.join(self.device_path, 'subsystem')))
+        else:
+            self.device_path = None
+            self.subsystem = None
+        # check device type
+        if self.subsystem == 'usb-serial':
+            self.usb_interface_path = os.path.dirname(self.device_path)
+        elif self.subsystem == 'usb':
+            self.usb_interface_path = self.device_path
+        else:
+            self.usb_interface_path = None
+        # fill-in info for USB devices
+        if self.usb_interface_path is not None:
+            self.usb_device_path = os.path.dirname(self.usb_interface_path)
+
+            try:
+                num_if = int(self.read_line(self.usb_device_path, 'bNumInterfaces'))
+            except ValueError:
+                num_if = 1
+
+            self.vid = int(self.read_line(self.usb_device_path, 'idVendor'), 16)
+            self.pid = int(self.read_line(self.usb_device_path, 'idProduct'), 16)
+            self.serial_number = self.read_line(self.usb_device_path, 'serial')
+            if num_if > 1:  # multi interface devices like FT4232
+                self.location = os.path.basename(self.usb_interface_path)
+            else:
+                self.location = os.path.basename(self.usb_device_path)
+
+            self.manufacturer = self.read_line(self.usb_device_path, 'manufacturer')
+            self.product = self.read_line(self.usb_device_path, 'product')
+            self.interface = self.read_line(self.usb_interface_path, 'interface')
+
+        if self.subsystem in ('usb', 'usb-serial'):
+            self.apply_usb_info()
+        #~ elif self.subsystem in ('pnp', 'amba'):  # PCI based devices, raspi
+        elif self.subsystem == 'pnp':  # PCI based devices
+            self.description = self.name
+            self.hwid = self.read_line(self.device_path, 'id')
+        elif self.subsystem == 'amba':  # raspi
+            self.description = self.name
+            self.hwid = os.path.basename(self.device_path)
+
+        if is_link:
+            self.hwid += ' LINK={}'.format(device)
+
+    def read_line(self, *args):
+        """\
+        Helper function to read a single line from a file.
+        One or more parameters are allowed, they are joined with os.path.join.
+        Returns None on errors..
+        """
+        try:
+            with open(os.path.join(*args)) as f:
+                line = f.readline().strip()
+            return line
+        except IOError:
+            return None
+
+
+def comports(include_links=False):
+    devices = glob.glob('/dev/ttyS*')           # built-in serial ports
+    devices.extend(glob.glob('/dev/ttyUSB*'))   # usb-serial with own driver
+    devices.extend(glob.glob('/dev/ttyXRUSB*')) # xr-usb-serial port exar (DELL Edge 3001)
+    devices.extend(glob.glob('/dev/ttyACM*'))   # usb-serial with CDC-ACM profile
+    devices.extend(glob.glob('/dev/ttyAMA*'))   # ARM internal port (raspi)
+    devices.extend(glob.glob('/dev/rfcomm*'))   # BT serial devices
+    devices.extend(glob.glob('/dev/ttyAP*'))    # Advantech multi-port serial controllers
+    if include_links:
+        devices.extend(list_ports_common.list_links(devices))
+    return [info
+            for info in [SysFS(d) for d in devices]
+            if info.subsystem != "platform"]    # hide non-present internal serial ports
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# test
+if __name__ == '__main__':
+    for info in sorted(comports()):
+        print("{0}: {0.subsystem}".format(info))
diff --git a/src/devtools/datool/serial/tools/list_ports_osx.py b/src/devtools/datool/serial/tools/list_ports_osx.py
new file mode 100755
index 0000000..51b4e8c
--- /dev/null
+++ b/src/devtools/datool/serial/tools/list_ports_osx.py
@@ -0,0 +1,299 @@
+#!/usr/bin/env python
+#
+# This is a module that gathers a list of serial ports including details on OSX
+#
+# code originally from https://github.com/makerbot/pyserial/tree/master/serial/tools
+# with contributions from cibomahto, dgs3, FarMcKon, tedbrandston
+# and modifications by cliechti, hoihu, hardkrash
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2013-2020
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+
+# List all of the callout devices in OS/X by querying IOKit.
+
+# See the following for a reference of how to do this:
+# http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html#//apple_ref/doc/uid/TP30000384-CIHGEAFD
+
+# More help from darwin_hid.py
+
+# Also see the 'IORegistryExplorer' for an idea of what we are actually searching
+
+from __future__ import absolute_import
+
+import ctypes
+
+from serial.tools import list_ports_common
+
+iokit = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/IOKit.framework/IOKit')
+cf = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')
+
+# kIOMasterPortDefault is no longer exported in BigSur but no biggie, using NULL works just the same
+kIOMasterPortDefault = 0 # WAS: ctypes.c_void_p.in_dll(iokit, "kIOMasterPortDefault")
+kCFAllocatorDefault = ctypes.c_void_p.in_dll(cf, "kCFAllocatorDefault")
+
+kCFStringEncodingMacRoman = 0
+kCFStringEncodingUTF8 = 0x08000100
+
+# defined in `IOKit/usb/USBSpec.h`
+kUSBVendorString = 'USB Vendor Name'
+kUSBSerialNumberString = 'USB Serial Number'
+
+# `io_name_t` defined as `typedef char io_name_t[128];`
+# in `device/device_types.h`
+io_name_size = 128
+
+# defined in `mach/kern_return.h`
+KERN_SUCCESS = 0
+# kern_return_t defined as `typedef int kern_return_t;` in `mach/i386/kern_return.h`
+kern_return_t = ctypes.c_int
+
+iokit.IOServiceMatching.restype = ctypes.c_void_p
+
+iokit.IOServiceGetMatchingServices.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
+iokit.IOServiceGetMatchingServices.restype = kern_return_t
+
+iokit.IORegistryEntryGetParentEntry.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
+iokit.IOServiceGetMatchingServices.restype = kern_return_t
+
+iokit.IORegistryEntryCreateCFProperty.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint32]
+iokit.IORegistryEntryCreateCFProperty.restype = ctypes.c_void_p
+
+iokit.IORegistryEntryGetPath.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
+iokit.IORegistryEntryGetPath.restype = kern_return_t
+
+iokit.IORegistryEntryGetName.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
+iokit.IORegistryEntryGetName.restype = kern_return_t
+
+iokit.IOObjectGetClass.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
+iokit.IOObjectGetClass.restype = kern_return_t
+
+iokit.IOObjectRelease.argtypes = [ctypes.c_void_p]
+
+
+cf.CFStringCreateWithCString.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int32]
+cf.CFStringCreateWithCString.restype = ctypes.c_void_p
+
+cf.CFStringGetCStringPtr.argtypes = [ctypes.c_void_p, ctypes.c_uint32]
+cf.CFStringGetCStringPtr.restype = ctypes.c_char_p
+
+cf.CFStringGetCString.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_long, ctypes.c_uint32]
+cf.CFStringGetCString.restype = ctypes.c_bool
+
+cf.CFNumberGetValue.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_void_p]
+cf.CFNumberGetValue.restype = ctypes.c_void_p
+
+# void CFRelease ( CFTypeRef cf );
+cf.CFRelease.argtypes = [ctypes.c_void_p]
+cf.CFRelease.restype = None
+
+# CFNumber type defines
+kCFNumberSInt8Type = 1
+kCFNumberSInt16Type = 2
+kCFNumberSInt32Type = 3
+kCFNumberSInt64Type = 4
+
+
+def get_string_property(device_type, property):
+    """
+    Search the given device for the specified string property
+
+    @param device_type Type of Device
+    @param property String to search for
+    @return Python string containing the value, or None if not found.
+    """
+    key = cf.CFStringCreateWithCString(
+            kCFAllocatorDefault,
+            property.encode("utf-8"),
+            kCFStringEncodingUTF8)
+
+    CFContainer = iokit.IORegistryEntryCreateCFProperty(
+            device_type,
+            key,
+            kCFAllocatorDefault,
+            0)
+    output = None
+
+    if CFContainer:
+        output = cf.CFStringGetCStringPtr(CFContainer, 0)
+        if output is not None:
+            output = output.decode('utf-8')
+        else:
+            buffer = ctypes.create_string_buffer(io_name_size);
+            success = cf.CFStringGetCString(CFContainer, ctypes.byref(buffer), io_name_size, kCFStringEncodingUTF8)
+            if success:
+                output = buffer.value.decode('utf-8')
+        cf.CFRelease(CFContainer)
+    return output
+
+
+def get_int_property(device_type, property, cf_number_type):
+    """
+    Search the given device for the specified string property
+
+    @param device_type Device to search
+    @param property String to search for
+    @param cf_number_type CFType number
+
+    @return Python string containing the value, or None if not found.
+    """
+    key = cf.CFStringCreateWithCString(
+            kCFAllocatorDefault,
+            property.encode("utf-8"),
+            kCFStringEncodingUTF8)
+
+    CFContainer = iokit.IORegistryEntryCreateCFProperty(
+            device_type,
+            key,
+            kCFAllocatorDefault,
+            0)
+
+    if CFContainer:
+        if (cf_number_type == kCFNumberSInt32Type):
+            number = ctypes.c_uint32()
+        elif (cf_number_type == kCFNumberSInt16Type):
+            number = ctypes.c_uint16()
+        cf.CFNumberGetValue(CFContainer, cf_number_type, ctypes.byref(number))
+        cf.CFRelease(CFContainer)
+        return number.value
+    return None
+
+def IORegistryEntryGetName(device):
+    devicename = ctypes.create_string_buffer(io_name_size);
+    res = iokit.IORegistryEntryGetName(device, ctypes.byref(devicename))
+    if res != KERN_SUCCESS:
+        return None
+    # this works in python2 but may not be valid. Also I don't know if
+    # this encoding is guaranteed. It may be dependent on system locale.
+    return devicename.value.decode('utf-8')
+
+def IOObjectGetClass(device):
+    classname = ctypes.create_string_buffer(io_name_size)
+    iokit.IOObjectGetClass(device, ctypes.byref(classname))
+    return classname.value
+
+def GetParentDeviceByType(device, parent_type):
+    """ Find the first parent of a device that implements the parent_type
+        @param IOService Service to inspect
+        @return Pointer to the parent type, or None if it was not found.
+    """
+    # First, try to walk up the IOService tree to find a parent of this device that is a IOUSBDevice.
+    parent_type = parent_type.encode('utf-8')
+    while IOObjectGetClass(device) != parent_type:
+        parent = ctypes.c_void_p()
+        response = iokit.IORegistryEntryGetParentEntry(
+                device,
+                "IOService".encode("utf-8"),
+                ctypes.byref(parent))
+        # If we weren't able to find a parent for the device, we're done.
+        if response != KERN_SUCCESS:
+            return None
+        device = parent
+    return device
+
+
+def GetIOServicesByType(service_type):
+    """
+    returns iterator over specified service_type
+    """
+    serial_port_iterator = ctypes.c_void_p()
+
+    iokit.IOServiceGetMatchingServices(
+            kIOMasterPortDefault,
+            iokit.IOServiceMatching(service_type.encode('utf-8')),
+            ctypes.byref(serial_port_iterator))
+
+    services = []
+    while iokit.IOIteratorIsValid(serial_port_iterator):
+        service = iokit.IOIteratorNext(serial_port_iterator)
+        if not service:
+            break
+        services.append(service)
+    iokit.IOObjectRelease(serial_port_iterator)
+    return services
+
+
+def location_to_string(locationID):
+    """
+    helper to calculate port and bus number from locationID
+    """
+    loc = ['{}-'.format(locationID >> 24)]
+    while locationID & 0xf00000:
+        if len(loc) > 1:
+            loc.append('.')
+        loc.append('{}'.format((locationID >> 20) & 0xf))
+        locationID <<= 4
+    return ''.join(loc)
+
+
+class SuitableSerialInterface(object):
+    pass
+
+
+def scan_interfaces():
+    """
+    helper function to scan USB interfaces
+    returns a list of SuitableSerialInterface objects with name and id attributes
+    """
+    interfaces = []
+    for service in GetIOServicesByType('IOSerialBSDClient'):
+        device = get_string_property(service, "IOCalloutDevice")
+        if device:
+            usb_device = GetParentDeviceByType(service, "IOUSBInterface")
+            if usb_device:
+                name = get_string_property(usb_device, "USB Interface Name") or None
+                locationID = get_int_property(usb_device, "locationID", kCFNumberSInt32Type) or ''
+                i = SuitableSerialInterface()
+                i.id = locationID
+                i.name = name
+                interfaces.append(i)
+    return interfaces
+
+
+def search_for_locationID_in_interfaces(serial_interfaces, locationID):
+    for interface in serial_interfaces:
+        if (interface.id == locationID):
+            return interface.name
+    return None
+
+
+def comports(include_links=False):
+    # XXX include_links is currently ignored. are links in /dev even supported here?
+    # Scan for all iokit serial ports
+    services = GetIOServicesByType('IOSerialBSDClient')
+    ports = []
+    serial_interfaces = scan_interfaces()
+    for service in services:
+        # First, add the callout device file.
+        device = get_string_property(service, "IOCalloutDevice")
+        if device:
+            info = list_ports_common.ListPortInfo(device)
+            # If the serial port is implemented by IOUSBDevice
+            # NOTE IOUSBDevice was deprecated as of 10.11 and finally on Apple Silicon
+            # devices has been completely removed.  Thanks to @oskay for this patch.
+            usb_device = GetParentDeviceByType(service, "IOUSBHostDevice")
+            if not usb_device:
+                usb_device = GetParentDeviceByType(service, "IOUSBDevice")
+            if usb_device:
+                # fetch some useful informations from properties
+                info.vid = get_int_property(usb_device, "idVendor", kCFNumberSInt16Type)
+                info.pid = get_int_property(usb_device, "idProduct", kCFNumberSInt16Type)
+                info.serial_number = get_string_property(usb_device, kUSBSerialNumberString)
+                # We know this is a usb device, so the
+                # IORegistryEntryName should always be aliased to the
+                # usb product name string descriptor.
+                info.product = IORegistryEntryGetName(usb_device) or 'n/a'
+                info.manufacturer = get_string_property(usb_device, kUSBVendorString)
+                locationID = get_int_property(usb_device, "locationID", kCFNumberSInt32Type)
+                info.location = location_to_string(locationID)
+                info.interface = search_for_locationID_in_interfaces(serial_interfaces, locationID)
+                info.apply_usb_info()
+            ports.append(info)
+    return ports
+
+# test
+if __name__ == '__main__':
+    for port, desc, hwid in sorted(comports()):
+        print("{}: {} [{}]".format(port, desc, hwid))
diff --git a/src/devtools/datool/serial/tools/list_ports_posix.py b/src/devtools/datool/serial/tools/list_ports_posix.py
new file mode 100755
index 0000000..79bc8ed
--- /dev/null
+++ b/src/devtools/datool/serial/tools/list_ports_posix.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+#
+# This is a module that gathers a list of serial ports on POSIXy systems.
+# For some specific implementations, see also list_ports_linux, list_ports_osx
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2011-2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+"""\
+The ``comports`` function is expected to return an iterable that yields tuples
+of 3 strings: port name, human readable description and a hardware ID.
+
+As currently no method is known to get the second two strings easily, they are
+currently just identical to the port name.
+"""
+
+from __future__ import absolute_import
+
+import glob
+import sys
+import os
+from serial.tools import list_ports_common
+
+# try to detect the OS so that a device can be selected...
+plat = sys.platform.lower()
+
+if plat[:5] == 'linux':    # Linux (confirmed)  # noqa
+    from serial.tools.list_ports_linux import comports
+
+elif plat[:6] == 'darwin':   # OS X (confirmed)
+    from serial.tools.list_ports_osx import comports
+
+elif plat == 'cygwin':       # cygwin/win32
+    # cygwin accepts /dev/com* in many contexts
+    # (such as 'open' call, explicit 'ls'), but 'glob.glob'
+    # and bare 'ls' do not; so use /dev/ttyS* instead
+    def comports(include_links=False):
+        devices = glob.glob('/dev/ttyS*')
+        if include_links:
+            devices.extend(list_ports_common.list_links(devices))
+        return [list_ports_common.ListPortInfo(d) for d in devices]
+
+elif plat[:7] == 'openbsd':    # OpenBSD
+    def comports(include_links=False):
+        devices = glob.glob('/dev/cua*')
+        if include_links:
+            devices.extend(list_ports_common.list_links(devices))
+        return [list_ports_common.ListPortInfo(d) for d in devices]
+
+elif plat[:3] == 'bsd' or plat[:7] == 'freebsd':
+    def comports(include_links=False):
+        devices = glob.glob('/dev/cua*[!.init][!.lock]')
+        if include_links:
+            devices.extend(list_ports_common.list_links(devices))
+        return [list_ports_common.ListPortInfo(d) for d in devices]
+
+elif plat[:6] == 'netbsd':   # NetBSD
+    def comports(include_links=False):
+        """scan for available ports. return a list of device names."""
+        devices = glob.glob('/dev/dty*')
+        if include_links:
+            devices.extend(list_ports_common.list_links(devices))
+        return [list_ports_common.ListPortInfo(d) for d in devices]
+
+elif plat[:4] == 'irix':     # IRIX
+    def comports(include_links=False):
+        """scan for available ports. return a list of device names."""
+        devices = glob.glob('/dev/ttyf*')
+        if include_links:
+            devices.extend(list_ports_common.list_links(devices))
+        return [list_ports_common.ListPortInfo(d) for d in devices]
+
+elif plat[:2] == 'hp':       # HP-UX (not tested)
+    def comports(include_links=False):
+        """scan for available ports. return a list of device names."""
+        devices = glob.glob('/dev/tty*p0')
+        if include_links:
+            devices.extend(list_ports_common.list_links(devices))
+        return [list_ports_common.ListPortInfo(d) for d in devices]
+
+elif plat[:5] == 'sunos':    # Solaris/SunOS
+    def comports(include_links=False):
+        """scan for available ports. return a list of device names."""
+        devices = glob.glob('/dev/tty*c')
+        if include_links:
+            devices.extend(list_ports_common.list_links(devices))
+        return [list_ports_common.ListPortInfo(d) for d in devices]
+
+elif plat[:3] == 'aix':      # AIX
+    def comports(include_links=False):
+        """scan for available ports. return a list of device names."""
+        devices = glob.glob('/dev/tty*')
+        if include_links:
+            devices.extend(list_ports_common.list_links(devices))
+        return [list_ports_common.ListPortInfo(d) for d in devices]
+
+else:
+    # platform detection has failed...
+    import serial
+    sys.stderr.write("""\
+don't know how to enumerate ttys on this system.
+! I you know how the serial ports are named send this information to
+! the author of this module:
+
+sys.platform = {!r}
+os.name = {!r}
+pySerial version = {}
+
+also add the naming scheme of the serial ports and with a bit luck you can get
+this module running...
+""".format(sys.platform, os.name, serial.VERSION))
+    raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name))
+
+# test
+if __name__ == '__main__':
+    for port, desc, hwid in sorted(comports()):
+        print("{}: {} [{}]".format(port, desc, hwid))
diff --git a/src/devtools/datool/serial/tools/list_ports_windows.py b/src/devtools/datool/serial/tools/list_ports_windows.py
new file mode 100755
index 0000000..0b4a5b1
--- /dev/null
+++ b/src/devtools/datool/serial/tools/list_ports_windows.py
@@ -0,0 +1,427 @@
+#! python
+#
+# Enumerate serial ports on Windows including a human readable description
+# and hardware information.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2001-2016 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+from __future__ import absolute_import
+
+# pylint: disable=invalid-name,too-few-public-methods
+import re
+import ctypes
+from ctypes.wintypes import BOOL
+from ctypes.wintypes import HWND
+from ctypes.wintypes import DWORD
+from ctypes.wintypes import WORD
+from ctypes.wintypes import LONG
+from ctypes.wintypes import ULONG
+from ctypes.wintypes import HKEY
+from ctypes.wintypes import BYTE
+import serial
+from serial.win32 import ULONG_PTR
+from serial.tools import list_ports_common
+
+
+def ValidHandle(value, func, arguments):
+    if value == 0:
+        raise ctypes.WinError()
+    return value
+
+
+NULL = 0
+HDEVINFO = ctypes.c_void_p
+LPCTSTR = ctypes.c_wchar_p
+PCTSTR = ctypes.c_wchar_p
+PTSTR = ctypes.c_wchar_p
+LPDWORD = PDWORD = ctypes.POINTER(DWORD)
+#~ LPBYTE = PBYTE = ctypes.POINTER(BYTE)
+LPBYTE = PBYTE = ctypes.c_void_p        # XXX avoids error about types
+
+ACCESS_MASK = DWORD
+REGSAM = ACCESS_MASK
+
+
+class GUID(ctypes.Structure):
+    _fields_ = [
+        ('Data1', DWORD),
+        ('Data2', WORD),
+        ('Data3', WORD),
+        ('Data4', BYTE * 8),
+    ]
+
+    def __str__(self):
+        return "{{{:08x}-{:04x}-{:04x}-{}-{}}}".format(
+            self.Data1,
+            self.Data2,
+            self.Data3,
+            ''.join(["{:02x}".format(d) for d in self.Data4[:2]]),
+            ''.join(["{:02x}".format(d) for d in self.Data4[2:]]),
+        )
+
+
+class SP_DEVINFO_DATA(ctypes.Structure):
+    _fields_ = [
+        ('cbSize', DWORD),
+        ('ClassGuid', GUID),
+        ('DevInst', DWORD),
+        ('Reserved', ULONG_PTR),
+    ]
+
+    def __str__(self):
+        return "ClassGuid:{} DevInst:{}".format(self.ClassGuid, self.DevInst)
+
+
+PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA)
+
+PSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p
+
+setupapi = ctypes.windll.LoadLibrary("setupapi")
+SetupDiDestroyDeviceInfoList = setupapi.SetupDiDestroyDeviceInfoList
+SetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO]
+SetupDiDestroyDeviceInfoList.restype = BOOL
+
+SetupDiClassGuidsFromName = setupapi.SetupDiClassGuidsFromNameW
+SetupDiClassGuidsFromName.argtypes = [PCTSTR, ctypes.POINTER(GUID), DWORD, PDWORD]
+SetupDiClassGuidsFromName.restype = BOOL
+
+SetupDiEnumDeviceInfo = setupapi.SetupDiEnumDeviceInfo
+SetupDiEnumDeviceInfo.argtypes = [HDEVINFO, DWORD, PSP_DEVINFO_DATA]
+SetupDiEnumDeviceInfo.restype = BOOL
+
+SetupDiGetClassDevs = setupapi.SetupDiGetClassDevsW
+SetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD]
+SetupDiGetClassDevs.restype = HDEVINFO
+SetupDiGetClassDevs.errcheck = ValidHandle
+
+SetupDiGetDeviceRegistryProperty = setupapi.SetupDiGetDeviceRegistryPropertyW
+SetupDiGetDeviceRegistryProperty.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD]
+SetupDiGetDeviceRegistryProperty.restype = BOOL
+
+SetupDiGetDeviceInstanceId = setupapi.SetupDiGetDeviceInstanceIdW
+SetupDiGetDeviceInstanceId.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, PTSTR, DWORD, PDWORD]
+SetupDiGetDeviceInstanceId.restype = BOOL
+
+SetupDiOpenDevRegKey = setupapi.SetupDiOpenDevRegKey
+SetupDiOpenDevRegKey.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM]
+SetupDiOpenDevRegKey.restype = HKEY
+
+advapi32 = ctypes.windll.LoadLibrary("Advapi32")
+RegCloseKey = advapi32.RegCloseKey
+RegCloseKey.argtypes = [HKEY]
+RegCloseKey.restype = LONG
+
+RegQueryValueEx = advapi32.RegQueryValueExW
+RegQueryValueEx.argtypes = [HKEY, LPCTSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD]
+RegQueryValueEx.restype = LONG
+
+cfgmgr32 = ctypes.windll.LoadLibrary("Cfgmgr32")
+CM_Get_Parent = cfgmgr32.CM_Get_Parent
+CM_Get_Parent.argtypes = [PDWORD, DWORD, ULONG]
+CM_Get_Parent.restype = LONG
+
+CM_Get_Device_IDW = cfgmgr32.CM_Get_Device_IDW
+CM_Get_Device_IDW.argtypes = [DWORD, PTSTR, ULONG, ULONG]
+CM_Get_Device_IDW.restype = LONG
+
+CM_MapCrToWin32Err = cfgmgr32.CM_MapCrToWin32Err
+CM_MapCrToWin32Err.argtypes = [DWORD, DWORD]
+CM_MapCrToWin32Err.restype = DWORD
+
+
+DIGCF_PRESENT = 2
+DIGCF_DEVICEINTERFACE = 16
+INVALID_HANDLE_VALUE = 0
+ERROR_INSUFFICIENT_BUFFER = 122
+ERROR_NOT_FOUND = 1168
+SPDRP_HARDWAREID = 1
+SPDRP_FRIENDLYNAME = 12
+SPDRP_LOCATION_PATHS = 35
+SPDRP_MFG = 11
+DICS_FLAG_GLOBAL = 1
+DIREG_DEV = 0x00000001
+KEY_READ = 0x20019
+
+
+MAX_USB_DEVICE_TREE_TRAVERSAL_DEPTH = 5
+
+
+def get_parent_serial_number(child_devinst, child_vid, child_pid, depth=0, last_serial_number=None):
+    """ Get the serial number of the parent of a device.
+
+    Args:
+        child_devinst: The device instance handle to get the parent serial number of.
+        child_vid: The vendor ID of the child device.
+        child_pid: The product ID of the child device.
+        depth: The current iteration depth of the USB device tree.
+    """
+
+    # If the traversal depth is beyond the max, abandon attempting to find the serial number.
+    if depth > MAX_USB_DEVICE_TREE_TRAVERSAL_DEPTH:
+        return '' if not last_serial_number else last_serial_number
+
+    # Get the parent device instance.
+    devinst = DWORD()
+    ret = CM_Get_Parent(ctypes.byref(devinst), child_devinst, 0)
+
+    if ret:
+        win_error = CM_MapCrToWin32Err(DWORD(ret), DWORD(0))
+
+        # If there is no parent available, the child was the root device. We cannot traverse
+        # further.
+        if win_error == ERROR_NOT_FOUND:
+            return '' if not last_serial_number else last_serial_number
+
+        raise ctypes.WinError(win_error)
+
+    # Get the ID of the parent device and parse it for vendor ID, product ID, and serial number.
+    parentHardwareID = ctypes.create_unicode_buffer(250)
+
+    ret = CM_Get_Device_IDW(
+        devinst,
+        parentHardwareID,
+        ctypes.sizeof(parentHardwareID) - 1,
+        0)
+
+    if ret:
+        raise ctypes.WinError(CM_MapCrToWin32Err(DWORD(ret), DWORD(0)))
+
+    parentHardwareID_str = parentHardwareID.value
+    m = re.search(r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(&MI_(\d{2}))?(\\(.*))?',
+                  parentHardwareID_str,
+                  re.I)
+
+    # return early if we have no matches (likely malformed serial, traversed too far)
+    if not m:
+        return '' if not last_serial_number else last_serial_number
+
+    vid = None
+    pid = None
+    serial_number = None
+    if m.group(1):
+        vid = int(m.group(1), 16)
+    if m.group(3):
+        pid = int(m.group(3), 16)
+    if m.group(7):
+        serial_number = m.group(7)
+
+    # store what we found as a fallback for malformed serial values up the chain
+    found_serial_number = serial_number
+
+    # Check that the USB serial number only contains alpha-numeric characters. It may be a windows
+    # device ID (ephemeral ID).
+    if serial_number and not re.match(r'^\w+$', serial_number):
+        serial_number = None
+
+    if not vid or not pid:
+        # If pid and vid are not available at this device level, continue to the parent.
+        return get_parent_serial_number(devinst, child_vid, child_pid, depth + 1, found_serial_number)
+
+    if pid != child_pid or vid != child_vid:
+        # If the VID or PID has changed, we are no longer looking at the same physical device. The
+        # serial number is unknown.
+        return '' if not last_serial_number else last_serial_number
+
+    # In this case, the vid and pid of the parent device are identical to the child. However, if
+    # there still isn't a serial number available, continue to the next parent.
+    if not serial_number:
+        return get_parent_serial_number(devinst, child_vid, child_pid, depth + 1, found_serial_number)
+
+    # Finally, the VID and PID are identical to the child and a serial number is present, so return
+    # it.
+    return serial_number
+
+
+def iterate_comports():
+    """Return a generator that yields descriptions for serial ports"""
+    PortsGUIDs = (GUID * 8)()  # so far only seen one used, so hope 8 are enough...
+    ports_guids_size = DWORD()
+    if not SetupDiClassGuidsFromName(
+            "Ports",
+            PortsGUIDs,
+            ctypes.sizeof(PortsGUIDs),
+            ctypes.byref(ports_guids_size)):
+        raise ctypes.WinError()
+
+    ModemsGUIDs = (GUID * 8)()  # so far only seen one used, so hope 8 are enough...
+    modems_guids_size = DWORD()
+    if not SetupDiClassGuidsFromName(
+            "Modem",
+            ModemsGUIDs,
+            ctypes.sizeof(ModemsGUIDs),
+            ctypes.byref(modems_guids_size)):
+        raise ctypes.WinError()
+
+    GUIDs = PortsGUIDs[:ports_guids_size.value] + ModemsGUIDs[:modems_guids_size.value]
+
+    # repeat for all possible GUIDs
+    for index in range(len(GUIDs)):
+        bInterfaceNumber = None
+        g_hdi = SetupDiGetClassDevs(
+            ctypes.byref(GUIDs[index]),
+            None,
+            NULL,
+            DIGCF_PRESENT)  # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports
+
+        devinfo = SP_DEVINFO_DATA()
+        devinfo.cbSize = ctypes.sizeof(devinfo)
+        index = 0
+        while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)):
+            index += 1
+
+            # get the real com port name
+            hkey = SetupDiOpenDevRegKey(
+                g_hdi,
+                ctypes.byref(devinfo),
+                DICS_FLAG_GLOBAL,
+                0,
+                DIREG_DEV,  # DIREG_DRV for SW info
+                KEY_READ)
+            port_name_buffer = ctypes.create_unicode_buffer(250)
+            port_name_length = ULONG(ctypes.sizeof(port_name_buffer))
+            RegQueryValueEx(
+                hkey,
+                "PortName",
+                None,
+                None,
+                ctypes.byref(port_name_buffer),
+                ctypes.byref(port_name_length))
+            RegCloseKey(hkey)
+
+            # unfortunately does this method also include parallel ports.
+            # we could check for names starting with COM or just exclude LPT
+            # and hope that other "unknown" names are serial ports...
+            if port_name_buffer.value.startswith('LPT'):
+                continue
+
+            # hardware ID
+            szHardwareID = ctypes.create_unicode_buffer(250)
+            # try to get ID that includes serial number
+            if not SetupDiGetDeviceInstanceId(
+                    g_hdi,
+                    ctypes.byref(devinfo),
+                    #~ ctypes.byref(szHardwareID),
+                    szHardwareID,
+                    ctypes.sizeof(szHardwareID) - 1,
+                    None):
+                # fall back to more generic hardware ID if that would fail
+                if not SetupDiGetDeviceRegistryProperty(
+                        g_hdi,
+                        ctypes.byref(devinfo),
+                        SPDRP_HARDWAREID,
+                        None,
+                        ctypes.byref(szHardwareID),
+                        ctypes.sizeof(szHardwareID) - 1,
+                        None):
+                    # Ignore ERROR_INSUFFICIENT_BUFFER
+                    if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
+                        raise ctypes.WinError()
+            # stringify
+            szHardwareID_str = szHardwareID.value
+
+            info = list_ports_common.ListPortInfo(port_name_buffer.value, skip_link_detection=True)
+
+            # in case of USB, make a more readable string, similar to that form
+            # that we also generate on other platforms
+            if szHardwareID_str.startswith('USB'):
+                m = re.search(r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(&MI_(\d{2}))?(\\(.*))?', szHardwareID_str, re.I)
+                if m:
+                    info.vid = int(m.group(1), 16)
+                    if m.group(3):
+                        info.pid = int(m.group(3), 16)
+                    if m.group(5):
+                        bInterfaceNumber = int(m.group(5))
+
+                    # Check that the USB serial number only contains alpha-numeric characters. It
+                    # may be a windows device ID (ephemeral ID) for composite devices.
+                    if m.group(7) and re.match(r'^\w+$', m.group(7)):
+                        info.serial_number = m.group(7)
+                    else:
+                        info.serial_number = get_parent_serial_number(devinfo.DevInst, info.vid, info.pid)
+
+                # calculate a location string
+                loc_path_str = ctypes.create_unicode_buffer(250)
+                if SetupDiGetDeviceRegistryProperty(
+                        g_hdi,
+                        ctypes.byref(devinfo),
+                        SPDRP_LOCATION_PATHS,
+                        None,
+                        ctypes.byref(loc_path_str),
+                        ctypes.sizeof(loc_path_str) - 1,
+                        None):
+                    m = re.finditer(r'USBROOT\((\w+)\)|#USB\((\w+)\)', loc_path_str.value)
+                    location = []
+                    for g in m:
+                        if g.group(1):
+                            location.append('{:d}'.format(int(g.group(1)) + 1))
+                        else:
+                            if len(location) > 1:
+                                location.append('.')
+                            else:
+                                location.append('-')
+                            location.append(g.group(2))
+                    if bInterfaceNumber is not None:
+                        location.append(':{}.{}'.format(
+                            'x',  # XXX how to determine correct bConfigurationValue?
+                            bInterfaceNumber))
+                    if location:
+                        info.location = ''.join(location)
+                info.hwid = info.usb_info()
+            elif szHardwareID_str.startswith('FTDIBUS'):
+                m = re.search(r'VID_([0-9a-f]{4})\+PID_([0-9a-f]{4})(\+(\w+))?', szHardwareID_str, re.I)
+                if m:
+                    info.vid = int(m.group(1), 16)
+                    info.pid = int(m.group(2), 16)
+                    if m.group(4):
+                        info.serial_number = m.group(4)
+                # USB location is hidden by FDTI driver :(
+                info.hwid = info.usb_info()
+            else:
+                info.hwid = szHardwareID_str
+
+            # friendly name
+            szFriendlyName = ctypes.create_unicode_buffer(250)
+            if SetupDiGetDeviceRegistryProperty(
+                    g_hdi,
+                    ctypes.byref(devinfo),
+                    SPDRP_FRIENDLYNAME,
+                    #~ SPDRP_DEVICEDESC,
+                    None,
+                    ctypes.byref(szFriendlyName),
+                    ctypes.sizeof(szFriendlyName) - 1,
+                    None):
+                info.description = szFriendlyName.value
+            #~ else:
+                # Ignore ERROR_INSUFFICIENT_BUFFER
+                #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
+                    #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value))
+                # ignore errors and still include the port in the list, friendly name will be same as port name
+
+            # manufacturer
+            szManufacturer = ctypes.create_unicode_buffer(250)
+            if SetupDiGetDeviceRegistryProperty(
+                    g_hdi,
+                    ctypes.byref(devinfo),
+                    SPDRP_MFG,
+                    #~ SPDRP_DEVICEDESC,
+                    None,
+                    ctypes.byref(szManufacturer),
+                    ctypes.sizeof(szManufacturer) - 1,
+                    None):
+                info.manufacturer = szManufacturer.value
+            yield info
+        SetupDiDestroyDeviceInfoList(g_hdi)
+
+
+def comports(include_links=False):
+    """Return a list of info objects about serial ports"""
+    return list(iterate_comports())
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# test
+if __name__ == '__main__':
+    for port, desc, hwid in sorted(comports()):
+        print("{}: {} [{}]".format(port, desc, hwid))
diff --git a/src/devtools/datool/serial/tools/miniterm.py b/src/devtools/datool/serial/tools/miniterm.py
new file mode 100755
index 0000000..2cceff6
--- /dev/null
+++ b/src/devtools/datool/serial/tools/miniterm.py
@@ -0,0 +1,1042 @@
+#!/usr/bin/env python
+#
+# Very simple serial terminal
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C)2002-2020 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+from __future__ import absolute_import
+
+import codecs
+import os
+import sys
+import threading
+
+import serial
+from serial.tools.list_ports import comports
+from serial.tools import hexlify_codec
+
+# pylint: disable=wrong-import-order,wrong-import-position
+
+codecs.register(lambda c: hexlify_codec.getregentry() if c == 'hexlify' else None)
+
+try:
+    raw_input
+except NameError:
+    # pylint: disable=redefined-builtin,invalid-name
+    raw_input = input   # in python3 it's "raw"
+    unichr = chr
+
+
+def key_description(character):
+    """generate a readable description for a key"""
+    ascii_code = ord(character)
+    if ascii_code < 32:
+        return 'Ctrl+{:c}'.format(ord('@') + ascii_code)
+    else:
+        return repr(character)
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+class ConsoleBase(object):
+    """OS abstraction for console (input/output codec, no echo)"""
+
+    def __init__(self):
+        if sys.version_info >= (3, 0):
+            self.byte_output = sys.stdout.buffer
+        else:
+            self.byte_output = sys.stdout
+        self.output = sys.stdout
+
+    def setup(self):
+        """Set console to read single characters, no echo"""
+
+    def cleanup(self):
+        """Restore default console settings"""
+
+    def getkey(self):
+        """Read a single key from the console"""
+        return None
+
+    def write_bytes(self, byte_string):
+        """Write bytes (already encoded)"""
+        self.byte_output.write(byte_string)
+        self.byte_output.flush()
+
+    def write(self, text):
+        """Write string"""
+        self.output.write(text)
+        self.output.flush()
+
+    def cancel(self):
+        """Cancel getkey operation"""
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+    # context manager:
+    # switch terminal temporary to normal mode (e.g. to get user input)
+
+    def __enter__(self):
+        self.cleanup()
+        return self
+
+    def __exit__(self, *args, **kwargs):
+        self.setup()
+
+
+if os.name == 'nt':  # noqa
+    import msvcrt
+    import ctypes
+    import platform
+
+    class Out(object):
+        """file-like wrapper that uses os.write"""
+
+        def __init__(self, fd):
+            self.fd = fd
+
+        def flush(self):
+            pass
+
+        def write(self, s):
+            os.write(self.fd, s)
+
+    class Console(ConsoleBase):
+        fncodes = {
+            ';': '\1bOP',  # F1
+            '<': '\1bOQ',  # F2
+            '=': '\1bOR',  # F3
+            '>': '\1bOS',  # F4
+            '?': '\1b[15~',  # F5
+            '@': '\1b[17~',  # F6
+            'A': '\1b[18~',  # F7
+            'B': '\1b[19~',  # F8
+            'C': '\1b[20~',  # F9
+            'D': '\1b[21~',  # F10
+        }
+        navcodes = {
+            'H': '\x1b[A',  # UP
+            'P': '\x1b[B',  # DOWN
+            'K': '\x1b[D',  # LEFT
+            'M': '\x1b[C',  # RIGHT
+            'G': '\x1b[H',  # HOME
+            'O': '\x1b[F',  # END
+            'R': '\x1b[2~',  # INSERT
+            'S': '\x1b[3~',  # DELETE
+            'I': '\x1b[5~',  # PGUP
+            'Q': '\x1b[6~',  # PGDN        
+        }
+        
+        def __init__(self):
+            super(Console, self).__init__()
+            self._saved_ocp = ctypes.windll.kernel32.GetConsoleOutputCP()
+            self._saved_icp = ctypes.windll.kernel32.GetConsoleCP()
+            ctypes.windll.kernel32.SetConsoleOutputCP(65001)
+            ctypes.windll.kernel32.SetConsoleCP(65001)
+            # ANSI handling available through SetConsoleMode since Windows 10 v1511 
+            # https://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-win10th2-1
+            if platform.release() == '10' and int(platform.version().split('.')[2]) > 10586:
+                ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
+                import ctypes.wintypes as wintypes
+                if not hasattr(wintypes, 'LPDWORD'): # PY2
+                    wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)
+                SetConsoleMode = ctypes.windll.kernel32.SetConsoleMode
+                GetConsoleMode = ctypes.windll.kernel32.GetConsoleMode
+                GetStdHandle = ctypes.windll.kernel32.GetStdHandle
+                mode = wintypes.DWORD()
+                GetConsoleMode(GetStdHandle(-11), ctypes.byref(mode))
+                if (mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0:
+                    SetConsoleMode(GetStdHandle(-11), mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+                    self._saved_cm = mode
+            self.output = codecs.getwriter('UTF-8')(Out(sys.stdout.fileno()), 'replace')
+            # the change of the code page is not propagated to Python, manually fix it
+            sys.stderr = codecs.getwriter('UTF-8')(Out(sys.stderr.fileno()), 'replace')
+            sys.stdout = self.output
+            self.output.encoding = 'UTF-8'  # needed for input
+
+        def __del__(self):
+            ctypes.windll.kernel32.SetConsoleOutputCP(self._saved_ocp)
+            ctypes.windll.kernel32.SetConsoleCP(self._saved_icp)
+            try:
+                ctypes.windll.kernel32.SetConsoleMode(ctypes.windll.kernel32.GetStdHandle(-11), self._saved_cm)
+            except AttributeError: # in case no _saved_cm
+                pass
+
+        def getkey(self):
+            while True:
+                z = msvcrt.getwch()
+                if z == unichr(13):
+                    return unichr(10)
+                elif z is unichr(0) or z is unichr(0xe0):
+                    try:
+                        code = msvcrt.getwch()
+                        if z is unichr(0):
+                            return self.fncodes[code]
+                        else:
+                            return self.navcodes[code]
+                    except KeyError:
+                        pass
+                else:
+                    return z
+
+        def cancel(self):
+            # CancelIo, CancelSynchronousIo do not seem to work when using
+            # getwch, so instead, send a key to the window with the console
+            hwnd = ctypes.windll.kernel32.GetConsoleWindow()
+            ctypes.windll.user32.PostMessageA(hwnd, 0x100, 0x0d, 0)
+
+elif os.name == 'posix':
+    import atexit
+    import termios
+    import fcntl
+
+    class Console(ConsoleBase):
+        def __init__(self):
+            super(Console, self).__init__()
+            self.fd = sys.stdin.fileno()
+            self.old = termios.tcgetattr(self.fd)
+            atexit.register(self.cleanup)
+            if sys.version_info < (3, 0):
+                self.enc_stdin = codecs.getreader(sys.stdin.encoding)(sys.stdin)
+            else:
+                self.enc_stdin = sys.stdin
+
+        def setup(self):
+            new = termios.tcgetattr(self.fd)
+            new[3] = new[3] & ~termios.ICANON & ~termios.ECHO & ~termios.ISIG
+            new[6][termios.VMIN] = 1
+            new[6][termios.VTIME] = 0
+            termios.tcsetattr(self.fd, termios.TCSANOW, new)
+
+        def getkey(self):
+            c = self.enc_stdin.read(1)
+            if c == unichr(0x7f):
+                c = unichr(8)    # map the BS key (which yields DEL) to backspace
+            return c
+
+        def cancel(self):
+            fcntl.ioctl(self.fd, termios.TIOCSTI, b'\0')
+
+        def cleanup(self):
+            termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old)
+
+else:
+    raise NotImplementedError(
+        'Sorry no implementation for your platform ({}) available.'.format(sys.platform))
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+class Transform(object):
+    """do-nothing: forward all data unchanged"""
+    def rx(self, text):
+        """text received from serial port"""
+        return text
+
+    def tx(self, text):
+        """text to be sent to serial port"""
+        return text
+
+    def echo(self, text):
+        """text to be sent but displayed on console"""
+        return text
+
+
+class CRLF(Transform):
+    """ENTER sends CR+LF"""
+
+    def tx(self, text):
+        return text.replace('\n', '\r\n')
+
+
+class CR(Transform):
+    """ENTER sends CR"""
+
+    def rx(self, text):
+        return text.replace('\r', '\n')
+
+    def tx(self, text):
+        return text.replace('\n', '\r')
+
+
+class LF(Transform):
+    """ENTER sends LF"""
+
+
+class NoTerminal(Transform):
+    """remove typical terminal control codes from input"""
+
+    REPLACEMENT_MAP = dict((x, 0x2400 + x) for x in range(32) if unichr(x) not in '\r\n\b\t')
+    REPLACEMENT_MAP.update(
+        {
+            0x7F: 0x2421,  # DEL
+            0x9B: 0x2425,  # CSI
+        })
+
+    def rx(self, text):
+        return text.translate(self.REPLACEMENT_MAP)
+
+    echo = rx
+
+
+class NoControls(NoTerminal):
+    """Remove all control codes, incl. CR+LF"""
+
+    REPLACEMENT_MAP = dict((x, 0x2400 + x) for x in range(32))
+    REPLACEMENT_MAP.update(
+        {
+            0x20: 0x2423,  # visual space
+            0x7F: 0x2421,  # DEL
+            0x9B: 0x2425,  # CSI
+        })
+
+
+class Printable(Transform):
+    """Show decimal code for all non-ASCII characters and replace most control codes"""
+
+    def rx(self, text):
+        r = []
+        for c in text:
+            if ' ' <= c < '\x7f' or c in '\r\n\b\t':
+                r.append(c)
+            elif c < ' ':
+                r.append(unichr(0x2400 + ord(c)))
+            else:
+                r.extend(unichr(0x2080 + ord(d) - 48) for d in '{:d}'.format(ord(c)))
+                r.append(' ')
+        return ''.join(r)
+
+    echo = rx
+
+
+class Colorize(Transform):
+    """Apply different colors for received and echo"""
+
+    def __init__(self):
+        # XXX make it configurable, use colorama?
+        self.input_color = '\x1b[37m'
+        self.echo_color = '\x1b[31m'
+
+    def rx(self, text):
+        return self.input_color + text
+
+    def echo(self, text):
+        return self.echo_color + text
+
+
+class DebugIO(Transform):
+    """Print what is sent and received"""
+
+    def rx(self, text):
+        sys.stderr.write(' [RX:{!r}] '.format(text))
+        sys.stderr.flush()
+        return text
+
+    def tx(self, text):
+        sys.stderr.write(' [TX:{!r}] '.format(text))
+        sys.stderr.flush()
+        return text
+
+
+# other ideas:
+# - add date/time for each newline
+# - insert newline after: a) timeout b) packet end character
+
+EOL_TRANSFORMATIONS = {
+    'crlf': CRLF,
+    'cr': CR,
+    'lf': LF,
+}
+
+TRANSFORMATIONS = {
+    'direct': Transform,    # no transformation
+    'default': NoTerminal,
+    'nocontrol': NoControls,
+    'printable': Printable,
+    'colorize': Colorize,
+    'debug': DebugIO,
+}
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def ask_for_port():
+    """\
+    Show a list of ports and ask the user for a choice. To make selection
+    easier on systems with long device names, also allow the input of an
+    index.
+    """
+    sys.stderr.write('\n--- Available ports:\n')
+    ports = []
+    for n, (port, desc, hwid) in enumerate(sorted(comports()), 1):
+        sys.stderr.write('--- {:2}: {:20} {!r}\n'.format(n, port, desc))
+        ports.append(port)
+    while True:
+        port = raw_input('--- Enter port index or full name: ')
+        try:
+            index = int(port) - 1
+            if not 0 <= index < len(ports):
+                sys.stderr.write('--- Invalid index!\n')
+                continue
+        except ValueError:
+            pass
+        else:
+            port = ports[index]
+        return port
+
+
+class Miniterm(object):
+    """\
+    Terminal application. Copy data from serial port to console and vice versa.
+    Handle special keys from the console to show menu etc.
+    """
+
+    def __init__(self, serial_instance, echo=False, eol='crlf', filters=()):
+        self.console = Console()
+        self.serial = serial_instance
+        self.echo = echo
+        self.raw = False
+        self.input_encoding = 'UTF-8'
+        self.output_encoding = 'UTF-8'
+        self.eol = eol
+        self.filters = filters
+        self.update_transformations()
+        self.exit_character = unichr(0x1d)  # GS/CTRL+]
+        self.menu_character = unichr(0x14)  # Menu: CTRL+T
+        self.alive = None
+        self._reader_alive = None
+        self.receiver_thread = None
+        self.rx_decoder = None
+        self.tx_decoder = None
+
+    def _start_reader(self):
+        """Start reader thread"""
+        self._reader_alive = True
+        # start serial->console thread
+        self.receiver_thread = threading.Thread(target=self.reader, name='rx')
+        self.receiver_thread.daemon = True
+        self.receiver_thread.start()
+
+    def _stop_reader(self):
+        """Stop reader thread only, wait for clean exit of thread"""
+        self._reader_alive = False
+        if hasattr(self.serial, 'cancel_read'):
+            self.serial.cancel_read()
+        self.receiver_thread.join()
+
+    def start(self):
+        """start worker threads"""
+        self.alive = True
+        self._start_reader()
+        # enter console->serial loop
+        self.transmitter_thread = threading.Thread(target=self.writer, name='tx')
+        self.transmitter_thread.daemon = True
+        self.transmitter_thread.start()
+        self.console.setup()
+
+    def stop(self):
+        """set flag to stop worker threads"""
+        self.alive = False
+
+    def join(self, transmit_only=False):
+        """wait for worker threads to terminate"""
+        self.transmitter_thread.join()
+        if not transmit_only:
+            if hasattr(self.serial, 'cancel_read'):
+                self.serial.cancel_read()
+            self.receiver_thread.join()
+
+    def close(self):
+        self.serial.close()
+
+    def update_transformations(self):
+        """take list of transformation classes and instantiate them for rx and tx"""
+        transformations = [EOL_TRANSFORMATIONS[self.eol]] + [TRANSFORMATIONS[f]
+                                                             for f in self.filters]
+        self.tx_transformations = [t() for t in transformations]
+        self.rx_transformations = list(reversed(self.tx_transformations))
+
+    def set_rx_encoding(self, encoding, errors='replace'):
+        """set encoding for received data"""
+        self.input_encoding = encoding
+        self.rx_decoder = codecs.getincrementaldecoder(encoding)(errors)
+
+    def set_tx_encoding(self, encoding, errors='replace'):
+        """set encoding for transmitted data"""
+        self.output_encoding = encoding
+        self.tx_encoder = codecs.getincrementalencoder(encoding)(errors)
+
+    def dump_port_settings(self):
+        """Write current settings to sys.stderr"""
+        sys.stderr.write("\n--- Settings: {p.name}  {p.baudrate},{p.bytesize},{p.parity},{p.stopbits}\n".format(
+            p=self.serial))
+        sys.stderr.write('--- RTS: {:8}  DTR: {:8}  BREAK: {:8}\n'.format(
+            ('active' if self.serial.rts else 'inactive'),
+            ('active' if self.serial.dtr else 'inactive'),
+            ('active' if self.serial.break_condition else 'inactive')))
+        try:
+            sys.stderr.write('--- CTS: {:8}  DSR: {:8}  RI: {:8}  CD: {:8}\n'.format(
+                ('active' if self.serial.cts else 'inactive'),
+                ('active' if self.serial.dsr else 'inactive'),
+                ('active' if self.serial.ri else 'inactive'),
+                ('active' if self.serial.cd else 'inactive')))
+        except serial.SerialException:
+            # on RFC 2217 ports, it can happen if no modem state notification was
+            # yet received. ignore this error.
+            pass
+        sys.stderr.write('--- software flow control: {}\n'.format('active' if self.serial.xonxoff else 'inactive'))
+        sys.stderr.write('--- hardware flow control: {}\n'.format('active' if self.serial.rtscts else 'inactive'))
+        sys.stderr.write('--- serial input encoding: {}\n'.format(self.input_encoding))
+        sys.stderr.write('--- serial output encoding: {}\n'.format(self.output_encoding))
+        sys.stderr.write('--- EOL: {}\n'.format(self.eol.upper()))
+        sys.stderr.write('--- filters: {}\n'.format(' '.join(self.filters)))
+
+    def reader(self):
+        """loop and copy serial->console"""
+        try:
+            while self.alive and self._reader_alive:
+                # read all that is there or wait for one byte
+                data = self.serial.read(self.serial.in_waiting or 1)
+                if data:
+                    if self.raw:
+                        self.console.write_bytes(data)
+                    else:
+                        text = self.rx_decoder.decode(data)
+                        for transformation in self.rx_transformations:
+                            text = transformation.rx(text)
+                        self.console.write(text)
+        except serial.SerialException:
+            self.alive = False
+            self.console.cancel()
+            raise       # XXX handle instead of re-raise?
+
+    def writer(self):
+        """\
+        Loop and copy console->serial until self.exit_character character is
+        found. When self.menu_character is found, interpret the next key
+        locally.
+        """
+        menu_active = False
+        try:
+            while self.alive:
+                try:
+                    c = self.console.getkey()
+                except KeyboardInterrupt:
+                    c = '\x03'
+                if not self.alive:
+                    break
+                if menu_active:
+                    self.handle_menu_key(c)
+                    menu_active = False
+                elif c == self.menu_character:
+                    menu_active = True      # next char will be for menu
+                elif c == self.exit_character:
+                    self.stop()             # exit app
+                    break
+                else:
+                    #~ if self.raw:
+                    text = c
+                    for transformation in self.tx_transformations:
+                        text = transformation.tx(text)
+                    self.serial.write(self.tx_encoder.encode(text))
+                    if self.echo:
+                        echo_text = c
+                        for transformation in self.tx_transformations:
+                            echo_text = transformation.echo(echo_text)
+                        self.console.write(echo_text)
+        except:
+            self.alive = False
+            raise
+
+    def handle_menu_key(self, c):
+        """Implement a simple menu / settings"""
+        if c == self.menu_character or c == self.exit_character:
+            # Menu/exit character again -> send itself
+            self.serial.write(self.tx_encoder.encode(c))
+            if self.echo:
+                self.console.write(c)
+        elif c == '\x15':                       # CTRL+U -> upload file
+            self.upload_file()
+        elif c in '\x08hH?':                    # CTRL+H, h, H, ? -> Show help
+            sys.stderr.write(self.get_help_text())
+        elif c == '\x12':                       # CTRL+R -> Toggle RTS
+            self.serial.rts = not self.serial.rts
+            sys.stderr.write('--- RTS {} ---\n'.format('active' if self.serial.rts else 'inactive'))
+        elif c == '\x04':                       # CTRL+D -> Toggle DTR
+            self.serial.dtr = not self.serial.dtr
+            sys.stderr.write('--- DTR {} ---\n'.format('active' if self.serial.dtr else 'inactive'))
+        elif c == '\x02':                       # CTRL+B -> toggle BREAK condition
+            self.serial.break_condition = not self.serial.break_condition
+            sys.stderr.write('--- BREAK {} ---\n'.format('active' if self.serial.break_condition else 'inactive'))
+        elif c == '\x05':                       # CTRL+E -> toggle local echo
+            self.echo = not self.echo
+            sys.stderr.write('--- local echo {} ---\n'.format('active' if self.echo else 'inactive'))
+        elif c == '\x06':                       # CTRL+F -> edit filters
+            self.change_filter()
+        elif c == '\x0c':                       # CTRL+L -> EOL mode
+            modes = list(EOL_TRANSFORMATIONS)   # keys
+            eol = modes.index(self.eol) + 1
+            if eol >= len(modes):
+                eol = 0
+            self.eol = modes[eol]
+            sys.stderr.write('--- EOL: {} ---\n'.format(self.eol.upper()))
+            self.update_transformations()
+        elif c == '\x01':                       # CTRL+A -> set encoding
+            self.change_encoding()
+        elif c == '\x09':                       # CTRL+I -> info
+            self.dump_port_settings()
+        #~ elif c == '\x01':                       # CTRL+A -> cycle escape mode
+        #~ elif c == '\x0c':                       # CTRL+L -> cycle linefeed mode
+        elif c in 'pP':                         # P -> change port
+            self.change_port()
+        elif c in 'zZ':                         # S -> suspend / open port temporarily
+            self.suspend_port()
+        elif c in 'bB':                         # B -> change baudrate
+            self.change_baudrate()
+        elif c == '8':                          # 8 -> change to 8 bits
+            self.serial.bytesize = serial.EIGHTBITS
+            self.dump_port_settings()
+        elif c == '7':                          # 7 -> change to 8 bits
+            self.serial.bytesize = serial.SEVENBITS
+            self.dump_port_settings()
+        elif c in 'eE':                         # E -> change to even parity
+            self.serial.parity = serial.PARITY_EVEN
+            self.dump_port_settings()
+        elif c in 'oO':                         # O -> change to odd parity
+            self.serial.parity = serial.PARITY_ODD
+            self.dump_port_settings()
+        elif c in 'mM':                         # M -> change to mark parity
+            self.serial.parity = serial.PARITY_MARK
+            self.dump_port_settings()
+        elif c in 'sS':                         # S -> change to space parity
+            self.serial.parity = serial.PARITY_SPACE
+            self.dump_port_settings()
+        elif c in 'nN':                         # N -> change to no parity
+            self.serial.parity = serial.PARITY_NONE
+            self.dump_port_settings()
+        elif c == '1':                          # 1 -> change to 1 stop bits
+            self.serial.stopbits = serial.STOPBITS_ONE
+            self.dump_port_settings()
+        elif c == '2':                          # 2 -> change to 2 stop bits
+            self.serial.stopbits = serial.STOPBITS_TWO
+            self.dump_port_settings()
+        elif c == '3':                          # 3 -> change to 1.5 stop bits
+            self.serial.stopbits = serial.STOPBITS_ONE_POINT_FIVE
+            self.dump_port_settings()
+        elif c in 'xX':                         # X -> change software flow control
+            self.serial.xonxoff = (c == 'X')
+            self.dump_port_settings()
+        elif c in 'rR':                         # R -> change hardware flow control
+            self.serial.rtscts = (c == 'R')
+            self.dump_port_settings()
+        elif c in 'qQ':
+            self.stop()                         # Q -> exit app
+        else:
+            sys.stderr.write('--- unknown menu character {} --\n'.format(key_description(c)))
+
+    def upload_file(self):
+        """Ask user for filenname and send its contents"""
+        sys.stderr.write('\n--- File to upload: ')
+        sys.stderr.flush()
+        with self.console:
+            filename = sys.stdin.readline().rstrip('\r\n')
+            if filename:
+                try:
+                    with open(filename, 'rb') as f:
+                        sys.stderr.write('--- Sending file {} ---\n'.format(filename))
+                        while True:
+                            block = f.read(1024)
+                            if not block:
+                                break
+                            self.serial.write(block)
+                            # Wait for output buffer to drain.
+                            self.serial.flush()
+                            sys.stderr.write('.')   # Progress indicator.
+                    sys.stderr.write('\n--- File {} sent ---\n'.format(filename))
+                except IOError as e:
+                    sys.stderr.write('--- ERROR opening file {}: {} ---\n'.format(filename, e))
+
+    def change_filter(self):
+        """change the i/o transformations"""
+        sys.stderr.write('\n--- Available Filters:\n')
+        sys.stderr.write('\n'.join(
+            '---   {:<10} = {.__doc__}'.format(k, v)
+            for k, v in sorted(TRANSFORMATIONS.items())))
+        sys.stderr.write('\n--- Enter new filter name(s) [{}]: '.format(' '.join(self.filters)))
+        with self.console:
+            new_filters = sys.stdin.readline().lower().split()
+        if new_filters:
+            for f in new_filters:
+                if f not in TRANSFORMATIONS:
+                    sys.stderr.write('--- unknown filter: {!r}\n'.format(f))
+                    break
+            else:
+                self.filters = new_filters
+                self.update_transformations()
+        sys.stderr.write('--- filters: {}\n'.format(' '.join(self.filters)))
+
+    def change_encoding(self):
+        """change encoding on the serial port"""
+        sys.stderr.write('\n--- Enter new encoding name [{}]: '.format(self.input_encoding))
+        with self.console:
+            new_encoding = sys.stdin.readline().strip()
+        if new_encoding:
+            try:
+                codecs.lookup(new_encoding)
+            except LookupError:
+                sys.stderr.write('--- invalid encoding name: {}\n'.format(new_encoding))
+            else:
+                self.set_rx_encoding(new_encoding)
+                self.set_tx_encoding(new_encoding)
+        sys.stderr.write('--- serial input encoding: {}\n'.format(self.input_encoding))
+        sys.stderr.write('--- serial output encoding: {}\n'.format(self.output_encoding))
+
+    def change_baudrate(self):
+        """change the baudrate"""
+        sys.stderr.write('\n--- Baudrate: ')
+        sys.stderr.flush()
+        with self.console:
+            backup = self.serial.baudrate
+            try:
+                self.serial.baudrate = int(sys.stdin.readline().strip())
+            except ValueError as e:
+                sys.stderr.write('--- ERROR setting baudrate: {} ---\n'.format(e))
+                self.serial.baudrate = backup
+            else:
+                self.dump_port_settings()
+
+    def change_port(self):
+        """Have a conversation with the user to change the serial port"""
+        with self.console:
+            try:
+                port = ask_for_port()
+            except KeyboardInterrupt:
+                port = None
+        if port and port != self.serial.port:
+            # reader thread needs to be shut down
+            self._stop_reader()
+            # save settings
+            settings = self.serial.getSettingsDict()
+            try:
+                new_serial = serial.serial_for_url(port, do_not_open=True)
+                # restore settings and open
+                new_serial.applySettingsDict(settings)
+                new_serial.rts = self.serial.rts
+                new_serial.dtr = self.serial.dtr
+                new_serial.open()
+                new_serial.break_condition = self.serial.break_condition
+            except Exception as e:
+                sys.stderr.write('--- ERROR opening new port: {} ---\n'.format(e))
+                new_serial.close()
+            else:
+                self.serial.close()
+                self.serial = new_serial
+                sys.stderr.write('--- Port changed to: {} ---\n'.format(self.serial.port))
+            # and restart the reader thread
+            self._start_reader()
+
+    def suspend_port(self):
+        """\
+        open port temporarily, allow reconnect, exit and port change to get
+        out of the loop
+        """
+        # reader thread needs to be shut down
+        self._stop_reader()
+        self.serial.close()
+        sys.stderr.write('\n--- Port closed: {} ---\n'.format(self.serial.port))
+        do_change_port = False
+        while not self.serial.is_open:
+            sys.stderr.write('--- Quit: {exit} | p: port change | any other key to reconnect ---\n'.format(
+                exit=key_description(self.exit_character)))
+            k = self.console.getkey()
+            if k == self.exit_character:
+                self.stop()             # exit app
+                break
+            elif k in 'pP':
+                do_change_port = True
+                break
+            try:
+                self.serial.open()
+            except Exception as e:
+                sys.stderr.write('--- ERROR opening port: {} ---\n'.format(e))
+        if do_change_port:
+            self.change_port()
+        else:
+            # and restart the reader thread
+            self._start_reader()
+            sys.stderr.write('--- Port opened: {} ---\n'.format(self.serial.port))
+
+    def get_help_text(self):
+        """return the help text"""
+        # help text, starts with blank line!
+        return """
+--- pySerial ({version}) - miniterm - help
+---
+--- {exit:8} Exit program (alias {menu} Q)
+--- {menu:8} Menu escape key, followed by:
+--- Menu keys:
+---    {menu:7} Send the menu character itself to remote
+---    {exit:7} Send the exit character itself to remote
+---    {info:7} Show info
+---    {upload:7} Upload file (prompt will be shown)
+---    {repr:7} encoding
+---    {filter:7} edit filters
+--- Toggles:
+---    {rts:7} RTS   {dtr:7} DTR   {brk:7} BREAK
+---    {echo:7} echo  {eol:7} EOL
+---
+--- Port settings ({menu} followed by the following):
+---    p          change port
+---    7 8        set data bits
+---    N E O S M  change parity (None, Even, Odd, Space, Mark)
+---    1 2 3      set stop bits (1, 2, 1.5)
+---    b          change baud rate
+---    x X        disable/enable software flow control
+---    r R        disable/enable hardware flow control
+""".format(version=getattr(serial, 'VERSION', 'unknown version'),
+           exit=key_description(self.exit_character),
+           menu=key_description(self.menu_character),
+           rts=key_description('\x12'),
+           dtr=key_description('\x04'),
+           brk=key_description('\x02'),
+           echo=key_description('\x05'),
+           info=key_description('\x09'),
+           upload=key_description('\x15'),
+           repr=key_description('\x01'),
+           filter=key_description('\x06'),
+           eol=key_description('\x0c'))
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# default args can be used to override when calling main() from an other script
+# e.g to create a miniterm-my-device.py
+def main(default_port=None, default_baudrate=9600, default_rts=None, default_dtr=None):
+    """Command line tool, entry point"""
+
+    import argparse
+
+    parser = argparse.ArgumentParser(
+        description='Miniterm - A simple terminal program for the serial port.')
+
+    parser.add_argument(
+        'port',
+        nargs='?',
+        help='serial port name ("-" to show port list)',
+        default=default_port)
+
+    parser.add_argument(
+        'baudrate',
+        nargs='?',
+        type=int,
+        help='set baud rate, default: %(default)s',
+        default=default_baudrate)
+
+    group = parser.add_argument_group('port settings')
+
+    group.add_argument(
+        '--parity',
+        choices=['N', 'E', 'O', 'S', 'M'],
+        type=lambda c: c.upper(),
+        help='set parity, one of {N E O S M}, default: N',
+        default='N')
+
+    group.add_argument(
+        '--rtscts',
+        action='store_true',
+        help='enable RTS/CTS flow control (default off)',
+        default=False)
+
+    group.add_argument(
+        '--xonxoff',
+        action='store_true',
+        help='enable software flow control (default off)',
+        default=False)
+
+    group.add_argument(
+        '--rts',
+        type=int,
+        help='set initial RTS line state (possible values: 0, 1)',
+        default=default_rts)
+
+    group.add_argument(
+        '--dtr',
+        type=int,
+        help='set initial DTR line state (possible values: 0, 1)',
+        default=default_dtr)
+
+    group.add_argument(
+        '--non-exclusive',
+        dest='exclusive',
+        action='store_false',
+        help='disable locking for native ports',
+        default=True)
+
+    group.add_argument(
+        '--ask',
+        action='store_true',
+        help='ask again for port when open fails',
+        default=False)
+
+    group = parser.add_argument_group('data handling')
+
+    group.add_argument(
+        '-e', '--echo',
+        action='store_true',
+        help='enable local echo (default off)',
+        default=False)
+
+    group.add_argument(
+        '--encoding',
+        dest='serial_port_encoding',
+        metavar='CODEC',
+        help='set the encoding for the serial port (e.g. hexlify, Latin1, UTF-8), default: %(default)s',
+        default='UTF-8')
+
+    group.add_argument(
+        '-f', '--filter',
+        action='append',
+        metavar='NAME',
+        help='add text transformation',
+        default=[])
+
+    group.add_argument(
+        '--eol',
+        choices=['CR', 'LF', 'CRLF'],
+        type=lambda c: c.upper(),
+        help='end of line mode',
+        default='CRLF')
+
+    group.add_argument(
+        '--raw',
+        action='store_true',
+        help='Do no apply any encodings/transformations',
+        default=False)
+
+    group = parser.add_argument_group('hotkeys')
+
+    group.add_argument(
+        '--exit-char',
+        type=int,
+        metavar='NUM',
+        help='Unicode of special character that is used to exit the application, default: %(default)s',
+        default=0x1d)  # GS/CTRL+]
+
+    group.add_argument(
+        '--menu-char',
+        type=int,
+        metavar='NUM',
+        help='Unicode code of special character that is used to control miniterm (menu), default: %(default)s',
+        default=0x14)  # Menu: CTRL+T
+
+    group = parser.add_argument_group('diagnostics')
+
+    group.add_argument(
+        '-q', '--quiet',
+        action='store_true',
+        help='suppress non-error messages',
+        default=False)
+
+    group.add_argument(
+        '--develop',
+        action='store_true',
+        help='show Python traceback on error',
+        default=False)
+
+    args = parser.parse_args()
+
+    if args.menu_char == args.exit_char:
+        parser.error('--exit-char can not be the same as --menu-char')
+
+    if args.filter:
+        if 'help' in args.filter:
+            sys.stderr.write('Available filters:\n')
+            sys.stderr.write('\n'.join(
+                '{:<10} = {.__doc__}'.format(k, v)
+                for k, v in sorted(TRANSFORMATIONS.items())))
+            sys.stderr.write('\n')
+            sys.exit(1)
+        filters = args.filter
+    else:
+        filters = ['default']
+
+    while True:
+        # no port given on command line -> ask user now
+        if args.port is None or args.port == '-':
+            try:
+                args.port = ask_for_port()
+            except KeyboardInterrupt:
+                sys.stderr.write('\n')
+                parser.error('user aborted and port is not given')
+            else:
+                if not args.port:
+                    parser.error('port is not given')
+        try:
+            serial_instance = serial.serial_for_url(
+                args.port,
+                args.baudrate,
+                parity=args.parity,
+                rtscts=args.rtscts,
+                xonxoff=args.xonxoff,
+                do_not_open=True)
+
+            if not hasattr(serial_instance, 'cancel_read'):
+                # enable timeout for alive flag polling if cancel_read is not available
+                serial_instance.timeout = 1
+
+            if args.dtr is not None:
+                if not args.quiet:
+                    sys.stderr.write('--- forcing DTR {}\n'.format('active' if args.dtr else 'inactive'))
+                serial_instance.dtr = args.dtr
+            if args.rts is not None:
+                if not args.quiet:
+                    sys.stderr.write('--- forcing RTS {}\n'.format('active' if args.rts else 'inactive'))
+                serial_instance.rts = args.rts
+
+            if isinstance(serial_instance, serial.Serial):
+                serial_instance.exclusive = args.exclusive
+
+            serial_instance.open()
+        except serial.SerialException as e:
+            sys.stderr.write('could not open port {!r}: {}\n'.format(args.port, e))
+            if args.develop:
+                raise
+            if not args.ask:
+                sys.exit(1)
+            else:
+                args.port = '-'
+        else:
+            break
+
+    miniterm = Miniterm(
+        serial_instance,
+        echo=args.echo,
+        eol=args.eol.lower(),
+        filters=filters)
+    miniterm.exit_character = unichr(args.exit_char)
+    miniterm.menu_character = unichr(args.menu_char)
+    miniterm.raw = args.raw
+    miniterm.set_rx_encoding(args.serial_port_encoding)
+    miniterm.set_tx_encoding(args.serial_port_encoding)
+
+    if not args.quiet:
+        sys.stderr.write('--- Miniterm on {p.name}  {p.baudrate},{p.bytesize},{p.parity},{p.stopbits} ---\n'.format(
+            p=miniterm.serial))
+        sys.stderr.write('--- Quit: {} | Menu: {} | Help: {} followed by {} ---\n'.format(
+            key_description(miniterm.exit_character),
+            key_description(miniterm.menu_character),
+            key_description(miniterm.menu_character),
+            key_description('\x08')))
+
+    miniterm.start()
+    try:
+        miniterm.join(True)
+    except KeyboardInterrupt:
+        pass
+    if not args.quiet:
+        sys.stderr.write('\n--- exit ---\n')
+    miniterm.join()
+    miniterm.close()
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+if __name__ == '__main__':
+    main()
diff --git a/src/devtools/datool/serial/urlhandler/__init__.py b/src/devtools/datool/serial/urlhandler/__init__.py
new file mode 100755
index 0000000..aa39021
--- /dev/null
+++ b/src/devtools/datool/serial/urlhandler/__init__.py
@@ -0,0 +1 @@
+# SPDX-License-Identifier:    BSD-3-Clause
\ No newline at end of file
diff --git a/src/devtools/datool/serial/urlhandler/protocol_alt.py b/src/devtools/datool/serial/urlhandler/protocol_alt.py
new file mode 100755
index 0000000..2e666ca
--- /dev/null
+++ b/src/devtools/datool/serial/urlhandler/protocol_alt.py
@@ -0,0 +1,57 @@
+#! python
+#
+# This module implements a special URL handler that allows selecting an
+# alternate implementation provided by some backends.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+#
+# URL format:    alt://port[?option[=value][&option[=value]]]
+# options:
+# - class=X used class named X instead of Serial
+#
+# example:
+#   use poll based implementation on Posix (Linux):
+#   python -m serial.tools.miniterm alt:///dev/ttyUSB0?class=PosixPollSerial
+
+from __future__ import absolute_import
+
+try:
+    import urlparse
+except ImportError:
+    import urllib.parse as urlparse
+
+import serial
+
+
+def serial_class_for_url(url):
+    """extract host and port from an URL string"""
+    parts = urlparse.urlsplit(url)
+    if parts.scheme != 'alt':
+        raise serial.SerialException(
+            'expected a string in the form "alt://port[?option[=value][&option[=value]]]": '
+            'not starting with alt:// ({!r})'.format(parts.scheme))
+    class_name = 'Serial'
+    try:
+        for option, values in urlparse.parse_qs(parts.query, True).items():
+            if option == 'class':
+                class_name = values[0]
+            else:
+                raise ValueError('unknown option: {!r}'.format(option))
+    except ValueError as e:
+        raise serial.SerialException(
+            'expected a string in the form '
+            '"alt://port[?option[=value][&option[=value]]]": {!r}'.format(e))
+    if not hasattr(serial, class_name):
+        raise ValueError('unknown class: {!r}'.format(class_name))
+    cls = getattr(serial, class_name)
+    if not issubclass(cls, serial.Serial):
+        raise ValueError('class {!r} is not an instance of Serial'.format(class_name))
+    return (''.join([parts.netloc, parts.path]), cls)
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+if __name__ == '__main__':
+    s = serial.serial_for_url('alt:///dev/ttyS0?class=PosixPollSerial')
+    print(s)
diff --git a/src/devtools/datool/serial/urlhandler/protocol_cp2110.py b/src/devtools/datool/serial/urlhandler/protocol_cp2110.py
new file mode 100755
index 0000000..44ad4eb
--- /dev/null
+++ b/src/devtools/datool/serial/urlhandler/protocol_cp2110.py
@@ -0,0 +1,258 @@
+#! python
+#
+# Backend for Silicon Labs CP2110/4 HID-to-UART devices.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
+# (C) 2019 Google LLC
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+# This backend implements support for HID-to-UART devices manufactured
+# by Silicon Labs and marketed as CP2110 and CP2114. The
+# implementation is (mostly) OS-independent and in userland. It relies
+# on cython-hidapi (https://github.com/trezor/cython-hidapi).
+
+# The HID-to-UART protocol implemented by CP2110/4 is described in the
+# AN434 document from Silicon Labs:
+# https://www.silabs.com/documents/public/application-notes/AN434-CP2110-4-Interface-Specification.pdf
+
+# TODO items:
+
+# - rtscts support is configured for hardware flow control, but the
+#   signaling is missing (AN434 suggests this is done through GPIO).
+# - Cancelling reads and writes is not supported.
+# - Baudrate validation is not implemented, as it depends on model and configuration.
+
+import struct
+import threading
+
+try:
+    import urlparse
+except ImportError:
+    import urllib.parse as urlparse
+
+try:
+    import Queue
+except ImportError:
+    import queue as Queue
+
+import hid  # hidapi
+
+import serial
+from serial.serialutil import SerialBase, SerialException, PortNotOpenError, to_bytes, Timeout
+
+
+# Report IDs and related constant
+_REPORT_GETSET_UART_ENABLE = 0x41
+_DISABLE_UART = 0x00
+_ENABLE_UART = 0x01
+
+_REPORT_SET_PURGE_FIFOS = 0x43
+_PURGE_TX_FIFO = 0x01
+_PURGE_RX_FIFO = 0x02
+
+_REPORT_GETSET_UART_CONFIG = 0x50
+
+_REPORT_SET_TRANSMIT_LINE_BREAK = 0x51
+_REPORT_SET_STOP_LINE_BREAK = 0x52
+
+
+class Serial(SerialBase):
+    # This is not quite correct. AN343 specifies that the minimum
+    # baudrate is different between CP2110 and CP2114, and it's halved
+    # when using non-8-bit symbols.
+    BAUDRATES = (300, 375, 600, 1200, 1800, 2400, 4800, 9600, 19200,
+                 38400, 57600, 115200, 230400, 460800, 500000, 576000,
+                 921600, 1000000)
+
+    def __init__(self, *args, **kwargs):
+        self._hid_handle = None
+        self._read_buffer = None
+        self._thread = None
+        super(Serial, self).__init__(*args, **kwargs)
+
+    def open(self):
+        if self._port is None:
+            raise SerialException("Port must be configured before it can be used.")
+        if self.is_open:
+            raise SerialException("Port is already open.")
+
+        self._read_buffer = Queue.Queue()
+
+        self._hid_handle = hid.device()
+        try:
+            portpath = self.from_url(self.portstr)
+            self._hid_handle.open_path(portpath)
+        except OSError as msg:
+            raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
+
+        try:
+            self._reconfigure_port()
+        except:
+            try:
+                self._hid_handle.close()
+            except:
+                pass
+            self._hid_handle = None
+            raise
+        else:
+            self.is_open = True
+            self._thread = threading.Thread(target=self._hid_read_loop)
+            self._thread.setDaemon(True)
+            self._thread.setName('pySerial CP2110 reader thread for {}'.format(self._port))
+            self._thread.start()
+
+    def from_url(self, url):
+        parts = urlparse.urlsplit(url)
+        if parts.scheme != "cp2110":
+            raise SerialException(
+                'expected a string in the forms '
+                '"cp2110:///dev/hidraw9" or "cp2110://0001:0023:00": '
+                'not starting with cp2110:// {{!r}}'.format(parts.scheme))
+        if parts.netloc:  # cp2100://BUS:DEVICE:ENDPOINT, for libusb
+            return parts.netloc.encode('utf-8')
+        return parts.path.encode('utf-8')
+
+    def close(self):
+        self.is_open = False
+        if self._thread:
+            self._thread.join(1)  # read timeout is 0.1
+            self._thread = None
+        self._hid_handle.close()
+        self._hid_handle = None
+
+    def _reconfigure_port(self):
+        parity_value = None
+        if self._parity == serial.PARITY_NONE:
+            parity_value = 0x00
+        elif self._parity == serial.PARITY_ODD:
+            parity_value = 0x01
+        elif self._parity == serial.PARITY_EVEN:
+            parity_value = 0x02
+        elif self._parity == serial.PARITY_MARK:
+            parity_value = 0x03
+        elif self._parity == serial.PARITY_SPACE:
+            parity_value = 0x04
+        else:
+            raise ValueError('Invalid parity: {!r}'.format(self._parity))
+
+        if self.rtscts:
+            flow_control_value = 0x01
+        else:
+            flow_control_value = 0x00
+
+        data_bits_value = None
+        if self._bytesize == 5:
+            data_bits_value = 0x00
+        elif self._bytesize == 6:
+            data_bits_value = 0x01
+        elif self._bytesize == 7:
+            data_bits_value = 0x02
+        elif self._bytesize == 8:
+            data_bits_value = 0x03
+        else:
+            raise ValueError('Invalid char len: {!r}'.format(self._bytesize))
+
+        stop_bits_value = None
+        if self._stopbits == serial.STOPBITS_ONE:
+            stop_bits_value = 0x00
+        elif self._stopbits == serial.STOPBITS_ONE_POINT_FIVE:
+            stop_bits_value = 0x01
+        elif self._stopbits == serial.STOPBITS_TWO:
+            stop_bits_value = 0x01
+        else:
+            raise ValueError('Invalid stop bit specification: {!r}'.format(self._stopbits))
+
+        configuration_report = struct.pack(
+            '>BLBBBB',
+            _REPORT_GETSET_UART_CONFIG,
+            self._baudrate,
+            parity_value,
+            flow_control_value,
+            data_bits_value,
+            stop_bits_value)
+
+        self._hid_handle.send_feature_report(configuration_report)
+
+        self._hid_handle.send_feature_report(
+            bytes((_REPORT_GETSET_UART_ENABLE, _ENABLE_UART)))
+        self._update_break_state()
+
+    @property
+    def in_waiting(self):
+        return self._read_buffer.qsize()
+
+    def reset_input_buffer(self):
+        if not self.is_open:
+            raise PortNotOpenError()
+        self._hid_handle.send_feature_report(
+            bytes((_REPORT_SET_PURGE_FIFOS, _PURGE_RX_FIFO)))
+        # empty read buffer
+        while self._read_buffer.qsize():
+            self._read_buffer.get(False)
+
+    def reset_output_buffer(self):
+        if not self.is_open:
+            raise PortNotOpenError()
+        self._hid_handle.send_feature_report(
+            bytes((_REPORT_SET_PURGE_FIFOS, _PURGE_TX_FIFO)))
+
+    def _update_break_state(self):
+        if not self._hid_handle:
+            raise PortNotOpenError()
+
+        if self._break_state:
+            self._hid_handle.send_feature_report(
+                bytes((_REPORT_SET_TRANSMIT_LINE_BREAK, 0)))
+        else:
+            # Note that while AN434 states "There are no data bytes in
+            # the payload other than the Report ID", either hidapi or
+            # Linux does not seem to send the report otherwise.
+            self._hid_handle.send_feature_report(
+                bytes((_REPORT_SET_STOP_LINE_BREAK, 0)))
+
+    def read(self, size=1):
+        if not self.is_open:
+            raise PortNotOpenError()
+
+        data = bytearray()
+        try:
+            timeout = Timeout(self._timeout)
+            while len(data) < size:
+                if self._thread is None:
+                    raise SerialException('connection failed (reader thread died)')
+                buf = self._read_buffer.get(True, timeout.time_left())
+                if buf is None:
+                    return bytes(data)
+                data += buf
+                if timeout.expired():
+                    break
+        except Queue.Empty:  # -> timeout
+            pass
+        return bytes(data)
+
+    def write(self, data):
+        if not self.is_open:
+            raise PortNotOpenError()
+        data = to_bytes(data)
+        tx_len = len(data)
+        while tx_len > 0:
+            to_be_sent = min(tx_len, 0x3F)
+            report = to_bytes([to_be_sent]) + data[:to_be_sent]
+            self._hid_handle.write(report)
+
+            data = data[to_be_sent:]
+            tx_len = len(data)
+
+    def _hid_read_loop(self):
+        try:
+            while self.is_open:
+                data = self._hid_handle.read(64, timeout_ms=100)
+                if not data:
+                    continue
+                data_len = data.pop(0)
+                assert data_len == len(data)
+                self._read_buffer.put(bytearray(data))
+        finally:
+            self._thread = None
diff --git a/src/devtools/datool/serial/urlhandler/protocol_hwgrep.py b/src/devtools/datool/serial/urlhandler/protocol_hwgrep.py
new file mode 100755
index 0000000..1a288c9
--- /dev/null
+++ b/src/devtools/datool/serial/urlhandler/protocol_hwgrep.py
@@ -0,0 +1,91 @@
+#! python
+#
+# This module implements a special URL handler that uses the port listing to
+# find ports by searching the string descriptions.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2011-2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+#
+# URL format:    hwgrep://<regexp>&<option>
+#
+# where <regexp> is a Python regexp according to the re module
+#
+# violating the normal definition for URLs, the charachter `&` is used to
+# separate parameters from the arguments (instead of `?`, but the question mark
+# is heavily used in regexp'es)
+#
+# options:
+# n=<N>     pick the N'th entry instead of the first one (numbering starts at 1)
+# skip_busy tries to open port to check if it is busy, fails on posix as ports are not locked!
+
+from __future__ import absolute_import
+
+import serial
+import serial.tools.list_ports
+
+try:
+    basestring
+except NameError:
+    basestring = str    # python 3  pylint: disable=redefined-builtin
+
+
+class Serial(serial.Serial):
+    """Just inherit the native Serial port implementation and patch the port property."""
+    # pylint: disable=no-member
+
+    @serial.Serial.port.setter
+    def port(self, value):
+        """translate port name before storing it"""
+        if isinstance(value, basestring) and value.startswith('hwgrep://'):
+            serial.Serial.port.__set__(self, self.from_url(value))
+        else:
+            serial.Serial.port.__set__(self, value)
+
+    def from_url(self, url):
+        """extract host and port from an URL string"""
+        if url.lower().startswith("hwgrep://"):
+            url = url[9:]
+        n = 0
+        test_open = False
+        args = url.split('&')
+        regexp = args.pop(0)
+        for arg in args:
+            if '=' in arg:
+                option, value = arg.split('=', 1)
+            else:
+                option = arg
+                value = None
+            if option == 'n':
+                # pick n'th element
+                n = int(value) - 1
+                if n < 1:
+                    raise ValueError('option "n" expects a positive integer larger than 1: {!r}'.format(value))
+            elif option == 'skip_busy':
+                # open to test if port is available. not the nicest way..
+                test_open = True
+            else:
+                raise ValueError('unknown option: {!r}'.format(option))
+        # use a for loop to get the 1st element from the generator
+        for port, desc, hwid in sorted(serial.tools.list_ports.grep(regexp)):
+            if test_open:
+                try:
+                    s = serial.Serial(port)
+                except serial.SerialException:
+                    # it has some error, skip this one
+                    continue
+                else:
+                    s.close()
+            if n:
+                n -= 1
+                continue
+            return port
+        else:
+            raise serial.SerialException('no ports found matching regexp {!r}'.format(url))
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+if __name__ == '__main__':
+    s = Serial(None)
+    s.port = 'hwgrep://ttyS0'
+    print(s)
diff --git a/src/devtools/datool/serial/urlhandler/protocol_loop.py b/src/devtools/datool/serial/urlhandler/protocol_loop.py
new file mode 100755
index 0000000..2aeebfc7
--- /dev/null
+++ b/src/devtools/datool/serial/urlhandler/protocol_loop.py
@@ -0,0 +1,308 @@
+#! python
+#
+# This module implements a loop back connection receiving itself what it sent.
+#
+# The purpose of this module is.. well... You can run the unit tests with it.
+# and it was so easy to implement ;-)
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2001-2020 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+#
+# URL format:    loop://[option[/option...]]
+# options:
+# - "debug" print diagnostic messages
+from __future__ import absolute_import
+
+import logging
+import numbers
+import time
+try:
+    import urlparse
+except ImportError:
+    import urllib.parse as urlparse
+try:
+    import queue
+except ImportError:
+    import Queue as queue
+
+from serial.serialutil import SerialBase, SerialException, to_bytes, iterbytes, SerialTimeoutException, PortNotOpenError
+
+# map log level names to constants. used in from_url()
+LOGGER_LEVELS = {
+    'debug': logging.DEBUG,
+    'info': logging.INFO,
+    'warning': logging.WARNING,
+    'error': logging.ERROR,
+}
+
+
+class Serial(SerialBase):
+    """Serial port implementation that simulates a loop back connection in plain software."""
+
+    BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+                 9600, 19200, 38400, 57600, 115200)
+
+    def __init__(self, *args, **kwargs):
+        self.buffer_size = 4096
+        self.queue = None
+        self.logger = None
+        self._cancel_write = False
+        super(Serial, self).__init__(*args, **kwargs)
+
+    def open(self):
+        """\
+        Open port with current settings. This may throw a SerialException
+        if the port cannot be opened.
+        """
+        if self.is_open:
+            raise SerialException("Port is already open.")
+        self.logger = None
+        self.queue = queue.Queue(self.buffer_size)
+
+        if self._port is None:
+            raise SerialException("Port must be configured before it can be used.")
+        # not that there is anything to open, but the function applies the
+        # options found in the URL
+        self.from_url(self.port)
+
+        # not that there anything to configure...
+        self._reconfigure_port()
+        # all things set up get, now a clean start
+        self.is_open = True
+        if not self._dsrdtr:
+            self._update_dtr_state()
+        if not self._rtscts:
+            self._update_rts_state()
+        self.reset_input_buffer()
+        self.reset_output_buffer()
+
+    def close(self):
+        if self.is_open:
+            self.is_open = False
+            try:
+                self.queue.put_nowait(None)
+            except queue.Full:
+                pass
+        super(Serial, self).close()
+
+    def _reconfigure_port(self):
+        """\
+        Set communication parameters on opened port. For the loop://
+        protocol all settings are ignored!
+        """
+        # not that's it of any real use, but it helps in the unit tests
+        if not isinstance(self._baudrate, numbers.Integral) or not 0 < self._baudrate < 2 ** 32:
+            raise ValueError("invalid baudrate: {!r}".format(self._baudrate))
+        if self.logger:
+            self.logger.info('_reconfigure_port()')
+
+    def from_url(self, url):
+        """extract host and port from an URL string"""
+        parts = urlparse.urlsplit(url)
+        if parts.scheme != "loop":
+            raise SerialException(
+                'expected a string in the form '
+                '"loop://[?logging={debug|info|warning|error}]": not starting '
+                'with loop:// ({!r})'.format(parts.scheme))
+        try:
+            # process options now, directly altering self
+            for option, values in urlparse.parse_qs(parts.query, True).items():
+                if option == 'logging':
+                    logging.basicConfig()   # XXX is that good to call it here?
+                    self.logger = logging.getLogger('pySerial.loop')
+                    self.logger.setLevel(LOGGER_LEVELS[values[0]])
+                    self.logger.debug('enabled logging')
+                else:
+                    raise ValueError('unknown option: {!r}'.format(option))
+        except ValueError as e:
+            raise SerialException(
+                'expected a string in the form '
+                '"loop://[?logging={debug|info|warning|error}]": {}'.format(e))
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    @property
+    def in_waiting(self):
+        """Return the number of bytes currently in the input buffer."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            # attention the logged value can differ from return value in
+            # threaded environments...
+            self.logger.debug('in_waiting -> {:d}'.format(self.queue.qsize()))
+        return self.queue.qsize()
+
+    def read(self, size=1):
+        """\
+        Read size bytes from the serial port. If a timeout is set it may
+        return less characters as requested. With no timeout it will block
+        until the requested number of bytes is read.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self._timeout is not None and self._timeout != 0:
+            timeout = time.time() + self._timeout
+        else:
+            timeout = None
+        data = bytearray()
+        while size > 0 and self.is_open:
+            try:
+                b = self.queue.get(timeout=self._timeout)  # XXX inter char timeout
+            except queue.Empty:
+                if self._timeout == 0:
+                    break
+            else:
+                if b is not None:
+                    data += b
+                    size -= 1
+                else:
+                    break
+            # check for timeout now, after data has been read.
+            # useful for timeout = 0 (non blocking) read
+            if timeout and time.time() > timeout:
+                if self.logger:
+                    self.logger.info('read timeout')
+                break
+        return bytes(data)
+
+    def cancel_read(self):
+        self.queue.put_nowait(None)
+
+    def cancel_write(self):
+        self._cancel_write = True
+
+    def write(self, data):
+        """\
+        Output the given byte string over the serial port. Can block if the
+        connection is blocked. May raise SerialException if the connection is
+        closed.
+        """
+        self._cancel_write = False
+        if not self.is_open:
+            raise PortNotOpenError()
+        data = to_bytes(data)
+        # calculate aprox time that would be used to send the data
+        time_used_to_send = 10.0 * len(data) / self._baudrate
+        # when a write timeout is configured check if we would be successful
+        # (not sending anything, not even the part that would have time)
+        if self._write_timeout is not None and time_used_to_send > self._write_timeout:
+            # must wait so that unit test succeeds
+            time_left = self._write_timeout
+            while time_left > 0 and not self._cancel_write:
+                time.sleep(min(time_left, 0.5))
+                time_left -= 0.5
+            if self._cancel_write:
+                return 0  # XXX
+            raise SerialTimeoutException('Write timeout')
+        for byte in iterbytes(data):
+            self.queue.put(byte, timeout=self._write_timeout)
+        return len(data)
+
+    def reset_input_buffer(self):
+        """Clear input buffer, discarding all that is in the buffer."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('reset_input_buffer()')
+        try:
+            while self.queue.qsize():
+                self.queue.get_nowait()
+        except queue.Empty:
+            pass
+
+    def reset_output_buffer(self):
+        """\
+        Clear output buffer, aborting the current output and
+        discarding all that is in the buffer.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('reset_output_buffer()')
+        try:
+            while self.queue.qsize():
+                self.queue.get_nowait()
+        except queue.Empty:
+            pass
+
+    @property
+    def out_waiting(self):
+        """Return how many bytes the in the outgoing buffer"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            # attention the logged value can differ from return value in
+            # threaded environments...
+            self.logger.debug('out_waiting -> {:d}'.format(self.queue.qsize()))
+        return self.queue.qsize()
+
+    def _update_break_state(self):
+        """\
+        Set break: Controls TXD. When active, to transmitting is
+        possible.
+        """
+        if self.logger:
+            self.logger.info('_update_break_state({!r})'.format(self._break_state))
+
+    def _update_rts_state(self):
+        """Set terminal status line: Request To Send"""
+        if self.logger:
+            self.logger.info('_update_rts_state({!r}) -> state of CTS'.format(self._rts_state))
+
+    def _update_dtr_state(self):
+        """Set terminal status line: Data Terminal Ready"""
+        if self.logger:
+            self.logger.info('_update_dtr_state({!r}) -> state of DSR'.format(self._dtr_state))
+
+    @property
+    def cts(self):
+        """Read terminal status line: Clear To Send"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('CTS -> state of RTS ({!r})'.format(self._rts_state))
+        return self._rts_state
+
+    @property
+    def dsr(self):
+        """Read terminal status line: Data Set Ready"""
+        if self.logger:
+            self.logger.info('DSR -> state of DTR ({!r})'.format(self._dtr_state))
+        return self._dtr_state
+
+    @property
+    def ri(self):
+        """Read terminal status line: Ring Indicator"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('returning dummy for RI')
+        return False
+
+    @property
+    def cd(self):
+        """Read terminal status line: Carrier Detect"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('returning dummy for CD')
+        return True
+
+    # - - - platform specific - - -
+    # None so far
+
+
+# simple client test
+if __name__ == '__main__':
+    import sys
+    s = Serial('loop://')
+    sys.stdout.write('{}\n'.format(s))
+
+    sys.stdout.write("write...\n")
+    s.write("hello\n")
+    s.flush()
+    sys.stdout.write("read: {!r}\n".format(s.read(5)))
+
+    s.close()
diff --git a/src/devtools/datool/serial/urlhandler/protocol_rfc2217.py b/src/devtools/datool/serial/urlhandler/protocol_rfc2217.py
new file mode 100755
index 0000000..ebeec3a
--- /dev/null
+++ b/src/devtools/datool/serial/urlhandler/protocol_rfc2217.py
@@ -0,0 +1,12 @@
+#! python
+#
+# This is a thin wrapper to load the rfc2217 implementation.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2011 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+from __future__ import absolute_import
+
+from serial.rfc2217 import Serial  # noqa
diff --git a/src/devtools/datool/serial/urlhandler/protocol_socket.py b/src/devtools/datool/serial/urlhandler/protocol_socket.py
new file mode 100755
index 0000000..2888467
--- /dev/null
+++ b/src/devtools/datool/serial/urlhandler/protocol_socket.py
@@ -0,0 +1,359 @@
+#! python
+#
+# This module implements a simple socket based client.
+# It does not support changing any port parameters and will silently ignore any
+# requests to do so.
+#
+# The purpose of this module is that applications using pySerial can connect to
+# TCP/IP to serial port converters that do not support RFC 2217.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+#
+# URL format:    socket://<host>:<port>[/option[/option...]]
+# options:
+# - "debug" print diagnostic messages
+
+from __future__ import absolute_import
+
+import errno
+import logging
+import select
+import socket
+import time
+try:
+    import urlparse
+except ImportError:
+    import urllib.parse as urlparse
+
+from serial.serialutil import SerialBase, SerialException, to_bytes, \
+    PortNotOpenError, SerialTimeoutException, Timeout
+
+# map log level names to constants. used in from_url()
+LOGGER_LEVELS = {
+    'debug': logging.DEBUG,
+    'info': logging.INFO,
+    'warning': logging.WARNING,
+    'error': logging.ERROR,
+}
+
+POLL_TIMEOUT = 5
+
+
+class Serial(SerialBase):
+    """Serial port implementation for plain sockets."""
+
+    BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+                 9600, 19200, 38400, 57600, 115200)
+
+    def open(self):
+        """\
+        Open port with current settings. This may throw a SerialException
+        if the port cannot be opened.
+        """
+        self.logger = None
+        if self._port is None:
+            raise SerialException("Port must be configured before it can be used.")
+        if self.is_open:
+            raise SerialException("Port is already open.")
+        try:
+            # timeout is used for write timeout support :/ and to get an initial connection timeout
+            self._socket = socket.create_connection(self.from_url(self.portstr), timeout=POLL_TIMEOUT)
+        except Exception as msg:
+            self._socket = None
+            raise SerialException("Could not open port {}: {}".format(self.portstr, msg))
+        # after connecting, switch to non-blocking, we're using select
+        self._socket.setblocking(False)
+
+        # not that there is anything to configure...
+        self._reconfigure_port()
+        # all things set up get, now a clean start
+        self.is_open = True
+        if not self._dsrdtr:
+            self._update_dtr_state()
+        if not self._rtscts:
+            self._update_rts_state()
+        self.reset_input_buffer()
+        self.reset_output_buffer()
+
+    def _reconfigure_port(self):
+        """\
+        Set communication parameters on opened port. For the socket://
+        protocol all settings are ignored!
+        """
+        if self._socket is None:
+            raise SerialException("Can only operate on open ports")
+        if self.logger:
+            self.logger.info('ignored port configuration change')
+
+    def close(self):
+        """Close port"""
+        if self.is_open:
+            if self._socket:
+                try:
+                    self._socket.shutdown(socket.SHUT_RDWR)
+                    self._socket.close()
+                except:
+                    # ignore errors.
+                    pass
+                self._socket = None
+            self.is_open = False
+            # in case of quick reconnects, give the server some time
+            time.sleep(0.3)
+
+    def from_url(self, url):
+        """extract host and port from an URL string"""
+        parts = urlparse.urlsplit(url)
+        if parts.scheme != "socket":
+            raise SerialException(
+                'expected a string in the form '
+                '"socket://<host>:<port>[?logging={debug|info|warning|error}]": '
+                'not starting with socket:// ({!r})'.format(parts.scheme))
+        try:
+            # process options now, directly altering self
+            for option, values in urlparse.parse_qs(parts.query, True).items():
+                if option == 'logging':
+                    logging.basicConfig()   # XXX is that good to call it here?
+                    self.logger = logging.getLogger('pySerial.socket')
+                    self.logger.setLevel(LOGGER_LEVELS[values[0]])
+                    self.logger.debug('enabled logging')
+                else:
+                    raise ValueError('unknown option: {!r}'.format(option))
+            if not 0 <= parts.port < 65536:
+                raise ValueError("port not in range 0...65535")
+        except ValueError as e:
+            raise SerialException(
+                'expected a string in the form '
+                '"socket://<host>:<port>[?logging={debug|info|warning|error}]": {}'.format(e))
+
+        return (parts.hostname, parts.port)
+
+    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+
+    @property
+    def in_waiting(self):
+        """Return the number of bytes currently in the input buffer."""
+        if not self.is_open:
+            raise PortNotOpenError()
+        # Poll the socket to see if it is ready for reading.
+        # If ready, at least one byte will be to read.
+        lr, lw, lx = select.select([self._socket], [], [], 0)
+        return len(lr)
+
+    # select based implementation, similar to posix, but only using socket API
+    # to be portable, additionally handle socket timeout which is used to
+    # emulate write timeouts
+    def read(self, size=1):
+        """\
+        Read size bytes from the serial port. If a timeout is set it may
+        return less characters as requested. With no timeout it will block
+        until the requested number of bytes is read.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        read = bytearray()
+        timeout = Timeout(self._timeout)
+        while len(read) < size:
+            try:
+                ready, _, _ = select.select([self._socket], [], [], timeout.time_left())
+                # If select was used with a timeout, and the timeout occurs, it
+                # returns with empty lists -> thus abort read operation.
+                # For timeout == 0 (non-blocking operation) also abort when
+                # there is nothing to read.
+                if not ready:
+                    break   # timeout
+                buf = self._socket.recv(size - len(read))
+                # read should always return some data as select reported it was
+                # ready to read when we get to this point, unless it is EOF
+                if not buf:
+                    raise SerialException('socket disconnected')
+                read.extend(buf)
+            except OSError as e:
+                # this is for Python 3.x where select.error is a subclass of
+                # OSError ignore BlockingIOErrors and EINTR. other errors are shown
+                # https://www.python.org/dev/peps/pep-0475.
+                if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+                    raise SerialException('read failed: {}'.format(e))
+            except (select.error, socket.error) as e:
+                # this is for Python 2.x
+                # ignore BlockingIOErrors and EINTR. all errors are shown
+                # see also http://www.python.org/dev/peps/pep-3151/#select
+                if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+                    raise SerialException('read failed: {}'.format(e))
+            if timeout.expired():
+                break
+        return bytes(read)
+
+    def write(self, data):
+        """\
+        Output the given byte string over the serial port. Can block if the
+        connection is blocked. May raise SerialException if the connection is
+        closed.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+
+        d = to_bytes(data)
+        tx_len = length = len(d)
+        timeout = Timeout(self._write_timeout)
+        while tx_len > 0:
+            try:
+                n = self._socket.send(d)
+                if timeout.is_non_blocking:
+                    # Zero timeout indicates non-blocking - simply return the
+                    # number of bytes of data actually written
+                    return n
+                elif not timeout.is_infinite:
+                    # when timeout is set, use select to wait for being ready
+                    # with the time left as timeout
+                    if timeout.expired():
+                        raise SerialTimeoutException('Write timeout')
+                    _, ready, _ = select.select([], [self._socket], [], timeout.time_left())
+                    if not ready:
+                        raise SerialTimeoutException('Write timeout')
+                else:
+                    assert timeout.time_left() is None
+                    # wait for write operation
+                    _, ready, _ = select.select([], [self._socket], [], None)
+                    if not ready:
+                        raise SerialException('write failed (select)')
+                d = d[n:]
+                tx_len -= n
+            except SerialException:
+                raise
+            except OSError as e:
+                # this is for Python 3.x where select.error is a subclass of
+                # OSError ignore BlockingIOErrors and EINTR. other errors are shown
+                # https://www.python.org/dev/peps/pep-0475.
+                if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+                    raise SerialException('write failed: {}'.format(e))
+            except select.error as e:
+                # this is for Python 2.x
+                # ignore BlockingIOErrors and EINTR. all errors are shown
+                # see also http://www.python.org/dev/peps/pep-3151/#select
+                if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+                    raise SerialException('write failed: {}'.format(e))
+            if not timeout.is_non_blocking and timeout.expired():
+                raise SerialTimeoutException('Write timeout')
+        return length - len(d)
+
+    def reset_input_buffer(self):
+        """Clear input buffer, discarding all that is in the buffer."""
+        if not self.is_open:
+            raise PortNotOpenError()
+
+        # just use recv to remove input, while there is some
+        ready = True
+        while ready:
+            ready, _, _ = select.select([self._socket], [], [], 0)
+            try:
+                if ready:
+                    ready = self._socket.recv(4096)
+            except OSError as e:
+                # this is for Python 3.x where select.error is a subclass of
+                # OSError ignore BlockingIOErrors and EINTR. other errors are shown
+                # https://www.python.org/dev/peps/pep-0475.
+                if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+                    raise SerialException('read failed: {}'.format(e))
+            except (select.error, socket.error) as e:
+                # this is for Python 2.x
+                # ignore BlockingIOErrors and EINTR. all errors are shown
+                # see also http://www.python.org/dev/peps/pep-3151/#select
+                if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR):
+                    raise SerialException('read failed: {}'.format(e))
+
+    def reset_output_buffer(self):
+        """\
+        Clear output buffer, aborting the current output and
+        discarding all that is in the buffer.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('ignored reset_output_buffer')
+
+    def send_break(self, duration=0.25):
+        """\
+        Send break condition. Timed, returns to idle state after given
+        duration.
+        """
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('ignored send_break({!r})'.format(duration))
+
+    def _update_break_state(self):
+        """Set break: Controls TXD. When active, to transmitting is
+        possible."""
+        if self.logger:
+            self.logger.info('ignored _update_break_state({!r})'.format(self._break_state))
+
+    def _update_rts_state(self):
+        """Set terminal status line: Request To Send"""
+        if self.logger:
+            self.logger.info('ignored _update_rts_state({!r})'.format(self._rts_state))
+
+    def _update_dtr_state(self):
+        """Set terminal status line: Data Terminal Ready"""
+        if self.logger:
+            self.logger.info('ignored _update_dtr_state({!r})'.format(self._dtr_state))
+
+    @property
+    def cts(self):
+        """Read terminal status line: Clear To Send"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('returning dummy for cts')
+        return True
+
+    @property
+    def dsr(self):
+        """Read terminal status line: Data Set Ready"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('returning dummy for dsr')
+        return True
+
+    @property
+    def ri(self):
+        """Read terminal status line: Ring Indicator"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('returning dummy for ri')
+        return False
+
+    @property
+    def cd(self):
+        """Read terminal status line: Carrier Detect"""
+        if not self.is_open:
+            raise PortNotOpenError()
+        if self.logger:
+            self.logger.info('returning dummy for cd)')
+        return True
+
+    # - - - platform specific - - -
+
+    # works on Linux and probably all the other POSIX systems
+    def fileno(self):
+        """Get the file handle of the underlying socket for use with select"""
+        return self._socket.fileno()
+
+
+#
+# simple client test
+if __name__ == '__main__':
+    import sys
+    s = Serial('socket://localhost:7000')
+    sys.stdout.write('{}\n'.format(s))
+
+    sys.stdout.write("write...\n")
+    s.write(b"hello\n")
+    s.flush()
+    sys.stdout.write("read: {}\n".format(s.read(5)))
+
+    s.close()
diff --git a/src/devtools/datool/serial/urlhandler/protocol_spy.py b/src/devtools/datool/serial/urlhandler/protocol_spy.py
new file mode 100755
index 0000000..67c700b
--- /dev/null
+++ b/src/devtools/datool/serial/urlhandler/protocol_spy.py
@@ -0,0 +1,290 @@
+#! python
+#
+# This module implements a special URL handler that wraps an other port,
+# print the traffic for debugging purposes. With this, it is possible
+# to debug the serial port traffic on every application that uses
+# serial_for_url.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+#
+# URL format:    spy://port[?option[=value][&option[=value]]]
+# options:
+# - dev=X   a file or device to write to
+# - color   use escape code to colorize output
+# - raw     forward raw bytes instead of hexdump
+#
+# example:
+#   redirect output to an other terminal window on Posix (Linux):
+#   python -m serial.tools.miniterm spy:///dev/ttyUSB0?dev=/dev/pts/14\&color
+
+from __future__ import absolute_import
+
+import sys
+import time
+
+import serial
+from serial.serialutil import  to_bytes
+
+try:
+    import urlparse
+except ImportError:
+    import urllib.parse as urlparse
+
+
+def sixteen(data):
+    """\
+    yield tuples of hex and ASCII display in multiples of 16. Includes a
+    space after 8 bytes and (None, None) after 16 bytes and at the end.
+    """
+    n = 0
+    for b in serial.iterbytes(data):
+        yield ('{:02X} '.format(ord(b)), b.decode('ascii') if b' ' <= b < b'\x7f' else '.')
+        n += 1
+        if n == 8:
+            yield (' ', '')
+        elif n >= 16:
+            yield (None, None)
+            n = 0
+    if n > 0:
+        while n < 16:
+            n += 1
+            if n == 8:
+                yield (' ', '')
+            yield ('   ', ' ')
+        yield (None, None)
+
+
+def hexdump(data):
+    """yield lines with hexdump of data"""
+    values = []
+    ascii = []
+    offset = 0
+    for h, a in sixteen(data):
+        if h is None:
+            yield (offset, ' '.join([''.join(values), ''.join(ascii)]))
+            del values[:]
+            del ascii[:]
+            offset += 0x10
+        else:
+            values.append(h)
+            ascii.append(a)
+
+
+class FormatRaw(object):
+    """Forward only RX and TX data to output."""
+
+    def __init__(self, output, color):
+        self.output = output
+        self.color = color
+        self.rx_color = '\x1b[32m'
+        self.tx_color = '\x1b[31m'
+
+    def rx(self, data):
+        """show received data"""
+        if self.color:
+            self.output.write(self.rx_color)
+        self.output.write(data)
+        self.output.flush()
+
+    def tx(self, data):
+        """show transmitted data"""
+        if self.color:
+            self.output.write(self.tx_color)
+        self.output.write(data)
+        self.output.flush()
+
+    def control(self, name, value):
+        """(do not) show control calls"""
+        pass
+
+
+class FormatHexdump(object):
+    """\
+    Create a hex dump of RX ad TX data, show when control lines are read or
+    written.
+
+    output example::
+
+        000000.000 Q-RX flushInput
+        000002.469 RTS  inactive
+        000002.773 RTS  active
+        000003.001 TX   48 45 4C 4C 4F                                    HELLO
+        000003.102 RX   48 45 4C 4C 4F                                    HELLO
+
+    """
+
+    def __init__(self, output, color):
+        self.start_time = time.time()
+        self.output = output
+        self.color = color
+        self.rx_color = '\x1b[32m'
+        self.tx_color = '\x1b[31m'
+        self.control_color = '\x1b[37m'
+
+    def write_line(self, timestamp, label, value, value2=''):
+        self.output.write('{:010.3f} {:4} {}{}\n'.format(timestamp, label, value, value2))
+        self.output.flush()
+
+    def rx(self, data):
+        """show received data as hex dump"""
+        if self.color:
+            self.output.write(self.rx_color)
+        if data:
+            for offset, row in hexdump(data):
+                self.write_line(time.time() - self.start_time, 'RX', '{:04X}  '.format(offset), row)
+        else:
+            self.write_line(time.time() - self.start_time, 'RX', '<empty>')
+
+    def tx(self, data):
+        """show transmitted data as hex dump"""
+        if self.color:
+            self.output.write(self.tx_color)
+        for offset, row in hexdump(data):
+            self.write_line(time.time() - self.start_time, 'TX', '{:04X}  '.format(offset), row)
+
+    def control(self, name, value):
+        """show control calls"""
+        if self.color:
+            self.output.write(self.control_color)
+        self.write_line(time.time() - self.start_time, name, value)
+
+
+class Serial(serial.Serial):
+    """\
+    Inherit the native Serial port implementation and wrap all the methods and
+    attributes.
+    """
+    # pylint: disable=no-member
+
+    def __init__(self, *args, **kwargs):
+        super(Serial, self).__init__(*args, **kwargs)
+        self.formatter = None
+        self.show_all = False
+
+    @serial.Serial.port.setter
+    def port(self, value):
+        if value is not None:
+            serial.Serial.port.__set__(self, self.from_url(value))
+
+    def from_url(self, url):
+        """extract host and port from an URL string"""
+        parts = urlparse.urlsplit(url)
+        if parts.scheme != 'spy':
+            raise serial.SerialException(
+                'expected a string in the form '
+                '"spy://port[?option[=value][&option[=value]]]": '
+                'not starting with spy:// ({!r})'.format(parts.scheme))
+        # process options now, directly altering self
+        formatter = FormatHexdump
+        color = False
+        output = sys.stderr
+        try:
+            for option, values in urlparse.parse_qs(parts.query, True).items():
+                if option == 'file':
+                    output = open(values[0], 'w')
+                elif option == 'color':
+                    color = True
+                elif option == 'raw':
+                    formatter = FormatRaw
+                elif option == 'all':
+                    self.show_all = True
+                else:
+                    raise ValueError('unknown option: {!r}'.format(option))
+        except ValueError as e:
+            raise serial.SerialException(
+                'expected a string in the form '
+                '"spy://port[?option[=value][&option[=value]]]": {}'.format(e))
+        self.formatter = formatter(output, color)
+        return ''.join([parts.netloc, parts.path])
+
+    def write(self, tx):
+        tx = to_bytes(tx)
+        self.formatter.tx(tx)
+        return super(Serial, self).write(tx)
+
+    def read(self, size=1):
+        rx = super(Serial, self).read(size)
+        if rx or self.show_all:
+            self.formatter.rx(rx)
+        return rx
+
+    if hasattr(serial.Serial, 'cancel_read'):
+        def cancel_read(self):
+            self.formatter.control('Q-RX', 'cancel_read')
+            super(Serial, self).cancel_read()
+
+    if hasattr(serial.Serial, 'cancel_write'):
+        def cancel_write(self):
+            self.formatter.control('Q-TX', 'cancel_write')
+            super(Serial, self).cancel_write()
+
+    @property
+    def in_waiting(self):
+        n = super(Serial, self).in_waiting
+        if self.show_all:
+            self.formatter.control('Q-RX', 'in_waiting -> {}'.format(n))
+        return n
+
+    def flush(self):
+        self.formatter.control('Q-TX', 'flush')
+        super(Serial, self).flush()
+
+    def reset_input_buffer(self):
+        self.formatter.control('Q-RX', 'reset_input_buffer')
+        super(Serial, self).reset_input_buffer()
+
+    def reset_output_buffer(self):
+        self.formatter.control('Q-TX', 'reset_output_buffer')
+        super(Serial, self).reset_output_buffer()
+
+    def send_break(self, duration=0.25):
+        self.formatter.control('BRK', 'send_break {}s'.format(duration))
+        super(Serial, self).send_break(duration)
+
+    @serial.Serial.break_condition.setter
+    def break_condition(self, level):
+        self.formatter.control('BRK', 'active' if level else 'inactive')
+        serial.Serial.break_condition.__set__(self, level)
+
+    @serial.Serial.rts.setter
+    def rts(self, level):
+        self.formatter.control('RTS', 'active' if level else 'inactive')
+        serial.Serial.rts.__set__(self, level)
+
+    @serial.Serial.dtr.setter
+    def dtr(self, level):
+        self.formatter.control('DTR', 'active' if level else 'inactive')
+        serial.Serial.dtr.__set__(self, level)
+
+    @serial.Serial.cts.getter
+    def cts(self):
+        level = super(Serial, self).cts
+        self.formatter.control('CTS', 'active' if level else 'inactive')
+        return level
+
+    @serial.Serial.dsr.getter
+    def dsr(self):
+        level = super(Serial, self).dsr
+        self.formatter.control('DSR', 'active' if level else 'inactive')
+        return level
+
+    @serial.Serial.ri.getter
+    def ri(self):
+        level = super(Serial, self).ri
+        self.formatter.control('RI', 'active' if level else 'inactive')
+        return level
+
+    @serial.Serial.cd.getter
+    def cd(self):
+        level = super(Serial, self).cd
+        self.formatter.control('CD', 'active' if level else 'inactive')
+        return level
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+if __name__ == '__main__':
+    ser = Serial(None)
+    ser.port = 'spy:///dev/ttyS0'
+    print(ser)
diff --git a/src/devtools/datool/serial/win32.py b/src/devtools/datool/serial/win32.py
new file mode 100755
index 0000000..157f470
--- /dev/null
+++ b/src/devtools/datool/serial/win32.py
@@ -0,0 +1,366 @@
+#! python
+#
+# Constants and types for use with Windows API, used by serialwin32.py
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier:    BSD-3-Clause
+
+# pylint: disable=invalid-name,too-few-public-methods,protected-access,too-many-instance-attributes
+
+from __future__ import absolute_import
+
+from ctypes import c_ulong, c_void_p, c_int64, c_char, \
+                   WinDLL, sizeof, Structure, Union, POINTER
+from ctypes.wintypes import HANDLE
+from ctypes.wintypes import BOOL
+from ctypes.wintypes import LPCWSTR
+from ctypes.wintypes import DWORD
+from ctypes.wintypes import WORD
+from ctypes.wintypes import BYTE
+_stdcall_libraries = {}
+_stdcall_libraries['kernel32'] = WinDLL('kernel32')
+
+INVALID_HANDLE_VALUE = HANDLE(-1).value
+
+
+# some details of the windows API differ between 32 and 64 bit systems..
+def is_64bit():
+    """Returns true when running on a 64 bit system"""
+    return sizeof(c_ulong) != sizeof(c_void_p)
+
+# ULONG_PTR is a an ordinary number, not a pointer and contrary to the name it
+# is either 32 or 64 bits, depending on the type of windows...
+# so test if this a 32 bit windows...
+if is_64bit():
+    ULONG_PTR = c_int64
+else:
+    ULONG_PTR = c_ulong
+
+
+class _SECURITY_ATTRIBUTES(Structure):
+    pass
+LPSECURITY_ATTRIBUTES = POINTER(_SECURITY_ATTRIBUTES)
+
+
+try:
+    CreateEventW = _stdcall_libraries['kernel32'].CreateEventW
+except AttributeError:
+    # Fallback to non wide char version for old OS...
+    from ctypes.wintypes import LPCSTR
+    CreateEventA = _stdcall_libraries['kernel32'].CreateEventA
+    CreateEventA.restype = HANDLE
+    CreateEventA.argtypes = [LPSECURITY_ATTRIBUTES, BOOL, BOOL, LPCSTR]
+    CreateEvent = CreateEventA
+
+    CreateFileA = _stdcall_libraries['kernel32'].CreateFileA
+    CreateFileA.restype = HANDLE
+    CreateFileA.argtypes = [LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE]
+    CreateFile = CreateFileA
+else:
+    CreateEventW.restype = HANDLE
+    CreateEventW.argtypes = [LPSECURITY_ATTRIBUTES, BOOL, BOOL, LPCWSTR]
+    CreateEvent = CreateEventW  # alias
+
+    CreateFileW = _stdcall_libraries['kernel32'].CreateFileW
+    CreateFileW.restype = HANDLE
+    CreateFileW.argtypes = [LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE]
+    CreateFile = CreateFileW  # alias
+
+
+class _OVERLAPPED(Structure):
+    pass
+
+OVERLAPPED = _OVERLAPPED
+
+
+class _COMSTAT(Structure):
+    pass
+
+COMSTAT = _COMSTAT
+
+
+class _DCB(Structure):
+    pass
+
+DCB = _DCB
+
+
+class _COMMTIMEOUTS(Structure):
+    pass
+
+COMMTIMEOUTS = _COMMTIMEOUTS
+
+GetLastError = _stdcall_libraries['kernel32'].GetLastError
+GetLastError.restype = DWORD
+GetLastError.argtypes = []
+
+LPOVERLAPPED = POINTER(_OVERLAPPED)
+LPDWORD = POINTER(DWORD)
+
+GetOverlappedResult = _stdcall_libraries['kernel32'].GetOverlappedResult
+GetOverlappedResult.restype = BOOL
+GetOverlappedResult.argtypes = [HANDLE, LPOVERLAPPED, LPDWORD, BOOL]
+
+ResetEvent = _stdcall_libraries['kernel32'].ResetEvent
+ResetEvent.restype = BOOL
+ResetEvent.argtypes = [HANDLE]
+
+LPCVOID = c_void_p
+
+WriteFile = _stdcall_libraries['kernel32'].WriteFile
+WriteFile.restype = BOOL
+WriteFile.argtypes = [HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED]
+
+LPVOID = c_void_p
+
+ReadFile = _stdcall_libraries['kernel32'].ReadFile
+ReadFile.restype = BOOL
+ReadFile.argtypes = [HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED]
+
+CloseHandle = _stdcall_libraries['kernel32'].CloseHandle
+CloseHandle.restype = BOOL
+CloseHandle.argtypes = [HANDLE]
+
+ClearCommBreak = _stdcall_libraries['kernel32'].ClearCommBreak
+ClearCommBreak.restype = BOOL
+ClearCommBreak.argtypes = [HANDLE]
+
+LPCOMSTAT = POINTER(_COMSTAT)
+
+ClearCommError = _stdcall_libraries['kernel32'].ClearCommError
+ClearCommError.restype = BOOL
+ClearCommError.argtypes = [HANDLE, LPDWORD, LPCOMSTAT]
+
+SetupComm = _stdcall_libraries['kernel32'].SetupComm
+SetupComm.restype = BOOL
+SetupComm.argtypes = [HANDLE, DWORD, DWORD]
+
+EscapeCommFunction = _stdcall_libraries['kernel32'].EscapeCommFunction
+EscapeCommFunction.restype = BOOL
+EscapeCommFunction.argtypes = [HANDLE, DWORD]
+
+GetCommModemStatus = _stdcall_libraries['kernel32'].GetCommModemStatus
+GetCommModemStatus.restype = BOOL
+GetCommModemStatus.argtypes = [HANDLE, LPDWORD]
+
+LPDCB = POINTER(_DCB)
+
+GetCommState = _stdcall_libraries['kernel32'].GetCommState
+GetCommState.restype = BOOL
+GetCommState.argtypes = [HANDLE, LPDCB]
+
+LPCOMMTIMEOUTS = POINTER(_COMMTIMEOUTS)
+
+GetCommTimeouts = _stdcall_libraries['kernel32'].GetCommTimeouts
+GetCommTimeouts.restype = BOOL
+GetCommTimeouts.argtypes = [HANDLE, LPCOMMTIMEOUTS]
+
+PurgeComm = _stdcall_libraries['kernel32'].PurgeComm
+PurgeComm.restype = BOOL
+PurgeComm.argtypes = [HANDLE, DWORD]
+
+SetCommBreak = _stdcall_libraries['kernel32'].SetCommBreak
+SetCommBreak.restype = BOOL
+SetCommBreak.argtypes = [HANDLE]
+
+SetCommMask = _stdcall_libraries['kernel32'].SetCommMask
+SetCommMask.restype = BOOL
+SetCommMask.argtypes = [HANDLE, DWORD]
+
+SetCommState = _stdcall_libraries['kernel32'].SetCommState
+SetCommState.restype = BOOL
+SetCommState.argtypes = [HANDLE, LPDCB]
+
+SetCommTimeouts = _stdcall_libraries['kernel32'].SetCommTimeouts
+SetCommTimeouts.restype = BOOL
+SetCommTimeouts.argtypes = [HANDLE, LPCOMMTIMEOUTS]
+
+WaitForSingleObject = _stdcall_libraries['kernel32'].WaitForSingleObject
+WaitForSingleObject.restype = DWORD
+WaitForSingleObject.argtypes = [HANDLE, DWORD]
+
+WaitCommEvent = _stdcall_libraries['kernel32'].WaitCommEvent
+WaitCommEvent.restype = BOOL
+WaitCommEvent.argtypes = [HANDLE, LPDWORD, LPOVERLAPPED]
+
+CancelIoEx = _stdcall_libraries['kernel32'].CancelIoEx
+CancelIoEx.restype = BOOL
+CancelIoEx.argtypes = [HANDLE, LPOVERLAPPED]
+
+ONESTOPBIT = 0  # Variable c_int
+TWOSTOPBITS = 2  # Variable c_int
+ONE5STOPBITS = 1
+
+NOPARITY = 0  # Variable c_int
+ODDPARITY = 1  # Variable c_int
+EVENPARITY = 2  # Variable c_int
+MARKPARITY = 3
+SPACEPARITY = 4
+
+RTS_CONTROL_HANDSHAKE = 2  # Variable c_int
+RTS_CONTROL_DISABLE = 0  # Variable c_int
+RTS_CONTROL_ENABLE = 1  # Variable c_int
+RTS_CONTROL_TOGGLE = 3  # Variable c_int
+SETRTS = 3
+CLRRTS = 4
+
+DTR_CONTROL_HANDSHAKE = 2  # Variable c_int
+DTR_CONTROL_DISABLE = 0  # Variable c_int
+DTR_CONTROL_ENABLE = 1  # Variable c_int
+SETDTR = 5
+CLRDTR = 6
+
+MS_DSR_ON = 32  # Variable c_ulong
+EV_RING = 256  # Variable c_int
+EV_PERR = 512  # Variable c_int
+EV_ERR = 128  # Variable c_int
+SETXOFF = 1  # Variable c_int
+EV_RXCHAR = 1  # Variable c_int
+GENERIC_WRITE = 1073741824  # Variable c_long
+PURGE_TXCLEAR = 4  # Variable c_int
+FILE_FLAG_OVERLAPPED = 1073741824  # Variable c_int
+EV_DSR = 16  # Variable c_int
+MAXDWORD = 4294967295  # Variable c_uint
+EV_RLSD = 32  # Variable c_int
+
+ERROR_SUCCESS = 0
+ERROR_NOT_ENOUGH_MEMORY = 8
+ERROR_OPERATION_ABORTED = 995
+ERROR_IO_INCOMPLETE = 996
+ERROR_IO_PENDING = 997  # Variable c_long
+ERROR_INVALID_USER_BUFFER = 1784
+
+MS_CTS_ON = 16  # Variable c_ulong
+EV_EVENT1 = 2048  # Variable c_int
+EV_RX80FULL = 1024  # Variable c_int
+PURGE_RXABORT = 2  # Variable c_int
+FILE_ATTRIBUTE_NORMAL = 128  # Variable c_int
+PURGE_TXABORT = 1  # Variable c_int
+SETXON = 2  # Variable c_int
+OPEN_EXISTING = 3  # Variable c_int
+MS_RING_ON = 64  # Variable c_ulong
+EV_TXEMPTY = 4  # Variable c_int
+EV_RXFLAG = 2  # Variable c_int
+MS_RLSD_ON = 128  # Variable c_ulong
+GENERIC_READ = 2147483648  # Variable c_ulong
+EV_EVENT2 = 4096  # Variable c_int
+EV_CTS = 8  # Variable c_int
+EV_BREAK = 64  # Variable c_int
+PURGE_RXCLEAR = 8  # Variable c_int
+INFINITE = 0xFFFFFFFF
+
+CE_RXOVER = 0x0001
+CE_OVERRUN = 0x0002
+CE_RXPARITY = 0x0004
+CE_FRAME = 0x0008
+CE_BREAK = 0x0010
+
+
+class N11_OVERLAPPED4DOLLAR_48E(Union):
+    pass
+
+
+class N11_OVERLAPPED4DOLLAR_484DOLLAR_49E(Structure):
+    pass
+
+
+N11_OVERLAPPED4DOLLAR_484DOLLAR_49E._fields_ = [
+    ('Offset', DWORD),
+    ('OffsetHigh', DWORD),
+]
+
+PVOID = c_void_p
+
+N11_OVERLAPPED4DOLLAR_48E._anonymous_ = ['_0']
+N11_OVERLAPPED4DOLLAR_48E._fields_ = [
+    ('_0', N11_OVERLAPPED4DOLLAR_484DOLLAR_49E),
+    ('Pointer', PVOID),
+]
+_OVERLAPPED._anonymous_ = ['_0']
+_OVERLAPPED._fields_ = [
+    ('Internal', ULONG_PTR),
+    ('InternalHigh', ULONG_PTR),
+    ('_0', N11_OVERLAPPED4DOLLAR_48E),
+    ('hEvent', HANDLE),
+]
+_SECURITY_ATTRIBUTES._fields_ = [
+    ('nLength', DWORD),
+    ('lpSecurityDescriptor', LPVOID),
+    ('bInheritHandle', BOOL),
+]
+_COMSTAT._fields_ = [
+    ('fCtsHold', DWORD, 1),
+    ('fDsrHold', DWORD, 1),
+    ('fRlsdHold', DWORD, 1),
+    ('fXoffHold', DWORD, 1),
+    ('fXoffSent', DWORD, 1),
+    ('fEof', DWORD, 1),
+    ('fTxim', DWORD, 1),
+    ('fReserved', DWORD, 25),
+    ('cbInQue', DWORD),
+    ('cbOutQue', DWORD),
+]
+_DCB._fields_ = [
+    ('DCBlength', DWORD),
+    ('BaudRate', DWORD),
+    ('fBinary', DWORD, 1),
+    ('fParity', DWORD, 1),
+    ('fOutxCtsFlow', DWORD, 1),
+    ('fOutxDsrFlow', DWORD, 1),
+    ('fDtrControl', DWORD, 2),
+    ('fDsrSensitivity', DWORD, 1),
+    ('fTXContinueOnXoff', DWORD, 1),
+    ('fOutX', DWORD, 1),
+    ('fInX', DWORD, 1),
+    ('fErrorChar', DWORD, 1),
+    ('fNull', DWORD, 1),
+    ('fRtsControl', DWORD, 2),
+    ('fAbortOnError', DWORD, 1),
+    ('fDummy2', DWORD, 17),
+    ('wReserved', WORD),
+    ('XonLim', WORD),
+    ('XoffLim', WORD),
+    ('ByteSize', BYTE),
+    ('Parity', BYTE),
+    ('StopBits', BYTE),
+    ('XonChar', c_char),
+    ('XoffChar', c_char),
+    ('ErrorChar', c_char),
+    ('EofChar', c_char),
+    ('EvtChar', c_char),
+    ('wReserved1', WORD),
+]
+_COMMTIMEOUTS._fields_ = [
+    ('ReadIntervalTimeout', DWORD),
+    ('ReadTotalTimeoutMultiplier', DWORD),
+    ('ReadTotalTimeoutConstant', DWORD),
+    ('WriteTotalTimeoutMultiplier', DWORD),
+    ('WriteTotalTimeoutConstant', DWORD),
+]
+__all__ = ['GetLastError', 'MS_CTS_ON', 'FILE_ATTRIBUTE_NORMAL',
+           'DTR_CONTROL_ENABLE', '_COMSTAT', 'MS_RLSD_ON',
+           'GetOverlappedResult', 'SETXON', 'PURGE_TXABORT',
+           'PurgeComm', 'N11_OVERLAPPED4DOLLAR_48E', 'EV_RING',
+           'ONESTOPBIT', 'SETXOFF', 'PURGE_RXABORT', 'GetCommState',
+           'RTS_CONTROL_ENABLE', '_DCB', 'CreateEvent',
+           '_COMMTIMEOUTS', '_SECURITY_ATTRIBUTES', 'EV_DSR',
+           'EV_PERR', 'EV_RXFLAG', 'OPEN_EXISTING', 'DCB',
+           'FILE_FLAG_OVERLAPPED', 'EV_CTS', 'SetupComm',
+           'LPOVERLAPPED', 'EV_TXEMPTY', 'ClearCommBreak',
+           'LPSECURITY_ATTRIBUTES', 'SetCommBreak', 'SetCommTimeouts',
+           'COMMTIMEOUTS', 'ODDPARITY', 'EV_RLSD',
+           'GetCommModemStatus', 'EV_EVENT2', 'PURGE_TXCLEAR',
+           'EV_BREAK', 'EVENPARITY', 'LPCVOID', 'COMSTAT', 'ReadFile',
+           'PVOID', '_OVERLAPPED', 'WriteFile', 'GetCommTimeouts',
+           'ResetEvent', 'EV_RXCHAR', 'LPCOMSTAT', 'ClearCommError',
+           'ERROR_IO_PENDING', 'EscapeCommFunction', 'GENERIC_READ',
+           'RTS_CONTROL_HANDSHAKE', 'OVERLAPPED',
+           'DTR_CONTROL_HANDSHAKE', 'PURGE_RXCLEAR', 'GENERIC_WRITE',
+           'LPDCB', 'CreateEventW', 'SetCommMask', 'EV_EVENT1',
+           'SetCommState', 'LPVOID', 'CreateFileW', 'LPDWORD',
+           'EV_RX80FULL', 'TWOSTOPBITS', 'LPCOMMTIMEOUTS', 'MAXDWORD',
+           'MS_DSR_ON', 'MS_RING_ON',
+           'N11_OVERLAPPED4DOLLAR_484DOLLAR_49E', 'EV_ERR',
+           'ULONG_PTR', 'CreateFile', 'NOPARITY', 'CloseHandle']
diff --git a/src/devtools/meta/src/common/src/SerPort.cpp b/src/devtools/meta/src/common/src/SerPort.cpp
old mode 100644
new mode 100755
index eaf952f..11e14c9
--- a/src/devtools/meta/src/common/src/SerPort.cpp
+++ b/src/devtools/meta/src/common/src/SerPort.cpp
@@ -525,9 +525,10 @@
 	{
 		/* keep last 2 zeroes to ensure double 0 termination */
 		int count = recv(m_ueventSocket, uevent_desc, sizeof(uevent_desc) - 2, 0);
-		if (count > 0) 
+		if (count > 0)
 		{
 			//META_LOG("[Meta][DEBUG] uevent_desc: %s, count: %d ", uevent_desc, count);
+			uevent_desc[count - 1] = '\0';
 			handleUsbUevent(uevent_desc, count);
 		}
 	}
diff --git a/src/extended/mii_mgr/Makefile b/src/extended/mii_mgr/Makefile
new file mode 100755
index 0000000..e5cfd1c
--- /dev/null
+++ b/src/extended/mii_mgr/Makefile
@@ -0,0 +1,32 @@
+EXEC = mii_mgr mii_mgr_cl45
+
+CFLAGS += -Wall -Werror
+
+ifneq ($(CONFIG_SUPPORT_OPENWRT), y)
+ifeq ($(CONFIG_GLIBC_2_20),y)
+CFLAGS += -DCONFIG_GLIBC_2_20
+endif
+CFLAGS += -I$(ROOTDIR)/$(LINUXDIR)
+ifeq ($(CONFIG_DEFAULTS_KERNEL_4_4),y)
+CFLAGS += -I$(ROOTDIR)/$(LINUXDIR)/drivers/net/ethernet/raeth
+else
+CFLAGS += -I$(ROOTDIR)/$(LINUXDIR)/drivers/net/raeth
+endif
+endif #CONFIG_SUPPORT_OPENWRT
+
+all: $(EXEC)
+
+mii_mgr: mii_mgr.o
+
+	$(CC) $(LDFLAGS) -o $@ $^
+
+mii_mgr_cl45: mii_mgr_cl45.o
+	$(CC) $(LDFLAGS) -o $@ $^
+
+romfs:
+	$(ROMFSINST) /bin/mii_mgr
+	$(ROMFSINST) /bin/mii_mgr_cl45
+
+clean:
+	-rm -f $(EXEC) *.elf *.gdb *.o
+
diff --git a/src/extended/mii_mgr/mii_mgr.c b/src/extended/mii_mgr/mii_mgr.c
new file mode 100755
index 0000000..56cbe4e
--- /dev/null
+++ b/src/extended/mii_mgr/mii_mgr.c
@@ -0,0 +1,152 @@
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <linux/if.h>
+#include <linux/mii.h>
+#include <linux/types.h>
+#include <unistd.h>
+
+#ifndef CONFIG_SUPPORT_OPENWRT
+#ifndef CONFIG_GLIBC_2_20
+#include <linux/autoconf.h>
+#endif
+#endif
+
+#include "ra_ioctl.h"
+
+#ifndef CONFIG_SUPPORT_OPENWRT
+#define ETH_DEVNAME "eth2"
+#else
+#define ETH_DEVNAME "eth0"
+#endif
+
+void show_usage(void)
+{
+#ifndef CONFIG_RT2860V2_AP_MEMORY_OPTIMIZATION
+	printf("mii_mgr -g -p [phy number] -r [register number]\n");
+	printf("  Get: mii_mgr -g -p 3 -r 4\n\n");
+	printf("mii_mgr -s -p [phy number] -r [register number] -v [0xvalue]\n");
+	printf("  Set: mii_mgr -s -p 4 -r 1 -v 0xff11\n\n");
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+	int sk, opt, ret = 0;
+	char options[] = "gsp:r:v:L:G:?t";
+	int method = 0;
+	struct ifreq ifr;
+	struct ra_mii_ioctl_data mii;
+
+#if defined (CONFIG_RALINK_MT7628)
+	struct ifreq ifr2;
+	struct ra_mii_ioctl_data mii2;
+	int page_select = 0;
+	int method2 = 0;
+#endif
+	if (argc < 6) {
+		show_usage();
+		return 0;
+	}
+
+	sk = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sk < 0) {
+		printf("Open socket failed\n");
+		return -1;
+	}
+
+	strncpy(ifr.ifr_name,ETH_DEVNAME, 5);
+	ifr.ifr_data = &mii;
+#if defined (CONFIG_RALINK_MT7628)
+	strncpy(ifr2.ifr_name, ETH_DEVNAME , 5);
+	ifr2.ifr_data = &mii2;
+#endif
+
+	while ((opt = getopt(argc, argv, options)) != -1) {
+		switch (opt) {
+			case 'g':
+				method = RAETH_MII_READ;
+				break;
+			case 's':
+				method = RAETH_MII_WRITE;
+				break;
+			case 'p':
+				mii.phy_id = strtoul(optarg, NULL, 10);
+#if defined (CONFIG_RALINK_MT7628)
+				mii2.phy_id = strtoul(optarg, NULL, 10);
+#endif
+				break;
+			case 'r':
+#if defined (CONFIG_RALINK_MT7621) || defined(CONFIG_MACH_MT7623)
+				if(mii.phy_id == 31) {
+					mii.reg_num = strtol(optarg, NULL, 16);
+				} else {
+					mii.reg_num = strtol(optarg, NULL, 10);
+				}
+#else
+				mii.reg_num = strtol(optarg, NULL, 10);
+#endif
+				break;
+			case 'L':
+#if defined (CONFIG_RALINK_MT7628)
+				mii2.reg_num = 31;
+				mii2.val_in = (strtol(optarg, NULL, 16) << 12);
+				mii2.val_in |= 0x8000;
+				page_select = 1;
+#endif
+				break;
+			case 'G':
+#if defined (CONFIG_RALINK_MT7628)
+				mii2.reg_num = 31;
+				mii2.val_in = (strtol(optarg, NULL, 16) << 12);
+				page_select = 1;
+#endif
+				break;
+
+			case 'v':
+				mii.val_in = strtol(optarg, NULL, 16);
+				break;
+			case '?':
+				show_usage();
+				break;
+		}
+	}
+
+#if defined (CONFIG_RALINK_MT7628)
+	if(page_select){
+	        method2 = RAETH_MII_WRITE;
+		ret = ioctl(sk, method2, &ifr2);
+		if (ret < 0) {
+			printf("mii_mgr: ioctl error\n");
+		}
+		else{
+			printf("Set: phy[%d].reg[%d] = %04x\n",
+							mii2.phy_id, mii2.reg_num, mii2.val_in);
+
+		}
+	}
+#endif
+	if ((method == RAETH_MII_READ) || (method == RAETH_MII_WRITE)){
+		ret = ioctl(sk, method, &ifr);
+		if (ret < 0) {
+			printf("mii_mgr: ioctl error\n");
+		}
+		else
+			switch (method) {
+				case RAETH_MII_READ:
+					printf("Get: phy[%d].reg[%d] = %04x\n",
+							mii.phy_id, mii.reg_num, mii.val_out);
+					break;
+				case RAETH_MII_WRITE:
+					printf("Set: phy[%d].reg[%d] = %04x\n",
+							mii.phy_id, mii.reg_num, mii.val_in);
+					break;
+			}
+	}
+	close(sk);
+	return ret;
+}
diff --git a/src/extended/mii_mgr/mii_mgr_cl45.c b/src/extended/mii_mgr/mii_mgr_cl45.c
new file mode 100755
index 0000000..7edd927
--- /dev/null
+++ b/src/extended/mii_mgr/mii_mgr_cl45.c
@@ -0,0 +1,103 @@
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <linux/if.h>
+#include <linux/mii.h>
+#include <linux/types.h>
+#include <unistd.h>
+
+#ifndef CONFIG_SUPPORT_OPENWRT
+#ifndef CONFIG_GLIBC_2_20
+#include <linux/autoconf.h>
+#endif
+#endif
+
+#ifndef CONFIG_SUPPORT_OPENWRT
+#define ETH_DEVNAME "eth2"
+#else
+#define ETH_DEVNAME "eth0"
+#endif
+#include "ra_ioctl.h"
+
+void show_usage(void)
+{
+#ifndef CONFIG_RT2860V2_AP_MEMORY_OPTIMIZATION
+	printf("Get: mii_mgr_cl45 -g -p [port number] -d [dev number] -r [register number]\n");
+	printf("Example: mii_mgr_cl45 -g -p 3 -d 0x5 -r 0x4\n\n");
+	printf("Set: mii_mgr_cl45 -s -p [port number] -d [dev number] -r [register number] -v [value]\n");
+	printf("Example: mii_mgr_cl45 -s -p 4 -d 0x6 -r 0x1 -v 0xff11\n\n");
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+	int sk, opt, ret = 0;
+	char options[] = "gsp:d:r:v:?t";
+	int method = 0;
+	struct ifreq ifr;
+	struct ra_mii_ioctl_data mii;
+
+	if (argc < 8) {
+		show_usage();
+		return 0;
+	}
+
+	sk = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sk < 0) {
+		printf("Open socket failed\n");
+		return -1;
+	}
+
+	strncpy(ifr.ifr_name, ETH_DEVNAME, 5);
+	ifr.ifr_data = &mii;
+
+	while ((opt = getopt(argc, argv, options)) != -1) {
+		switch (opt) {
+			case 'g':
+				method = RAETH_MII_READ_CL45;
+				break;
+			case 's':
+				method = RAETH_MII_WRITE_CL45;
+				break;
+			case 'p':
+				mii.port_num = strtoul(optarg, NULL, 16);
+				break;
+			case 'd':
+				mii.dev_addr = strtoul(optarg, NULL, 16);
+				break;
+			case 'r':
+				mii.reg_addr = strtol(optarg, NULL, 16);
+				break;
+			case 'v':
+				mii.val_in = strtol(optarg, NULL, 16);
+				break;
+			case '?':
+				show_usage();
+				break;
+		}
+	}
+
+	if ((method == RAETH_MII_READ_CL45) || (method == RAETH_MII_WRITE_CL45)){
+		ret = ioctl(sk, method, &ifr);
+		if (ret < 0) {
+			printf("mii_mgr_cl45: ioctl error\n");
+		}
+		else
+			switch (method) {
+				case RAETH_MII_READ_CL45:
+					printf("Get: port%d dev%Xh_reg%Xh = 0x%04X\n",
+							mii.port_num, mii.dev_addr, mii.reg_addr, mii.val_out);
+					break;
+				case RAETH_MII_WRITE_CL45:
+					printf("Set: port%d dev%Xh_reg%Xh = 0x%04X\n",
+							mii.port_num, mii.dev_addr, mii.reg_addr, mii.val_in);
+					break;
+			}
+	}
+	close(sk);
+	return ret;
+}
diff --git a/src/extended/mii_mgr/mii_mgr_rtk.c b/src/extended/mii_mgr/mii_mgr_rtk.c
new file mode 100755
index 0000000..8c83869
--- /dev/null
+++ b/src/extended/mii_mgr/mii_mgr_rtk.c
@@ -0,0 +1,81 @@
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <linux/if.h>
+#include <linux/mii.h>
+#include <linux/types.h>
+#include <unistd.h>
+
+#include "ra_ioctl.h"
+
+#ifndef CONFIG_SUPPORT_OPENWRT
+#define ETH_DEVNAME "eth2"
+#else
+#define ETH_DEVNAME "eth0"
+#endif
+
+void show_usage(void)
+{
+	printf("mii_mgr -g -p [phy number] -r [register number]\n");
+	printf("  Get: mii_mgr -g -p 3 -r 4\n\n");
+	printf("mii_mgr -s -p [phy number] -r [register number] -v [0xvalue]\n");
+	printf("  Set: mii_mgr -s -p 4 -r 1 -v 0xff11\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+	int sk, opt, ret = 0;
+	char options[] = "gsp:r:v:L:G:?t";
+	struct ifreq ifr;
+	struct ra_switch_ioctl_data data;
+
+	if (argc < 6) {
+		show_usage();
+		return 0;
+	}
+
+	sk = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sk < 0) {
+		printf("Open socket failed\n");
+		return -1;
+	}
+
+	strncpy(ifr.ifr_name, ETH_DEVNAME , 5);
+	ifr.ifr_data = &data;
+
+	while ((opt = getopt(argc, argv, options)) != -1) {
+		switch (opt) {
+			case 'g':
+				data.cmd = SW_IOCTL_GET_PHY_REG;
+				break;
+			case 's':
+				data.cmd = SW_IOCTL_SET_PHY_REG;
+				break;
+			case 'p':
+				data.port = strtoul(optarg, NULL, 10);
+				break;
+			case 'r':
+				data.reg_addr = strtol(optarg, NULL, 10);
+				break;
+			case 'v':
+				data.reg_val = strtol(optarg, NULL, 16);
+				break;
+			case '?':
+				show_usage();
+				break;
+		}
+	}
+
+	if ((data.cmd == SW_IOCTL_GET_PHY_REG) || (data.cmd == SW_IOCTL_SET_PHY_REG)){
+		ret = ioctl(sk, RAETH_SW_IOCTL, &ifr);
+		if (ret < 0) {
+			printf("mii_mgr: ioctl error\n");
+		}
+	}
+	close(sk);
+	return ret;
+}
diff --git a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb-ivt-emmc.dts b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb-ivt-emmc.dts
old mode 100644
new mode 100755
index a383d58..442f46d
--- a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb-ivt-emmc.dts
+++ b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb-ivt-emmc.dts
@@ -39,8 +39,10 @@
 		atag,videolfb-vramSize= <0x1be0000>;
 		atag,videolfb-lcmname=
 			"nt35595_fhd_dsi_cmd_truly_nt50358_drv";
+#if defined(CONFIG_MTK_AEE_FEATURE)
 		aee,enable = "mini";
 		mrdump,cblock = <0x12e000 0x2000>;
+#endif
 		atag,boot = <0x03000000 0x02080041 0x0>;
 	};
 
@@ -65,43 +67,17 @@
 };
 
 &snps_mac {
-	phy-mode ="rgmii-rxid";
-	phy-handle = <&eth_phy0>;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth_default>;
-	pinctrl-1 = <&eth_sleep>;
-	mediatek,tx-delay-ps = <560>;
-	mediatek,rx-delay-ps = <1440>;
-	snps,reset-gpio = <&pio 24 GPIO_ACTIVE_LOW>;
-	snps,reset-active-low;
-	snps,reset-delays-us = <0 1000 0>;
 	status = "okay";
-
-	mdio {
+	phy-mode ="sgmii";
+	fixed-link {
+		speed = <1000>;
+		pause;
+		full-duplex;
+	};
+	snps_mdio: mdio-bus {
 		compatible = "snps,dwmac-mdio";
 		#address-cells = <1>;
 		#size-cells = <0>;
-		eth_phy0: eth_phy0@0 {
-			compatible = "ethernet-phy-id0022.1640";
-			phy-intr-gpio = <&pio 25 0>;
-			reg = <0x0>;
-			rxc-skew-psec = <4294967096>;
-			txc-skew-psec = <4294966596>;
-			txd0-skew-psec = <600>;
-			txd1-skew-psec = <600>;
-			txd2-skew-psec = <600>;
-			txd3-skew-psec = <600>;
-			txen-skew-psec = <600>;
-		};
-		eth_phy1: eth_phy1@7 {
-			compatible = "ethernet-phy-ieee802.3-c45";
-			marvell,88q2110 = <1000 0>;
-			reg = <0x7>;
-		};
-		eth_phy2: eth_phy2@4 {
-			compatible = "ethernet-phy-id0180.DD00";
-			reg = <0x4>;
-		};
 	};
 };
 
@@ -114,16 +90,6 @@
 	pinctrl-1 = <&eth_smi_mdio_pinctl>;
 	pinctrl-2 = <&eth_smi_mdc_pinctl>;
 	status = "okay";
-	gmac0: mac@0 {
-		compatible = "mediatek,eth-mac";
-		reg = <0>;
-		phy-mode = "sgmii";
-		fixed-link {
-			speed = <1000>;
-			full-duplex;
-			pause;
-		};
-	};
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
@@ -861,7 +827,7 @@
 		mdio_pins {
 			pinmux = <PINMUX_GPIO12__FUNC_GBE_MDC>,
 				 <PINMUX_GPIO13__FUNC_GBE_MDIO>;
-			drive-strength = <4>;
+			drive-strength = <3>;
 			bias-disable;
 		};
 	};
diff --git a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts
old mode 100644
new mode 100755
index 85f7d53..cb2b193
--- a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts
+++ b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts
@@ -35,8 +35,9 @@
 
 	chosen {
 		bootargs = "console=tty0 console=ttyS0,921600n1 ubi.mtd=14 \
-		root=ubi0_0 ubi.mtd=38,0,2 ubi.mtd=5,0,1 \
-		ubi.mtd=9,0,1 ubi.mtd=10,0,1 ubi.mtd=11,0,1 ubi.mtd=40,0,1 ubi.mtd=27,0,1\
+		ubi.mtd=38,0,2 ubi.mtd=5,0,1 \
+		ubi.mtd=9,0,1 ubi.mtd=10,0,1 ubi.mtd=11,0,1 ubi.mtd=40,0,1 \
+		ubi.mtd=27,0,1 ubi.mtd=20,0,1 ubi.mtd=22,0,1 \
 		rootwait \
 		androidboot.selinux=permissive androidboot.hardware=mt6890 \
 		initcall_debug=1 page_owner=on";
@@ -49,8 +50,10 @@
 		atag,videolfb-vramSize= <0x1be0000>;
 		atag,videolfb-lcmname=
 			"nt35595_fhd_dsi_cmd_truly_nt50358_drv";
+#if defined(CONFIG_MTK_AEE_FEATURE)
 		aee,enable = "mini";
 		mrdump,cblock = <0x12e000 0x2000>;
+#endif
 		atag,boot = <0x03000000 0x02080041 0x0>;
 	};
 
@@ -136,6 +139,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+#if defined(CONFIG_MTK_SGMII_NETSYS)
 		phy-mode = "sgmii";
 		phy-handle = <&eth_phy1>;
                 /*modify by chencheng 0817*/
@@ -146,22 +150,22 @@
 			pause;
 		};
 		*/
+#endif
 	};
-
+	
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+#if defined(CONFIG_MTK_SGMII_NETSYS)
 		phy-mode = "sgmii";
-		//phy-handle = <&eth_phy2>;
-		
 		fixed-link {
 			speed = <1000>;
 			full-duplex;
 			pause;
 		};
-		
+#endif
 	};
-
+	
 	mdio: mdio-bus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -170,11 +174,6 @@
 			compatible = "ethernet-phy-ieee802.3-c22";
 			reg = <0x1>;
 		};
-		eth_phy2: eth_phy2@7 {   /*modify by chencheng 0817*/
-		    phy-mode = "sgmii";
-			compatible = "ethernet-phy-ieee802.3-c45";
-			reg = <0x7>;
-		};
 	};
 };
 
@@ -664,7 +663,7 @@
 		mdio_pins {
 			pinmux = <PINMUX_GPIO12__FUNC_GBE_MDC>,
 				 <PINMUX_GPIO13__FUNC_GBE_MDIO>;
-			drive-strength = <4>;
+			drive-strength = <3>;
 			bias-disable;
 
 		};
@@ -1343,6 +1342,7 @@
 /*zhengzhou 0316 ++++*/
 	compatible = "linux,extcon-usb-gpio";
 	vbus-voltage = <5000000>;
+	vbus-supply = <&otg_vbus>;
 	vbus-current = <1800000>;
 	/*zhengzhou 0316 ----*/
 };
diff --git a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi
old mode 100644
new mode 100755
index 013eb87..8d89be9
--- a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi
+++ b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi
@@ -437,17 +437,14 @@
 			ftrace-size = <0x1000>;
 			pmsg-size = <0x10000>;
 		};
-
-		reserved-memory-aee {
-			reg = <0x0 0x4340a000 0x0 0x100000>;
-			compatible = "mediatek,aee-lk";
-		};
 		
+#if defined(CONFIG_MTK_AEE_FEATURE)
 		reserve-memory-emi_isu_buf {
 			compatible = "mediatek,emi_isu_buf";
 			no-map;
 			reg = <0 0x60800000 0 0x800000>;
 		};
+#endif
 
 		wocpu0_emi: wocpu0_emi@50000000 {
                         compatible = "mediatek,wocpu0_emi";
@@ -470,11 +467,13 @@
                         shared = <1>;
                 };
 
+#if defined(CONFIG_OPTEE)
 		reserve-memory-tee {
 			compatible = "mediatek,reserve-memory-tee";
 			no-map;
 			reg = <0 0x4e9a0000 0 0xb00000>;
 		};
+#endif
 	};
 
 	gic: interrupt-controller {
@@ -580,7 +579,8 @@
 			<&topckgen_clk CLK_TOP_SNPS_ETH_62P4M_PTP_SEL>,
 			<&topckgen_clk CLK_TOP_SNPS_ETH_50M_RMII_SEL>,
 			<&topckgen_clk CLK_TOP_EIP97_SEL>,
-			<&infracfg_ao_clk CLK_IFRAO_AUDIO_26M_BCLK>;
+			<&infracfg_ao_clk CLK_IFRAO_AUDIO_26M_BCLK>,
+			<&topckgen_clk CLK_TOP_HSM_ARC_SEL>;
 		clock-names = "mm",
 			"mfg",
 			"snps_eth_312p5m_sel",
@@ -588,7 +588,8 @@
 			"snps_ptp_sel",
 			"snps_rmii_sel",
 			"eip97_sel",
-			"audio";
+			"audio",
+			"hsm_sel";
 		/*status="disabled";*/
 	};
 
@@ -2442,6 +2443,7 @@
 			"pwm7";
 	};
 
+#if defined(CONFIG_MTK_SGMII_NETSYS)
 	sgmii0@10060000 {
 		compatible = "mediatek,sgmii0";
 		reg = <0 0x10060000 0 0x8000>;
@@ -2453,6 +2455,7 @@
 		reg = <0 0x10070000 0 0x8000>;
 		interrupts = <GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>;
 	};
+#endif
 
 	sys_cirq@10204000 {
 		compatible = "mediatek,sys_cirq";
@@ -3006,7 +3009,7 @@
 			  <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
 			  <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,/*zhengzhou uart*/
 			  <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;/*zhengzhou uart*/
-		dma-requests = <8>;
+		dma-requests = <6>;
 		dma-bits = <34>;
 		clocks = <&clk26m>;
 		#dma-cells = <1>;
@@ -3104,6 +3107,7 @@
 		status = "ok";
 	};
 
+#if defined(CONFIG_MTK_SGMII_NETSYS)
 	pd-sgmii_0_phy {
 		compatible = "mediatek,sgmii-bring-up";
 		power-domains = <&scpsys MT6890_POWER_DOMAIN_SGMII_0_PHY>;
@@ -3157,6 +3161,7 @@
         /*modify by CLK SW Pei-hsuan Cheng */
 		power-domains = <&scpsys MT6890_POWER_DOMAIN_SGMII_1_PHY>;
 	};
+#endif
 
 	ethsys: ethsys@15000000 {
 		#address-cells = <1>;
@@ -3181,7 +3186,11 @@
         };
 
 	eth: ethernet@15100000 {
+#if defined(CONFIG_MTK_SGMII_NETSYS)
 		compatible = "mediatek,mt6890-eth",
+#else
+		compatible = "mediatek,mt2735-eth",
+#endif
 			     "syscon";
 		reg = <0 0x15100000 0 0x20000>;
 		interrupts-extended = <&gic GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,
@@ -3193,6 +3202,7 @@
 				<&gic GIC_SPI 390 IRQ_TYPE_LEVEL_HIGH>,
 				<&gic GIC_SPI 392 IRQ_TYPE_LEVEL_HIGH>,
 				<&pio 63 IRQ_TYPE_LEVEL_LOW>;
+#if defined(CONFIG_MTK_SGMII_NETSYS)
 		clocks = <&topckgen_clk CLK_TOP_NETSYS_SEL>,
 			 <&topckgen_clk CLK_TOP_MEDSYS_SEL>,
 			 <&topckgen_clk CLK_TOP_NETSYS_500M_SEL>,
@@ -3204,17 +3214,31 @@
 		clock-names = "net_sel", "med_sel", "net_500_sel",
 			      "med_mcu_sel", "wed_mcu_sel",
 			      "net_2x_sel", "sgmii_sel", "sgmii_sbus_sel";
+#else
+		clocks = <&topckgen_clk CLK_TOP_NETSYS_SEL>,
+			 <&topckgen_clk CLK_TOP_MEDSYS_SEL>,
+			 <&topckgen_clk CLK_TOP_NETSYS_500M_SEL>,
+			 <&topckgen_clk CLK_TOP_NETSYS_MED_MCU_SEL>,
+			 <&topckgen_clk CLK_TOP_NETSYS_WED_MCU_SEL>,
+			 <&topckgen_clk CLK_TOP_NETSYS_2X_SEL>;
+		clock-names = "net_sel", "med_sel", "net_500_sel",
+			      "med_mcu_sel", "wed_mcu_sel",
+			      "net_2x_sel";
+#endif
         /*modify by CLK SW Pei-hsuan Cheng
 		power-domains = <&scpsys MT6890_POWER_DOMAIN_NETSYS>;*/
 		mediatek,ethsys = <&ethsys>;
 		mediatek,wo = <&wo>;
+#if defined(CONFIG_MTK_SGMII_NETSYS)
 		mediatek,sgmiisys = <&sgmiisys_0>,<&sgmiisys_1>;
 		mediatek,sgmiisys_phy = <&sgmiisys_phy_0>,<&sgmiisys_phy_1>;
+#endif
 		#address-cells = <1>;
 		#size-cells = <0>;
 		status = "okay";
 	};
 
+#if defined(CONFIG_MTK_SGMII_NETSYS)
 	snps-pdsgmii_0_phy {
 		compatible = "mediatek,sgmii-up";
 		power-domains = <&scpsys MT6890_POWER_DOMAIN_SGMII_0_PHY>;
@@ -3224,6 +3248,7 @@
 		compatible = "mediatek,sgmii-up";
 		power-domains = <&scpsys MT6890_POWER_DOMAIN_SGMII_0_TOP>;
 	};
+#endif
 
 	stmmac_axi_setup: stmmac-axi-config {
 		snps,wr_osr_lmt = <0x7>;
@@ -3281,6 +3306,20 @@
 		interrupts = <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
 		interrupt-names = "macirq";
 		mac-address = [00 55 7b b5 7d f7];
+#if defined(CONFIG_MTK_SGMII_SNPS)
+		clock-names = "mac_main",
+			      "ptp_ref",
+			      "eth_cg",
+			      "eth_rmii",
+			      "sgmii_sel",
+			      "sgmii_sbus_sel";
+		clocks = <&topckgen_clk CLK_TOP_SNPS_ETH_312P5M_SEL>,
+			 <&topckgen_clk CLK_TOP_SNPS_ETH_62P4M_PTP_SEL>,
+			 <&topckgen_clk CLK_TOP_SNPS_ETH_250M_SEL>,
+			 <&topckgen_clk CLK_TOP_SNPS_ETH_50M_RMII_SEL>,
+			 <&topckgen_clk CLK_TOP_SGMII_SEL>,
+			 <&topckgen_clk CLK_TOP_SGMII_SBUS_SEL>;
+#else
 		clock-names = "mac_main",
 			      "ptp_ref",
 			      "eth_cg",
@@ -3289,12 +3328,17 @@
 			 <&topckgen_clk CLK_TOP_SNPS_ETH_62P4M_PTP_SEL>,
 			 <&topckgen_clk CLK_TOP_SNPS_ETH_250M_SEL>,
 			 <&topckgen_clk CLK_TOP_SNPS_ETH_50M_RMII_SEL>;
+#endif
 		mediatek,pericfg = <&infracfg_ao>;
 		snps,axi-config = <&stmmac_axi_setup>;
 		snps,mtl-rx-config = <&mtl_rx_setup>;
 		snps,mtl-tx-config = <&mtl_tx_setup>;
 		/*modify by CLK SW Pei-hsuan Cheng */
 		power-domains = <&scpsys MT6890_POWER_DOMAIN_ETH>;
+#if defined(CONFIG_MTK_SGMII_SNPS)
+		mediatek,sgmiisys = <&sgmiisys_0>;
+		mediatek,sgmiisys_phy = <&sgmiisys_phy_0>;
+#endif
 		snps,txpbl = <16>;
 		snps,rxpbl = <16>;
 		clk_csr = <0>;
@@ -4386,7 +4430,7 @@
 	/*zhengzhou 0316 +++*/
 	    compatible = "linux,extcon-usb-gpio";
         id-gpio = <&pio 40 GPIO_ACTIVE_HIGH>;
-		//vbus-gpio = <&pio 42 GPIO_ACTIVE_HIGH>;//tianyan@2021.11.29 modify for usb otg
+		vbus-gpio = <&pio 42 GPIO_ACTIVE_HIGH>;//tianyan@2021.11.29 modify for usb otg
 		/*compatible = "mediatek,extcon-usb";*/
 	/*	dev-conn = <&ssusb>;*/
 	/*	 id-gpio = <&pio 12 GPIO_ACTIVE_HIGH>;*/
diff --git a/src/kernel/linux/v4.19/drivers/char/rpmb/drrpmb_gp/public/dci.h b/src/kernel/linux/v4.19/drivers/char/rpmb/drrpmb_gp/public/dci.h
old mode 100644
new mode 100755
index cd8ba4b..5dafab5
--- a/src/kernel/linux/v4.19/drivers/char/rpmb/drrpmb_gp/public/dci.h
+++ b/src/kernel/linux/v4.19/drivers/char/rpmb/drrpmb_gp/public/dci.h
@@ -1,15 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (c) 2013-2016 TRUSTONIC LIMITED
- * All Rights Reserved.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (c) 2021 Mediatek Inc.
  */
 
 /**
diff --git a/src/kernel/linux/v4.19/drivers/clk/mediatek/clk-mt6890.c b/src/kernel/linux/v4.19/drivers/clk/mediatek/clk-mt6890.c
index de820bc..897d0ef 100755
--- a/src/kernel/linux/v4.19/drivers/clk/mediatek/clk-mt6890.c
+++ b/src/kernel/linux/v4.19/drivers/clk/mediatek/clk-mt6890.c
@@ -522,7 +522,9 @@
 			"netsys_sel", 1, 1),
 	FACTOR(CLK_TOP_MEDSYS, "medsys_ck",
 			"medsys_sel", 1, 1),
-	/* HSM isn't in kernel */
+	/* HSM CRYPTO isn't in kernel */
+	FACTOR(CLK_TOP_HSM_ARC, "hsm_arc_ck",
+			"hsm_arc_sel", 1, 1),
 	FACTOR(CLK_TOP_EIP97, "eip97_ck",
 			"eip97_sel", 1, 1),
 	FACTOR(CLK_TOP_SNPS_ETH_312P5M, "snps_eth_312p5m_ck",
@@ -857,6 +859,13 @@
 	"univpll_d7"
 };
 
+static const char * const hsm_arc_parents[] = {
+	"tck_26m_mx9_ck",
+	"mainpll_d4_d8",
+	"mainpll_d4_d4",
+	"mainpll_d6_d2"
+};
+
 static const char * const eip97_parents[] = {
 	"tck_26m_mx9_ck",
 	"net2pll_ck",
@@ -1174,9 +1183,13 @@
 		CLK_CFG_9_CLR/* set parent */, 16/* lsb */, 3/* width */,
 		INV_BIT/* pdn bit */, CLK_CFG_UPDATE1/* upd ofs */,
 		TOP_MUX_MEDSYS_SHIFT/* upd shift */),
-	/* HSM isn't in kernel */
+	/* HSM crypto isn't in kernel */
 	/* CLK_CFG_10 */
-	/* HSM isn't in kernel */
+	MUX_CLR_SET_UPD(CLK_TOP_HSM_ARC_SEL/* dts */, "hsm_arc_sel",
+		hsm_arc_parents/* parent */, CLK_CFG_10, CLK_CFG_10_SET,
+		CLK_CFG_10_CLR/* set parent */, 0/* lsb */, 2/* width */,
+		INV_BIT/* pdn bit */, CLK_CFG_UPDATE1/* upd ofs */,
+		TOP_MUX_HSM_ARC_SHIFT/* upd shift */),
 	MUX_CLR_SET_UPD(CLK_TOP_EIP97_SEL/* dts */, "eip97_sel",
 		eip97_parents/* parent */, CLK_CFG_10, CLK_CFG_10_SET,
 		CLK_CFG_10_CLR/* set parent */, 8/* lsb */, 3/* width */,
@@ -1445,8 +1458,13 @@
 		CLK_CFG_9_CLR/* set parent */, 16/* lsb */, 3/* width */,
 		23/* pdn */, CLK_CFG_UPDATE1/* upd ofs */,
 		TOP_MUX_MEDSYS_SHIFT/* upd shift */),
-	/* HSM isn't in kernel. */
+	/* HSM crypto isn't in kernel. */
 	/* CLK_CFG_10 */
+	MUX_CLR_SET_UPD(CLK_TOP_HSM_ARC_SEL/* dts */, "hsm_arc_sel",
+		hsm_arc_parents/* parent */, CLK_CFG_10, CLK_CFG_10_SET,
+		CLK_CFG_10_CLR/* set parent */, 0/* lsb */, 2/* width */,
+		7/* pdn */, CLK_CFG_UPDATE1/* upd ofs */,
+		TOP_MUX_HSM_ARC_SHIFT/* upd shift */),
 	MUX_CLR_SET_UPD(CLK_TOP_EIP97_SEL/* dts */, "eip97_sel",
 		eip97_parents/* parent */, CLK_CFG_10, CLK_CFG_10_SET,
 		CLK_CFG_10_CLR/* set parent */, 8/* lsb */, 3/* width */,
diff --git a/src/kernel/linux/v4.19/drivers/extcon/extcon-usb-gpio.c b/src/kernel/linux/v4.19/drivers/extcon/extcon-usb-gpio.c
old mode 100644
new mode 100755
index 5376286..aad7637
--- a/src/kernel/linux/v4.19/drivers/extcon/extcon-usb-gpio.c
+++ b/src/kernel/linux/v4.19/drivers/extcon/extcon-usb-gpio.c
@@ -76,8 +76,11 @@
 	/* check ID and VBUS and update cable state */
 	id = info->id_gpiod ?
 		gpiod_get_value_cansleep(info->id_gpiod) : 1;
+	//vbus = info->vbus_gpiod ?
+		//gpiod_get_value_cansleep(info->vbus_gpiod) : id;//tianyan@2021.11.29 modify for usb otg
+		
 	vbus = info->vbus_gpiod ?
-		gpiod_get_value_cansleep(info->vbus_gpiod) : id;
+		gpiod_get_value_cansleep(info->vbus_gpiod) : 0;//tianyan@2021.11.29 modify for usb otg
 
 	/* at first we clean states which are no longer active */
 	if (id)
@@ -217,6 +220,12 @@
 {
 	struct usb_extcon_info *info = dev_get_drvdata(dev);
 	int ret = 0;
+	
+	if (info->vbus_gpiod) {//tianyan@2021.11.29 modify for usb otg
+		ret = enable_irq_wake(info->vbus_irq);
+		if (ret) 
+			return ret;
+	}
 
 	if (device_may_wakeup(dev)) {
 		if (info->id_gpiod) {
@@ -256,6 +265,12 @@
 	struct usb_extcon_info *info = dev_get_drvdata(dev);
 	int ret = 0;
 
+	if (info->vbus_gpiod) {//tianyan@2021.11.29 modify for usb otg
+		ret = disable_irq_wake(info->vbus_irq);
+		if (ret) 
+			return ret;
+	}
+
 	if (!device_may_wakeup(dev))
 		pinctrl_pm_select_default_state(dev);
 
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/Makefile b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/Makefile
old mode 100644
new mode 100755
index 584b459..37b94b5
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/Makefile
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/Makefile
@@ -2,54 +2,28 @@
 
 obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \
 				       mtk-vcodec-enc.o \
-				       mtk-vcodec-common.o \
+				       mtk-vcodec-common.o
 
-mtk-vcodec-dec-y := mtk_vcodec_dec_drv.o \
-		vdec_drv_if.o \
-		mtk_vcodec_dec.o \
-		mtk_vcodec_dec_stateful.o \
-		mtk_vcodec_dec_stateless.o \
-		mtk_vcodec_dec_pm.o \
-		mtk_vcodec_fw.o \
-		vcodec_dvfs.o \
-
-ifdef CONFIG_VIDEO_MEDIATEK_VCU
-	mtk-vcodec-dec-y += vdec/vdec_common_if.o \
-		vdec_vcu_if.o
-endif
-ifdef CONFIG_VIDEO_MEDIATEK_VPU
-	mtk-vcodec-dec-y += vdec/vdec_h264_if.o \
-		vdec/vdec_h264_req_if.o \
+mtk-vcodec-dec-y := vdec/vdec_h264_if.o \
 		vdec/vdec_vp8_if.o \
 		vdec/vdec_vp9_if.o \
-		vdec_vpu_if.o
-endif
+		mtk_vcodec_dec_drv.o \
+		vdec_drv_if.o \
+		vdec_vpu_if.o \
+		mtk_vcodec_dec.o \
+		mtk_vcodec_dec_pm.o \
 
-mtk-vcodec-enc-y := mtk_vcodec_enc.o \
+
+mtk-vcodec-enc-y := venc/venc_vp8_if.o \
+		venc/venc_h264_if.o \
+		mtk_vcodec_enc.o \
 		mtk_vcodec_enc_drv.o \
 		mtk_vcodec_enc_pm.o \
 		venc_drv_if.o \
-
-ifdef CONFIG_VIDEO_MEDIATEK_VCU
-	mtk-vcodec-enc-y += venc/venc_common_if.o \
-		venc_vcu_if.o
-endif
-ifdef CONFIG_VIDEO_MEDIATEK_VPU
-	mtk-vcodec-enc-y += venc/venc_vp8_if.o \
-		venc/venc_h264_if.o \
-		venc_vpu_if.o
-endif
+		venc_vpu_if.o \
 
 
 mtk-vcodec-common-y := mtk_vcodec_intr.o \
 		mtk_vcodec_util.o\
 
-ifdef CONFIG_VIDEO_MEDIATEK_VCU
-	ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vcu
-endif
-ifdef CONFIG_VIDEO_MEDIATEK_VPU
-	ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu
-endif
-ifdef CONFIG_VB2_MEDIATEK_DMA
-	ccflags-y += -I$(srctree)/drivers/media/platform/mtk-videobuf
-endif
+ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
old mode 100644
new mode 100755
index 44480be..0c8a8b4
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
@@ -16,7 +16,6 @@
 #include <media/v4l2-event.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-dma-contig.h>
-#include <linux/delay.h>
 
 #include "mtk_vcodec_drv.h"
 #include "mtk_vcodec_dec.h"
@@ -25,122 +24,72 @@
 #include "vdec_drv_if.h"
 #include "mtk_vcodec_dec_pm.h"
 
+#define OUT_FMT_IDX	0
+#define CAP_FMT_IDX	3
+
+#define MTK_VDEC_MIN_W	64U
+#define MTK_VDEC_MIN_H	64U
 #define DFT_CFG_WIDTH	MTK_VDEC_MIN_W
 #define DFT_CFG_HEIGHT	MTK_VDEC_MIN_H
 
-static struct mtk_video_fmt
-	mtk_video_formats[MTK_MAX_DEC_CODECS_SUPPORT] = { {0} };
-static struct mtk_codec_framesizes
-	mtk_vdec_framesizes[MTK_MAX_DEC_CODECS_SUPPORT] = { {0} };
-static struct mtk_video_fmt *default_out_fmt;
-static struct mtk_video_fmt *default_cap_fmt;
+static struct mtk_video_fmt mtk_video_formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_H264,
+		.type = MTK_FMT_DEC,
+		.num_planes = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_VP8,
+		.type = MTK_FMT_DEC,
+		.num_planes = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_VP9,
+		.type = MTK_FMT_DEC,
+		.num_planes = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_MT21C,
+		.type = MTK_FMT_FRAME,
+		.num_planes = 2,
+	},
+};
+
+static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = {
+	{
+		.fourcc	= V4L2_PIX_FMT_H264,
+		.stepwise = {  MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
+				MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
+	},
+	{
+		.fourcc	= V4L2_PIX_FMT_VP8,
+		.stepwise = {  MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
+				MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_VP9,
+		.stepwise = {  MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
+				MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
+	},
+};
 
 #define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes)
 #define NUM_FORMATS ARRAY_SIZE(mtk_video_formats)
 
-static void get_supported_format(struct mtk_vcodec_ctx *ctx)
-{
-	unsigned int i;
-	const struct mtk_video_fmt *fmt = NULL;
-	const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
-
-	memcpy(mtk_video_formats, dec_pdata->vdec_formats,
-		sizeof(struct mtk_video_fmt) * dec_pdata->num_formats);
-	for (i = 0; i < dec_pdata->num_formats; i++) {
-		fmt = &dec_pdata->vdec_formats[i];
-		if (dec_pdata->default_out_fmt == fmt)
-			default_out_fmt = &mtk_video_formats[i];
-
-		if (dec_pdata->default_cap_fmt == fmt)
-			default_cap_fmt = &mtk_video_formats[i];
-	}
-
-	if (vdec_if_get_param(ctx,
-		GET_PARAM_CAPABILITY_SUPPORTED_FORMATS,
-		&mtk_video_formats)  != 0) {
-		mtk_v4l2_debug(1, "warning!! Cannot get supported format");
-		return;
-	}
-
-	for (i = 0; i < MTK_MAX_DEC_CODECS_SUPPORT; i++) {
-		if (mtk_video_formats[i].fourcc != 0)
-			mtk_v4l2_debug(1,
-			  "fmt[%d] fourcc %d type %d planes %d",
-			  i, mtk_video_formats[i].fourcc,
-			  mtk_video_formats[i].type,
-			  mtk_video_formats[i].num_planes);
-	}
-	for (i = 0; i < MTK_MAX_DEC_CODECS_SUPPORT; i++) {
-		if (mtk_video_formats[i].fourcc != 0 &&
-			mtk_video_formats[i].type == MTK_FMT_DEC) {
-			default_out_fmt = &mtk_video_formats[i];
-			break;
-		}
-	}
-	for (i = 0; i < MTK_MAX_DEC_CODECS_SUPPORT; i++) {
-		if (mtk_video_formats[i].fourcc != 0 &&
-			mtk_video_formats[i].type == MTK_FMT_FRAME) {
-			default_cap_fmt = &mtk_video_formats[i];
-			break;
-		}
-	}
-}
-
-static struct mtk_video_fmt *mtk_vdec_find_format(struct mtk_vcodec_ctx *ctx,
-	struct v4l2_format *f, unsigned int t)
+static struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f)
 {
 	struct mtk_video_fmt *fmt;
 	unsigned int k;
 
-	mtk_v4l2_debug(3, "[%d] fourcc %d", ctx->id, f->fmt.pix_mp.pixelformat);
-	for (k = 0; k < MTK_MAX_DEC_CODECS_SUPPORT &&
-		 mtk_video_formats[k].fourcc != 0; k++) {
+	for (k = 0; k < NUM_FORMATS; k++) {
 		fmt = &mtk_video_formats[k];
-		if (fmt->fourcc == f->fmt.pix_mp.pixelformat &&
-			mtk_video_formats[k].type == t)
+		if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
 			return fmt;
 	}
 
 	return NULL;
 }
 
-void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx,
-				unsigned int pixelformat)
-{
-	const struct mtk_video_fmt *fmt;
-	struct mtk_q_data *dst_q_data;
-	unsigned int k;
-
-	dst_q_data = &ctx->q_data[MTK_Q_DATA_DST];
-	for (k = 0; k < MTK_MAX_DEC_CODECS_SUPPORT; k++) {
-		fmt = &mtk_video_formats[k];
-		if (fmt->fourcc == pixelformat) {
-			mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)",
-				dst_q_data->fmt->fourcc, pixelformat);
-			dst_q_data->fmt = fmt;
-			return;
-		}
-	}
-
-	mtk_v4l2_err("Cannot get fourcc(%d), using init value", pixelformat);
-}
-
-struct mtk_video_fmt *mtk_find_fmt_by_pixel(unsigned int pixelformat)
-{
-	struct mtk_video_fmt *fmt;
-	unsigned int k;
-
-	for (k = 0; k < MTK_MAX_DEC_CODECS_SUPPORT; k++) {
-		fmt = &mtk_video_formats[k];
-		if (fmt->fourcc == pixelformat)
-			return fmt;
-	}
-	mtk_v4l2_err("Error!! Cannot find fourcc: %d use default", pixelformat);
-
-	return default_out_fmt;
-}
-
-
 static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx,
 					      enum v4l2_buf_type type)
 {
@@ -150,6 +99,369 @@
 	return &ctx->q_data[MTK_Q_DATA_DST];
 }
 
+/*
+ * This function tries to clean all display buffers, the buffers will return
+ * in display order.
+ * Note the buffers returned from codec driver may still be in driver's
+ * reference list.
+ */
+static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx)
+{
+	struct vdec_fb *disp_frame_buffer = NULL;
+	struct mtk_video_dec_buf *dstbuf;
+
+	mtk_v4l2_debug(3, "[%d]", ctx->id);
+	if (vdec_if_get_param(ctx,
+			GET_PARAM_DISP_FRAME_BUFFER,
+			&disp_frame_buffer)) {
+		mtk_v4l2_err("[%d]Cannot get param : GET_PARAM_DISP_FRAME_BUFFER",
+			ctx->id);
+		return NULL;
+	}
+
+	if (disp_frame_buffer == NULL) {
+		mtk_v4l2_debug(3, "No display frame buffer");
+		return NULL;
+	}
+
+	dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf,
+				frame_buffer);
+	mutex_lock(&ctx->lock);
+	if (dstbuf->used) {
+		vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0,
+					ctx->picinfo.y_bs_sz);
+		vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1,
+					ctx->picinfo.c_bs_sz);
+
+		dstbuf->ready_to_display = true;
+
+		mtk_v4l2_debug(2,
+				"[%d]status=%x queue id=%d to done_list %d",
+				ctx->id, disp_frame_buffer->status,
+				dstbuf->vb.vb2_buf.index,
+				dstbuf->queued_in_vb2);
+
+		v4l2_m2m_buf_done(&dstbuf->vb, VB2_BUF_STATE_DONE);
+		ctx->decoded_frame_cnt++;
+	}
+	mutex_unlock(&ctx->lock);
+	return &dstbuf->vb.vb2_buf;
+}
+
+/*
+ * This function tries to clean all capture buffers that are not used as
+ * reference buffers by codec driver any more
+ * In this case, we need re-queue buffer to vb2 buffer if user space
+ * already returns this buffer to v4l2 or this buffer is just the output of
+ * previous sps/pps/resolution change decode, or do nothing if user
+ * space still owns this buffer
+ */
+static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx)
+{
+	struct mtk_video_dec_buf *dstbuf;
+	struct vdec_fb *free_frame_buffer = NULL;
+
+	if (vdec_if_get_param(ctx,
+				GET_PARAM_FREE_FRAME_BUFFER,
+				&free_frame_buffer)) {
+		mtk_v4l2_err("[%d] Error!! Cannot get param", ctx->id);
+		return NULL;
+	}
+	if (free_frame_buffer == NULL) {
+		mtk_v4l2_debug(3, " No free frame buffer");
+		return NULL;
+	}
+
+	mtk_v4l2_debug(3, "[%d] tmp_frame_addr = 0x%p",
+			ctx->id, free_frame_buffer);
+
+	dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf,
+				frame_buffer);
+
+	mutex_lock(&ctx->lock);
+	if (dstbuf->used) {
+		if ((dstbuf->queued_in_vb2) &&
+		    (dstbuf->queued_in_v4l2) &&
+		    (free_frame_buffer->status == FB_ST_FREE)) {
+			/*
+			 * After decode sps/pps or non-display buffer, we don't
+			 * need to return capture buffer to user space, but
+			 * just re-queue this capture buffer to vb2 queue.
+			 * This reduce overheads that dq/q unused capture
+			 * buffer. In this case, queued_in_vb2 = true.
+			 */
+			mtk_v4l2_debug(2,
+				"[%d]status=%x queue id=%d to rdy_queue %d",
+				ctx->id, free_frame_buffer->status,
+				dstbuf->vb.vb2_buf.index,
+				dstbuf->queued_in_vb2);
+			v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb);
+		} else if ((dstbuf->queued_in_vb2 == false) &&
+			   (dstbuf->queued_in_v4l2 == true)) {
+			/*
+			 * If buffer in v4l2 driver but not in vb2 queue yet,
+			 * and we get this buffer from free_list, it means
+			 * that codec driver do not use this buffer as
+			 * reference buffer anymore. We should q buffer to vb2
+			 * queue, so later work thread could get this buffer
+			 * for decode. In this case, queued_in_vb2 = false
+			 * means this buffer is not from previous decode
+			 * output.
+			 */
+			mtk_v4l2_debug(2,
+					"[%d]status=%x queue id=%d to rdy_queue",
+					ctx->id, free_frame_buffer->status,
+					dstbuf->vb.vb2_buf.index);
+			v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb);
+			dstbuf->queued_in_vb2 = true;
+		} else {
+			/*
+			 * Codec driver do not need to reference this capture
+			 * buffer and this buffer is not in v4l2 driver.
+			 * Then we don't need to do any thing, just add log when
+			 * we need to debug buffer flow.
+			 * When this buffer q from user space, it could
+			 * directly q to vb2 buffer
+			 */
+			mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d",
+					ctx->id, free_frame_buffer->status,
+					dstbuf->vb.vb2_buf.index,
+					dstbuf->queued_in_vb2,
+					dstbuf->queued_in_v4l2);
+		}
+		dstbuf->used = false;
+	}
+	mutex_unlock(&ctx->lock);
+	return &dstbuf->vb.vb2_buf;
+}
+
+static void clean_display_buffer(struct mtk_vcodec_ctx *ctx)
+{
+	struct vb2_buffer *framptr;
+
+	do {
+		framptr = get_display_buffer(ctx);
+	} while (framptr);
+}
+
+static void clean_free_buffer(struct mtk_vcodec_ctx *ctx)
+{
+	struct vb2_buffer *framptr;
+
+	do {
+		framptr = get_free_buffer(ctx);
+	} while (framptr);
+}
+
+static void mtk_vdec_queue_res_chg_event(struct mtk_vcodec_ctx *ctx)
+{
+	static const struct v4l2_event ev_src_ch = {
+		.type = V4L2_EVENT_SOURCE_CHANGE,
+		.u.src_change.changes =
+		V4L2_EVENT_SRC_CH_RESOLUTION,
+	};
+
+	mtk_v4l2_debug(1, "[%d]", ctx->id);
+	v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
+}
+
+static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx)
+{
+	bool res_chg;
+	int ret = 0;
+
+	ret = vdec_if_decode(ctx, NULL, NULL, &res_chg);
+	if (ret)
+		mtk_v4l2_err("DecodeFinal failed, ret=%d", ret);
+
+	clean_display_buffer(ctx);
+	clean_free_buffer(ctx);
+}
+
+static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx)
+{
+	unsigned int dpbsize = 0;
+	int ret;
+
+	if (vdec_if_get_param(ctx,
+				GET_PARAM_PIC_INFO,
+				&ctx->last_decoded_picinfo)) {
+		mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR",
+				ctx->id);
+		return -EINVAL;
+	}
+
+	if (ctx->last_decoded_picinfo.pic_w == 0 ||
+		ctx->last_decoded_picinfo.pic_h == 0 ||
+		ctx->last_decoded_picinfo.buf_w == 0 ||
+		ctx->last_decoded_picinfo.buf_h == 0) {
+		mtk_v4l2_err("Cannot get correct pic info");
+		return -EINVAL;
+	}
+
+	if ((ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w) ||
+	    (ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h))
+		return 0;
+
+	mtk_v4l2_debug(1,
+			"[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)",
+			ctx->id, ctx->last_decoded_picinfo.pic_w,
+			ctx->last_decoded_picinfo.pic_h,
+			ctx->picinfo.pic_w, ctx->picinfo.pic_h,
+			ctx->last_decoded_picinfo.buf_w,
+			ctx->last_decoded_picinfo.buf_h);
+
+	ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize);
+	if (dpbsize == 0)
+		mtk_v4l2_err("Incorrect dpb size, ret=%d", ret);
+
+	ctx->dpb_size = dpbsize;
+
+	return ret;
+}
+
+static void mtk_vdec_worker(struct work_struct *work)
+{
+	struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx,
+				decode_work);
+	struct mtk_vcodec_dev *dev = ctx->dev;
+	struct vb2_buffer *src_buf, *dst_buf;
+	struct mtk_vcodec_mem buf;
+	struct vdec_fb *pfb;
+	bool res_chg = false;
+	int ret;
+	struct mtk_video_dec_buf *dst_buf_info, *src_buf_info;
+	struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2;
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	if (src_buf == NULL) {
+		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+		mtk_v4l2_debug(1, "[%d] src_buf empty!!", ctx->id);
+		return;
+	}
+
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	if (dst_buf == NULL) {
+		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+		mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id);
+		return;
+	}
+
+	src_vb2_v4l2 = container_of(src_buf, struct vb2_v4l2_buffer, vb2_buf);
+	src_buf_info = container_of(src_vb2_v4l2, struct mtk_video_dec_buf, vb);
+
+	dst_vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf);
+	dst_buf_info = container_of(dst_vb2_v4l2, struct mtk_video_dec_buf, vb);
+
+	pfb = &dst_buf_info->frame_buffer;
+	pfb->base_y.va = vb2_plane_vaddr(dst_buf, 0);
+	pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+	pfb->base_y.size = ctx->picinfo.y_bs_sz + ctx->picinfo.y_len_sz;
+
+	pfb->base_c.va = vb2_plane_vaddr(dst_buf, 1);
+	pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1);
+	pfb->base_c.size = ctx->picinfo.c_bs_sz + ctx->picinfo.c_len_sz;
+	pfb->status = 0;
+	mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id);
+
+	mtk_v4l2_debug(3,
+			"id=%d Framebuf  pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx",
+			dst_buf->index, pfb,
+			pfb->base_y.va, &pfb->base_y.dma_addr,
+			&pfb->base_c.dma_addr, pfb->base_y.size);
+
+	if (src_buf_info->lastframe) {
+		mtk_v4l2_debug(1, "Got empty flush input buffer.");
+		src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+
+		/* update dst buf status */
+		dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+		mutex_lock(&ctx->lock);
+		dst_buf_info->used = false;
+		mutex_unlock(&ctx->lock);
+
+		vdec_if_decode(ctx, NULL, NULL, &res_chg);
+		clean_display_buffer(ctx);
+		vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 0, 0);
+		vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0);
+		dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_LAST;
+		v4l2_m2m_buf_done(&dst_buf_info->vb, VB2_BUF_STATE_DONE);
+		clean_free_buffer(ctx);
+		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+		return;
+	}
+	buf.va = vb2_plane_vaddr(src_buf, 0);
+	buf.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+	buf.size = (size_t)src_buf->planes[0].bytesused;
+	if (!buf.va) {
+		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+		mtk_v4l2_err("[%d] id=%d src_addr is NULL!!",
+				ctx->id, src_buf->index);
+		return;
+	}
+	mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p",
+			ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf);
+	dst_buf_info->vb.vb2_buf.timestamp
+			= src_buf_info->vb.vb2_buf.timestamp;
+	dst_buf_info->vb.timecode
+			= src_buf_info->vb.timecode;
+	mutex_lock(&ctx->lock);
+	dst_buf_info->used = true;
+	mutex_unlock(&ctx->lock);
+	src_buf_info->used = true;
+
+	ret = vdec_if_decode(ctx, &buf, pfb, &res_chg);
+
+	if (ret) {
+		mtk_v4l2_err(
+			" <===[%d], src_buf[%d] sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>",
+			ctx->id,
+			src_buf->index,
+			buf.size,
+			src_buf_info->vb.vb2_buf.timestamp,
+			dst_buf->index,
+			ret, res_chg);
+		src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+		if (ret == -EIO) {
+			mutex_lock(&ctx->lock);
+			src_buf_info->error = true;
+			mutex_unlock(&ctx->lock);
+		}
+		v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_ERROR);
+	} else if (res_chg == false) {
+		/*
+		 * we only return src buffer with VB2_BUF_STATE_DONE
+		 * when decode success without resolution change
+		 */
+		src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+		v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE);
+	}
+
+	dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+	clean_display_buffer(ctx);
+	clean_free_buffer(ctx);
+
+	if (!ret && res_chg) {
+		mtk_vdec_pic_info_update(ctx);
+		/*
+		 * On encountering a resolution change in the stream.
+		 * The driver must first process and decode all
+		 * remaining buffers from before the resolution change
+		 * point, so call flush decode here
+		 */
+		mtk_vdec_flush_decoder(ctx);
+		/*
+		 * After all buffers containing decoded frames from
+		 * before the resolution change point ready to be
+		 * dequeued on the CAPTURE queue, the driver sends a
+		 * V4L2_EVENT_SOURCE_CHANGE event for source change
+		 * type V4L2_EVENT_SRC_CH_RESOLUTION
+		 */
+		mtk_vdec_queue_res_chg_event(ctx);
+	}
+	v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+}
+
 static int vidioc_try_decoder_cmd(struct file *file, void *priv,
 				struct v4l2_decoder_cmd *cmd)
 {
@@ -157,7 +469,8 @@
 	case V4L2_DEC_CMD_STOP:
 	case V4L2_DEC_CMD_START:
 		if (cmd->flags != 0) {
-			mtk_v4l2_debug(1, "cmd->flags=%u", cmd->flags);
+			mtk_v4l2_err("cmd->flags=%u", cmd->flags);
+			return -EINVAL;
 		}
 		break;
 	default:
@@ -173,13 +486,12 @@
 	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
 	struct vb2_queue *src_vq, *dst_vq;
 	int ret;
-	const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
 
 	ret = vidioc_try_decoder_cmd(file, priv, cmd);
 	if (ret)
 		return ret;
 
-	mtk_v4l2_debug(1, "decoder cmd=%u, flag=%u", cmd->cmd, cmd->flags);
+	mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd);
 	dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
 				V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	switch (cmd->cmd) {
@@ -190,12 +502,9 @@
 			mtk_v4l2_debug(1, "Output stream is off. No need to flush.");
 			return 0;
 		}
-		if (!dec_pdata->uses_stateless_api) {
-			ctx->empty_flush_buf->lastframe = true;
-			if (cmd->flags & V4L2_BUF_FLAG_EARLY_EOS)
-				ctx->empty_flush_buf->isEarlyEos = true;
-			else
-				ctx->empty_flush_buf->isEarlyEos = false;
+		if (!vb2_is_streaming(dst_vq)) {
+			mtk_v4l2_debug(1, "Capture stream is off. No need to flush.");
+			return 0;
 		}
 		v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf->vb);
 		v4l2_m2m_try_schedule(ctx->m2m_ctx);
@@ -214,52 +523,17 @@
 
 void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx)
 {
-	mtk_v4l2_debug(4, "ctx %p [%d]", ctx, ctx->id);
 	mutex_unlock(&ctx->dev->dec_mutex);
 }
 
 void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx)
 {
-	unsigned int suspend_block_cnt = 0;
-
-	while (ctx->dev->is_codec_suspending == 1) {
-		suspend_block_cnt++;
-		if (suspend_block_cnt > SUSPEND_TIMEOUT_CNT) {
-			mtk_v4l2_debug(4, "VDEC blocked by suspend\n");
-			suspend_block_cnt = 0;
-		}
-		usleep_range(10000, 20000);
-	}
-
-	mtk_v4l2_debug(4, "ctx %p [%d]", ctx, ctx->id);
 	mutex_lock(&ctx->dev->dec_mutex);
 }
 
-void mtk_vcodec_dec_empty_queues(struct mtk_vcodec_ctx *ctx)
-{
-	struct vb2_v4l2_buffer *src_buf = NULL, *dst_buf = NULL;
-	struct vb2_v4l2_buffer *last_buf = NULL;
-	int i = 0;
-
-	last_buf = &ctx->empty_flush_buf->vb;
-	while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) {
-		if (last_buf != src_buf)
-			v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
-	}
-
-	while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
-		for (i = 0; i < dst_buf->vb2_buf.num_planes; i++)
-			vb2_set_plane_payload(&dst_buf->vb2_buf, i, 0);
-		v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
-	}
-
-	ctx->state = MTK_STATE_FREE;
-}
-
 void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx)
 {
 	vdec_if_deinit(ctx);
-	memset(mtk_vdec_framesizes, 0, sizeof(mtk_vdec_framesizes));
 	ctx->state = MTK_STATE_FREE;
 }
 
@@ -267,23 +541,20 @@
 {
 	struct mtk_q_data *q_data;
 
-	ctx->dev->vdec_pdata->init_vdec_params(ctx);
-
 	ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex;
 	ctx->fh.m2m_ctx = ctx->m2m_ctx;
 	ctx->fh.ctrl_handler = &ctx->ctrl_hdl;
-	INIT_WORK(&ctx->decode_work, ctx->dev->vdec_pdata->worker);
+	INIT_WORK(&ctx->decode_work, mtk_vdec_worker);
 	ctx->colorspace = V4L2_COLORSPACE_REC709;
 	ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
 	ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
 	ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
-	get_supported_format(ctx);
 
 	q_data = &ctx->q_data[MTK_Q_DATA_SRC];
 	memset(q_data, 0, sizeof(struct mtk_q_data));
 	q_data->visible_width = DFT_CFG_WIDTH;
 	q_data->visible_height = DFT_CFG_HEIGHT;
-	q_data->fmt = default_out_fmt;
+	q_data->fmt = &mtk_video_formats[OUT_FMT_IDX];
 	q_data->field = V4L2_FIELD_NONE;
 
 	q_data->sizeimage[0] = DFT_CFG_WIDTH * DFT_CFG_HEIGHT;
@@ -295,7 +566,7 @@
 	q_data->visible_height = DFT_CFG_HEIGHT;
 	q_data->coded_width = DFT_CFG_WIDTH;
 	q_data->coded_height = DFT_CFG_HEIGHT;
-	q_data->fmt = default_cap_fmt;
+	q_data->fmt = &mtk_video_formats[CAP_FMT_IDX];
 	q_data->field = V4L2_FIELD_NONE;
 
 	v4l_bound_align_image(&q_data->coded_width,
@@ -311,126 +582,10 @@
 	q_data->bytesperline[1] = q_data->coded_width;
 }
 
-int mtk_vdec_set_param(struct mtk_vcodec_ctx *ctx)
-{
-	unsigned long in[8] = {0};
-
-	mtk_v4l2_debug(4,
-		"[%d] param change %d decode mode %d frame width %d frame height %d max width %d max height %d",
-		ctx->id, ctx->dec_param_change,
-		ctx->dec_params.decode_mode,
-		ctx->dec_params.frame_size_width,
-		ctx->dec_params.frame_size_height,
-		ctx->dec_params.fixed_max_frame_size_width,
-		ctx->dec_params.fixed_max_frame_size_height);
-
-	if (ctx->dec_param_change & MTK_DEC_PARAM_DECODE_MODE) {
-		in[0] = ctx->dec_params.decode_mode;
-		if (vdec_if_set_param(ctx, SET_PARAM_DECODE_MODE, in) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot set param", ctx->id);
-			return -EINVAL;
-		}
-		ctx->dec_param_change &= (~MTK_DEC_PARAM_DECODE_MODE);
-	}
-
-	if (ctx->dec_param_change & MTK_DEC_PARAM_FRAME_SIZE) {
-		in[0] = ctx->dec_params.frame_size_width;
-		in[1] = ctx->dec_params.frame_size_height;
-		if (in[0] != 0 && in[1] != 0) {
-			if (vdec_if_set_param(ctx,
-				SET_PARAM_FRAME_SIZE, in) != 0) {
-				mtk_v4l2_err("[%d] Error!! Cannot set param",
-					ctx->id);
-				return -EINVAL;
-			}
-		}
-		ctx->dec_param_change &= (~MTK_DEC_PARAM_FRAME_SIZE);
-	}
-
-	if (ctx->dec_param_change &
-		MTK_DEC_PARAM_FIXED_MAX_FRAME_SIZE) {
-		in[0] = ctx->dec_params.fixed_max_frame_size_width;
-		in[1] = ctx->dec_params.fixed_max_frame_size_height;
-		if (in[0] != 0 && in[1] != 0) {
-			if (vdec_if_set_param(ctx,
-				SET_PARAM_SET_FIXED_MAX_OUTPUT_BUFFER,
-				in) != 0) {
-				mtk_v4l2_err("[%d] Error!! Cannot set param",
-					ctx->id);
-				return -EINVAL;
-			}
-		}
-		ctx->dec_param_change &= (~MTK_DEC_PARAM_FIXED_MAX_FRAME_SIZE);
-	}
-
-	if (ctx->dec_param_change & MTK_DEC_PARAM_CRC_PATH) {
-		in[0] = (unsigned long)ctx->dec_params.crc_path;
-		if (vdec_if_set_param(ctx, SET_PARAM_CRC_PATH, in) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot set param", ctx->id);
-			return -EINVAL;
-		}
-		ctx->dec_param_change &= (~MTK_DEC_PARAM_CRC_PATH);
-	}
-
-	if (ctx->dec_param_change & MTK_DEC_PARAM_GOLDEN_PATH) {
-		in[0] = (unsigned long)ctx->dec_params.golden_path;
-		if (vdec_if_set_param(ctx, SET_PARAM_GOLDEN_PATH, in) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot set param", ctx->id);
-			return -EINVAL;
-		}
-		ctx->dec_param_change &= (~MTK_DEC_PARAM_GOLDEN_PATH);
-	}
-
-	if (ctx->dec_param_change & MTK_DEC_PARAM_WAIT_KEY_FRAME) {
-		in[0] = (unsigned long)ctx->dec_params.wait_key_frame;
-		if (vdec_if_set_param(ctx, SET_PARAM_WAIT_KEY_FRAME, in) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot set param", ctx->id);
-			return -EINVAL;
-		}
-		ctx->dec_param_change &= (~MTK_DEC_PARAM_WAIT_KEY_FRAME);
-	}
-
-	if (ctx->dec_param_change & MTK_DEC_PARAM_NAL_SIZE_LENGTH) {
-		in[0] = (unsigned long)ctx->dec_params.wait_key_frame;
-		if (vdec_if_set_param(ctx, SET_PARAM_NAL_SIZE_LENGTH,
-					in) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot set param", ctx->id);
-			return -EINVAL;
-		}
-		ctx->dec_param_change &= (~MTK_DEC_PARAM_NAL_SIZE_LENGTH);
-	}
-
-	if (ctx->dec_param_change & MTK_DEC_PARAM_OPERATING_RATE) {
-		in[0] = (unsigned long)ctx->dec_params.operating_rate;
-		if (vdec_if_set_param(ctx, SET_PARAM_OPERATING_RATE, in) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot set param", ctx->id);
-			return -EINVAL;
-		}
-		ctx->dec_param_change &= (~MTK_DEC_PARAM_OPERATING_RATE);
-	}
-
-	if (ctx->dec_param_change & MTK_DEC_PARAM_TOTAL_FRAME_BUFQ_COUNT) {
-		in[0] = (unsigned long)ctx->dec_params.total_frame_bufq_count;
-		if (vdec_if_set_param
-			(ctx, SET_PARAM_TOTAL_FRAME_BUFQ_COUNT, in) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot set param", ctx->id);
-			return -EINVAL;
-		}
-		ctx->dec_param_change &=
-			(~MTK_DEC_PARAM_TOTAL_FRAME_BUFQ_COUNT);
-	}
-
-	return 0;
-}
-
 static int vidioc_vdec_qbuf(struct file *file, void *priv,
 			    struct v4l2_buffer *buf)
 {
 	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-	struct vb2_queue *vq;
-	struct vb2_buffer *vb;
-	struct mtk_video_dec_buf *mtkbuf;
-	struct vb2_v4l2_buffer  *vb2_v4l2;
 
 	if (ctx->state == MTK_STATE_ABORT) {
 		mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
@@ -438,56 +593,13 @@
 		return -EIO;
 	}
 
-	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type);
-	vb = vq->bufs[buf->index];
-	vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-	mtkbuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
-
-	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-		ctx->input_max_ts =
-			(timeval_to_ns(&buf->timestamp) > ctx->input_max_ts) ?
-			timeval_to_ns(&buf->timestamp) : ctx->input_max_ts;
-
-		mtkbuf->lastframe = false;
-		mtkbuf->isEarlyEos = false;
-		if (buf->flags & V4L2_BUF_FLAG_LAST)
-			mtkbuf->isEarlyEos = true;
-		mtk_v4l2_debug(1, "[%d] id=%d getdata BS(%d,%d) vb=%p pts=%llu %llu %d",
-			ctx->id, buf->index,
-			buf->m.planes[0].bytesused,
-			buf->length, vb,
-			timeval_to_ns(&buf->timestamp),
-			ctx->input_max_ts,
-			mtkbuf->isEarlyEos);
-	} else
-		mtk_v4l2_debug(1, "[%d] id=%d FB (%d) vb=%p",
-				ctx->id, buf->index,
-				buf->length, mtkbuf);
-
-	if (buf->flags & V4L2_BUF_FLAG_NO_CACHE_CLEAN) {
-		mtk_v4l2_debug(4, "[%d] No need for Cache clean, buf->index:%d. mtkbuf:%p",
-			ctx->id, buf->index, mtkbuf);
-		mtkbuf->flags |= NO_CAHCE_CLEAN;
-	}
-
-	if (buf->flags & V4L2_BUF_FLAG_NO_CACHE_INVALIDATE) {
-		mtk_v4l2_debug(4, "[%d] No need for Cache invalidate, buf->index:%d. mtkbuf:%p",
-			ctx->id, buf->index, mtkbuf);
-		mtkbuf->flags |= NO_CAHCE_INVALIDATE;
-	}
-
 	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 }
 
 static int vidioc_vdec_dqbuf(struct file *file, void *priv,
 			     struct v4l2_buffer *buf)
 {
-	int ret = 0;
 	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-	struct vb2_queue *vq;
-	struct vb2_buffer *vb;
-	struct mtk_video_dec_buf *mtkbuf;
-	struct vb2_v4l2_buffer  *vb2_v4l2;
 
 	if (ctx->state == MTK_STATE_ABORT) {
 		mtk_v4l2_err("[%d] Call on DQBUF after unrecoverable error",
@@ -495,34 +607,16 @@
 		return -EIO;
 	}
 
-	ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-	buf->reserved = ctx->errormap_info[buf->index % VB2_MAX_FRAME];
-
-	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
-		ret == 0) {
-		vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type);
-		vb = vq->bufs[buf->index];
-		vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-		mtkbuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
-
-		if (mtkbuf->flags & CROP_CHANGED)
-			buf->flags |= V4L2_BUF_FLAG_CROP_CHANGED;
-		if (mtkbuf->flags & REF_FREED)
-			buf->flags |= V4L2_BUF_FLAG_REF_FREED;
-	}
-
-	return ret;
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
 }
 
 static int vidioc_vdec_querycap(struct file *file, void *priv,
 				struct v4l2_capability *cap)
 {
-	strscpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver));
-	strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
-	strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
+	strlcpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver));
+	strlcpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
+	strlcpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
 
-	cap->device_caps  = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
-	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -534,17 +628,12 @@
 		return v4l2_event_subscribe(fh, sub, 2, NULL);
 	case V4L2_EVENT_SOURCE_CHANGE:
 		return v4l2_src_change_event_subscribe(fh, sub);
-	case V4L2_EVENT_VDEC_ERROR:
-		return v4l2_event_subscribe(fh, sub, 0, NULL);
-	case V4L2_EVENT_MTK_VDEC_NOHEADER:
-		return v4l2_event_subscribe(fh, sub, 0, NULL);
 	default:
 		return v4l2_ctrl_subscribe_event(fh, sub);
 	}
 }
 
-static int vidioc_try_fmt(struct v4l2_format *f,
-			  const struct mtk_video_fmt *fmt)
+static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt)
 {
 	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
 	int i;
@@ -617,14 +706,12 @@
 static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
-	const struct mtk_video_fmt *fmt;
-	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+	struct mtk_video_fmt *fmt;
 
-	fmt = mtk_vdec_find_format(ctx, f, MTK_FMT_FRAME);
+	fmt = mtk_vdec_find_format(f);
 	if (!fmt) {
-		f->fmt.pix.pixelformat =
-			ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc;
-		fmt = mtk_vdec_find_format(ctx, f, MTK_FMT_FRAME);
+		f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc;
+		fmt = mtk_vdec_find_format(f);
 	}
 
 	return vidioc_try_fmt(f, fmt);
@@ -634,14 +721,12 @@
 				struct v4l2_format *f)
 {
 	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-	const struct mtk_video_fmt *fmt;
-	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+	struct mtk_video_fmt *fmt;
 
-	fmt = mtk_vdec_find_format(ctx, f, MTK_FMT_DEC);
+	fmt = mtk_vdec_find_format(f);
 	if (!fmt) {
-		f->fmt.pix.pixelformat =
-			ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc;
-		fmt = mtk_vdec_find_format(ctx, f, MTK_FMT_DEC);
+		f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc;
+		fmt = mtk_vdec_find_format(f);
 	}
 
 	if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
@@ -665,21 +750,18 @@
 
 	switch (s->target) {
 	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
-	case V4L2_SEL_TGT_CROP_DEFAULT:
 		s->r.left = 0;
 		s->r.top = 0;
 		s->r.width = ctx->picinfo.pic_w;
 		s->r.height = ctx->picinfo.pic_h;
 		break;
 	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-	case V4L2_SEL_TGT_CROP_BOUNDS:
 		s->r.left = 0;
 		s->r.top = 0;
 		s->r.width = ctx->picinfo.buf_w;
 		s->r.height = ctx->picinfo.buf_h;
 		break;
 	case V4L2_SEL_TGT_COMPOSE:
-	case V4L2_SEL_TGT_CROP:
 		if (vdec_if_get_param(ctx, GET_PARAM_CROP_INFO, &(s->r))) {
 			/* set to default value if header info not ready yet*/
 			s->r.left = 0;
@@ -714,7 +796,6 @@
 
 	switch (s->target) {
 	case V4L2_SEL_TGT_COMPOSE:
-	case V4L2_SEL_TGT_CROP:
 		s->r.left = 0;
 		s->r.top = 0;
 		s->r.width = ctx->picinfo.pic_w;
@@ -732,13 +813,10 @@
 {
 	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
 	struct v4l2_pix_format_mplane *pix_mp;
-	struct mtk_q_data *q_data, *out_q_data;
-	int ret = 0, width = 0, height = 0;
+	struct mtk_q_data *q_data;
+	int ret = 0;
 	struct mtk_video_fmt *fmt;
 
-	const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
-	uint64_t size[2];
-
 	mtk_v4l2_debug(3, "[%d]", ctx->id);
 
 	q_data = mtk_vdec_get_q_data(ctx, f->type);
@@ -746,8 +824,7 @@
 		return -EINVAL;
 
 	pix_mp = &f->fmt.pix_mp;
-	if (!dec_pdata->uses_stateless_api &&
-	    (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
+	if ((f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
 	    vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) {
 		mtk_v4l2_err("out_q_ctx buffers already requested");
 		ret = -EBUSY;
@@ -759,28 +836,18 @@
 		ret = -EBUSY;
 	}
 
-	fmt = mtk_vdec_find_format(ctx, f,
-		(f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
-		MTK_FMT_DEC : MTK_FMT_FRAME);
+	fmt = mtk_vdec_find_format(f);
 	if (fmt == NULL) {
 		if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 			f->fmt.pix.pixelformat =
-				default_out_fmt->fourcc;
-			fmt = mtk_vdec_find_format(ctx, f, MTK_FMT_DEC);
+				mtk_video_formats[OUT_FMT_IDX].fourcc;
+			fmt = mtk_vdec_find_format(f);
 		} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 			f->fmt.pix.pixelformat =
-				default_cap_fmt->fourcc;
-			fmt = mtk_vdec_find_format(ctx, f, MTK_FMT_FRAME);
+				mtk_video_formats[CAP_FMT_IDX].fourcc;
+			fmt = mtk_vdec_find_format(f);
 		}
 	}
-	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-		width = pix_mp->width;
-		height = pix_mp->height;
-		out_q_data = mtk_vdec_get_q_data(ctx, f->type);
-		if (!out_q_data)
-			return -EINVAL;
-	}
-
 
 	q_data->fmt = fmt;
 	vidioc_try_fmt(f, q_data->fmt);
@@ -788,15 +855,12 @@
 		q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
 		q_data->coded_width = pix_mp->width;
 		q_data->coded_height = pix_mp->height;
-		size[0] = pix_mp->width;
-		size[1] = pix_mp->height;
 
 		ctx->colorspace = f->fmt.pix_mp.colorspace;
 		ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
 		ctx->quantization = f->fmt.pix_mp.quantization;
 		ctx->xfer_func = f->fmt.pix_mp.xfer_func;
 
-		ctx->current_codec = fmt->fourcc;
 		if (ctx->state == MTK_STATE_FREE) {
 			ret = vdec_if_init(ctx, q_data->fmt->fourcc);
 			if (ret) {
@@ -804,55 +868,10 @@
 					ctx->id, ret);
 				return -EINVAL;
 			}
-			vdec_if_set_param(ctx, SET_PARAM_FRAME_SIZE,
-					(void *)size);
-
 			ctx->state = MTK_STATE_INIT;
 		}
 	}
-	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-		vdec_if_set_param(ctx, SET_PARAM_FB_NUM_PLANES,
-			(void *) &q_data->fmt->num_planes);
 
-	/* Tolerate both OUTPUT and CAPTURE queues for compatibility reasons */
-	if (dec_pdata->uses_stateless_api) {
-		ctx->picinfo.pic_w = pix_mp->width;
-		ctx->picinfo.pic_h = pix_mp->height;
-
-		ret = vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo);
-		if (ret) {
-			mtk_v4l2_err("[%d]Error!! Get GET_PARAM_PICTURE_INFO Fail",
-				ctx->id);
-			return -EINVAL;
-		}
-
-		ctx->last_decoded_picinfo = ctx->picinfo;
-		if (pix_mp->num_planes == 1) {
-			ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
-				ctx->picinfo.fb_sz[0] +
-				ctx->picinfo.fb_sz[1];
-			ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] =
-				ctx->picinfo.buf_w;
-		} else {
-			ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
-				ctx->picinfo.fb_sz[0];
-			ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] =
-				ctx->picinfo.buf_w;
-			ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] =
-				ctx->picinfo.fb_sz[1];
-			ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] =
-				ctx->picinfo.buf_w;
-		}
-
-		ctx->q_data[MTK_Q_DATA_DST].coded_width = ctx->picinfo.buf_w;
-		ctx->q_data[MTK_Q_DATA_DST].coded_height = ctx->picinfo.buf_h;
-		mtk_v4l2_debug(2, "[%d] vdec_if_init() num_plane = %d wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x",
-			ctx->id, pix_mp->num_planes,
-			ctx->picinfo.buf_w, ctx->picinfo.buf_h,
-			ctx->picinfo.pic_w, ctx->picinfo.pic_h,
-			ctx->q_data[MTK_Q_DATA_DST].sizeimage[0],
-			ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]);
-	}
 	return 0;
 }
 
@@ -861,83 +880,45 @@
 {
 	int i = 0;
 	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-	const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
 
 	if (fsize->index != 0)
 		return -EINVAL;
-	if (mtk_vdec_framesizes[0].fourcc == 0) {
-		memcpy(mtk_vdec_framesizes, dec_pdata->vdec_framesizes,
-			sizeof(struct mtk_codec_framesizes) *
-			dec_pdata->num_framesizes);
 
-		if (vdec_if_get_param(ctx, GET_PARAM_CAPABILITY_FRAME_SIZES,
-			&mtk_vdec_framesizes) != 0) {
-			mtk_v4l2_debug(1, "[%d] Error!! Cannot get frame size",
-				ctx->id);
-			return -EINVAL;
-		}
-
-		for (i = 0; i < MTK_MAX_DEC_CODECS_SUPPORT; i++) {
-			if (mtk_vdec_framesizes[i].fourcc != 0) {
-				mtk_v4l2_debug(1,
-				"vdec_fs[%d] fourcc %d, profile %d, level %d, s %d %d %d %d %d %d\n",
-				i, mtk_vdec_framesizes[i].fourcc,
-				mtk_vdec_framesizes[i].profile,
-				mtk_vdec_framesizes[i].level,
-				mtk_vdec_framesizes[i].stepwise.min_width,
-				mtk_vdec_framesizes[i].stepwise.max_width,
-				mtk_vdec_framesizes[i].stepwise.step_width,
-				mtk_vdec_framesizes[i].stepwise.min_height,
-				mtk_vdec_framesizes[i].stepwise.max_height,
-				mtk_vdec_framesizes[i].stepwise.step_height);
-			}
-		}
-	}
-
-	for (i = 0; i < MTK_MAX_DEC_CODECS_SUPPORT &&
-		 mtk_vdec_framesizes[i].fourcc != 0; ++i) {
+	for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) {
 		if (fsize->pixel_format != mtk_vdec_framesizes[i].fourcc)
 			continue;
 
 		fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-		fsize->reserved[0] = mtk_vdec_framesizes[i].profile;
-		fsize->reserved[1] = mtk_vdec_framesizes[i].level;
 		fsize->stepwise = mtk_vdec_framesizes[i].stepwise;
 		if (!(ctx->dev->dec_capability &
-			  VCODEC_CAPABILITY_4K_DISABLED)) {
-			mtk_v4l2_debug(1, "4K is enabled");
+				VCODEC_CAPABILITY_4K_DISABLED)) {
+			mtk_v4l2_debug(3, "4K is enabled");
 			fsize->stepwise.max_width =
 					VCODEC_DEC_4K_CODED_WIDTH;
 			fsize->stepwise.max_height =
 					VCODEC_DEC_4K_CODED_HEIGHT;
 		}
-		mtk_v4l2_debug(4, "%x, %d %d %d %d %d %d %d %d %d %d",
-					   ctx->dev->dec_capability,
-					   fsize->reserved[0],
-					   fsize->reserved[1],
-					   fsize->stepwise.min_width,
-					   fsize->stepwise.max_width,
-					   fsize->stepwise.step_width,
-					   fsize->stepwise.min_height,
-					   fsize->stepwise.max_height,
-					   fsize->stepwise.step_height,
-					   fsize->reserved[0],
-					   fsize->reserved[1]);
+		mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d",
+				ctx->dev->dec_capability,
+				fsize->stepwise.min_width,
+				fsize->stepwise.max_width,
+				fsize->stepwise.step_width,
+				fsize->stepwise.min_height,
+				fsize->stepwise.max_height,
+				fsize->stepwise.step_height);
 		return 0;
 	}
 
 	return -EINVAL;
 }
 
-static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv,
-				bool output_queue)
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue)
 {
 	struct mtk_video_fmt *fmt;
 	int i, j = 0;
 
-	for (i = 0; i < MTK_MAX_DEC_CODECS_SUPPORT; i++) {
-		if (output_queue &&
-			(mtk_video_formats[i].type != MTK_FMT_DEC))
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (output_queue && (mtk_video_formats[i].type != MTK_FMT_DEC))
 			continue;
 		if (!output_queue &&
 			(mtk_video_formats[i].type != MTK_FMT_FRAME))
@@ -948,28 +929,25 @@
 		++j;
 	}
 
-	if (i == MTK_MAX_DEC_CODECS_SUPPORT ||
-		mtk_video_formats[i].fourcc == 0)
+	if (i == NUM_FORMATS)
 		return -EINVAL;
 
 	fmt = &mtk_video_formats[i];
 	f->pixelformat = fmt->fourcc;
-	f->flags = 0;
-	memset(f->reserved, 0, sizeof(f->reserved));
 
 	return 0;
 }
 
-static int vidioc_vdec_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
+static int vidioc_vdec_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
 					       struct v4l2_fmtdesc *f)
 {
-	return vidioc_enum_fmt(f, priv, false);
+	return vidioc_enum_fmt(f, false);
 }
 
 static int vidioc_vdec_enum_fmt_vid_out_mplane(struct file *file, void *priv,
 					       struct v4l2_fmtdesc *f)
 {
-	return vidioc_enum_fmt(f, priv, true);
+	return vidioc_enum_fmt(f, true);
 }
 
 static int vidioc_vdec_g_fmt(struct file *file, void *priv,
@@ -979,8 +957,6 @@
 	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
 	struct vb2_queue *vq;
 	struct mtk_q_data *q_data;
-	unsigned int fourcc;
-	unsigned int i = 0;
 
 	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 	if (!vq) {
@@ -1004,13 +980,14 @@
 		 * So we just return picinfo yet, and update picinfo in
 		 * stop_streaming hook function
 		 */
-		q_data->sizeimage[0] = ctx->picinfo.fb_sz[0];
-		q_data->sizeimage[1] = ctx->picinfo.fb_sz[1];
+		q_data->sizeimage[0] = ctx->picinfo.y_bs_sz +
+					ctx->picinfo.y_len_sz;
+		q_data->sizeimage[1] = ctx->picinfo.c_bs_sz +
+					ctx->picinfo.c_len_sz;
 		q_data->bytesperline[0] = ctx->last_decoded_picinfo.buf_w;
 		q_data->bytesperline[1] = ctx->last_decoded_picinfo.buf_w;
 		q_data->coded_width = ctx->picinfo.buf_w;
 		q_data->coded_height = ctx->picinfo.buf_h;
-		ctx->last_decoded_picinfo.cap_fourcc = q_data->fmt->fourcc;
 
 		/*
 		 * Width and height are set to the dimensions
@@ -1018,15 +995,8 @@
 		 * further processing stages should crop to this
 		 * rectangle.
 		 */
-		fourcc = ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc;
-		if (fourcc == V4L2_PIX_FMT_RV30 ||
-			fourcc == V4L2_PIX_FMT_RV40) {
-			pix_mp->width = 1920;
-			pix_mp->height = 1088;
-		} else {
-			pix_mp->width = q_data->coded_width;
-			pix_mp->height = q_data->coded_height;
-		}
+		pix_mp->width = q_data->coded_width;
+		pix_mp->height = q_data->coded_height;
 
 		/*
 		 * Set pixelformat to the format in which mt vcodec
@@ -1034,28 +1004,11 @@
 		 */
 		pix_mp->num_planes = q_data->fmt->num_planes;
 		pix_mp->pixelformat = q_data->fmt->fourcc;
-		if (fourcc == V4L2_PIX_FMT_RV30 ||
-			fourcc == V4L2_PIX_FMT_RV40) {
-			for (i = 0; i < pix_mp->num_planes; i++) {
-				pix_mp->plane_fmt[i].bytesperline = 1920;
-				pix_mp->plane_fmt[i].sizeimage =
-					q_data->sizeimage[i];
-			}
-		} else {
-			for (i = 0; i < pix_mp->num_planes; i++) {
-				pix_mp->plane_fmt[i].bytesperline =
-					q_data->bytesperline[i];
-				pix_mp->plane_fmt[i].sizeimage =
-					q_data->sizeimage[i];
-			}
-		}
-		mtk_v4l2_debug(1, "fourcc:(%d %d),bytesperline:%d,sizeimage:%d,%d,%d\n",
-			ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc,
-			q_data->fmt->fourcc,
-			pix_mp->plane_fmt[0].bytesperline,
-			pix_mp->plane_fmt[0].sizeimage,
-			pix_mp->plane_fmt[1].bytesperline,
-			pix_mp->plane_fmt[1].sizeimage);
+		pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
+		pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
+		pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1];
+		pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1];
+
 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		/*
 		 * This is run on OUTPUT
@@ -1070,29 +1023,14 @@
 		pix_mp->pixelformat = q_data->fmt->fourcc;
 		pix_mp->num_planes = q_data->fmt->num_planes;
 	} else {
+		pix_mp->width = q_data->coded_width;
+		pix_mp->height = q_data->coded_height;
 		pix_mp->num_planes = q_data->fmt->num_planes;
 		pix_mp->pixelformat = q_data->fmt->fourcc;
-		fourcc = ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc;
-
-		if (fourcc == V4L2_PIX_FMT_RV30 ||
-			fourcc == V4L2_PIX_FMT_RV40) {
-			for (i = 0; i < pix_mp->num_planes; i++) {
-				pix_mp->width = 1920;
-				pix_mp->height = 1088;
-				pix_mp->plane_fmt[i].bytesperline = 1920;
-				pix_mp->plane_fmt[i].sizeimage =
-					q_data->sizeimage[i];
-			}
-		} else {
-			pix_mp->width = q_data->coded_width;
-			pix_mp->height = q_data->coded_height;
-			for (i = 0; i < pix_mp->num_planes; i++) {
-				pix_mp->plane_fmt[i].bytesperline =
-					q_data->bytesperline[i];
-				pix_mp->plane_fmt[i].sizeimage =
-					q_data->sizeimage[i];
-			}
-		}
+		pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
+		pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
+		pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1];
+		pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1];
 
 		mtk_v4l2_debug(1, "[%d] type=%d state=%d Format information could not be read, not ready yet!",
 				ctx->id, f->type, ctx->state);
@@ -1101,7 +1039,7 @@
 	return 0;
 }
 
-int vb2ops_vdec_queue_setup(struct vb2_queue *vq,
+static int vb2ops_vdec_queue_setup(struct vb2_queue *vq,
 				unsigned int *nbuffers,
 				unsigned int *nplanes,
 				unsigned int sizes[],
@@ -1125,7 +1063,7 @@
 		}
 	} else {
 		if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-			*nplanes = q_data->fmt->num_planes;
+			*nplanes = 2;
 		else
 			*nplanes = 1;
 
@@ -1141,14 +1079,11 @@
 	return 0;
 }
 
-int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb)
+static int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb)
 {
 	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 	struct mtk_q_data *q_data;
 	int i;
-	struct mtk_video_dec_buf *mtkbuf;
-	struct vb2_v4l2_buffer *vb2_v4l2;
-	unsigned int plane = 0;
 
 	mtk_v4l2_debug(3, "[%d] (%d) id=%d",
 			ctx->id, vb->vb2_queue->type, vb->index);
@@ -1163,56 +1098,142 @@
 		}
 	}
 
-	// Check if need to proceed cache operations
-	vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-	mtkbuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
-
-	if (!(mtkbuf->flags & NO_CAHCE_CLEAN) &&
-		!(ctx->dec_params.svp_mode) &&
-		(vb->vb2_queue->memory == VB2_MEMORY_DMABUF)) {
-		struct vdec_fb fb_param;
-
-		for (plane = 0; plane < vb->num_planes; plane++) {
-			struct vb2_dc_buf *dc_buf = vb->planes[plane].mem_priv;
-
-			mtk_v4l2_debug(4, "[%d] Cache sync+", ctx->id);
-			dma_sync_sg_for_device(&ctx->dev->plat_dev->dev,
-				dc_buf->dma_sgt->sgl,
-				dc_buf->dma_sgt->orig_nents,
-				DMA_TO_DEVICE);
-			fb_param.fb_base[plane].dma_addr =
-				vb2_dma_contig_plane_dma_addr(vb,
-				plane);
-			if (vb->vb2_queue->type ==
-					V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-				fb_param.fb_base[plane].size =
-					(size_t)vb->planes[0].bytesused;
-			else
-				fb_param.fb_base[plane].size =
-					ctx->picinfo.fb_sz[plane];
-
-			mtk_v4l2_debug(4,
-			  "[%d] [%d] [%d]Cache sync- TD for %p sz=%d dev %p",
-			  ctx->id,
-			  vb->vb2_queue->type,
-			  plane,
-			  (void *)fb_param.fb_base[plane].dma_addr,
-			  (unsigned int)fb_param.fb_base[plane].size,
-			  &ctx->dev->plat_dev->dev);
-		}
-	}
-
 	return 0;
 }
 
-void vb2ops_vdec_buf_finish(struct vb2_buffer *vb)
+static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_buffer *src_buf;
+	struct mtk_vcodec_mem src_mem;
+	bool res_chg = false;
+	int ret = 0;
+	unsigned int dpbsize = 1;
+	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vb2_v4l2 = NULL;
+	struct mtk_video_dec_buf *buf = NULL;
+
+	mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p",
+			ctx->id, vb->vb2_queue->type,
+			vb->index, vb);
+	/*
+	 * check if this buffer is ready to be used after decode
+	 */
+	if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		vb2_v4l2 = to_vb2_v4l2_buffer(vb);
+		buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
+		mutex_lock(&ctx->lock);
+		if (buf->used == false) {
+			v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
+			buf->queued_in_vb2 = true;
+			buf->queued_in_v4l2 = true;
+			buf->ready_to_display = false;
+		} else {
+			buf->queued_in_vb2 = false;
+			buf->queued_in_v4l2 = true;
+			buf->ready_to_display = false;
+		}
+		mutex_unlock(&ctx->lock);
+		return;
+	}
+
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
+
+	if (ctx->state != MTK_STATE_INIT) {
+		mtk_v4l2_debug(3, "[%d] already init driver %d",
+				ctx->id, ctx->state);
+		return;
+	}
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	if (!src_buf) {
+		mtk_v4l2_err("No src buffer");
+		return;
+	}
+	vb2_v4l2 = to_vb2_v4l2_buffer(src_buf);
+	buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
+	if (buf->lastframe) {
+		/* This shouldn't happen. Just in case. */
+		mtk_v4l2_err("Invalid flush buffer.");
+		v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+		return;
+	}
+
+	src_mem.va = vb2_plane_vaddr(src_buf, 0);
+	src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+	src_mem.size = (size_t)src_buf->planes[0].bytesused;
+	mtk_v4l2_debug(2,
+			"[%d] buf id=%d va=%p dma=%pad size=%zx",
+			ctx->id, src_buf->index,
+			src_mem.va, &src_mem.dma_addr,
+			src_mem.size);
+
+	ret = vdec_if_decode(ctx, &src_mem, NULL, &res_chg);
+	if (ret || !res_chg) {
+		/*
+		 * fb == NULL menas to parse SPS/PPS header or
+		 * resolution info in src_mem. Decode can fail
+		 * if there is no SPS header or picture info
+		 * in bs
+		 */
+
+		src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+		if (ret == -EIO) {
+			mtk_v4l2_err("[%d] Unrecoverable error in vdec_if_decode.",
+					ctx->id);
+			ctx->state = MTK_STATE_ABORT;
+			v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
+						VB2_BUF_STATE_ERROR);
+		} else {
+			v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
+						VB2_BUF_STATE_DONE);
+		}
+		mtk_v4l2_debug(ret ? 0 : 1,
+			       "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d",
+			       ctx->id, src_buf->index,
+			       src_mem.size, ret, res_chg);
+		return;
+	}
+
+	if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo)) {
+		mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR",
+				ctx->id);
+		return;
+	}
+
+	ctx->last_decoded_picinfo = ctx->picinfo;
+	ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
+						ctx->picinfo.y_bs_sz +
+						ctx->picinfo.y_len_sz;
+	ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] =
+						ctx->picinfo.buf_w;
+	ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] =
+						ctx->picinfo.c_bs_sz +
+						ctx->picinfo.c_len_sz;
+	ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] = ctx->picinfo.buf_w;
+	mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x",
+			ctx->id,
+			ctx->picinfo.buf_w, ctx->picinfo.buf_h,
+			ctx->picinfo.pic_w, ctx->picinfo.pic_h,
+			ctx->q_data[MTK_Q_DATA_DST].sizeimage[0],
+			ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]);
+
+	ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize);
+	if (dpbsize == 0)
+		mtk_v4l2_err("[%d] GET_PARAM_DPB_SIZE fail=%d", ctx->id, ret);
+
+	ctx->dpb_size = dpbsize;
+	ctx->state = MTK_STATE_HEADER;
+	mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size);
+
+	mtk_vdec_queue_res_chg_event(ctx);
+}
+
+static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb)
 {
 	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 	struct vb2_v4l2_buffer *vb2_v4l2;
 	struct mtk_video_dec_buf *buf;
 	bool buf_error;
-	unsigned int plane = 0;
-	struct mtk_video_dec_buf *mtkbuf;
 
 	vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
 	buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
@@ -1228,43 +1249,9 @@
 		mtk_v4l2_err("Unrecoverable error on buffer.");
 		ctx->state = MTK_STATE_ABORT;
 	}
-
-	if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-		return;
-
-	// Check if need to proceed cache operations for Capture Queue
-	vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-	mtkbuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
-
-	if (!(mtkbuf->flags & NO_CAHCE_INVALIDATE) &&
-		!(ctx->dec_params.svp_mode) &&
-		(vb->vb2_queue->memory == VB2_MEMORY_DMABUF)) {
-		for (plane = 0; plane < buf->frame_buffer.num_planes; plane++) {
-			struct vdec_fb dst_mem;
-			struct vb2_dc_buf *dc_buf = vb->planes[plane].mem_priv;
-
-			mtk_v4l2_debug(4, "[%d] Cache sync+", ctx->id);
-			dma_sync_sg_for_cpu(&ctx->dev->plat_dev->dev,
-				dc_buf->dma_sgt->sgl,
-				dc_buf->dma_sgt->orig_nents, DMA_FROM_DEVICE);
-
-			dst_mem.fb_base[plane].dma_addr =
-				vb2_dma_contig_plane_dma_addr(vb, plane);
-			dst_mem.fb_base[plane].size = ctx->picinfo.fb_sz[plane];
-
-			mtk_v4l2_debug(4,
-				"[%d] Cache sync- FD for %p sz=%d dev %p pfb %p",
-				ctx->id,
-				(void *)dst_mem.fb_base[plane].dma_addr,
-				(unsigned int)dst_mem.fb_base[plane].size,
-				&ctx->dev->plat_dev->dev,
-				&buf->frame_buffer);
-		}
-	}
-
 }
 
-int vb2ops_vdec_buf_init(struct vb2_buffer *vb)
+static int vb2ops_vdec_buf_init(struct vb2_buffer *vb)
 {
 	struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb,
 					struct vb2_v4l2_buffer, vb2_buf);
@@ -1272,61 +1259,43 @@
 					struct mtk_video_dec_buf, vb);
 
 	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-		/* User could use different struct dma_buf*
-		 * with the same index & enter this buf_init.
-		 * once this buffer buf->used == true will reset in mistake
-		 * VB2 use kzalloc for struct mtk_video_dec_buf,
-		 * so init could be no need
-		 */
-		if (buf->used == false)
-			buf->queued_in_v4l2 = false;
-	} else	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-		/* Do not reset EOS for 1st buffer with Early EOS*/
-		//buf->lastframe = NON_EOS;
+		buf->used = false;
+		buf->ready_to_display = false;
+		buf->queued_in_v4l2 = false;
 	} else {
-		mtk_v4l2_err("%s: unknown queue type", __func__);
-		return -EINVAL;
+		buf->lastframe = false;
 	}
 
 	return 0;
 }
 
-int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+static int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
 {
 	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
 
 	if (ctx->state == MTK_STATE_FLUSH)
 		ctx->state = MTK_STATE_HEADER;
 
-	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-		mtk_v4l2_debug(4, "V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE q->num_buffers = %d",
-			q->num_buffers);
-		ctx->dec_params.total_frame_bufq_count = q->num_buffers;
-		ctx->dec_param_change |= MTK_DEC_PARAM_TOTAL_FRAME_BUFQ_COUNT;
-	}
-
-	mtk_vdec_set_param(ctx);
 	return 0;
 }
 
-void vb2ops_vdec_stop_streaming(struct vb2_queue *q)
+static void vb2ops_vdec_stop_streaming(struct vb2_queue *q)
 {
-	struct vb2_v4l2_buffer *src_buf = NULL, *dst_buf = NULL;
-	struct vb2_v4l2_buffer *last_buf = NULL;
+	struct vb2_buffer *src_buf = NULL, *dst_buf = NULL;
 	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
-	int i = 0;
-	int ret;
 
 	mtk_v4l2_debug(3, "[%d] (%d) state=(%x) ctx->decoded_frame_cnt=%d",
 			ctx->id, q->type, ctx->state, ctx->decoded_frame_cnt);
 
-	last_buf = &ctx->empty_flush_buf->vb;
 	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-		if (ctx->state >= MTK_STATE_HEADER)
-			ctx->dev->vdec_pdata->flush_decoder(ctx);
 		while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) {
-			if (last_buf != src_buf)
-				v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+			struct vb2_v4l2_buffer *vb2_v4l2 =
+					to_vb2_v4l2_buffer(src_buf);
+			struct mtk_video_dec_buf *buf_info = container_of(
+					vb2_v4l2, struct mtk_video_dec_buf, vb);
+			if (!buf_info->lastframe)
+				v4l2_m2m_buf_done(vb2_v4l2,
+						VB2_BUF_STATE_ERROR);
 		}
 		return;
 	}
@@ -1339,28 +1308,25 @@
 		 * VIDIOC_G_FMT< etc. return previous resolution.
 		 * So we update picinfo here
 		 */
+		ctx->picinfo = ctx->last_decoded_picinfo;
 
 		mtk_v4l2_debug(2,
-				"[%d]-> new(%d,%d), old(%d,%d), real(%d,%d), DPB(%d,%d)",
+				"[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)",
 				ctx->id, ctx->last_decoded_picinfo.pic_w,
 				ctx->last_decoded_picinfo.pic_h,
 				ctx->picinfo.pic_w, ctx->picinfo.pic_h,
 				ctx->last_decoded_picinfo.buf_w,
-				ctx->last_decoded_picinfo.buf_h,
-				ctx->dpb_size, ctx->last_dpb_size);
-		ctx->picinfo = ctx->last_decoded_picinfo;
-		ctx->dpb_size = ctx->last_dpb_size;
+				ctx->last_decoded_picinfo.buf_h);
 
-		ret = ctx->dev->vdec_pdata->flush_decoder(ctx);
-		if (ret)
-			mtk_v4l2_err("DecodeFinal failed, ret=%d", ret);
+		mtk_vdec_flush_decoder(ctx);
 	}
 	ctx->state = MTK_STATE_FLUSH;
 
 	while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
-		for (i = 0; i < dst_buf->vb2_buf.num_planes; i++)
-			vb2_set_plane_payload(&dst_buf->vb2_buf, i, 0);
-		v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+		vb2_set_plane_payload(dst_buf, 0, 0);
+		vb2_set_plane_payload(dst_buf, 1, 0);
+		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf),
+					VB2_BUF_STATE_ERROR);
 	}
 
 }
@@ -1383,8 +1349,7 @@
 		return 0;
 
 	if ((ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w) ||
-	    (ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h)	||
-	    (ctx->last_dpb_size != ctx->dpb_size))
+	    (ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h))
 		return 0;
 
 	if (ctx->state != MTK_STATE_HEADER)
@@ -1393,12 +1358,17 @@
 	return 1;
 }
 
-int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl)
+static void m2mops_vdec_job_abort(void *priv)
+{
+	struct mtk_vcodec_ctx *ctx = priv;
+
+	ctx->state = MTK_STATE_ABORT;
+}
+
+static int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl);
 	int ret = 0;
-	static unsigned int value;
-	struct mtk_color_desc *color_desc;
 
 	switch (ctrl->id) {
 	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
@@ -1409,77 +1379,59 @@
 			ctrl->val = 0;
 		}
 		break;
-	case V4L2_CID_MPEG_MTK_FRAME_INTERVAL:
-		if (vdec_if_get_param(ctx,
-				GET_PARAM_FRAME_INTERVAL, &value) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot get param",
-				ctx->id);
-			ret = -EINVAL;
-		}
-		ctrl->p_new.p_u32 = &value;
-		mtk_v4l2_debug(2, "V4L2_CID_MPEG_MTK_FRAME_INTERVAL val = %u",
-			*(ctrl->p_new.p_u32));
-		break;
-	case V4L2_CID_MPEG_MTK_COLOR_DESC:
-		color_desc = (struct mtk_color_desc *)ctrl->p_new.p_u32;
-		if (vdec_if_get_param(ctx,
-				GET_PARAM_COLOR_DESC, color_desc) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot get param",
-				ctx->id);
-			ret = -EINVAL;
-		}
-	break;
-	case V4L2_CID_MPEG_MTK_ASPECT_RATIO:
-		if (vdec_if_get_param(ctx,
-				GET_PARAM_ASPECT_RATIO, &ctrl->val) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot get param",
-				ctx->id);
-			ret = -EINVAL;
-		}
-	break;
-	case V4L2_CID_MPEG_MTK_FIX_BUFFERS:
-		if (vdec_if_get_param(ctx,
-				GET_PARAM_PLATFORM_SUPPORTED_FIX_BUFFERS,
-				&ctrl->val) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot get param",
-				ctx->id);
-			ret = -EINVAL;
-		}
-	break;
-	case V4L2_CID_MPEG_MTK_FIX_BUFFERS_SVP:
-		if (vdec_if_get_param(ctx,
-				GET_PARAM_PLATFORM_SUPPORTED_FIX_BUFFERS_SVP,
-				&ctrl->val) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot get param",
-				ctx->id);
-			ret = -EINVAL;
-		}
-	break;
-	case V4L2_CID_MPEG_MTK_INTERLACING:
-		if (vdec_if_get_param(ctx,
-				GET_PARAM_INTERLACING, &ctrl->val) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot get param",
-				ctx->id);
-			ret = -EINVAL;
-		}
-	break;
-	case V4L2_CID_MPEG_MTK_CODEC_TYPE:
-		if (vdec_if_get_param(ctx,
-				GET_PARAM_CODEC_TYPE, &ctrl->val) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot get param",
-				ctx->id);
-			ret = -EINVAL;
-		}
-	break;
 	default:
 		ret = -EINVAL;
 	}
 	return ret;
 }
 
+static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = {
+	.g_volatile_ctrl = mtk_vdec_g_v_ctrl,
+};
+
+int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx)
+{
+	struct v4l2_ctrl *ctrl;
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 1);
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl,
+				&mtk_vcodec_dec_ctrl_ops,
+				V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+				0, 32, 1, 1);
+	ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl,
+				&mtk_vcodec_dec_ctrl_ops,
+				V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
+				V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+				0, V4L2_MPEG_VIDEO_VP9_PROFILE_0);
+
+	if (ctx->ctrl_hdl.error) {
+		mtk_v4l2_err("Adding control failed %d",
+				ctx->ctrl_hdl.error);
+		return ctx->ctrl_hdl.error;
+	}
+
+	v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
+	return 0;
+}
+
 const struct v4l2_m2m_ops mtk_vdec_m2m_ops = {
 	.device_run	= m2mops_vdec_device_run,
 	.job_ready	= m2mops_vdec_job_ready,
+	.job_abort	= m2mops_vdec_job_abort,
+};
+
+static const struct vb2_ops mtk_vdec_vb2_ops = {
+	.queue_setup	= vb2ops_vdec_queue_setup,
+	.buf_prepare	= vb2ops_vdec_buf_prepare,
+	.buf_queue	= vb2ops_vdec_buf_queue,
+	.wait_prepare	= vb2_ops_wait_prepare,
+	.wait_finish	= vb2_ops_wait_finish,
+	.buf_init	= vb2ops_vdec_buf_init,
+	.buf_finish	= vb2ops_vdec_buf_finish,
+	.start_streaming	= vb2ops_vdec_start_streaming,
+	.stop_streaming	= vb2ops_vdec_stop_streaming,
 };
 
 const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = {
@@ -1528,15 +1480,8 @@
 	src_vq->io_modes	= VB2_DMABUF | VB2_MMAP;
 	src_vq->drv_priv	= ctx;
 	src_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf);
-	src_vq->allow_zero_bytesused = 1;
-	src_vq->ops		= ctx->dev->vdec_pdata->vdec_vb2_ops;
-#ifdef CONFIG_VB2_MEDIATEK_DMA
-	src_vq->mem_ops         = &mtk_dma_contig_memops;
-	mtk_v4l2_debug(4, "src_vq use mtk_dma_contig_memops");
-#else
-	src_vq->mem_ops         = &vb2_dma_contig_memops;
-	mtk_v4l2_debug(4, "src_vq use vb2_dma_contig_memops");
-#endif
+	src_vq->ops		= &mtk_vdec_vb2_ops;
+	src_vq->mem_ops		= &vb2_dma_contig_memops;
 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	src_vq->lock		= &ctx->dev->dev_mutex;
 	src_vq->dev             = &ctx->dev->plat_dev->dev;
@@ -1550,15 +1495,8 @@
 	dst_vq->io_modes	= VB2_DMABUF | VB2_MMAP;
 	dst_vq->drv_priv	= ctx;
 	dst_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf);
-	dst_vq->allow_zero_bytesused = 1;
-	dst_vq->ops		= ctx->dev->vdec_pdata->vdec_vb2_ops;
-#ifdef CONFIG_VB2_MEDIATEK_DMA
-	dst_vq->mem_ops         = &mtk_dma_contig_memops;
-	mtk_v4l2_debug(4, "dst_vq use mtk_dma_contig_memops");
-#else
-	dst_vq->mem_ops         = &vb2_dma_contig_memops;
-	mtk_v4l2_debug(4, "dst_vq use vb2_dma_contig_memops");
-#endif
+	dst_vq->ops		= &mtk_vdec_vb2_ops;
+	dst_vq->mem_ops		= &vb2_dma_contig_memops;
 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	dst_vq->lock		= &ctx->dev->dev_mutex;
 	dst_vq->dev             = &ctx->dev->plat_dev->dev;
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
old mode 100644
new mode 100755
index 2466db3..dc4fc1d
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
@@ -24,38 +24,34 @@
 #define VCODEC_DEC_4K_CODED_HEIGHT	2304U
 #define MTK_VDEC_MAX_W	2048U
 #define MTK_VDEC_MAX_H	1088U
-#define MTK_VDEC_MIN_W	64U
-#define MTK_VDEC_MIN_H	64U
 
 #define MTK_VDEC_IRQ_STATUS_DEC_SUCCESS        0x10000
 
 /**
  * struct vdec_fb  - decoder frame buffer
- * @fb_base	: planes memory info
+ * @base_y	: Y plane memory info
+ * @base_c	: C plane memory info
  * @status      : frame buffer status (vdec_fb_status)
- * @num_planes		:frame buffer plane number
- * @index		:frame buffer index in vb2 queue
  */
 struct vdec_fb {
-	struct mtk_vcodec_mem fb_base[VIDEO_MAX_PLANES];
+	struct mtk_vcodec_mem	base_y;
+	struct mtk_vcodec_mem	base_c;
 	unsigned int	status;
-	unsigned int    num_planes;
-	unsigned int    index;
 };
 
 /**
  * struct mtk_video_dec_buf - Private data related to each VB2 buffer.
- * @vb:	VB2 buffer
+ * @b:		VB2 buffer
  * @list:	link list
  * @used:	Capture buffer contain decoded frame data and keep in
  *			codec data structure
+ * @ready_to_display:	Capture buffer not display yet
  * @queued_in_vb2:	Capture buffer is queue in vb2
  * @queued_in_v4l2:	Capture buffer is in v4l2 driver, but not in vb2
  *			queue yet
  * @lastframe:		Intput buffer is last buffer - EOS
  * @error:		An unrecoverable error occurs on this buffer.
  * @frame_buffer:	Decode status, and buffer information of Capture buffer
- * @bs_buffer:	Output buffer info
  *
  * Note : These status information help us track and debug buffer state
  */
@@ -64,25 +60,17 @@
 	struct list_head	list;
 
 	bool	used;
+	bool	ready_to_display;
 	bool	queued_in_vb2;
 	bool	queued_in_v4l2;
-	bool lastframe;
-	bool isEarlyEos;
+	bool	lastframe;
 	bool	error;
-
-	union {
-		struct vdec_fb	frame_buffer;
-		struct mtk_vcodec_mem	bs_buffer;
-	};
-	int flags;
+	struct vdec_fb	frame_buffer;
 };
 
 extern const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops;
 extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops;
-extern const struct media_device_ops mtk_vcodec_media_ops;
 
-extern const struct mtk_vcodec_dec_pdata	mtk_frame_pdata;
-extern const struct mtk_vcodec_dec_pdata	mtk_req_8183_pdata;
 
 /*
  * mtk_vdec_lock/mtk_vdec_unlock are for ctx instance to
@@ -95,28 +83,8 @@
 int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
 			   struct vb2_queue *dst_vq);
 void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx);
-void mtk_vcodec_dec_empty_queues(struct mtk_vcodec_ctx *ctx);
 void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx);
-int mtk_vdec_set_param(struct mtk_vcodec_ctx *ctx);
-void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx,
-		unsigned int pixelformat);
-struct mtk_video_fmt *mtk_find_fmt_by_pixel(unsigned int pixelformat);
-
-int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl);
-
-/*
- * VB2 ops
- */
-int vb2ops_vdec_queue_setup(struct vb2_queue *vq,
-				unsigned int *nbuffers,
-				unsigned int *nplanes,
-				unsigned int sizes[],
-				struct device *alloc_devs[]);
-int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb);
-void vb2ops_vdec_buf_finish(struct vb2_buffer *vb);
-int vb2ops_vdec_buf_init(struct vb2_buffer *vb);
-int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count);
-void vb2ops_vdec_stop_streaming(struct vb2_queue *q);
+int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx);
 
 
 #endif /* _MTK_VCODEC_DEC_H_ */
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
old mode 100644
new mode 100755
index c620a0e..4334b73
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -22,18 +22,13 @@
 #include <media/v4l2-event.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-dma-contig.h>
-#include <media/v4l2-device.h>
-#include <linux/iommu.h>
-#include <linux/pm_wakeup.h>
-#include <linux/delay.h>
-#include <linux/suspend.h>
 
 #include "mtk_vcodec_drv.h"
 #include "mtk_vcodec_dec.h"
 #include "mtk_vcodec_dec_pm.h"
 #include "mtk_vcodec_intr.h"
 #include "mtk_vcodec_util.h"
-#include "mtk_vcodec_fw.h"
+#include "mtk_vpu.h"
 
 #define VDEC_HW_ACTIVE	0x10
 #define VDEC_IRQ_CFG	0x11
@@ -42,7 +37,6 @@
 
 module_param(mtk_v4l2_dbg_level, int, 0644);
 module_param(mtk_vcodec_dbg, bool, 0644);
-struct mtk_vcodec_dev *vdec_dev;
 
 /* Wake up context wait_queue */
 static void wake_up_ctx(struct mtk_vcodec_ctx *ctx)
@@ -91,6 +85,22 @@
 	return IRQ_HANDLED;
 }
 
+static void mtk_vcodec_dec_reset_handler(void *priv)
+{
+	struct mtk_vcodec_dev *dev = priv;
+	struct mtk_vcodec_ctx *ctx;
+
+	mtk_v4l2_err("Watchdog timeout!!");
+
+	mutex_lock(&dev->dev_mutex);
+	list_for_each_entry(ctx, &dev->ctx_list, list) {
+		ctx->state = MTK_STATE_ABORT;
+		mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ERROR",
+				ctx->id);
+	}
+	mutex_unlock(&dev->dev_mutex);
+}
+
 static int fops_vcodec_open(struct file *file)
 {
 	struct mtk_vcodec_dev *dev = video_drvdata(file);
@@ -120,7 +130,7 @@
 	mutex_init(&ctx->lock);
 
 	ctx->type = MTK_INST_DECODER;
-	ret = dev->vdec_pdata->ctrls_setup(ctx);
+	ret = mtk_vcodec_dec_ctrls_setup(ctx);
 	if (ret) {
 		mtk_v4l2_err("Failed to setup mt vcodec controls");
 		goto err_ctrls_setup;
@@ -137,26 +147,26 @@
 				V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
 	ctx->empty_flush_buf->vb.vb2_buf.vb2_queue = src_vq;
 	ctx->empty_flush_buf->lastframe = true;
-	ctx->empty_flush_buf->isEarlyEos = false;
 	mtk_vcodec_dec_set_default_params(ctx);
 
 	if (v4l2_fh_is_singular(&ctx->fh)) {
 		mtk_vcodec_dec_pw_on(&dev->pm);
 		/*
-		 * load fireware to checks if it was loaded already and
+		 * vpu_load_firmware checks if it was loaded already and
 		 * does nothing in that case
 		 */
-		ret = mtk_vcodec_fw_load_firmware(dev->ipi_msg_handle);
+		ret = vpu_load_firmware(dev->vpu_plat_dev);
 		if (ret < 0) {
 			/*
 			 * Return 0 if downloading firmware successfully,
 			 * otherwise it is failed
 			 */
-			mtk_v4l2_err("failed to load firmware!");
+			mtk_v4l2_err("vpu_load_firmware failed!");
 			goto err_load_fw;
 		}
 
-		dev->dec_capability = mtk_vcodec_fw_get_vdec_capa(dev->ipi_msg_handle);
+		dev->dec_capability =
+			vpu_get_vdec_hw_capa(dev->vpu_plat_dev);
 		mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability);
 	}
 
@@ -196,7 +206,6 @@
 	 * Second, the decoder will be flushed and all the buffers will be
 	 * returned in stop_streaming.
 	 */
-	mtk_vcodec_dec_empty_queues(ctx);
 	v4l2_m2m_ctx_release(ctx->m2m_ctx);
 	mtk_vcodec_dec_release(ctx);
 
@@ -222,66 +231,11 @@
 	.mmap		= v4l2_m2m_fop_mmap,
 };
 
-/**
- * Suspend callbacks after user space processes are frozen
- * Since user space processes are frozen, there is no need and cannot hold same
- * mutex that protects lock owner while checking status.
- * If video codec hardware is still active now, must not to enter suspend.
- **/
-static int mtk_vcodec_dec_suspend(struct device *pDev)
-{
-	if (mutex_is_locked(&vdec_dev->dec_mutex)) {
-		mtk_v4l2_debug(0, "fail due to videocodec activity");
-		return -EBUSY;
-	}
-	mtk_v4l2_debug(1, "done");
-	return 0;
-}
-
-static int mtk_vcodec_dec_resume(struct device *pDev)
-{
-	mtk_v4l2_debug(1, "done");
-	return 0;
-}
-
-static int mtk_vcodec_dec_suspend_notifier(struct notifier_block *nb,
-					unsigned long action, void *data)
-{
-	int wait_cnt = 0;
-
-	mtk_v4l2_debug(1, "action = %ld", action);
-	switch (action) {
-	case PM_SUSPEND_PREPARE:
-		vdec_dev->is_codec_suspending = 1;
-		do {
-			usleep_range(10000, 20000);
-			wait_cnt++;
-			if (wait_cnt > 5) {
-				mtk_v4l2_err("waiting fail");
-				/* Current task is still not finished, don't
-				 * care, will check again in real suspend
-				 */
-				return NOTIFY_DONE;
-			}
-		} while (mutex_is_locked(&vdec_dev->dec_mutex));
-
-		return NOTIFY_OK;
-	case PM_POST_SUSPEND:
-		vdec_dev->is_codec_suspending = 0;
-		return NOTIFY_OK;
-	default:
-		return NOTIFY_DONE;
-	}
-	return NOTIFY_DONE;
-}
-
 static int mtk_vcodec_probe(struct platform_device *pdev)
 {
 	struct mtk_vcodec_dev *dev;
 	struct video_device *vfd_dec;
 	struct resource *res;
-	phandle rproc_phandle;
-	enum mtk_vcodec_fw_type fw_type;
 	int i, ret;
 
 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
@@ -291,24 +245,14 @@
 	INIT_LIST_HEAD(&dev->ctx_list);
 	dev->plat_dev = pdev;
 
-	dev->vdec_pdata = of_device_get_match_data(&pdev->dev);
-	if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
-				  &rproc_phandle)) {
-		fw_type = VPU;
-	} else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp",
-				  &rproc_phandle)) {
-		fw_type = SCP;
-	} else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vcu",
-				  &rproc_phandle)) {
-		fw_type = VCU;
-	} else {
-		mtk_v4l2_err("Could not get vdec IPI device");
-		return -ENODEV;
+	dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev);
+	if (dev->vpu_plat_dev == NULL) {
+		mtk_v4l2_err("[VPU] vpu device in not ready");
+		return -EPROBE_DEFER;
 	}
-	dev->ipi_msg_handle = mtk_vcodec_fw_select(dev, fw_type, rproc_phandle,
-						   VPU_RST_DEC);
-	if (IS_ERR(dev->ipi_msg_handle))
-		return PTR_ERR(dev->ipi_msg_handle);
+
+	vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_dec_reset_handler,
+			dev, VPU_RST_DEC);
 
 	ret = mtk_vcodec_init_dec_pm(dev);
 	if (ret < 0) {
@@ -319,9 +263,9 @@
 	for (i = 0; i < NUM_MAX_VDEC_REG_BASE; i++) {
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
 		if (res == NULL) {
-			dev_err(&pdev->dev,
-				"get index:%d memory resource failed.", i);
-			break;
+			dev_err(&pdev->dev, "get memory resource failed.");
+			ret = -ENXIO;
+			goto err_res;
 		}
 		dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res);
 		if (IS_ERR((__force void *)dev->reg_base[i])) {
@@ -351,7 +295,6 @@
 	disable_irq(dev->dec_irq);
 	mutex_init(&dev->dec_mutex);
 	mutex_init(&dev->dev_mutex);
-	mutex_init(&dev->dec_dvfs_mutex);
 	spin_lock_init(&dev->irqlock);
 
 	snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s",
@@ -402,32 +345,7 @@
 		goto err_event_workq;
 	}
 
-	if (dev->vdec_pdata->uses_stateless_api) {
-		dev->mdev_dec.dev = &pdev->dev;
-		strscpy(dev->mdev_dec.model, MTK_VCODEC_DEC_NAME,
-				sizeof(dev->mdev_dec.model));
-
-		media_device_init(&dev->mdev_dec);
-		dev->mdev_dec.ops = &mtk_vcodec_media_ops;
-		dev->v4l2_dev.mdev = &dev->mdev_dec;
-
-		ret = v4l2_m2m_register_media_controller(dev->m2m_dev_dec,
-			dev->vfd_dec, MEDIA_ENT_F_PROC_VIDEO_DECODER);
-		if (ret) {
-			mtk_v4l2_err("Failed to register media controller");
-			goto err_reg_cont;
-		}
-
-		ret = media_device_register(&dev->mdev_dec);
-		if (ret) {
-			mtk_v4l2_err("Failed to register media device");
-			goto err_media_reg;
-		}
-
-		mtk_v4l2_debug(0, "media registered as /dev/media%d",
-			vfd_dec->num);
-	}
-	ret = video_register_device(vfd_dec, VFL_TYPE_GRABBER, -1);
+	ret = video_register_device(vfd_dec, VFL_TYPE_GRABBER, 0);
 	if (ret) {
 		mtk_v4l2_err("Failed to register video device");
 		goto err_dec_reg;
@@ -436,22 +354,9 @@
 	mtk_v4l2_debug(0, "decoder registered as /dev/video%d",
 		vfd_dec->num);
 
-	mtk_prepare_vdec_dvfs(dev);
-	ret = mtk_prepare_vdec_emi_bw(dev);
-	if (ret)
-		goto err_dec_reg;
-	pm_notifier(mtk_vcodec_dec_suspend_notifier, 0);
-	dev->is_codec_suspending = 0;
-	vdec_dev = dev;
 	return 0;
 
 err_dec_reg:
-	if (dev->vdec_pdata->uses_stateless_api)
-		media_device_unregister(&dev->mdev_dec);
-err_media_reg:
-	if (dev->vdec_pdata->uses_stateless_api)
-		v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec);
-err_reg_cont:
 	destroy_workqueue(dev->decode_workqueue);
 err_event_workq:
 	v4l2_m2m_release(dev->m2m_dev_dec);
@@ -464,13 +369,8 @@
 	return ret;
 }
 
-extern const struct mtk_vcodec_dec_pdata mtk_frame_8173_pdata;
-extern const struct mtk_vcodec_dec_pdata mtk_req_8183_pdata;
-
 static const struct of_device_id mtk_vcodec_match[] = {
-	{.compatible = "mediatek,mt8173-vcodec-dec", .data = &mtk_frame_pdata},
-	{.compatible = "mediatek,mt8183-vcodec-dec", .data = &mtk_req_8183_pdata},
-	{.compatible = "mediatek,mt6779-vcodec-dec", .data = &mtk_frame_pdata},
+	{.compatible = "mediatek,mt8173-vcodec-dec",},
 	{},
 };
 
@@ -480,18 +380,8 @@
 {
 	struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev);
 
-	mtk_unprepare_vdec_emi_bw();
-	mtk_unprepare_vdec_dvfs();
-
 	flush_workqueue(dev->decode_workqueue);
 	destroy_workqueue(dev->decode_workqueue);
-
-	if (media_devnode_is_registered(dev->mdev_dec.devnode)) {
-		media_device_unregister(&dev->mdev_dec);
-		v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec);
-		media_device_cleanup(&dev->mdev_dec);
-	}
-
 	if (dev->m2m_dev_dec)
 		v4l2_m2m_release(dev->m2m_dev_dec);
 
@@ -503,16 +393,11 @@
 	return 0;
 }
 
-static const struct dev_pm_ops mtk_vcodec_dec_pm_ops = {
-	.suspend = mtk_vcodec_dec_suspend,
-	.resume = mtk_vcodec_dec_resume,
-};
 static struct platform_driver mtk_vcodec_dec_driver = {
 	.probe	= mtk_vcodec_probe,
 	.remove	= mtk_vcodec_dec_remove,
 	.driver	= {
 		.name	= MTK_VCODEC_DEC_NAME,
-		.pm = &mtk_vcodec_dec_pm_ops,
 		.of_match_table = mtk_vcodec_match,
 	},
 };
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
old mode 100644
new mode 100755
index 9d1f74b..79ca03a
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
@@ -16,90 +16,83 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
+#include <soc/mediatek/smi.h>
 
 #include "mtk_vcodec_dec_pm.h"
 #include "mtk_vcodec_util.h"
-
-#ifdef CONFIG_MEDIATEK_DVFS
-#include <linux/pm_opp.h>
-#include <linux/regulator/consumer.h>
-#include "vcodec_dvfs.h"
-static struct regulator *reg;
-static unsigned long vdec_freq;
-static u32 vdec_freq_step_size;
-static unsigned long *vdec_freq_steps;
-static u32 vdec_high_volt;
-static struct codec_history *vdec_hists;
-static struct codec_job *vdec_jobs;
-#endif
-
-#ifdef CONFIG_MEDIATEK_EMI_BW
-#include <linux/interconnect-provider.h>
-#define STD_VDEC_FREQ 312
-static unsigned int h264_frm_scale[4] = {12, 24, 40, 12};
-static unsigned int h265_frm_scale[4] = {12, 24, 40, 12};
-static unsigned int vp9_frm_scale[4] = {12, 24, 40, 12};
-static unsigned int vp8_frm_scale[4] = {12, 24, 40, 12};
-static unsigned int mp24_frm_scale[5] = {16, 20, 32, 50, 16};
-
-static struct icc_path *vdec_mc;
-static struct icc_path *vdec_ufo;
-static struct icc_path *vdec_pp;
-static struct icc_path *vdec_pred_rd;
-static struct icc_path *vdec_pred_wr;
-static struct icc_path *vdec_ppwrap;
-static struct icc_path *vdec_tile;
-static struct icc_path *vdec_vld;
-static struct icc_path *vdec_vld2;
-static struct icc_path *vdec_avc_mv;
-static struct icc_path *vdec_ufo_enc;
-static struct icc_path *vdec_rg_ctrl_dma;
-#endif
+#include "mtk_vpu.h"
 
 int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
 {
+	struct device_node *node;
 	struct platform_device *pdev;
 	struct mtk_vcodec_pm *pm;
-	struct mtk_vcodec_clk *dec_clk;
-	struct mtk_vcodec_clk_info *clk_info;
-	int i = 0, ret = 0;
+	int ret = 0;
 
 	pdev = mtkdev->plat_dev;
 	pm = &mtkdev->pm;
 	pm->mtkdev = mtkdev;
-	dec_clk = &pm->vdec_clk;
+	node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0);
+	if (!node) {
+		mtk_v4l2_err("of_parse_phandle mediatek,larb fail!");
+		return -1;
+	}
 
+	pdev = of_find_device_by_node(node);
+	if (WARN_ON(!pdev)) {
+		of_node_put(node);
+		return -1;
+	}
+	pm->larbvdec = &pdev->dev;
 	pdev = mtkdev->plat_dev;
 	pm->dev = &pdev->dev;
 
-	dec_clk->clk_num =
-		of_property_count_strings(pdev->dev.of_node, "clock-names");
-	if (dec_clk->clk_num > 0) {
-		dec_clk->clk_info = devm_kcalloc(&pdev->dev,
-			dec_clk->clk_num, sizeof(*clk_info),
-			GFP_KERNEL);
-		if (!dec_clk->clk_info)
-			return -ENOMEM;
-	} else {
-		mtk_v4l2_err("Failed to get vdec clock count");
-		return -EINVAL;
+	pm->vcodecpll = devm_clk_get(&pdev->dev, "vcodecpll");
+	if (IS_ERR(pm->vcodecpll)) {
+		mtk_v4l2_err("devm_clk_get vcodecpll fail");
+		ret = PTR_ERR(pm->vcodecpll);
 	}
 
-	for (i = 0; i < dec_clk->clk_num; i++) {
-		clk_info = &dec_clk->clk_info[i];
-		ret = of_property_read_string_index(pdev->dev.of_node,
-			"clock-names", i, &clk_info->clk_name);
-		if (ret) {
-			mtk_v4l2_err("Failed to get clock name id = %d", i);
-			return ret;
-		}
-		clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
-			clk_info->clk_name);
-		if (IS_ERR(clk_info->vcodec_clk)) {
-			mtk_v4l2_err("devm_clk_get (%d)%s fail", i,
-				clk_info->clk_name);
-			return PTR_ERR(clk_info->vcodec_clk);
-		}
+	pm->univpll_d2 = devm_clk_get(&pdev->dev, "univpll_d2");
+	if (IS_ERR(pm->univpll_d2)) {
+		mtk_v4l2_err("devm_clk_get univpll_d2 fail");
+		ret = PTR_ERR(pm->univpll_d2);
+	}
+
+	pm->clk_cci400_sel = devm_clk_get(&pdev->dev, "clk_cci400_sel");
+	if (IS_ERR(pm->clk_cci400_sel)) {
+		mtk_v4l2_err("devm_clk_get clk_cci400_sel fail");
+		ret = PTR_ERR(pm->clk_cci400_sel);
+	}
+
+	pm->vdec_sel = devm_clk_get(&pdev->dev, "vdec_sel");
+	if (IS_ERR(pm->vdec_sel)) {
+		mtk_v4l2_err("devm_clk_get vdec_sel fail");
+		ret = PTR_ERR(pm->vdec_sel);
+	}
+
+	pm->vdecpll = devm_clk_get(&pdev->dev, "vdecpll");
+	if (IS_ERR(pm->vdecpll)) {
+		mtk_v4l2_err("devm_clk_get vdecpll fail");
+		ret = PTR_ERR(pm->vdecpll);
+	}
+
+	pm->vencpll = devm_clk_get(&pdev->dev, "vencpll");
+	if (IS_ERR(pm->vencpll)) {
+		mtk_v4l2_err("devm_clk_get vencpll fail");
+		ret = PTR_ERR(pm->vencpll);
+	}
+
+	pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel");
+	if (IS_ERR(pm->venc_lt_sel)) {
+		mtk_v4l2_err("devm_clk_get venc_lt_sel fail");
+		ret = PTR_ERR(pm->venc_lt_sel);
+	}
+
+	pm->vdec_bus_clk_src = devm_clk_get(&pdev->dev, "vdec_bus_clk_src");
+	if (IS_ERR(pm->vdec_bus_clk_src)) {
+		mtk_v4l2_err("devm_clk_get vdec_bus_clk_src");
+		ret = PTR_ERR(pm->vdec_bus_clk_src);
 	}
 
 	pm_runtime_enable(&pdev->dev);
@@ -132,356 +125,78 @@
 
 void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
 {
-	struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk;
-	int ret, i = 0;
+	int ret;
 
-	for (i = 0; i < dec_clk->clk_num; i++) {
-		ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk);
-		if (ret) {
-			mtk_v4l2_err("clk_prepare_enable %d %s fail %d", i,
-				dec_clk->clk_info[i].clk_name, ret);
-			goto error;
-		}
-	}
+	ret = clk_set_rate(pm->vcodecpll, 1482 * 1000000);
+	if (ret)
+		mtk_v4l2_err("clk_set_rate vcodecpll fail %d", ret);
 
-	return;
+	ret = clk_set_rate(pm->vencpll, 800 * 1000000);
+	if (ret)
+		mtk_v4l2_err("clk_set_rate vencpll fail %d", ret);
 
-error:
-	for (i -= 1; i >= 0; i--)
-		clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
+	ret = clk_prepare_enable(pm->vcodecpll);
+	if (ret)
+		mtk_v4l2_err("clk_prepare_enable vcodecpll fail %d", ret);
+
+	ret = clk_prepare_enable(pm->vencpll);
+	if (ret)
+		mtk_v4l2_err("clk_prepare_enable vencpll fail %d", ret);
+
+	ret = clk_prepare_enable(pm->vdec_bus_clk_src);
+	if (ret)
+		mtk_v4l2_err("clk_prepare_enable vdec_bus_clk_src fail %d",
+				ret);
+
+	ret = clk_prepare_enable(pm->venc_lt_sel);
+	if (ret)
+		mtk_v4l2_err("clk_prepare_enable venc_lt_sel fail %d", ret);
+
+	ret = clk_set_parent(pm->venc_lt_sel, pm->vdec_bus_clk_src);
+	if (ret)
+		mtk_v4l2_err("clk_set_parent venc_lt_sel vdec_bus_clk_src fail %d",
+				ret);
+
+	ret = clk_prepare_enable(pm->univpll_d2);
+	if (ret)
+		mtk_v4l2_err("clk_prepare_enable univpll_d2 fail %d", ret);
+
+	ret = clk_prepare_enable(pm->clk_cci400_sel);
+	if (ret)
+		mtk_v4l2_err("clk_prepare_enable clk_cci400_sel fail %d", ret);
+
+	ret = clk_set_parent(pm->clk_cci400_sel, pm->univpll_d2);
+	if (ret)
+		mtk_v4l2_err("clk_set_parent clk_cci400_sel univpll_d2 fail %d",
+				ret);
+
+	ret = clk_prepare_enable(pm->vdecpll);
+	if (ret)
+		mtk_v4l2_err("clk_prepare_enable vdecpll fail %d", ret);
+
+	ret = clk_prepare_enable(pm->vdec_sel);
+	if (ret)
+		mtk_v4l2_err("clk_prepare_enable vdec_sel fail %d", ret);
+
+	ret = clk_set_parent(pm->vdec_sel, pm->vdecpll);
+	if (ret)
+		mtk_v4l2_err("clk_set_parent vdec_sel vdecpll fail %d", ret);
+
+	ret = mtk_smi_larb_get(pm->larbvdec);
+	if (ret)
+		mtk_v4l2_err("mtk_smi_larb_get larbvdec fail %d", ret);
+
 }
 
 void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm)
 {
-	struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk;
-	int i = 0;
-
-	for (i = dec_clk->clk_num - 1; i >= 0; i--)
-		clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
-}
-void mtk_prepare_vdec_dvfs(struct mtk_vcodec_dev *mtkdev)
-{
-#ifdef CONFIG_MEDIATEK_DVFS
-	unsigned long freq = 0;
-	int i = 0;
-	struct platform_device *pdev;
-	struct dev_pm_opp *opp;
-
-	pdev = mtkdev->plat_dev;
-
-	dev_pm_opp_of_add_table(&pdev->dev);
-
-	reg = devm_regulator_get(&pdev->dev, "dvfsrc-vcore");
-	if (!IS_ERR(reg)) {
-		mtk_v4l2_debug(1,
-			"devm_regulator_get success, regualtor:%p\n", reg);
-	} else {
-		mtk_v4l2_err("devm_regulator_get fail!!\n");
-		return;
-	}
-	vdec_freq_step_size = dev_pm_opp_get_opp_count(&pdev->dev);
-	vdec_freq_steps = kcalloc(
-		vdec_freq_step_size, sizeof(unsigned long), GFP_KERNEL);
-	while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(&pdev->dev, &freq))) {
-		vdec_freq_steps[i] = freq;
-		mtk_v4l2_debug(3, "i:%d, freq:%lu\n", i, freq);
-		freq++;
-		i++;
-		dev_pm_opp_put(opp);
-	}
-	freq = vdec_freq_steps[vdec_freq_step_size - 1];
-	opp = dev_pm_opp_find_freq_ceil(&pdev->dev, &freq);
-	vdec_high_volt = dev_pm_opp_get_voltage(opp);
-	dev_pm_opp_put(opp);
-	/*convert to MHZ from HZ*/
-	for (i = 0; i < vdec_freq_step_size; i++)
-		vdec_freq_steps[i] = vdec_freq_steps[i]/ONE_MHZ;
-	mtk_v4l2_debug(1, "%s, vdec_freq_step_size:%d, high_volt:%d\n",
-	    __func__, vdec_freq_step_size, vdec_high_volt);
-#endif
-}
-
-void mtk_unprepare_vdec_dvfs(void)
-{
-#ifdef CONFIG_MEDIATEK_DVFS
-	kfree(vdec_freq_steps);
-#endif
-}
-int mtk_prepare_vdec_emi_bw(struct mtk_vcodec_dev *mtkdev)
-{
-	int ret = 0;
-#ifdef CONFIG_MEDIATEK_EMI_BW
-	struct platform_device *pdev;
-
-	pdev = mtkdev->plat_dev;
-	vdec_mc = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_MC");
-	if (IS_ERR_OR_NULL(vdec_mc)) {
-		mtk_v4l2_err("of_icc_get vdec_mc fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_mc));
-		return PTR_ERR_OR_ZERO(vdec_mc);
-	}
-	vdec_ufo = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_UFO");
-	if (IS_ERR_OR_NULL(vdec_ufo)) {
-		mtk_v4l2_err("of_icc_get vdec_ufo fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_ufo));
-		return PTR_ERR_OR_ZERO(vdec_ufo);
-	}
-	vdec_pp = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_PP");
-	if (IS_ERR_OR_NULL(vdec_pp)) {
-		mtk_v4l2_err("of_icc_get vdec_pp fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_pp));
-		return PTR_ERR_OR_ZERO(vdec_pp);
-	}
-	vdec_pred_rd = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_PRED_RD");
-	if (IS_ERR_OR_NULL(vdec_pred_rd)) {
-		mtk_v4l2_err("of_icc_get vdec_pred_rd fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_pred_rd));
-		return PTR_ERR_OR_ZERO(vdec_pred_rd);
-	}
-	vdec_pred_wr = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_PRED_WR");
-	if (IS_ERR_OR_NULL(vdec_pred_wr)) {
-		mtk_v4l2_err("of_icc_get vdec_pred_wr fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_pred_wr));
-		return PTR_ERR_OR_ZERO(vdec_pred_wr);
-	}
-	vdec_ppwrap = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_PPWRAP");
-	if (IS_ERR_OR_NULL(vdec_ppwrap)) {
-		mtk_v4l2_err("of_icc_get vdec_ppwrap fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_ppwrap));
-		return PTR_ERR_OR_ZERO(vdec_ppwrap);
-	}
-	vdec_tile = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_TILE");
-	if (IS_ERR_OR_NULL(vdec_tile)) {
-		mtk_v4l2_err("of_icc_get vdec_tile fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_tile));
-		return PTR_ERR_OR_ZERO(vdec_tile);
-	}
-	vdec_vld = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_VLD");
-	if (IS_ERR_OR_NULL(vdec_vld)) {
-		mtk_v4l2_err("of_icc_get vdec_vld fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_vld));
-		return PTR_ERR_OR_ZERO(vdec_vld);
-	}
-	vdec_vld2 = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_VLD2");
-	if (IS_ERR_OR_NULL(vdec_vld2)) {
-		mtk_v4l2_err("of_icc_get vdec_vld2 fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_vld2));
-		return PTR_ERR_OR_ZERO(vdec_vld2);
-	}
-	vdec_avc_mv = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_AVC_MV");
-	if (IS_ERR_OR_NULL(vdec_avc_mv)) {
-		mtk_v4l2_err("of_icc_get vdec_avc_mv fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_avc_mv));
-		return PTR_ERR_OR_ZERO(vdec_avc_mv);
-	}
-	vdec_ufo_enc = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_UFO_ENC");
-	if (IS_ERR_OR_NULL(vdec_ufo_enc)) {
-		mtk_v4l2_err("of_icc_get vdec_ufo_enc fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_ufo_enc));
-		return PTR_ERR_OR_ZERO(vdec_ufo_enc);
-	}
-	vdec_rg_ctrl_dma = of_icc_get(&pdev->dev, "MT_MM_M4U_VDEC_RG_CTRL_DMA");
-	if (IS_ERR_OR_NULL(vdec_rg_ctrl_dma)) {
-		mtk_v4l2_err("of_icc_get vdec_rg_ctrl_dma fail:%d!!\n",
-			PTR_ERR_OR_ZERO(vdec_rg_ctrl_dma));
-		return PTR_ERR_OR_ZERO(vdec_rg_ctrl_dma);
-	}
-#endif
-	return ret;
-}
-
-void mtk_unprepare_vdec_emi_bw(void)
-{
-}
-
-void mtk_vdec_dvfs_begin(struct mtk_vcodec_ctx *ctx)
-{
-#ifdef CONFIG_MEDIATEK_DVFS
-	int freq = 0;
-	int target_freq_mhz = 0;
-	int low_volt = 0;
-	unsigned long target_freq = 0;
-	struct codec_job *vdec_cur_job = 0;
-	struct platform_device *pdev;
-	struct mtk_vcodec_pm *pm;
-	struct dev_pm_opp *opp;
-
-	pm = &ctx->dev->pm;
-	pdev = ctx->dev->plat_dev;
-
-	mutex_lock(&ctx->dev->dec_dvfs_mutex);
-	vdec_cur_job = move_job_to_head(&ctx->id, &vdec_jobs);
-	if (vdec_cur_job != 0) {
-		vdec_cur_job->start = get_time_us();
-		freq = est_freq(vdec_cur_job->handle, &vdec_jobs,
-					vdec_hists);
-		target_freq_mhz = match_freq(freq, vdec_freq_steps,
-					vdec_freq_step_size);
-		target_freq = target_freq_mhz * ONE_MHZ;
-
-		if (freq > 0) {
-			vdec_freq = freq;
-			if (vdec_freq > target_freq_mhz)
-				vdec_freq = target_freq_mhz;
-			vdec_cur_job->mhz = (int)target_freq_mhz;
-			opp = dev_pm_opp_find_freq_ceil(&pdev->dev,
-				&target_freq);
-			if (!IS_ERR(opp))
-				opp = dev_pm_opp_find_freq_floor(&pdev->dev,
-					&target_freq);
-			else {
-				mtk_v4l2_debug(1, "%s:%d, get opp fail\n",
-					__func__, __LINE__);
-				mutex_unlock(&ctx->dev->dec_dvfs_mutex);
-				return;
-			}
-			low_volt = dev_pm_opp_get_voltage(opp);
-			regulator_set_voltage(reg, low_volt, vdec_high_volt);
-		}
-	} else {
-		target_freq_mhz = match_freq(DEFAULT_MHZ, vdec_freq_steps,
-						vdec_freq_step_size);
-		target_freq = target_freq_mhz * ONE_MHZ;
-		opp = dev_pm_opp_find_freq_ceil(&pdev->dev, &target_freq);
-		if (!IS_ERR(opp))
-			opp = dev_pm_opp_find_freq_floor(&pdev->dev,
-				&target_freq);
-		else {
-			mtk_v4l2_debug(1, "%s:%d, get opp fail\n",
-				__func__, __LINE__);
-			mutex_unlock(&ctx->dev->dec_dvfs_mutex);
-			return;
-		}
-		low_volt = dev_pm_opp_get_voltage(opp);
-		regulator_set_voltage(reg, low_volt, vdec_high_volt);
-	}
-	mutex_unlock(&ctx->dev->dec_dvfs_mutex);
-#endif
-}
-void mtk_vdec_dvfs_end(struct mtk_vcodec_ctx *ctx)
-{
-#ifdef CONFIG_MEDIATEK_DVFS
-	int low_volt = 0;
-
-	struct codec_job *vdec_cur_job = 0;
-
-	/* vdec dvfs */
-	mutex_lock(&ctx->dev->dec_dvfs_mutex);
-	vdec_cur_job = vdec_jobs;
-	if (vdec_cur_job->handle == &ctx->id) {
-		vdec_cur_job->end = get_time_us();
-		update_hist(vdec_cur_job, &vdec_hists, 0);
-		vdec_jobs = vdec_jobs->next;
-		kfree(vdec_cur_job);
-	} else {
-		/* print error log */
-	}
-	regulator_set_voltage(reg, low_volt, vdec_high_volt);
-
-	mutex_unlock(&ctx->dev->dec_dvfs_mutex);
-#endif
-}
-void mtk_vdec_emi_bw_begin(struct mtk_vcodec_ctx *ctx)
-{
-#ifdef CONFIG_MEDIATEK_EMI_BW
-	int b_freq_idx = 0;
-	int f_type = 1; /* TODO */
-	long emi_bw = 0;
-	long emi_bw_input = 0;
-	long emi_bw_output = 0;
-
-	if (vdec_freq_step_size > 1)
-		b_freq_idx = vdec_freq_step_size - 1;
-
-	emi_bw = 8L * 1920 * 1080 * 3 * 10 * vdec_freq;
-	emi_bw_input = 8 * vdec_freq / STD_VDEC_FREQ;
-	emi_bw_output = 1920 * 1088 * 3 * 30 * 10 * vdec_freq /
-			2 / 3 / STD_VDEC_FREQ / 1024 / 1024;
-
-	switch (ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc) {
-	case V4L2_PIX_FMT_H264:
-		emi_bw = emi_bw * h264_frm_scale[f_type] / (2 * STD_VDEC_FREQ);
-		break;
-	case V4L2_PIX_FMT_H265:
-		emi_bw = emi_bw * h265_frm_scale[f_type] / (2 * STD_VDEC_FREQ);
-		break;
-	case V4L2_PIX_FMT_VP8:
-		emi_bw = emi_bw * vp8_frm_scale[f_type] / (2 * STD_VDEC_FREQ);
-		break;
-	case V4L2_PIX_FMT_VP9:
-		emi_bw = emi_bw * vp9_frm_scale[f_type] / (2 * STD_VDEC_FREQ);
-		break;
-	case V4L2_PIX_FMT_MPEG4:
-	case V4L2_PIX_FMT_H263:
-	case V4L2_PIX_FMT_S263:
-	case V4L2_PIX_FMT_XVID:
-	case V4L2_PIX_FMT_DIVX3:
-	case V4L2_PIX_FMT_DIVX4:
-	case V4L2_PIX_FMT_DIVX5:
-	case V4L2_PIX_FMT_DIVX6:
-	case V4L2_PIX_FMT_MPEG1:
-	case V4L2_PIX_FMT_MPEG2:
-		emi_bw = emi_bw * mp24_frm_scale[f_type] / (2 * STD_VDEC_FREQ);
-		break;
-	}
-
-	/* bits/s to MBytes/s */
-	emi_bw = emi_bw / (1024 * 1024) / 8;
-
-	if (0) {    /* UFO */
-		emi_bw = emi_bw * 6 / 10;
-		emi_bw_output = emi_bw_output * 6 / 10;
-	}
-
-	emi_bw = emi_bw - emi_bw_output - (emi_bw_input * 2);
-	if (emi_bw < 0)
-		emi_bw = 0;
-
-	icc_set_bw(vdec_mc, MBps_to_icc(emi_bw), 0);
-	icc_set_bw(vdec_pp, MBps_to_icc(emi_bw_output), 0);
-	icc_set_bw(vdec_pred_rd, MBps_to_icc(1), 0);
-	icc_set_bw(vdec_pred_wr, MBps_to_icc(1), 0);
-	icc_set_bw(vdec_ppwrap, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_tile, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_vld, MBps_to_icc(emi_bw_input), 0);
-	icc_set_bw(vdec_vld2, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_avc_mv, MBps_to_icc(emi_bw_input * 2), 0);
-	icc_set_bw(vdec_rg_ctrl_dma, MBps_to_icc(0), 0);
-#endif
-}
-static void mtk_vdec_emi_bw_end(void)
-{
-#ifdef CONFIG_MEDIATEK_EMI_BW
-	icc_set_bw(vdec_ufo, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_ufo_enc, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_mc, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_pp, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_pred_rd, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_pred_wr, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_ppwrap, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_tile, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_vld, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_vld2, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_avc_mv, MBps_to_icc(0), 0);
-	icc_set_bw(vdec_rg_ctrl_dma, MBps_to_icc(0), 0);
-#endif
-}
-void mtk_vdec_pmqos_prelock(struct mtk_vcodec_ctx *ctx)
-{
-	mutex_lock(&ctx->dev->dec_dvfs_mutex);
-	#ifdef CONFIG_MEDIATEK_DVFS
-	add_job(&ctx->id, &vdec_jobs);
-	#endif
-	mutex_unlock(&ctx->dev->dec_dvfs_mutex);
-}
-void mtk_vdec_pmqos_begin_frame(struct mtk_vcodec_ctx *ctx)
-{
-	mtk_vdec_dvfs_begin(ctx);
-	mtk_vdec_emi_bw_begin(ctx);
-}
-
-void mtk_vdec_pmqos_end_frame(struct mtk_vcodec_ctx *ctx)
-{
-	mtk_vdec_dvfs_end(ctx);
-	mtk_vdec_emi_bw_end();
+	mtk_smi_larb_put(pm->larbvdec);
+	clk_disable_unprepare(pm->vdec_sel);
+	clk_disable_unprepare(pm->vdecpll);
+	clk_disable_unprepare(pm->univpll_d2);
+	clk_disable_unprepare(pm->clk_cci400_sel);
+	clk_disable_unprepare(pm->venc_lt_sel);
+	clk_disable_unprepare(pm->vdec_bus_clk_src);
+	clk_disable_unprepare(pm->vencpll);
+	clk_disable_unprepare(pm->vcodecpll);
 }
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
old mode 100644
new mode 100755
index 21cf9f9..86a7825
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
@@ -25,12 +25,4 @@
 void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm);
 void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm);
 
-void mtk_prepare_vdec_dvfs(struct mtk_vcodec_dev *dev);
-void mtk_unprepare_vdec_dvfs(void);
-int mtk_prepare_vdec_emi_bw(struct mtk_vcodec_dev *dev);
-void mtk_unprepare_vdec_emi_bw(void);
-
-void mtk_vdec_pmqos_prelock(struct mtk_vcodec_ctx *ctx);
-void mtk_vdec_pmqos_begin_frame(struct mtk_vcodec_ctx *ctx);
-void mtk_vdec_pmqos_end_frame(struct mtk_vcodec_ctx *ctx);
 #endif /* _MTK_VCODEC_DEC_PM_H_ */
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
old mode 100644
new mode 100755
index 97b4b82..3cffb38
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -1,17 +1,17 @@
 /*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- *         Tiffany Lin <tiffany.lin@mediatek.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
+* Copyright (c) 2016 MediaTek Inc.
+* Author: PC Chen <pc.chen@mediatek.com>
+*         Tiffany Lin <tiffany.lin@mediatek.com>
+*
+* 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.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
 
 #ifndef _MTK_VCODEC_DRV_H_
 #define _MTK_VCODEC_DRV_H_
@@ -23,20 +23,15 @@
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-core.h>
 #include "mtk_vcodec_util.h"
-#ifdef CONFIG_VB2_MEDIATEK_DMA
-#include "mtk-dma-contig.h"
-#endif
 
 #define MTK_VCODEC_DRV_NAME	"mtk_vcodec_drv"
 #define MTK_VCODEC_DEC_NAME	"mtk-vcodec-dec"
 #define MTK_VCODEC_ENC_NAME	"mtk-vcodec-enc"
 #define MTK_PLATFORM_STR	"platform:mt8173"
 
-#define MTK_SLOWMOTION_GCE_TH   120
 #define MTK_VCODEC_MAX_PLANES	3
 #define MTK_V4L2_BENCHMARK	0
 #define WAIT_INTR_TIMEOUT_MS	1000
-#define SUSPEND_TIMEOUT_CNT     5000
 
 /**
  * enum mtk_hw_reg_idx - MTK hw register base index
@@ -54,16 +49,14 @@
 	VDEC_HWQ,
 	VDEC_HWB,
 	VDEC_HWG,
-	NUM_MAX_VDEC_REG_BASE
-};
-
-enum mtk_enc_dtsi_reg_idx {
+	NUM_MAX_VDEC_REG_BASE,
+	/* h264 encoder */
+	VENC_SYS = NUM_MAX_VDEC_REG_BASE,
+	/* vp8 encoder */
 	VENC_LT_SYS,
-	VENC_SYS,
-	NUM_MAX_VENC_REG_BASE
+	NUM_MAX_VCODEC_REG_BASE
 };
 
-
 /**
  * enum mtk_instance_type - The type of an MTK Vcodec instance.
  */
@@ -99,34 +92,6 @@
 	MTK_ENCODE_PARAM_INTRA_PERIOD = (1 << 2),
 	MTK_ENCODE_PARAM_FORCE_INTRA = (1 << 3),
 	MTK_ENCODE_PARAM_GOP_SIZE = (1 << 4),
-	MTK_ENCODE_PARAM_SCENARIO = (1 << 5),
-	MTK_ENCODE_PARAM_NONREFP = (1 << 6),
-	MTK_ENCODE_PARAM_DETECTED_FRAMERATE = (1 << 7),
-	MTK_ENCODE_PARAM_RFS_ON = (1 << 8),
-	MTK_ENCODE_PARAM_PREPEND_SPSPPS_TO_IDR = (1 << 9),
-	MTK_ENCODE_PARAM_OPERATION_RATE = (1 << 10),
-	MTK_ENCODE_PARAM_BITRATE_MODE = (1 << 11),
-
-};
-/*
- * enum venc_yuv_fmt - The type of input yuv format
- * (VCU related: If you change the order, you must also update the VCU codes.)
- * @VENC_YUV_FORMAT_I420: I420 YUV format
- * @VENC_YUV_FORMAT_YV12: YV12 YUV format
- * @VENC_YUV_FORMAT_NV12: NV12 YUV format
- * @VENC_YUV_FORMAT_NV21: NV21 YUV format
- */
-enum venc_yuv_fmt {
-	VENC_YUV_FORMAT_I420 = 3,
-	VENC_YUV_FORMAT_YV12 = 5,
-	VENC_YUV_FORMAT_NV12 = 6,
-	VENC_YUV_FORMAT_NV21 = 7,
-	VENC_YUV_FORMAT_24bitRGB888 = 11,
-	VENC_YUV_FORMAT_24bitBGR888 = 12,
-	VENC_YUV_FORMAT_32bitRGBA8888 = 13,
-	VENC_YUV_FORMAT_32bitBGRA8888 = 14,
-	VENC_YUV_FORMAT_32bitARGB8888 = 15,
-	VENC_YUV_FORMAT_32bitABGR8888 = 16,
 };
 
 enum mtk_fmt_type {
@@ -145,6 +110,15 @@
 };
 
 /**
+ * struct mtk_codec_framesizes - Structure used to store information about
+ *							framesizes
+ */
+struct mtk_codec_framesizes {
+	u32	fourcc;
+	struct	v4l2_frmsize_stepwise	stepwise;
+};
+
+/**
  * struct mtk_q_type - Type of queue
  */
 enum mtk_q_type {
@@ -163,7 +137,7 @@
 	enum v4l2_field	field;
 	unsigned int	bytesperline[MTK_VCODEC_MAX_PLANES];
 	unsigned int	sizeimage[MTK_VCODEC_MAX_PLANES];
-	const struct mtk_video_fmt	*fmt;
+	struct mtk_video_fmt	*fmt;
 };
 
 /**
@@ -177,9 +151,9 @@
  * @intra_period: I frame period
  * @gop_size: group of picture size, it's used as the intra frame period
  * @framerate_num: frame rate numerator. ex: framerate_num=30 and
- *		   framerate_denom=1 means FPS is 30
+ *		   framerate_denom=1 menas FPS is 30
  * @framerate_denom: frame rate denominator. ex: framerate_num=30 and
- *		     framerate_denom=1 means FPS is 30
+ *		     framerate_denom=1 menas FPS is 30
  * @h264_max_qp: Max value for H.264 quantization parameter
  * @h264_profile: V4L2 defined H.264 profile
  * @h264_level: V4L2 defined H.264 level
@@ -196,92 +170,32 @@
 	unsigned int	framerate_num;
 	unsigned int	framerate_denom;
 	unsigned int	h264_max_qp;
-	unsigned int	profile;
-	unsigned int	level;
-	unsigned int    force_intra;
-	unsigned int    scenario;
-	unsigned int    nonrefp;
-	unsigned int    detectframerate;
-	unsigned int    rfs;
-	unsigned int    prependheader;
-	unsigned int    operationrate;
-	unsigned int    bitratemode;
-};
-/*
- * struct venc_enc_prm - encoder settings for VENC_SET_PARAM_ENC used in
- *                                        venc_if_set_param()
- * @input_fourcc: input yuv format
- * @h264_profile: V4L2 defined H.264 profile
- * @h264_level: V4L2 defined H.264 level
- * @width: image width
- * @height: image height
- * @buf_width: buffer width
- * @buf_height: buffer height
- * @frm_rate: frame rate in fps
- * @intra_period: intra frame period
- * @bitrate: target bitrate in bps
- * @gop_size: group of picture size
- * @sizeimage: image size for each plane
- */
-struct venc_enc_param {
-	enum venc_yuv_fmt input_yuv_fmt;
-	unsigned int profile;
-	unsigned int level;
-	unsigned int width;
-	unsigned int height;
-	unsigned int buf_width;
-	unsigned int buf_height;
-	unsigned int frm_rate;
-	unsigned int intra_period;
-	unsigned int bitrate;
-	unsigned int gop_size;
-	unsigned int scenario;
-	unsigned int nonrefp;
-	unsigned int detectframerate;
-	unsigned int rfs;
-	unsigned int prependheader;
-	unsigned int operationrate;
-	unsigned int bitratemode;
-	unsigned int sizeimage[MTK_VCODEC_MAX_PLANES];
-};
-/*
- * struct venc_frm_buf - frame buffer information used in venc_if_encode()
- * @fb_addr: plane frame buffer addresses
- * @num_planes: frmae buffer plane num
- */
-struct venc_frm_buf {
-	struct mtk_vcodec_mem fb_addr[MTK_VCODEC_MAX_PLANES];
-	unsigned int num_planes;
-	unsigned long timestamp;
-};
-
-/**
- * struct mtk_vcodec_clk_info - Structure used to store clock name
- */
-struct mtk_vcodec_clk_info {
-	const char	*clk_name;
-	struct clk	*vcodec_clk;
-};
-
-/**
- * struct mtk_vcodec_clk - Structure used to store vcodec clock information
- */
-struct mtk_vcodec_clk {
-	struct mtk_vcodec_clk_info	*clk_info;
-	int	clk_num;
+	unsigned int	h264_profile;
+	unsigned int	h264_level;
+	unsigned int	force_intra;
 };
 
 /**
  * struct mtk_vcodec_pm - Power management data structure
  */
 struct mtk_vcodec_pm {
-	struct mtk_vcodec_clk	vdec_clk;
+	struct clk	*vdec_bus_clk_src;
+	struct clk	*vencpll;
 
-	struct mtk_vcodec_clk	venc_clk;
+	struct clk	*vcodecpll;
+	struct clk	*univpll_d2;
+	struct clk	*clk_cci400_sel;
+	struct clk	*vdecpll;
+	struct clk	*vdec_sel;
+	struct clk	*vencpll_d2;
+	struct clk	*venc_sel;
+	struct clk	*univpll1_d2;
+	struct clk	*venc_lt_sel;
+	struct device	*larbvdec;
+	struct device	*larbvenc;
+	struct device	*larbvenclt;
 	struct device	*dev;
 	struct mtk_vcodec_dev	*mtkdev;
-	int enc_larb_num;
-	struct device_node *chip_node;
 };
 
 /**
@@ -290,72 +204,24 @@
  * @pic_h: picture height
  * @buf_w: picture buffer width (64 aligned up from pic_w)
  * @buf_h: picture buffer heiht (64 aligned up from pic_h)
- * @fb_sz: bitstream size
+ * @y_bs_sz: Y bitstream size
+ * @c_bs_sz: CbCr bitstream size
+ * @y_len_sz: additional size required to store decompress information for y
+ *		plane
+ * @c_len_sz: additional size required to store decompress information for cbcr
+ *		plane
  * E.g. suppose picture size is 176x144,
  *      buffer size will be aligned to 176x160.
- * @cap_fourcc: fourcc number(may changed when resolution change)
- * @reserved: align struct to 64-bit in order to adjust 32-bit and 64-bit os.
  */
 struct vdec_pic_info {
-/** from yunfei upstream
 	unsigned int pic_w;
 	unsigned int pic_h;
 	unsigned int buf_w;
 	unsigned int buf_h;
-	unsigned int fb_sz[VIDEO_MAX_PLANES];
-	unsigned int cap_fourcc;
-	unsigned int reserved;
-*/
-	__u32 pic_w;
-	__u32 pic_h;
-	__u32 buf_w;
-	__u32 buf_h;
-	__u32 fb_sz[VIDEO_MAX_PLANES];
-	__u32 bitdepth;
-	__u32 layout_mode;
-	unsigned int cap_fourcc;
-};
-
-enum mtk_dec_param {
-	MTK_DEC_PARAM_NONE = 0,
-	MTK_DEC_PARAM_DECODE_MODE = (1 << 0),
-	MTK_DEC_PARAM_FRAME_SIZE = (1 << 1),
-	MTK_DEC_PARAM_FIXED_MAX_FRAME_SIZE = (1 << 2),
-	MTK_DEC_PARAM_CRC_PATH = (1 << 3),
-	MTK_DEC_PARAM_GOLDEN_PATH = (1 << 4),
-	MTK_DEC_PARAM_WAIT_KEY_FRAME = (1 << 5),
-	MTK_DEC_PARAM_NAL_SIZE_LENGTH = (1 << 6),
-	MTK_DEC_PARAM_FIXED_MAX_OUTPUT_BUFFER = (1 << 7),
-	MTK_DEC_PARAM_SEC_DECODE = (1 << 8),
-	MTK_DEC_PARAM_OPERATING_RATE = (1 << 9),
-	MTK_DEC_PARAM_TOTAL_FRAME_BUFQ_COUNT = (1 << 10)
-};
-
-struct mtk_dec_params {
-	unsigned int    decode_mode;
-	unsigned int    frame_size_width;
-	unsigned int    frame_size_height;
-	unsigned int    fixed_max_frame_size_width;
-	unsigned int    fixed_max_frame_size_height;
-	char            *crc_path;
-	char            *golden_path;
-	unsigned int    fb_num_planes;
-	unsigned int	wait_key_frame;
-	unsigned int	nal_size_length;
-	unsigned int	svp_mode;
-	unsigned int	operating_rate;
-	unsigned int	total_frame_bufq_count;
-};
-
-/**
- * struct mtk_codec_framesizes - Structure used to store information about
- *							framesizes
- */
-struct mtk_codec_framesizes {
-	__u32	fourcc;
-	__u32	profile;
-	__u32	level;
-	struct	v4l2_frmsize_stepwise	stepwise;
+	unsigned int y_bs_sz;
+	unsigned int c_bs_sz;
+	unsigned int y_len_sz;
+	unsigned int c_len_sz;
 };
 
 /**
@@ -389,9 +255,6 @@
  * @encode_work: worker for the encoding
  * @last_decoded_picinfo: pic information get from latest decode
  * @empty_flush_buf: a fake size-0 capture buffer that indicates flush
- * @ctrls: CID controls
- * @codec_type: current set input codec, in V4L2 pixel format
- * @cap_count_sem: count of available capture buffers
  *
  * @colorspace: enum v4l2_colorspace; supplemental to pixelformat
  * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
@@ -412,18 +275,13 @@
 	enum mtk_instance_state state;
 	enum mtk_encode_param param_change;
 	struct mtk_enc_params enc_params;
-	enum mtk_dec_param dec_param_change;
-	struct mtk_dec_params dec_params;
 
 	const struct vdec_common_if *dec_if;
 	const struct venc_common_if *enc_if;
-	void *drv_handle;
+	unsigned long drv_handle;
 
 	struct vdec_pic_info picinfo;
 	int dpb_size;
-	int last_dpb_size;
-	unsigned int errormap_info[VB2_MAX_FRAME];
-	u64 input_max_ts;
 
 	int int_cond;
 	int int_type;
@@ -435,13 +293,6 @@
 	struct work_struct encode_work;
 	struct vdec_pic_info last_decoded_picinfo;
 	struct mtk_video_dec_buf *empty_flush_buf;
-	struct mtk_video_enc_buf *enc_flush_buf;
-	struct v4l2_ctrl **ctrls;
-	struct vb2_buffer *pend_src_buf;
-	int slowmotion;
-	int oal_vcodec;
-
-	int current_codec;
 
 	enum v4l2_colorspace colorspace;
 	enum v4l2_ycbcr_encoding ycbcr_enc;
@@ -450,78 +301,25 @@
 
 	int decoded_frame_cnt;
 	struct mutex lock;
-	struct mutex worker_lock;
 
 };
 
 /**
- * struct mtk_vcodec_dec_pdata - compatible data for each IC
- * @init_vdec_params: init vdec params
- * @ctrls_setup: init vcodec dec ctrls
- * @worker: worker to start a decode job
- * @flush_decoder: function that flushes the decoder
- *
- * @vdec_vb2_ops: struct vb2_ops
- *
- * @vdec_formats: supported video decoder formats
- * @num_formats: count of video decoder formats
- * @default_out_fmt: default output buffer format
- * @default_cap_fmt: default capture buffer format
- *
- * @vdec_framesizes: supported video decoder frame sizes
- * @num_framesizes: count of video decoder frame sizes
- *
- * @uses_stateless_api: whether the decoder uses the stateless API with requests
- */
-
-struct mtk_vcodec_dec_pdata {
-	void (*init_vdec_params)(struct mtk_vcodec_ctx *ctx);
-	int (*ctrls_setup)(struct mtk_vcodec_ctx *ctx);
-	void (*worker)(struct work_struct *work);
-	int (*flush_decoder)(struct mtk_vcodec_ctx *ctx);
-
-	struct vb2_ops *vdec_vb2_ops;
-
-	const struct mtk_video_fmt *vdec_formats;
-	const int num_formats;
-	const struct mtk_video_fmt *default_out_fmt;
-	const struct mtk_video_fmt *default_cap_fmt;
-
-	const struct mtk_codec_framesizes *vdec_framesizes;
-	const int num_framesizes;
-
-	bool uses_stateless_api;
-};
-
-/**
- * struct mtk_vcodec_enc_pdata - compatibler data for each IC
- *
- * @uses_ext: whether the encoder uses the extended firmware messaging format
- * @supports_vp8: whether the encoder supports VP8
- */
-struct mtk_vcodec_enc_pdata {
-	bool uses_ext;
-	bool supports_vp8;
-};
-
-/**
  * struct mtk_vcodec_dev - driver data
  * @v4l2_dev: V4L2 device to register video devices for.
  * @vfd_dec: Video device for decoder
- * @mdev_dec: Media device for decoder
  * @vfd_enc: Video device for encoder.
  *
  * @m2m_dev_dec: m2m device for decoder
  * @m2m_dev_enc: m2m device for encoder.
  * @plat_dev: platform device
+ * @vpu_plat_dev: mtk vpu platform device
  * @ctx_list: list of struct mtk_vcodec_ctx
  * @irqlock: protect data access by irq handler and work thread
  * @curr_ctx: The context that is waiting for codec hardware
  *
  * @reg_base: Mapped address of MTK Vcodec registers.
- * @vdec_pdata: Current arch private data.
  *
- * @ipi_msg_handle: Current arch ipi message handle.
  * @id_counter: used to identify current opened instance
  *
  * @encode_workqueue: encode work queue
@@ -545,22 +343,16 @@
 struct mtk_vcodec_dev {
 	struct v4l2_device v4l2_dev;
 	struct video_device *vfd_dec;
-	struct media_device mdev_dec;
 	struct video_device *vfd_enc;
 
 	struct v4l2_m2m_dev *m2m_dev_dec;
 	struct v4l2_m2m_dev *m2m_dev_enc;
 	struct platform_device *plat_dev;
-	struct platform_device *vcu_plat_dev;
+	struct platform_device *vpu_plat_dev;
 	struct list_head ctx_list;
 	spinlock_t irqlock;
 	struct mtk_vcodec_ctx *curr_ctx;
-	void __iomem *reg_base[NUM_MAX_VDEC_REG_BASE];
-	void __iomem *enc_reg_base[NUM_MAX_VENC_REG_BASE];
-	const struct mtk_vcodec_dec_pdata *vdec_pdata;
-	const struct mtk_vcodec_enc_pdata *venc_pdata;
-
-	struct mtk_vcodec_fw *ipi_msg_handle;
+	void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE];
 
 	unsigned long id_counter;
 
@@ -577,14 +369,10 @@
 
 	struct mutex dec_mutex;
 	struct mutex enc_mutex;
-	struct mutex dec_dvfs_mutex;
-	struct semaphore enc_sem;
-	struct mutex enc_dvfs_mutex;
 
 	struct mtk_vcodec_pm pm;
 	unsigned int dec_capability;
 	unsigned int enc_capability;
-	bool is_codec_suspending;
 };
 
 static inline struct mtk_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh)
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
old mode 100644
new mode 100755
index d76548d..6ad4085
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -1,25 +1,22 @@
 /*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- *         Tiffany Lin <tiffany.lin@mediatek.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
+* Copyright (c) 2016 MediaTek Inc.
+* Author: PC Chen <pc.chen@mediatek.com>
+*         Tiffany Lin <tiffany.lin@mediatek.com>
+*
+* 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.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
 
 #include <media/v4l2-event.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-dma-contig.h>
 #include <soc/mediatek/smi.h>
-#include <linux/delay.h>
-#include <linux/semaphore.h>
-#include <linux/log2.h>
 
 #include "mtk_vcodec_drv.h"
 #include "mtk_vcodec_enc.h"
@@ -39,175 +36,56 @@
 
 
 static void mtk_venc_worker(struct work_struct *work);
-static struct mtk_video_fmt
-	mtk_video_formats[MTK_MAX_ENC_CODECS_SUPPORT] = { {0} };
-static struct mtk_codec_framesizes
-	mtk_venc_framesizes[MTK_MAX_ENC_CODECS_SUPPORT] = { {0} };
-static unsigned int default_out_fmt_idx;
-static unsigned int default_cap_fmt_idx;
 
-static void get_supported_format(struct mtk_vcodec_ctx *ctx)
-{
-	unsigned int i;
+static struct mtk_video_fmt mtk_video_formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_NV12M,
+		.type = MTK_FMT_FRAME,
+		.num_planes = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV21M,
+		.type = MTK_FMT_FRAME,
+		.num_planes = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV420M,
+		.type = MTK_FMT_FRAME,
+		.num_planes = 3,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YVU420M,
+		.type = MTK_FMT_FRAME,
+		.num_planes = 3,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_H264,
+		.type = MTK_FMT_ENC,
+		.num_planes = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_VP8,
+		.type = MTK_FMT_ENC,
+		.num_planes = 1,
+	},
+};
 
-	if (mtk_video_formats[0].fourcc == 0) {
-		if (venc_if_get_param(ctx,
-			GET_PARAM_CAPABILITY_SUPPORTED_FORMATS,
-			&mtk_video_formats) != 0) {
-			mtk_v4l2_err("Error!! Cannot get supported format");
-			return;
-		}
-		for (i = 0; i < MTK_MAX_ENC_CODECS_SUPPORT; i++) {
-			if (mtk_video_formats[i].fourcc != 0 &&
-			    mtk_video_formats[i].type == MTK_FMT_FRAME) {
-				default_out_fmt_idx = i;
-				break;
-			}
-		}
-		for (i = 0; i < MTK_MAX_ENC_CODECS_SUPPORT; i++) {
-			if (mtk_video_formats[i].fourcc != 0 &&
-			    mtk_video_formats[i].type == MTK_FMT_ENC) {
-				default_cap_fmt_idx = i;
-				break;
-			}
-		}
-	}
-}
-static void get_supported_framesizes(struct mtk_vcodec_ctx *ctx)
-{
-	unsigned int i;
+#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats)
 
-	if (mtk_venc_framesizes[0].fourcc == 0) {
-		if (venc_if_get_param(ctx, GET_PARAM_CAPABILITY_FRAME_SIZES,
-				      &mtk_venc_framesizes) != 0) {
-			mtk_v4l2_err("[%d] Error!! Cannot get frame size",
-				ctx->id);
-			return;
-		}
+static const struct mtk_codec_framesizes mtk_venc_framesizes[] = {
+	{
+		.fourcc	= V4L2_PIX_FMT_H264,
+		.stepwise = { MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16,
+			      MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16 },
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_VP8,
+		.stepwise = { MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16,
+			      MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16 },
+	},
+};
 
-		for (i = 0; i < MTK_MAX_ENC_CODECS_SUPPORT; i++) {
-			if (mtk_venc_framesizes[i].fourcc != 0)
-				mtk_v4l2_debug(1, "venc_fs[%d] %d s %d %d %d %d %d %d\n",
-				i, mtk_venc_framesizes[i].fourcc,
-				mtk_venc_framesizes[i].stepwise.min_width,
-				mtk_venc_framesizes[i].stepwise.max_width,
-				mtk_venc_framesizes[i].stepwise.step_width,
-				mtk_venc_framesizes[i].stepwise.min_height,
-				mtk_venc_framesizes[i].stepwise.max_height,
-				mtk_venc_framesizes[i].stepwise.step_height);
-		}
-	}
-}
-static void get_free_buffers(struct mtk_vcodec_ctx *ctx,
-				struct venc_done_result *pResult)
-{
-	venc_if_get_param(ctx, GET_PARAM_FREE_BUFFERS, pResult);
-}
-static void return_free_buffers(struct mtk_vcodec_ctx *ctx)
-{
-	struct venc_done_result rResult;
-	struct venc_frm_buf *pfrm;
-	struct mtk_vcodec_mem *pbs;
-	struct mtk_video_enc_buf *bs_info, *frm_info;
-	struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2;
-	struct vb2_buffer *dst_buf;
-
-	do {
-		dst_vb2_v4l2 = NULL;
-		src_vb2_v4l2 = NULL;
-		pfrm = NULL;
-		pbs = NULL;
-
-		get_free_buffers(ctx, &rResult);
-
-		if (rResult.bs_va != 0) {
-			pbs = (struct mtk_vcodec_mem *)rResult.bs_va;
-			bs_info = container_of(pbs,
-				struct mtk_video_enc_buf, bs_buf);
-			dst_vb2_v4l2 = &bs_info->vb;
-		}
-
-		if (rResult.frm_va != 0) {
-			pfrm = (struct venc_frm_buf *)rResult.frm_va;
-			frm_info = container_of(pfrm,
-				struct mtk_video_enc_buf, frm_buf);
-			src_vb2_v4l2 = &frm_info->vb;
-		}
-
-		if (src_vb2_v4l2 && dst_vb2_v4l2) {
-			if (rResult.is_key_frm)
-				dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_KEYFRAME;
-
-			dst_vb2_v4l2->vb2_buf.timestamp =
-				src_vb2_v4l2->vb2_buf.timestamp;
-			dst_vb2_v4l2->timecode = src_vb2_v4l2->timecode;
-			dst_vb2_v4l2->flags |= src_vb2_v4l2->flags;
-			dst_vb2_v4l2->sequence = src_vb2_v4l2->sequence;
-			dst_buf = &dst_vb2_v4l2->vb2_buf;
-			dst_buf->planes[0].bytesused = rResult.bs_size;
-			v4l2_m2m_buf_done(src_vb2_v4l2, VB2_BUF_STATE_DONE);
-			v4l2_m2m_buf_done(dst_vb2_v4l2, VB2_BUF_STATE_DONE);
-
-			mtk_v4l2_debug(1, "venc_if_encode bs size=%d",
-				rResult.bs_size);
-		} else if (!src_vb2_v4l2 && dst_vb2_v4l2) {
-			dst_buf = &dst_vb2_v4l2->vb2_buf;
-			dst_buf->planes[0].bytesused = rResult.bs_size;
-			dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_LAST;
-			v4l2_m2m_buf_done(dst_vb2_v4l2,
-					VB2_BUF_STATE_DONE);
-		} else if (!src_vb2_v4l2 || !dst_vb2_v4l2) {
-			if (!src_vb2_v4l2)
-				mtk_v4l2_debug(1, "NULL enc src buffer\n");
-
-			if (!dst_vb2_v4l2)
-				mtk_v4l2_debug(1, "NULL enc dst buffer\n");
-		}
-	} while (rResult.bs_va || rResult.frm_va);
-}
-
-
-static struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f,
-						  unsigned int t)
-{
-	struct mtk_video_fmt *fmt;
-	unsigned int k;
-
-	mtk_v4l2_debug(3, "fourcc %d", f->fmt.pix_mp.pixelformat);
-	for (k = 0; k < MTK_MAX_ENC_CODECS_SUPPORT; k++) {
-		fmt = &mtk_video_formats[k];
-		if (fmt->fourcc == f->fmt.pix.pixelformat && fmt->type == t)
-			return fmt;
-	}
-	return NULL;
-}
-
-static int vidioc_venc_check_supported_profile_level(__u32 fourcc,
-	unsigned int pl, bool is_profile)
-{
-	struct v4l2_format f;
-	int i = 0;
-
-	f.fmt.pix.pixelformat = fourcc;
-	if (mtk_venc_find_format(&f, MTK_FMT_ENC) == NULL)
-		return false;
-	for (i = 0; i < MTK_MAX_ENC_CODECS_SUPPORT; i++) {
-		if (mtk_venc_framesizes[i].fourcc == fourcc) {
-			if (is_profile) {
-				if (mtk_venc_framesizes[i].profile & (1 << pl))
-					return true;
-				else
-					return false;
-			} else {
-				if (mtk_venc_framesizes[i].level >= pl)
-					return true;
-				else
-					return false;
-			}
-		}
-	}
-	return false;
-}
+#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_venc_framesizes)
 
 static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl)
 {
@@ -215,10 +93,6 @@
 	struct mtk_enc_params *p = &ctx->enc_params;
 	int ret = 0;
 
-	mtk_v4l2_debug(4, "[%d] id %d val %d array[0] %d array[1] %d",
-				   ctx->id, ctrl->id, ctrl->val,
-				   ctrl->p_new.p_u32[0], ctrl->p_new.p_u32[1]);
-
 	switch (ctrl->id) {
 	case V4L2_CID_MPEG_VIDEO_BITRATE:
 		mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE val = %d",
@@ -254,54 +128,12 @@
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
 		mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_PROFILE val = %d",
 			       ctrl->val);
-		if (!vidioc_venc_check_supported_profile_level(
-				V4L2_PIX_FMT_H264, ctrl->val, 1)) {
-			mtk_v4l2_err("ERROR H264_PROFILE check Error! val:%d",
-				ctrl->val);
-		}
-		p->profile = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
-		mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H265_PROFILE val = %d",
-			       ctrl->val);
-		if (!vidioc_venc_check_supported_profile_level(
-				V4L2_PIX_FMT_H265, ctrl->val, 1))
-			return -EINVAL;
-		p->profile = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
-		mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE val = %d",
-			       ctrl->val);
-		if (!vidioc_venc_check_supported_profile_level(
-			    V4L2_PIX_FMT_MPEG4, ctrl->val, 1))
-			return -EINVAL;
-		p->profile = ctrl->val;
+		p->h264_profile = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
 		mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_LEVEL val = %d",
 			       ctrl->val);
-		if (!vidioc_venc_check_supported_profile_level(
-				V4L2_PIX_FMT_H264, ctrl->val, 0)) {
-			mtk_v4l2_err("ERROR H264_LEVEL check Error! val:%d",
-				ctrl->val);
-		}
-		p->level = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_H265_TIER_LEVEL:
-		mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H265_TIER_LEVEL val = %d",
-			       ctrl->val);
-		if (!vidioc_venc_check_supported_profile_level(
-				V4L2_PIX_FMT_H265, ctrl->val, 0))
-			return -EINVAL;
-		p->level = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
-		mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL val = %d",
-			       ctrl->val);
-		if (!vidioc_venc_check_supported_profile_level(
-			    V4L2_PIX_FMT_MPEG4, ctrl->val, 0))
-			return -EINVAL;
-		p->level = ctrl->val;
+		p->h264_level = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
 		mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_I_PERIOD val = %d",
@@ -320,57 +152,8 @@
 		p->force_intra = 1;
 		ctx->param_change |= MTK_ENCODE_PARAM_FORCE_INTRA;
 		break;
-	case V4L2_CID_MPEG_MTK_ENCODE_SCENARIO:
-		mtk_v4l2_debug(2,
-			"V4L2_CID_MPEG_MTK_ENCODE_SCENARIO: %d",
-			ctrl->val);
-		p->scenario = ctrl->val;
-		ctx->param_change |= MTK_ENCODE_PARAM_SCENARIO;
-		break;
-	case V4L2_CID_MPEG_MTK_ENCODE_NONREFP:
-		mtk_v4l2_debug(2,
-			"V4L2_CID_MPEG_MTK_ENCODE_NONREFP: %d",
-			ctrl->val);
-		p->nonrefp = ctrl->val;
-		ctx->param_change |= MTK_ENCODE_PARAM_NONREFP;
-		break;
-	case V4L2_CID_MPEG_MTK_ENCODE_DETECTED_FRAMERATE:
-		mtk_v4l2_debug(2,
-			"V4L2_CID_MPEG_MTK_ENCODE_DETECTED_FRAMERATE: %d",
-			ctrl->val);
-		p->detectframerate = ctrl->val;
-		ctx->param_change |= MTK_ENCODE_PARAM_DETECTED_FRAMERATE;
-		break;
-	case V4L2_CID_MPEG_MTK_ENCODE_RFS_ON:
-		mtk_v4l2_debug(2,
-			"V4L2_CID_MPEG_MTK_ENCODE_RFS_ON: %d",
-			ctrl->val);
-		p->rfs = ctrl->val;
-		ctx->param_change |= MTK_ENCODE_PARAM_RFS_ON;
-		break;
-	case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
-		mtk_v4l2_debug(2,
-			"V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: %d",
-			ctrl->val);
-		p->prependheader = ctrl->val;
-		ctx->param_change |= MTK_ENCODE_PARAM_PREPEND_SPSPPS_TO_IDR;
-		break;
-	case V4L2_CID_MPEG_MTK_ENCODE_OPERATION_RATE:
-		mtk_v4l2_debug(2,
-			"V4L2_CID_MPEG_MTK_ENCODE_OPERATION_RATE: %d",
-			ctrl->val);
-		p->operationrate = ctrl->val;
-		ctx->param_change |= MTK_ENCODE_PARAM_OPERATION_RATE;
-		break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-		mtk_v4l2_debug(2,
-			"V4L2_CID_MPEG_VIDEO_BITRATE_MODE: %d",
-			ctrl->val);
-		p->bitratemode = ctrl->val;
-		ctx->param_change |= MTK_ENCODE_PARAM_BITRATE_MODE;
-		break;
 	default:
-		mtk_v4l2_err("ctrl-id=%d not support!", ctrl->id);
+		ret = -EINVAL;
 		break;
 	}
 
@@ -383,11 +166,10 @@
 
 static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue)
 {
-	const struct mtk_video_fmt *fmt;
+	struct mtk_video_fmt *fmt;
 	int i, j = 0;
 
-	for (i = 0; i < MTK_MAX_ENC_CODECS_SUPPORT &&
-	     mtk_video_formats[i].fourcc != 0; ++i) {
+	for (i = 0; i < NUM_FORMATS; ++i) {
 		if (output_queue && mtk_video_formats[i].type != MTK_FMT_FRAME)
 			continue;
 		if (!output_queue && mtk_video_formats[i].type != MTK_FMT_ENC)
@@ -409,22 +191,16 @@
 				  struct v4l2_frmsizeenum *fsize)
 {
 	int i = 0;
-	struct mtk_vcodec_ctx *ctx = fh_to_ctx(fh);
 
 	if (fsize->index != 0)
 		return -EINVAL;
 
-	get_supported_framesizes(ctx);
-
-	for (i = 0; i < MTK_MAX_ENC_CODECS_SUPPORT &&
-	     mtk_venc_framesizes[i].fourcc != 0; ++i) {
+	for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) {
 		if (fsize->pixel_format != mtk_venc_framesizes[i].fourcc)
 			continue;
 
 		fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
 		fsize->stepwise = mtk_venc_framesizes[i].stepwise;
-		fsize->reserved[0] = mtk_venc_framesizes[i].profile;
-		fsize->reserved[1] = mtk_venc_framesizes[i].level;
 		return 0;
 	}
 
@@ -446,11 +222,9 @@
 static int vidioc_venc_querycap(struct file *file, void *priv,
 				struct v4l2_capability *cap)
 {
-	strscpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver));
-	strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
-	strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
-	cap->device_caps  = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
-	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	strlcpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver));
+	strlcpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
+	strlcpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
 
 	return 0;
 }
@@ -462,6 +236,7 @@
 
 	if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 		return -EINVAL;
+
 	ctx->enc_params.framerate_num =
 			a->parm.output.timeperframe.denominator;
 	ctx->enc_params.framerate_denom =
@@ -480,6 +255,7 @@
 
 	if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 		return -EINVAL;
+
 	a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
 	a->parm.output.timeperframe.denominator =
 			ctx->enc_params.framerate_num;
@@ -498,17 +274,27 @@
 	return &ctx->q_data[MTK_Q_DATA_DST];
 }
 
+static struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f)
+{
+	struct mtk_video_fmt *fmt;
+	unsigned int k;
+
+	for (k = 0; k < NUM_FORMATS; k++) {
+		fmt = &mtk_video_formats[k];
+		if (fmt->fourcc == f->fmt.pix.pixelformat)
+			return fmt;
+	}
+
+	return NULL;
+}
+
 /* V4L2 specification suggests the driver corrects the format struct if any of
  * the dimensions is unsupported
  */
-static int vidioc_try_fmt(struct v4l2_format *f,
-			const struct mtk_video_fmt *fmt,
-			struct mtk_vcodec_ctx *ctx)
+static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt)
 {
 	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-	int org_w, org_h, i;
-	__u32 bs_fourcc;
-	struct mtk_codec_framesizes *spec_size_info = NULL;
+	int i;
 
 	pix_fmt_mp->field = V4L2_FIELD_NONE;
 
@@ -516,160 +302,73 @@
 		pix_fmt_mp->num_planes = 1;
 		pix_fmt_mp->plane_fmt[0].bytesperline = 0;
 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-		get_supported_framesizes(ctx);
-		if (ctx->q_data[MTK_Q_DATA_DST].fmt != NULL) {
-			bs_fourcc =
-				ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc;
-		} else {
-			bs_fourcc =
-				mtk_video_formats[default_cap_fmt_idx].fourcc;
-		}
-		for (i = 0; i < MTK_MAX_ENC_CODECS_SUPPORT; i++) {
-			if (mtk_venc_framesizes[i].fourcc == bs_fourcc)
-				spec_size_info = &mtk_venc_framesizes[i];
-		}
-		if (!spec_size_info) {
-			mtk_v4l2_err("fail to get spec_size_info");
-			return -EINVAL;
-		}
+		int tmp_w, tmp_h;
 
-		mtk_v4l2_debug(1,
-			       "pix_fmt_mp->pixelformat %d bs fmt %d min_w %d min_h %d max_w %d max_h %d\n",
-			       pix_fmt_mp->pixelformat, bs_fourcc,
-			       spec_size_info->stepwise.min_width,
-			       spec_size_info->stepwise.min_height,
-			       spec_size_info->stepwise.max_width,
-			       spec_size_info->stepwise.max_height);
+		pix_fmt_mp->height = clamp(pix_fmt_mp->height,
+					MTK_VENC_MIN_H,
+					MTK_VENC_MAX_H);
+		pix_fmt_mp->width = clamp(pix_fmt_mp->width,
+					MTK_VENC_MIN_W,
+					MTK_VENC_MAX_W);
 
-		if ((spec_size_info->stepwise.step_width &
-		     (spec_size_info->stepwise.step_width - 1)) != 0)
-			mtk_v4l2_err("Unsupport stepwise.step_width not 2^ %d\n",
-				     spec_size_info->stepwise.step_width);
-		if ((spec_size_info->stepwise.step_height &
-		     (spec_size_info->stepwise.step_height - 1)) != 0)
-			mtk_v4l2_err("Unsupport stepwise.step_height not 2^ %d\n",
-				     spec_size_info->stepwise.step_height);
-
-
-		/* find next closer width align 16, height align 16, size align
-		 * 64 rectangle without MBAFF encoder
-		 * (with MBAFF height align should be 32)
-		 * width height swappable
+		/* find next closer width align 16, heign align 32, size align
+		 * 64 rectangle
 		 */
-		if (pix_fmt_mp->height > pix_fmt_mp->width) {
-			pix_fmt_mp->height = clamp(pix_fmt_mp->height,
-				(spec_size_info->stepwise.min_height),
-				(spec_size_info->stepwise.max_width));
-			pix_fmt_mp->width = clamp(pix_fmt_mp->width,
-				(spec_size_info->stepwise.min_width),
-				(spec_size_info->stepwise.max_height));
-			org_w = pix_fmt_mp->width;
-			org_h = pix_fmt_mp->height;
-			v4l_bound_align_image(&pix_fmt_mp->width,
-				spec_size_info->stepwise.min_width,
-				spec_size_info->stepwise.max_height,
-				ilog2(spec_size_info->stepwise.step_width),
-				&pix_fmt_mp->height,
-				spec_size_info->stepwise.min_height,
-				spec_size_info->stepwise.max_width,
-				ilog2(spec_size_info->stepwise.step_height),
-				6);
+		tmp_w = pix_fmt_mp->width;
+		tmp_h = pix_fmt_mp->height;
+		v4l_bound_align_image(&pix_fmt_mp->width,
+					MTK_VENC_MIN_W,
+					MTK_VENC_MAX_W, 4,
+					&pix_fmt_mp->height,
+					MTK_VENC_MIN_H,
+					MTK_VENC_MAX_H, 5, 6);
 
-			if (pix_fmt_mp->width < org_w &&
-			    (pix_fmt_mp->width +
-			     spec_size_info->stepwise.step_width) <=
-			    spec_size_info->stepwise.max_height)
-				pix_fmt_mp->width +=
-					spec_size_info->stepwise.step_width;
-			if (pix_fmt_mp->height < org_h &&
-			    (pix_fmt_mp->height +
-			     spec_size_info->stepwise.step_height) <=
-			    spec_size_info->stepwise.max_width)
-				pix_fmt_mp->height +=
-					spec_size_info->stepwise.step_height;
-		} else {
-			pix_fmt_mp->height = clamp(pix_fmt_mp->height,
-				(spec_size_info->stepwise.min_height),
-				(spec_size_info->stepwise.max_height));
-			pix_fmt_mp->width = clamp(pix_fmt_mp->width,
-				(spec_size_info->stepwise.min_width),
-				(spec_size_info->stepwise.max_width));
-			org_w = pix_fmt_mp->width;
-			org_h = pix_fmt_mp->height;
-			v4l_bound_align_image(&pix_fmt_mp->width,
-				spec_size_info->stepwise.min_width,
-				spec_size_info->stepwise.max_width,
-				ilog2(spec_size_info->stepwise.step_width),
-				&pix_fmt_mp->height,
-				spec_size_info->stepwise.min_height,
-				spec_size_info->stepwise.max_height,
-				ilog2(spec_size_info->stepwise.step_height),
-				6);
-
-			if (pix_fmt_mp->width < org_w &&
-			    (pix_fmt_mp->width +
-			     spec_size_info->stepwise.step_width) <=
-			    spec_size_info->stepwise.max_width)
-				pix_fmt_mp->width +=
-					spec_size_info->stepwise.step_width;
-			if (pix_fmt_mp->height < org_h &&
-			    (pix_fmt_mp->height +
-			     spec_size_info->stepwise.step_height) <=
-			    spec_size_info->stepwise.max_height)
-				pix_fmt_mp->height +=
-					spec_size_info->stepwise.step_height;
-		}
-
-		pix_fmt_mp->num_planes = fmt->num_planes;
-
-		if (pix_fmt_mp->num_planes == 1U) {
-			pix_fmt_mp->plane_fmt[0].sizeimage =
-				(pix_fmt_mp->width * pix_fmt_mp->height) +
-				(pix_fmt_mp->width * pix_fmt_mp->height) / 2;
-			pix_fmt_mp->plane_fmt[0].bytesperline =
-				pix_fmt_mp->width;
-		} else if (pix_fmt_mp->num_planes == 2U) {
-			pix_fmt_mp->plane_fmt[0].sizeimage =
-				pix_fmt_mp->width * pix_fmt_mp->height;
-			pix_fmt_mp->plane_fmt[0].bytesperline =
-				pix_fmt_mp->width;
-			pix_fmt_mp->plane_fmt[1].sizeimage =
-				(pix_fmt_mp->width * pix_fmt_mp->height) / 2;
-			pix_fmt_mp->plane_fmt[1].bytesperline =
-				pix_fmt_mp->width;
-		} else if (pix_fmt_mp->num_planes == 3U) {
-			pix_fmt_mp->plane_fmt[0].sizeimage =
-				pix_fmt_mp->width * pix_fmt_mp->height;
-			pix_fmt_mp->plane_fmt[0].bytesperline =
-				pix_fmt_mp->width;
-			pix_fmt_mp->plane_fmt[1].sizeimage =
-				(pix_fmt_mp->width * pix_fmt_mp->height) / 4;
-			pix_fmt_mp->plane_fmt[1].bytesperline =
-				pix_fmt_mp->width / 2;
-			pix_fmt_mp->plane_fmt[2].sizeimage =
-				(pix_fmt_mp->width * pix_fmt_mp->height) / 4;
-			pix_fmt_mp->plane_fmt[2].bytesperline =
-				pix_fmt_mp->width / 2;
-		} else
-			mtk_v4l2_err("Unsupport num planes = %d\n",
-				     pix_fmt_mp->num_planes);
+		if (pix_fmt_mp->width < tmp_w &&
+			(pix_fmt_mp->width + 16) <= MTK_VENC_MAX_W)
+			pix_fmt_mp->width += 16;
+		if (pix_fmt_mp->height < tmp_h &&
+			(pix_fmt_mp->height + 32) <= MTK_VENC_MAX_H)
+			pix_fmt_mp->height += 32;
 
 		mtk_v4l2_debug(0,
-			       "w/h (%d, %d) -> (%d,%d), sizeimage[%d,%d,%d]",
-			       org_w, org_h,
-			       pix_fmt_mp->width, pix_fmt_mp->height,
-			       pix_fmt_mp->plane_fmt[0].sizeimage,
-			       pix_fmt_mp->plane_fmt[1].sizeimage,
-			       pix_fmt_mp->plane_fmt[2].sizeimage);
+			"before resize width=%d, height=%d, after resize width=%d, height=%d, sizeimage=%d %d",
+			tmp_w, tmp_h, pix_fmt_mp->width,
+			pix_fmt_mp->height,
+			pix_fmt_mp->plane_fmt[0].sizeimage,
+			pix_fmt_mp->plane_fmt[1].sizeimage);
+
+		pix_fmt_mp->num_planes = fmt->num_planes;
+		pix_fmt_mp->plane_fmt[0].sizeimage =
+				pix_fmt_mp->width * pix_fmt_mp->height +
+				((ALIGN(pix_fmt_mp->width, 16) * 2) * 16);
+		pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width;
+
+		if (pix_fmt_mp->num_planes == 2) {
+			pix_fmt_mp->plane_fmt[1].sizeimage =
+				(pix_fmt_mp->width * pix_fmt_mp->height) / 2 +
+				(ALIGN(pix_fmt_mp->width, 16) * 16);
+			pix_fmt_mp->plane_fmt[2].sizeimage = 0;
+			pix_fmt_mp->plane_fmt[1].bytesperline =
+							pix_fmt_mp->width;
+			pix_fmt_mp->plane_fmt[2].bytesperline = 0;
+		} else if (pix_fmt_mp->num_planes == 3) {
+			pix_fmt_mp->plane_fmt[1].sizeimage =
+			pix_fmt_mp->plane_fmt[2].sizeimage =
+				(pix_fmt_mp->width * pix_fmt_mp->height) / 4 +
+				((ALIGN(pix_fmt_mp->width, 16) / 2) * 16);
+			pix_fmt_mp->plane_fmt[1].bytesperline =
+				pix_fmt_mp->plane_fmt[2].bytesperline =
+				pix_fmt_mp->width / 2;
+		}
 	}
 
 	for (i = 0; i < pix_fmt_mp->num_planes; i++)
 		memset(&(pix_fmt_mp->plane_fmt[i].reserved[0]), 0x0,
-		       sizeof(pix_fmt_mp->plane_fmt[0].reserved));
+			   sizeof(pix_fmt_mp->plane_fmt[0].reserved));
 
 	pix_fmt_mp->flags = 0;
 	memset(&pix_fmt_mp->reserved, 0x0,
-	       sizeof(pix_fmt_mp->reserved));
+		sizeof(pix_fmt_mp->reserved));
 
 	return 0;
 }
@@ -682,45 +381,23 @@
 
 	switch (q_data_src->fmt->fourcc) {
 	case V4L2_PIX_FMT_YUV420M:
-	case V4L2_PIX_FMT_YUV420:
 		param->input_yuv_fmt = VENC_YUV_FORMAT_I420;
 		break;
 	case V4L2_PIX_FMT_YVU420M:
-	case V4L2_PIX_FMT_YVU420:
 		param->input_yuv_fmt = VENC_YUV_FORMAT_YV12;
 		break;
 	case V4L2_PIX_FMT_NV12M:
-	case V4L2_PIX_FMT_NV12:
 		param->input_yuv_fmt = VENC_YUV_FORMAT_NV12;
 		break;
 	case V4L2_PIX_FMT_NV21M:
-	case V4L2_PIX_FMT_NV21:
 		param->input_yuv_fmt = VENC_YUV_FORMAT_NV21;
 		break;
-	case V4L2_PIX_FMT_RGB24:
-		param->input_yuv_fmt = VENC_YUV_FORMAT_24bitRGB888;
-		break;
-	case V4L2_PIX_FMT_BGR24:
-		param->input_yuv_fmt = VENC_YUV_FORMAT_24bitBGR888;
-		break;
-	case V4L2_PIX_FMT_ARGB32:
-		param->input_yuv_fmt = VENC_YUV_FORMAT_32bitRGBA8888;
-		break;
-	case V4L2_PIX_FMT_ABGR32:
-		param->input_yuv_fmt = VENC_YUV_FORMAT_32bitBGRA8888;
-		break;
-	case V4L2_PIX_FMT_BGR32:
-		param->input_yuv_fmt = VENC_YUV_FORMAT_32bitARGB8888;
-		break;
-	case V4L2_PIX_FMT_RGB32:
-		param->input_yuv_fmt = VENC_YUV_FORMAT_32bitABGR8888;
-		break;
 	default:
 		mtk_v4l2_err("Unsupport fourcc =%d", q_data_src->fmt->fourcc);
 		break;
 	}
-	param->profile = enc_params->profile;
-	param->level = enc_params->level;
+	param->h264_profile = enc_params->h264_profile;
+	param->h264_level = enc_params->h264_level;
 
 	/* Config visible resolution */
 	param->width = q_data_src->visible_width;
@@ -733,21 +410,14 @@
 	param->intra_period = enc_params->intra_period;
 	param->gop_size = enc_params->gop_size;
 	param->bitrate = enc_params->bitrate;
-	param->operationrate = enc_params->operationrate;
-	param->scenario = enc_params->scenario;
-	param->prependheader = enc_params->prependheader;
-	param->bitratemode = enc_params->bitratemode;
-
-	ctx->slowmotion = (enc_params->operationrate >= MTK_SLOWMOTION_GCE_TH);
 
 	mtk_v4l2_debug(0,
-	"fmt 0x%x, P/L %d/%d, w/h %d/%d, buf %d/%d, fps/bps %d/%d(%d), gop %d, i_period %d opr %d smvr %d",
-	param->input_yuv_fmt, param->profile,
-	param->level, param->width, param->height,
-	param->buf_width, param->buf_height,
-	param->frm_rate, param->bitrate, param->bitratemode,
-	param->gop_size, param->intra_period,
-	param->operationrate, ctx->slowmotion);
+		"fmt 0x%x, P/L %d/%d, w/h %d/%d, buf %d/%d, fps/bps %d/%d, gop %d, i_period %d",
+		param->input_yuv_fmt, param->h264_profile,
+		param->h264_level, param->width, param->height,
+		param->buf_width, param->buf_height,
+		param->frm_rate, param->bitrate,
+		param->gop_size, param->intra_period);
 }
 
 static int vidioc_venc_s_fmt_cap(struct file *file, void *priv,
@@ -759,7 +429,6 @@
 	int i, ret;
 	struct mtk_video_fmt *fmt;
 
-	mtk_v4l2_debug(4, "[%d] type %d", ctx->id, f->type);
 	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 	if (!vq) {
 		mtk_v4l2_err("fail to get vq");
@@ -777,15 +446,14 @@
 		return -EINVAL;
 	}
 
-	fmt = mtk_venc_find_format(f, MTK_FMT_ENC);
+	fmt = mtk_venc_find_format(f);
 	if (!fmt) {
-		f->fmt.pix.pixelformat =
-			mtk_video_formats[default_cap_fmt_idx].fourcc;
-		fmt = mtk_venc_find_format(f, MTK_FMT_ENC);
+		f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc;
+		fmt = mtk_venc_find_format(f);
 	}
 
 	q_data->fmt = fmt;
-	ret = vidioc_try_fmt(f, q_data->fmt, ctx);
+	ret = vidioc_try_fmt(f, q_data->fmt);
 	if (ret)
 		return ret;
 
@@ -822,6 +490,7 @@
 	struct mtk_q_data *q_data;
 	int ret, i;
 	struct mtk_video_fmt *fmt;
+	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
 
 	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 	if (!vq) {
@@ -840,17 +509,23 @@
 		return -EINVAL;
 	}
 
-	fmt = mtk_venc_find_format(f, MTK_FMT_FRAME);
+	fmt = mtk_venc_find_format(f);
 	if (!fmt) {
-		f->fmt.pix.pixelformat =
-			mtk_video_formats[default_out_fmt_idx].fourcc;
-		fmt = mtk_venc_find_format(f, MTK_FMT_FRAME);
+		f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc;
+		fmt = mtk_venc_find_format(f);
 	}
 
+	pix_fmt_mp->height = clamp(pix_fmt_mp->height,
+				MTK_VENC_MIN_H,
+				MTK_VENC_MAX_H);
+	pix_fmt_mp->width = clamp(pix_fmt_mp->width,
+				MTK_VENC_MIN_W,
+				MTK_VENC_MAX_W);
+
 	q_data->visible_width = f->fmt.pix_mp.width;
 	q_data->visible_height = f->fmt.pix_mp.height;
 	q_data->fmt = fmt;
-	ret = vidioc_try_fmt(f, q_data->fmt, ctx);
+	ret = vidioc_try_fmt(f, q_data->fmt);
 	if (ret)
 		return ret;
 
@@ -916,31 +591,28 @@
 	struct mtk_video_fmt *fmt;
 	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
 
-	fmt = mtk_venc_find_format(f, MTK_FMT_ENC);
+	fmt = mtk_venc_find_format(f);
 	if (!fmt) {
-		f->fmt.pix.pixelformat =
-			mtk_video_formats[default_cap_fmt_idx].fourcc;
-		fmt = mtk_venc_find_format(f, MTK_FMT_ENC);
+		f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc;
+		fmt = mtk_venc_find_format(f);
 	}
 	f->fmt.pix_mp.colorspace = ctx->colorspace;
 	f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
 	f->fmt.pix_mp.quantization = ctx->quantization;
 	f->fmt.pix_mp.xfer_func = ctx->xfer_func;
 
-	return vidioc_try_fmt(f, fmt, ctx);
+	return vidioc_try_fmt(f, fmt);
 }
 
 static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
 					 struct v4l2_format *f)
 {
 	struct mtk_video_fmt *fmt;
-	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
 
-	fmt = mtk_venc_find_format(f, MTK_FMT_FRAME);
+	fmt = mtk_venc_find_format(f);
 	if (!fmt) {
-		f->fmt.pix.pixelformat =
-			mtk_video_formats[default_out_fmt_idx].fourcc;
-		fmt = mtk_venc_find_format(f, MTK_FMT_FRAME);
+		f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc;
+		fmt = mtk_venc_find_format(f);
 	}
 	if (!f->fmt.pix_mp.colorspace) {
 		f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
@@ -949,7 +621,7 @@
 		f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
 	}
 
-	return vidioc_try_fmt(f, fmt, ctx);
+	return vidioc_try_fmt(f, fmt);
 }
 
 static int vidioc_venc_g_selection(struct file *file, void *priv,
@@ -992,14 +664,12 @@
 	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
 	struct mtk_q_data *q_data;
 
-	if (!V4L2_TYPE_IS_OUTPUT(s->type))
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
 		return -EINVAL;
 
 	q_data = mtk_venc_get_q_data(ctx, s->type);
-	if (!q_data) {
-		mtk_v4l2_err("[%d] q_data iS NULL\n", ctx->id);
+	if (!q_data)
 		return -EINVAL;
-	}
 
 	switch (s->target) {
 	case V4L2_SEL_TGT_CROP:
@@ -1012,7 +682,7 @@
 		q_data->visible_height = s->r.height;
 		break;
 	default:
-		mtk_v4l2_err("[Err] target is %X\n", s->target);
+		return -EINVAL;
 	}
 	return 0;
 }
@@ -1021,58 +691,12 @@
 			    struct v4l2_buffer *buf)
 {
 	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-	struct vb2_queue *vq;
-	struct vb2_buffer *vb;
-	struct mtk_video_enc_buf *mtkbuf;
-	struct vb2_v4l2_buffer *vb2_v4l2;
 
 	if (ctx->state == MTK_STATE_ABORT) {
 		mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
-			     ctx->id);
+				ctx->id);
 		return -EIO;
 	}
-	// Check if need to proceed cache operations
-	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type);
-	vb = vq->bufs[buf->index];
-	vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-	mtkbuf = container_of(vb2_v4l2, struct mtk_video_enc_buf, vb);
-
-	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-		if (buf->m.planes[0].bytesused == 0) {
-			mtkbuf->lastframe = EOS;
-			mtk_v4l2_debug(0, "[%d] index=%d Eos FB(%d,%d) vb=%p pts=%llu",
-				ctx->id, buf->index,
-				buf->bytesused,
-				buf->length, vb, vb->timestamp);
-		} else if (buf->flags & V4L2_BUF_FLAG_LAST) {
-			mtkbuf->lastframe = EOS_WITH_DATA;
-			mtk_v4l2_debug(0, "[%d] id=%d EarlyEos FB(%d,%d) vb=%p pts=%llu",
-				ctx->id, buf->index, buf->m.planes[0].bytesused,
-				buf->length, vb, vb->timestamp);
-		} else {
-			mtkbuf->lastframe = NON_EOS;
-			mtk_v4l2_debug(1, "[%d] id=%d getdata FB(%d,%d) vb=%p pts=%llu type:%d",
-				ctx->id, buf->index,
-				buf->m.planes[0].bytesused,
-				buf->length, mtkbuf, vb->timestamp,
-				buf->type);
-		}
-	} else
-		mtk_v4l2_debug(1, "[%d] index=%d type:%d BS (%d) vb=%p",
-				ctx->id, buf->index, buf->type,
-				buf->length, mtkbuf);
-
-	if (buf->flags & V4L2_BUF_FLAG_NO_CACHE_CLEAN) {
-		mtk_v4l2_debug(4, "[%d] No need for Cache clean, buf->index:%d. mtkbuf:%p",
-		   ctx->id, buf->index, mtkbuf);
-		mtkbuf->flags |= NO_CAHCE_CLEAN;
-	}
-
-	if (buf->flags & V4L2_BUF_FLAG_NO_CACHE_INVALIDATE) {
-		mtk_v4l2_debug(4, "[%d] No need for Cache invalidate, buf->index:%d. mtkbuf:%p",
-		   ctx->id, buf->index, mtkbuf);
-		mtkbuf->flags |= NO_CAHCE_INVALIDATE;
-	}
 
 	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 }
@@ -1091,39 +715,6 @@
 	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
 }
 
-static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh,
-				     const struct v4l2_event_subscription *sub)
-{
-	switch (sub->type) {
-	case V4L2_EVENT_EOS:
-		return v4l2_event_subscribe(fh, sub, 2, NULL);
-	case V4L2_EVENT_MTK_VENC_ERROR:
-		return v4l2_event_subscribe(fh, sub, 0, NULL);
-	default:
-		return v4l2_ctrl_subscribe_event(fh, sub);
-	}
-
-}
-static void mtk_vdec_queue_stop_enc_event(struct mtk_vcodec_ctx *ctx)
-{
-	static const struct v4l2_event ev_eos = {
-		.type = V4L2_EVENT_EOS,
-	};
-
-	mtk_v4l2_debug(1, "[%d]", ctx->id);
-	v4l2_event_queue_fh(&ctx->fh, &ev_eos);
-}
-
-static void mtk_venc_queue_error_event(struct mtk_vcodec_ctx *ctx)
-{
-	static const struct v4l2_event ev_error = {
-		.type = V4L2_EVENT_MTK_VENC_ERROR,
-	};
-
-	mtk_v4l2_debug(1, "[%d]", ctx->id);
-	v4l2_event_queue_fh(&ctx->fh, &ev_error);
-}
-
 const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
 	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,
 	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
@@ -1141,7 +732,7 @@
 	.vidioc_try_fmt_vid_cap_mplane	= vidioc_try_fmt_vid_cap_mplane,
 	.vidioc_try_fmt_vid_out_mplane	= vidioc_try_fmt_vid_out_mplane,
 	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
-	.vidioc_subscribe_event		= vidioc_vdec_subscribe_evt,
+	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
 
 	.vidioc_s_parm			= vidioc_venc_s_parm,
@@ -1192,8 +783,6 @@
 	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 	struct mtk_q_data *q_data;
 	int i;
-	struct mtk_video_enc_buf *mtkbuf;
-	struct vb2_v4l2_buffer *vb2_v4l2;
 
 	q_data = mtk_venc_get_q_data(ctx, vb->vb2_queue->type);
 
@@ -1204,78 +793,10 @@
 				q_data->sizeimage[i]);
 			return -EINVAL;
 		}
-
-		// Check if need to proceed cache operations
-		vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-		mtkbuf = container_of(vb2_v4l2, struct mtk_video_enc_buf, vb);
-
-		if (!(mtkbuf->flags & NO_CAHCE_CLEAN)) {
-			struct mtk_vcodec_mem src_mem;
-			struct dma_buf_attachment *buf_att;
-			struct sg_table *sgt;
-
-			buf_att = dma_buf_attach(vb->planes[i].dbuf,
-				&ctx->dev->plat_dev->dev);
-			sgt = dma_buf_map_attachment(buf_att, DMA_TO_DEVICE);
-			dma_sync_sg_for_device(&ctx->dev->plat_dev->dev,
-				sgt->sgl,
-				sgt->orig_nents,
-				DMA_TO_DEVICE);
-			dma_buf_unmap_attachment(buf_att, sgt, DMA_TO_DEVICE);
-
-			src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(vb, i);
-			src_mem.size = (size_t)(vb->planes[i].bytesused -
-				vb->planes[i].data_offset);
-			dma_buf_detach(vb->planes[i].dbuf, buf_att);
-
-			mtk_v4l2_debug(4, "[%d] Cache sync TD for %p sz=%d dev %p ",
-				ctx->id,
-				(void *)src_mem.dma_addr,
-				(unsigned int)src_mem.size,
-				&ctx->dev->plat_dev->dev);
-		}
 	}
 
 	return 0;
 }
-static void vb2ops_venc_buf_finish(struct vb2_buffer *vb)
-{
-	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-	struct mtk_video_enc_buf *mtkbuf;
-	struct vb2_v4l2_buffer *vb2_v4l2;
-
-    // Check if need to proceed cache operations
-	vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-	mtkbuf = container_of(vb2_v4l2, struct mtk_video_enc_buf, vb);
-
-	if (!(mtkbuf->flags & NO_CAHCE_INVALIDATE)) {
-		if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-			struct mtk_vcodec_mem dst_mem;
-
-			struct dma_buf_attachment *buf_att;
-			struct sg_table *sgt;
-
-			buf_att = dma_buf_attach(vb->planes[0].dbuf,
-				&ctx->dev->plat_dev->dev);
-			sgt = dma_buf_map_attachment(buf_att, DMA_FROM_DEVICE);
-			dma_sync_sg_for_cpu(&ctx->dev->plat_dev->dev, sgt->sgl,
-				sgt->orig_nents, DMA_FROM_DEVICE);
-			dma_buf_unmap_attachment(buf_att, sgt, DMA_FROM_DEVICE);
-
-			dst_mem.dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
-			dst_mem.size = (size_t)vb->planes[0].bytesused;
-			dma_buf_detach(vb->planes[0].dbuf, buf_att);
-
-			mtk_v4l2_debug(4,
-				"[%d] Cache sync FD for %p sz=%d dev %p",
-				ctx->id,
-				(void *)dst_mem.dma_addr,
-				(unsigned int)dst_mem.size,
-				&ctx->dev->plat_dev->dev);
-		}
-	}
-}
-
 
 static void vb2ops_venc_buf_queue(struct vb2_buffer *vb)
 {
@@ -1307,7 +828,9 @@
 	int ret;
 	int i;
 
-	/* once state turn into MTK_STATE_ABORT clear it */
+	/* Once state turn into MTK_STATE_ABORT, we need stop_streaming
+	  * to clear it
+	  */
 	if ((ctx->state == MTK_STATE_ABORT) || (ctx->state == MTK_STATE_FREE)) {
 		ret = -EIO;
 		goto err_set_param;
@@ -1331,9 +854,7 @@
 	}
 	ctx->param_change = MTK_ENCODE_PARAM_NONE;
 
-	if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264 ||
-	     ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H265 ||
-	     ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_MPEG4) &&
+	if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264) &&
 	    (ctx->enc_params.seq_hdr_mode !=
 				V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE)) {
 		ret = venc_if_set_param(ctx,
@@ -1366,19 +887,21 @@
 static void vb2ops_venc_stop_streaming(struct vb2_queue *q)
 {
 	struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
-	struct vb2_v4l2_buffer *src_buf, *dst_buf;
+	struct vb2_buffer *src_buf, *dst_buf;
 	int ret;
 
 	mtk_v4l2_debug(2, "[%d]-> type=%d", ctx->id, q->type);
 
 	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
-			dst_buf->vb2_buf.planes[0].bytesused = 0;
-			v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+			dst_buf->planes[0].bytesused = 0;
+			v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf),
+					VB2_BUF_STATE_ERROR);
 		}
 	} else {
 		while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx)))
-			v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+			v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
+					VB2_BUF_STATE_ERROR);
 	}
 
 	if ((q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
@@ -1406,7 +929,6 @@
 	.buf_queue		= vb2ops_venc_buf_queue,
 	.wait_prepare		= vb2_ops_wait_prepare,
 	.wait_finish		= vb2_ops_wait_finish,
-	.buf_finish             = vb2ops_venc_buf_finish,
 	.start_streaming	= vb2ops_venc_start_streaming,
 	.stop_streaming		= vb2ops_venc_stop_streaming,
 };
@@ -1415,7 +937,8 @@
 {
 	struct mtk_vcodec_ctx *ctx = priv;
 	int ret;
-	struct vb2_v4l2_buffer *src_buf, *dst_buf;
+	struct vb2_buffer *src_buf, *dst_buf;
+	struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2;
 	struct mtk_vcodec_mem bs_buf;
 	struct venc_done_result enc_result;
 
@@ -1425,15 +948,14 @@
 		return -EINVAL;
 	}
 
-	bs_buf.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
-	bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
-	bs_buf.size = (size_t)dst_buf->vb2_buf.planes[0].length;
-	bs_buf.dmabuf = dst_buf->planes[0].dbuf;
+	bs_buf.va = vb2_plane_vaddr(dst_buf, 0);
+	bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+	bs_buf.size = (size_t)dst_buf->planes[0].length;
 
 	mtk_v4l2_debug(1,
 			"[%d] buf id=%d va=0x%p dma_addr=0x%llx size=%zu",
 			ctx->id,
-			dst_buf->vb2_buf.index, bs_buf.va,
+			dst_buf->index, bs_buf.va,
 			(u64)bs_buf.dma_addr,
 			bs_buf.size);
 
@@ -1441,27 +963,27 @@
 			VENC_START_OPT_ENCODE_SEQUENCE_HEADER,
 			NULL, &bs_buf, &enc_result);
 
-	get_free_buffers(ctx, &enc_result);
-
-	if (enc_result.bs_va == 0) {
-		dst_buf->vb2_buf.planes[0].bytesused = 0;
+	if (ret) {
+		dst_buf->planes[0].bytesused = 0;
 		ctx->state = MTK_STATE_ABORT;
-		mtk_venc_queue_error_event(ctx);
-		v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
-		mtk_v4l2_err("failed=%d", ret);
+		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf),
+				  VB2_BUF_STATE_ERROR);
+		mtk_v4l2_err("venc_if_encode failed=%d", ret);
 		return -EINVAL;
 	}
 	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
 	if (src_buf) {
-		dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
-		dst_buf->timecode = src_buf->timecode;
+		src_vb2_v4l2 = to_vb2_v4l2_buffer(src_buf);
+		dst_vb2_v4l2 = to_vb2_v4l2_buffer(dst_buf);
+		dst_buf->timestamp = src_buf->timestamp;
+		dst_vb2_v4l2->timecode = src_vb2_v4l2->timecode;
 	} else {
 		mtk_v4l2_err("No timestamp for the header buffer.");
 	}
 
 	ctx->state = MTK_STATE_HEADER;
-	dst_buf->vb2_buf.planes[0].bytesused = enc_result.bs_size;
-	v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+	dst_buf->planes[0].bytesused = enc_result.bs_size;
+	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), VB2_BUF_STATE_DONE);
 
 	return 0;
 }
@@ -1469,7 +991,9 @@
 static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx)
 {
 	struct venc_enc_param enc_prm;
-	struct vb2_v4l2_buffer *vb2_v4l2 = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	struct vb2_v4l2_buffer *vb2_v4l2 =
+			container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
 	struct mtk_video_enc_buf *mtk_buf =
 			container_of(vb2_v4l2, struct mtk_video_enc_buf, vb);
 
@@ -1519,91 +1043,6 @@
 						 NULL);
 	}
 
-	if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_SCENARIO) {
-		enc_prm.scenario = mtk_buf->enc_params.scenario;
-		mtk_v4l2_debug(1, "[%d] idx=%d, change param scenario=%d",
-			       ctx->id,
-			       mtk_buf->vb.vb2_buf.index,
-			       mtk_buf->enc_params.scenario);
-		if (mtk_buf->enc_params.scenario)
-			ret |= venc_if_set_param(ctx,
-						 VENC_SET_PARAM_SCENARIO,
-						 &enc_prm);
-	}
-
-	if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_NONREFP) {
-		enc_prm.nonrefp = mtk_buf->enc_params.nonrefp;
-		mtk_v4l2_debug(1, "[%d] idx=%d, change param nonref=%d",
-			       ctx->id,
-			       mtk_buf->vb.vb2_buf.index,
-			       mtk_buf->enc_params.nonrefp);
-		ret |= venc_if_set_param(ctx,
-					 VENC_SET_PARAM_NONREFP,
-					 &enc_prm);
-	}
-
-	if (!ret &&
-	mtk_buf->param_change & MTK_ENCODE_PARAM_DETECTED_FRAMERATE) {
-		enc_prm.detectframerate = mtk_buf->enc_params.detectframerate;
-		mtk_v4l2_debug(1, "[%d] idx=%d, change param detectfr=%d",
-				ctx->id,
-				mtk_buf->vb.vb2_buf.index,
-				mtk_buf->enc_params.detectframerate);
-		ret |= venc_if_set_param(ctx,
-					VENC_SET_PARAM_DETECTED_FRAMERATE,
-					&enc_prm);
-	}
-
-	if (!ret &&
-	mtk_buf->param_change & MTK_ENCODE_PARAM_RFS_ON) {
-		enc_prm.rfs = mtk_buf->enc_params.rfs;
-		mtk_v4l2_debug(1, "[%d] idx=%d, change param rfs=%d",
-				ctx->id,
-				mtk_buf->vb.vb2_buf.index,
-				mtk_buf->enc_params.rfs);
-		ret |= venc_if_set_param(ctx,
-					VENC_SET_PARAM_RFS_ON,
-					&enc_prm);
-	}
-
-	if (!ret &&
-	mtk_buf->param_change & MTK_ENCODE_PARAM_PREPEND_SPSPPS_TO_IDR) {
-		enc_prm.prependheader = mtk_buf->enc_params.prependheader;
-		mtk_v4l2_debug(1, "[%d] idx=%d, prepend spspps idr=%d",
-				ctx->id,
-				mtk_buf->vb.vb2_buf.index,
-				mtk_buf->enc_params.prependheader);
-		ret |= venc_if_set_param(ctx,
-					VENC_SET_PARAM_PREPEND_SPSPPS_TO_IDR,
-					&enc_prm);
-	}
-
-	if (!ret &&
-	mtk_buf->param_change & MTK_ENCODE_PARAM_OPERATION_RATE) {
-		enc_prm.operationrate = mtk_buf->enc_params.operationrate;
-		mtk_v4l2_debug(1, "[%d] idx=%d, operationrate=%d",
-				ctx->id,
-				mtk_buf->vb.vb2_buf.index,
-				mtk_buf->enc_params.operationrate);
-		ret |= venc_if_set_param(ctx,
-					VENC_SET_PARAM_OPERATION_RATE,
-					&enc_prm);
-		ctx->slowmotion =
-			(mtk_buf->enc_params.operationrate >=
-				MTK_SLOWMOTION_GCE_TH);
-	}
-
-	if (!ret &&
-	mtk_buf->param_change & MTK_ENCODE_PARAM_BITRATE_MODE) {
-		enc_prm.bitratemode = mtk_buf->enc_params.bitratemode;
-		mtk_v4l2_debug(1, "[%d] idx=%d, bitratemode=%d",
-				ctx->id,
-				mtk_buf->vb.vb2_buf.index,
-				mtk_buf->enc_params.bitratemode);
-		ret |= venc_if_set_param(ctx,
-					VENC_SET_PARAM_BITRATE_MODE,
-					&enc_prm);
-	}
 	mtk_buf->param_change = MTK_ENCODE_PARAM_NONE;
 
 	if (ret) {
@@ -1628,24 +1067,12 @@
 {
 	struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx,
 				    encode_work);
-	struct mtk_q_data *q_data_src = &ctx->q_data[MTK_Q_DATA_SRC];
 	struct vb2_buffer *src_buf, *dst_buf;
-	struct venc_frm_buf *pfrm_buf;
-	struct mtk_vcodec_mem *pbs_buf;
+	struct venc_frm_buf frm_buf;
+	struct mtk_vcodec_mem bs_buf;
 	struct venc_done_result enc_result;
-	int ret, i, length;
-	struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2, *pend_src_vb2_v4l2;
-	struct mtk_video_enc_buf *dst_buf_info, *src_buf_info;
-	struct venc_inst *inst = NULL;
-
-	mutex_lock(&ctx->worker_lock);
-
-	if (ctx->state == MTK_STATE_ABORT) {
-		v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx);
-		mtk_v4l2_debug(1, " %d", ctx->state);
-		mutex_unlock(&ctx->worker_lock);
-		return;
-	}
+	int ret, i;
+	struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2;
 
 	/* check dst_buf, dst_buf may be removed in device_run
 	 * to stored encdoe header so we need check dst_buf and
@@ -1654,174 +1081,75 @@
 	dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
 	if (!dst_buf) {
 		v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx);
-		mutex_unlock(&ctx->worker_lock);
 		return;
 	}
 
 	src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	memset(&frm_buf, 0, sizeof(frm_buf));
+	for (i = 0; i < src_buf->num_planes ; i++) {
+		frm_buf.fb_addr[i].va = vb2_plane_vaddr(src_buf, i);
+		frm_buf.fb_addr[i].dma_addr =
+				vb2_dma_contig_plane_dma_addr(src_buf, i);
+		frm_buf.fb_addr[i].size =
+				(size_t)src_buf->planes[i].length;
+	}
+	bs_buf.va = vb2_plane_vaddr(dst_buf, 0);
+	bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+	bs_buf.size = (size_t)dst_buf->planes[0].length;
+
+	mtk_v4l2_debug(2,
+			"Framebuf VA=%p PA=%llx Size=0x%zx;VA=%p PA=0x%llx Size=0x%zx;VA=%p PA=0x%llx Size=%zu",
+			frm_buf.fb_addr[0].va,
+			(u64)frm_buf.fb_addr[0].dma_addr,
+			frm_buf.fb_addr[0].size,
+			frm_buf.fb_addr[1].va,
+			(u64)frm_buf.fb_addr[1].dma_addr,
+			frm_buf.fb_addr[1].size,
+			frm_buf.fb_addr[2].va,
+			(u64)frm_buf.fb_addr[2].dma_addr,
+			frm_buf.fb_addr[2].size);
+
+	ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME,
+			     &frm_buf, &bs_buf, &enc_result);
+
 	src_vb2_v4l2 = to_vb2_v4l2_buffer(src_buf);
 	dst_vb2_v4l2 = to_vb2_v4l2_buffer(dst_buf);
 
-	src_buf_info = container_of(src_vb2_v4l2, struct mtk_video_enc_buf, vb);
-	dst_buf_info = container_of(dst_vb2_v4l2, struct mtk_video_enc_buf, vb);
-	pbs_buf = &dst_buf_info->bs_buf;
-	pfrm_buf = &src_buf_info->frm_buf;
+	dst_buf->timestamp = src_buf->timestamp;
+	dst_vb2_v4l2->timecode = src_vb2_v4l2->timecode;
 
-	pbs_buf->va = vb2_plane_vaddr(dst_buf, 0);
-	pbs_buf->dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
-	pbs_buf->size = (size_t)dst_buf->planes[0].length;
-	pbs_buf->dmabuf = dst_buf->planes[0].dbuf;
+	if (enc_result.is_key_frm)
+		dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_KEYFRAME;
 
-	if (src_buf_info->lastframe == EOS) {
-		if (ctx->oal_vcodec == 1) {
-			ret = venc_if_encode(ctx,
-					 VENC_START_OPT_ENCODE_FRAME_FINAL,
-					 NULL, pbs_buf, &enc_result);
-
-			pend_src_vb2_v4l2 =
-				to_vb2_v4l2_buffer(ctx->pend_src_buf);
-			dst_vb2_v4l2->flags |= pend_src_vb2_v4l2->flags;
-			dst_vb2_v4l2->vb2_buf.timestamp =
-				pend_src_vb2_v4l2->vb2_buf.timestamp;
-			dst_vb2_v4l2->timecode = pend_src_vb2_v4l2->timecode;
-			dst_vb2_v4l2->sequence = pend_src_vb2_v4l2->sequence;
-			dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_LAST;
-			if (enc_result.is_key_frm)
-				dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_KEYFRAME;
-
-			if (ret) {
-				dst_buf->planes[0].bytesused = 0;
-				v4l2_m2m_buf_done(pend_src_vb2_v4l2,
-						VB2_BUF_STATE_ERROR);
-				v4l2_m2m_buf_done(dst_vb2_v4l2,
-						VB2_BUF_STATE_ERROR);
-				mtk_v4l2_err("last venc_if_encode failed=%d",
-									ret);
-				if (ret == -EIO)
-					ctx->state = MTK_STATE_ABORT;
-			} else {
-				dst_buf->planes[0].bytesused =
-							enc_result.bs_size;
-				v4l2_m2m_buf_done(pend_src_vb2_v4l2,
-							VB2_BUF_STATE_DONE);
-				v4l2_m2m_buf_done(dst_vb2_v4l2,
-							VB2_BUF_STATE_DONE);
-			}
-
-			ctx->pend_src_buf = NULL;
-		} else {
-			ret = venc_if_encode(ctx,
-					VENC_START_OPT_ENCODE_FRAME_FINAL,
-					NULL, pbs_buf, &enc_result);
-			dst_vb2_v4l2->vb2_buf.timestamp =
-				src_vb2_v4l2->vb2_buf.timestamp;
-			dst_vb2_v4l2->timecode = src_vb2_v4l2->timecode;
-			if (ret) {
-				mtk_v4l2_err("last venc_if_encode failed=%d",
-									ret);
-				v4l2_m2m_buf_done(dst_vb2_v4l2,
-							VB2_BUF_STATE_ERROR);
-				if (ret == -EIO)
-					ctx->state = MTK_STATE_ABORT;
-			} else {
-				if (ctx->drv_handle != 0) {
-					inst =
-					(struct venc_inst *)ctx->drv_handle;
-					mtk_v4l2_debug(0,
-						"enc final free cnt %d",
-						 inst->vsi->list_free.count);
-				}
-				return_free_buffers(ctx);
-			}
-		}
-		mtk_vdec_queue_stop_enc_event(ctx);
-		if (src_buf->planes[0].bytesused == 0U) {
-			src_vb2_v4l2->flags |= V4L2_BUF_FLAG_LAST;
-			vb2_set_plane_payload(&src_buf_info->vb.vb2_buf, 0, 0);
-			v4l2_m2m_buf_done(src_vb2_v4l2,
-				VB2_BUF_STATE_DONE);
-		}
-		v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx);
-		mutex_unlock(&ctx->worker_lock);
-		return;
-	} else if (src_buf_info->lastframe == EOS_WITH_DATA) {
-		mtk_v4l2_debug(0, "[%d] EarlyEos: encode last frame %d",
-			ctx->id, src_buf->planes[0].bytesused);
-		src_vb2_v4l2->flags |= V4L2_BUF_FLAG_LAST;
-		dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_LAST;
-		ctx->enc_flush_buf->lastframe = EOS;
-		v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->enc_flush_buf->vb);
-	}
-
-	memset(pfrm_buf, 0, sizeof(struct venc_frm_buf));
-	for (i = 0; i < src_buf->num_planes ; i++) {
-		pfrm_buf->fb_addr[i].va = vb2_plane_vaddr(src_buf, i) +
-			(size_t)src_buf->planes[i].data_offset;
-		pfrm_buf->fb_addr[i].dma_addr =
-			vb2_dma_contig_plane_dma_addr(src_buf, i) +
-			(size_t)src_buf->planes[i].data_offset;
-		pfrm_buf->fb_addr[i].size =
-				(size_t)(src_buf->planes[i].bytesused-
-				src_buf->planes[i].data_offset);
-		pfrm_buf->fb_addr[i].dmabuf =
-				src_buf->planes[i].dbuf;
-		pfrm_buf->fb_addr[i].data_offset =
-				src_buf->planes[i].data_offset;
-
-		mtk_v4l2_debug(2, "fb_addr[%d].va %p, offset %d, dma_addr %p, size %d\n",
-			i, pfrm_buf->fb_addr[i].va,
-			src_buf->planes[i].data_offset,
-			(void *)pfrm_buf->fb_addr[i].dma_addr,
-			(int)pfrm_buf->fb_addr[i].size);
-	}
-	pfrm_buf->num_planes = src_buf->num_planes;
-	pfrm_buf->timestamp = src_vb2_v4l2->vb2_buf.timestamp;
-	length = q_data_src->coded_width * q_data_src->coded_height;
-
-	mtk_v4l2_debug(2,
-			"Framebuf VA=%p PA=%llx Size=0x%zx Offset=%d;VA=%p PA=0x%llx Size=0x%zx Offset=%d;VA=%p PA=0x%llx Size=%zu Offset=%d",
-			pfrm_buf->fb_addr[0].va,
-			(u64)pfrm_buf->fb_addr[0].dma_addr,
-			pfrm_buf->fb_addr[0].size,
-			src_buf->planes[0].data_offset,
-			pfrm_buf->fb_addr[1].va,
-			(u64)pfrm_buf->fb_addr[1].dma_addr,
-			pfrm_buf->fb_addr[1].size,
-			src_buf->planes[1].data_offset,
-			pfrm_buf->fb_addr[2].va,
-			(u64)pfrm_buf->fb_addr[2].dma_addr,
-			pfrm_buf->fb_addr[2].size,
-			src_buf->planes[2].data_offset);
-
-	ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME,
-				 pfrm_buf, pbs_buf, &enc_result);
 	if (ret) {
+		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
+				  VB2_BUF_STATE_ERROR);
 		dst_buf->planes[0].bytesused = 0;
-		v4l2_m2m_buf_done(src_vb2_v4l2, VB2_BUF_STATE_ERROR);
-		v4l2_m2m_buf_done(dst_vb2_v4l2, VB2_BUF_STATE_ERROR);
+		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf),
+				  VB2_BUF_STATE_ERROR);
 		mtk_v4l2_err("venc_if_encode failed=%d", ret);
-		if (ret == -EIO)
-			ctx->state = MTK_STATE_ABORT;
-	} else
-		return_free_buffers(ctx);
+	} else {
+		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
+				  VB2_BUF_STATE_DONE);
+		dst_buf->planes[0].bytesused = enc_result.bs_size;
+		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf),
+				  VB2_BUF_STATE_DONE);
+		mtk_v4l2_debug(2, "venc_if_encode bs size=%d",
+				 enc_result.bs_size);
+	}
 
 	v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx);
 
 	mtk_v4l2_debug(1, "<=== src_buf[%d] dst_buf[%d] venc_if_encode ret=%d Size=%u===>",
 			src_buf->index, dst_buf->index, ret,
 			enc_result.bs_size);
-	mutex_unlock(&ctx->worker_lock);
 }
 
 static void m2mops_venc_device_run(void *priv)
 {
 	struct mtk_vcodec_ctx *ctx = priv;
 
-	mtk_venc_param_change(ctx);
-	if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264 ||
-	     ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H265 ||
-	     ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_MPEG4 ||
-	     ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H263) &&
+	if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264) &&
 	    (ctx->state != MTK_STATE_HEADER)) {
 		/* encode h264 sps/pps header */
 		mtk_venc_encode_header(ctx);
@@ -1829,6 +1157,7 @@
 		return;
 	}
 
+	mtk_venc_param_change(ctx);
 	queue_work(ctx->dev->encode_workqueue, &ctx->encode_work);
 }
 
@@ -1872,7 +1201,6 @@
 	ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
 	ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
 
-	get_supported_format(ctx);
 	q_data = &ctx->q_data[MTK_Q_DATA_SRC];
 	memset(q_data, 0, sizeof(struct mtk_q_data));
 	q_data->visible_width = DFT_CFG_WIDTH;
@@ -1881,7 +1209,7 @@
 	q_data->coded_height = DFT_CFG_HEIGHT;
 	q_data->field = V4L2_FIELD_NONE;
 
-	q_data->fmt = &mtk_video_formats[default_out_fmt_idx];
+	q_data->fmt = &mtk_video_formats[OUT_FMT_IDX];
 
 	v4l_bound_align_image(&q_data->coded_width,
 				MTK_VENC_MIN_W,
@@ -1910,7 +1238,7 @@
 	memset(q_data, 0, sizeof(struct mtk_q_data));
 	q_data->coded_width = DFT_CFG_WIDTH;
 	q_data->coded_height = DFT_CFG_HEIGHT;
-	q_data->fmt = &mtk_video_formats[default_cap_fmt_idx];
+	q_data->fmt = &mtk_video_formats[CAP_FMT_IDX];
 	q_data->field = V4L2_FIELD_NONE;
 	ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
 		DFT_CFG_WIDTH * DFT_CFG_HEIGHT;
@@ -1922,13 +1250,11 @@
 {
 	const struct v4l2_ctrl_ops *ops = &mtk_vcodec_enc_ctrl_ops;
 	struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl;
-	struct v4l2_ctrl_config cfg;
-	struct v4l2_ctrl *ctrl;
 
 	v4l2_ctrl_handler_init(handler, MTK_MAX_CTRLS_HINT);
 
 	v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE,
-			  1, 400000000, 1, 20000000);
+			1, 4000000, 1, 4000000);
 	v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_B_FRAMES,
 			0, 2, 1, 0);
 	v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
@@ -1949,78 +1275,10 @@
 			0, V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE);
 	v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
 			V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
-		0, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
-	memset(&cfg, 0, sizeof(cfg));
-	cfg.id = V4L2_CID_MPEG_MTK_ENCODE_SCENARIO;
-	cfg.type = V4L2_CTRL_TYPE_INTEGER;
-	cfg.flags = V4L2_CTRL_FLAG_WRITE_ONLY;
-	cfg.name = "Video encode scenario";
-	cfg.min = 0;
-	cfg.max = 32;
-	cfg.step = 1;
-	cfg.def = 0;
-	cfg.ops = ops;
-	ctrl = v4l2_ctrl_new_custom(handler, &cfg, NULL);
-
-	memset(&cfg, 0, sizeof(cfg));
-	cfg.id = V4L2_CID_MPEG_MTK_ENCODE_NONREFP;
-	cfg.type = V4L2_CTRL_TYPE_INTEGER;
-	cfg.flags = V4L2_CTRL_FLAG_WRITE_ONLY;
-	cfg.name = "Video encode nonrefp";
-	cfg.min = 0;
-	cfg.max = 32;
-	cfg.step = 1;
-	cfg.def = 0;
-	cfg.ops = ops;
-	ctrl = v4l2_ctrl_new_custom(handler, &cfg, NULL);
-
-	memset(&cfg, 0, sizeof(cfg));
-	cfg.id = V4L2_CID_MPEG_MTK_ENCODE_DETECTED_FRAMERATE;
-	cfg.type = V4L2_CTRL_TYPE_INTEGER;
-	cfg.flags = V4L2_CTRL_FLAG_WRITE_ONLY;
-	cfg.name = "Video encode detect framerate";
-	cfg.min = 0;
-	cfg.max = 32;
-	cfg.step = 1;
-	cfg.def = 0;
-	cfg.ops = ops;
-	ctrl = v4l2_ctrl_new_custom(handler, &cfg, NULL);
-
-	memset(&cfg, 0, sizeof(cfg));
-	cfg.id = V4L2_CID_MPEG_MTK_ENCODE_RFS_ON;
-	cfg.type = V4L2_CTRL_TYPE_INTEGER;
-	cfg.flags = V4L2_CTRL_FLAG_WRITE_ONLY;
-	cfg.name = "Video encode slice loss indication";
-	cfg.min = 0;
-	cfg.max = 1;
-	cfg.step = 1;
-	cfg.def = 0;
-	cfg.ops = ops;
-	ctrl = v4l2_ctrl_new_custom(handler, &cfg, NULL);
-
-	memset(&cfg, 0, sizeof(cfg));
-	cfg.id = V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR;
-	cfg.type = V4L2_CTRL_TYPE_INTEGER;
-	cfg.flags = V4L2_CTRL_FLAG_WRITE_ONLY;
-	cfg.name = "Video encode slice loss indication";
-	cfg.min = 0;
-	cfg.max = 1;
-	cfg.step = 1;
-	cfg.def = 0;
-	cfg.ops = ops;
-	ctrl = v4l2_ctrl_new_custom(handler, &cfg, NULL);
-
-	memset(&cfg, 0, sizeof(cfg));
-	cfg.id = V4L2_CID_MPEG_MTK_ENCODE_OPERATION_RATE;
-	cfg.type = V4L2_CTRL_TYPE_INTEGER;
-	cfg.flags = V4L2_CTRL_FLAG_WRITE_ONLY;
-	cfg.name = "Video encode operation rate";
-	cfg.min = 0;
-	cfg.max = 2048;
-	cfg.step = 1;
-	cfg.def = 0;
-	cfg.ops = ops;
-	ctrl = v4l2_ctrl_new_custom(handler, &cfg, NULL);
+			0, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
+	v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+			V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+			0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
 	if (handler->error) {
 		mtk_v4l2_err("Init control handler fail %d",
 				handler->error);
@@ -2051,7 +1309,6 @@
 	src_vq->mem_ops		= &vb2_dma_contig_memops;
 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	src_vq->lock		= &ctx->dev->dev_mutex;
-	src_vq->allow_zero_bytesused = 1;
 	src_vq->dev		= &ctx->dev->plat_dev->dev;
 
 	ret = vb2_queue_init(src_vq);
@@ -2061,12 +1318,11 @@
 	dst_vq->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 	dst_vq->io_modes	= VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
 	dst_vq->drv_priv	= ctx;
-	dst_vq->buf_struct_size = sizeof(struct mtk_video_enc_buf);
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	dst_vq->ops		= &mtk_venc_vb2_ops;
 	dst_vq->mem_ops		= &vb2_dma_contig_memops;
 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	dst_vq->lock		= &ctx->dev->dev_mutex;
-	dst_vq->allow_zero_bytesused = 1;
 	dst_vq->dev		= &ctx->dev->plat_dev->dev;
 
 	return vb2_queue_init(dst_vq);
@@ -2074,56 +1330,26 @@
 
 int mtk_venc_unlock(struct mtk_vcodec_ctx *ctx)
 {
-	mtk_v4l2_debug(4, "ctx %p [%d]", ctx, ctx->id);
-	up(&ctx->dev->enc_sem);
+	struct mtk_vcodec_dev *dev = ctx->dev;
+
+	mutex_unlock(&dev->enc_mutex);
 	return 0;
 }
 
 int mtk_venc_lock(struct mtk_vcodec_ctx *ctx)
 {
-	unsigned int suspend_block_cnt = 0;
+	struct mtk_vcodec_dev *dev = ctx->dev;
 
-	while (ctx->dev->is_codec_suspending == 1) {
-		suspend_block_cnt++;
-		if (suspend_block_cnt > SUSPEND_TIMEOUT_CNT) {
-			mtk_v4l2_debug(4, "VENC blocked by suspend\n");
-			suspend_block_cnt = 0;
-		}
-		usleep_range(10000, 20000);
-	}
-
-	mtk_v4l2_debug(4, "ctx %p [%d]", ctx, ctx->id);
-	return down_interruptible(&ctx->dev->enc_sem);
+	mutex_lock(&dev->enc_mutex);
+	return 0;
 }
 
-void mtk_vcodec_enc_empty_queues(struct file *file, struct mtk_vcodec_ctx *ctx)
-{
-	struct vb2_buffer *src_buf = NULL, *dst_buf = NULL;
-	struct v4l2_fh *fh = file->private_data;
-
-	// error handle for release before stream-off
-	//  stream off both queue mannually.
-	v4l2_m2m_streamoff(file, fh->m2m_ctx,
-		V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-	v4l2_m2m_streamoff(file, fh->m2m_ctx,
-		V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-
-	while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx)))
-		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
-			VB2_BUF_STATE_ERROR);
-
-	while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
-		dst_buf->planes[0].bytesused = 0;
-		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf),
-			VB2_BUF_STATE_ERROR);
-	}
-
-	ctx->state = MTK_STATE_FREE;
-}
 void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx)
 {
 	int ret = venc_if_deinit(ctx);
 
 	if (ret)
 		mtk_v4l2_err("venc_if_deinit failed=%d", ret);
+
+	ctx->state = MTK_STATE_FREE;
 }
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
old mode 100644
new mode 100755
index 696c250..d7a154a
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
@@ -28,11 +28,6 @@
 
 #define MTK_VENC_IRQ_STATUS_OFFSET	0x05C
 #define MTK_VENC_IRQ_ACK_OFFSET	0x060
-enum eos_types {
-	NON_EOS = 0,
-	EOS_WITH_DATA,
-	EOS
-};
 
 /**
  * struct mtk_video_enc_buf - Private data related to each VB2 buffer.
@@ -47,10 +42,6 @@
 	struct list_head list;
 	u32 param_change;
 	struct mtk_enc_params enc_params;
-	enum eos_types lastframe;
-	int    flags;
-	struct mtk_vcodec_mem bs_buf;
-	struct venc_frm_buf frm_buf;
 };
 
 extern const struct v4l2_ioctl_ops mtk_venc_ioctl_ops;
@@ -60,7 +51,6 @@
 int mtk_venc_lock(struct mtk_vcodec_ctx *ctx);
 int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq,
 			      struct vb2_queue *dst_vq);
-void mtk_vcodec_enc_empty_queues(struct file *file, struct mtk_vcodec_ctx *ctx);
 void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx);
 int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx);
 void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx);
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
old mode 100644
new mode 100755
index 5b4e6a6..83f859e
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
@@ -23,22 +23,16 @@
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-dma-contig.h>
 #include <linux/pm_runtime.h>
-#include <linux/pm_wakeup.h>
-#include <linux/iommu.h>
-#include <linux/delay.h>
-#include <linux/suspend.h>
-#include <linux/semaphore.h>
 
 #include "mtk_vcodec_drv.h"
 #include "mtk_vcodec_enc.h"
 #include "mtk_vcodec_enc_pm.h"
 #include "mtk_vcodec_intr.h"
 #include "mtk_vcodec_util.h"
-#include "mtk_vcodec_fw.h"
+#include "mtk_vpu.h"
 
 module_param(mtk_v4l2_dbg_level, int, S_IRUGO | S_IWUSR);
 module_param(mtk_vcodec_dbg, bool, S_IRUGO | S_IWUSR);
-struct mtk_vcodec_dev *venc_dev;
 
 /* Wake up context wait_queue */
 static void wake_up_ctx(struct mtk_vcodec_ctx *ctx, unsigned int reason)
@@ -81,9 +75,9 @@
 	spin_unlock_irqrestore(&dev->irqlock, flags);
 
 	mtk_v4l2_debug(1, "id=%d", ctx->id);
-	addr = dev->enc_reg_base[VENC_SYS] + MTK_VENC_IRQ_ACK_OFFSET;
+	addr = dev->reg_base[VENC_SYS] + MTK_VENC_IRQ_ACK_OFFSET;
 
-	ctx->irq_status = readl(dev->enc_reg_base[VENC_SYS] +
+	ctx->irq_status = readl(dev->reg_base[VENC_SYS] +
 				(MTK_VENC_IRQ_STATUS_OFFSET));
 
 	clean_irq_status(ctx->irq_status, addr);
@@ -104,10 +98,10 @@
 	spin_unlock_irqrestore(&dev->irqlock, flags);
 
 	mtk_v4l2_debug(1, "id=%d", ctx->id);
-	ctx->irq_status = readl(dev->enc_reg_base[VENC_LT_SYS] +
+	ctx->irq_status = readl(dev->reg_base[VENC_LT_SYS] +
 				(MTK_VENC_IRQ_STATUS_OFFSET));
 
-	addr = dev->enc_reg_base[VENC_LT_SYS] + MTK_VENC_IRQ_ACK_OFFSET;
+	addr = dev->reg_base[VENC_LT_SYS] + MTK_VENC_IRQ_ACK_OFFSET;
 
 	clean_irq_status(ctx->irq_status, addr);
 
@@ -115,29 +109,37 @@
 	return IRQ_HANDLED;
 }
 
+static void mtk_vcodec_enc_reset_handler(void *priv)
+{
+	struct mtk_vcodec_dev *dev = priv;
+	struct mtk_vcodec_ctx *ctx;
+
+	mtk_v4l2_debug(0, "Watchdog timeout!!");
+
+	mutex_lock(&dev->dev_mutex);
+	list_for_each_entry(ctx, &dev->ctx_list, list) {
+		ctx->state = MTK_STATE_ABORT;
+		mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT",
+				ctx->id);
+	}
+	mutex_unlock(&dev->dev_mutex);
+}
+
 static int fops_vcodec_open(struct file *file)
 {
 	struct mtk_vcodec_dev *dev = video_drvdata(file);
 	struct mtk_vcodec_ctx *ctx = NULL;
-	struct mtk_video_enc_buf *mtk_buf = NULL;
-	struct vb2_queue *src_vq;
 	int ret = 0;
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
-	mtk_buf = kzalloc(sizeof(*mtk_buf), GFP_KERNEL);
-	if (!mtk_buf) {
-		kfree(ctx);
-		return -ENOMEM;
-	}
 
 	mutex_lock(&dev->dev_mutex);
 	/*
 	 * Use simple counter to uniquely identify this context. Only
 	 * used for logging.
 	 */
-	ctx->enc_flush_buf = mtk_buf;
 	ctx->id = dev->id_counter++;
 	v4l2_fh_init(&ctx->fh, video_devdata(file));
 	file->private_data = &ctx->fh;
@@ -161,19 +163,14 @@
 				ret);
 		goto err_m2m_ctx_init;
 	}
-	src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
-		V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-	ctx->enc_flush_buf->vb.vb2_buf.vb2_queue = src_vq;
-	ctx->enc_flush_buf->lastframe = EOS;
-	ctx->enc_flush_buf->vb.vb2_buf.planes[0].bytesused = 1;
 	mtk_vcodec_enc_set_default_params(ctx);
 
 	if (v4l2_fh_is_singular(&ctx->fh)) {
 		/*
-		 * load fireware to checks if it was loaded already and
+		 * vpu_load_firmware checks if it was loaded already and
 		 * does nothing in that case
 		 */
-		ret = mtk_vcodec_fw_load_firmware(dev->ipi_msg_handle);
+		ret = vpu_load_firmware(dev->vpu_plat_dev);
 		if (ret < 0) {
 			/*
 			 * Return 0 if downloading firmware successfully,
@@ -183,7 +180,8 @@
 			goto err_load_fw;
 		}
 
-		dev->dec_capability = mtk_vcodec_fw_get_venc_capa(dev->ipi_msg_handle);
+		dev->enc_capability =
+			vpu_get_venc_hw_capa(dev->vpu_plat_dev);
 		mtk_v4l2_debug(0, "encoder capability %x", dev->enc_capability);
 	}
 
@@ -205,7 +203,6 @@
 err_ctrls_setup:
 	v4l2_fh_del(&ctx->fh);
 	v4l2_fh_exit(&ctx->fh);
-	kfree(ctx->enc_flush_buf);
 	kfree(ctx);
 	mutex_unlock(&dev->dev_mutex);
 
@@ -220,15 +217,13 @@
 	mtk_v4l2_debug(1, "[%d] encoder", ctx->id);
 	mutex_lock(&dev->dev_mutex);
 
-	mtk_vcodec_enc_empty_queues(file, ctx);
-	v4l2_m2m_ctx_release(ctx->m2m_ctx);
 	mtk_vcodec_enc_release(ctx);
 	v4l2_fh_del(&ctx->fh);
 	v4l2_fh_exit(&ctx->fh);
 	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
 
 	list_del_init(&ctx->list);
-	kfree(ctx->enc_flush_buf);
 	kfree(ctx);
 	mutex_unlock(&dev->dev_mutex);
 	return 0;
@@ -243,62 +238,12 @@
 	.mmap		= v4l2_m2m_fop_mmap,
 };
 
-static int mtk_vcodec_enc_suspend(struct device *pDev)
-{
-	int val = 0;
-
-	val = down_trylock(&venc_dev->enc_sem);
-	if (val == 1) {
-		mtk_v4l2_err("fail due to videocodec activity");
-		return -EBUSY;
-	}
-	up(&venc_dev->enc_sem);
-	mtk_v4l2_debug(1, "done");
-	return 0;
-}
-static int mtk_vcodec_enc_resume(struct device *pDev)
-{
-	mtk_v4l2_debug(1, "done");
-	return 0;
-}
-static int mtk_vcodec_enc_suspend_notifier(struct notifier_block *nb,
-					unsigned long action, void *data)
-{
-	int wait_cnt = 0;
-	int val = 0;
-
-	mtk_v4l2_debug(1, "action = %ld", action);
-	switch (action) {
-	case PM_SUSPEND_PREPARE:
-		venc_dev->is_codec_suspending = 1;
-		do {
-			usleep_range(10000, 20000);
-			wait_cnt++;
-			if (wait_cnt > 5) {
-				mtk_v4l2_err("waiting fail");
-				return NOTIFY_DONE;
-			}
-			val = down_trylock(&venc_dev->enc_sem);
-		} while (val == 1);
-		up(&venc_dev->enc_sem);
-		return NOTIFY_OK;
-	case PM_POST_SUSPEND:
-		venc_dev->is_codec_suspending = 0;
-		return NOTIFY_OK;
-	default:
-		return NOTIFY_DONE;
-	}
-	return NOTIFY_DONE;
-}
 static int mtk_vcodec_probe(struct platform_device *pdev)
 {
 	struct mtk_vcodec_dev *dev;
 	struct video_device *vfd_enc;
 	struct resource *res;
-	phandle rproc_phandle;
-	enum mtk_vcodec_fw_type fw_type;
-	struct mtk_vcodec_pm *pm;
-	int i, ret;
+	int i, j, ret;
 
 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
 	if (!dev)
@@ -307,70 +252,31 @@
 	INIT_LIST_HEAD(&dev->ctx_list);
 	dev->plat_dev = pdev;
 
-	dev->vdec_pdata = of_device_get_match_data(&pdev->dev);
-	if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
-				  &rproc_phandle)) {
-		fw_type = VPU;
-	} else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp",
-				  &rproc_phandle)) {
-		fw_type = SCP;
-	} else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vcu",
-				  &rproc_phandle)){
-		fw_type = VCU;
-	} else {
-		mtk_v4l2_err("Could not get vdec IPI device1");
+	dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev);
+	if (dev->vpu_plat_dev == NULL) {
+		mtk_v4l2_err("[VPU] vpu device in not ready");
 		return -EPROBE_DEFER;
 	}
 
-	dev->ipi_msg_handle = mtk_vcodec_fw_select(dev, fw_type, rproc_phandle,
-						   VPU_RST_ENC);
-	if (dev->ipi_msg_handle == NULL)
-		return -EINVAL;
+	vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_enc_reset_handler,
+				dev, VPU_RST_ENC);
 
-	dev->venc_pdata = of_device_get_match_data(&pdev->dev);
 	ret = mtk_vcodec_init_enc_pm(dev);
 	if (ret < 0) {
-		mtk_v4l2_err("Failed to get mt vcodec clock source!");
+		dev_err(&pdev->dev, "Failed to get mt vcodec clock source!");
 		return ret;
 	}
-	pm = &dev->pm;
-	pm->chip_node = of_find_compatible_node(NULL,
-		NULL, "mediatek,venc_gcon");
-	if (pm->chip_node) {
-		for (i = VENC_SYS; i < NUM_MAX_VENC_REG_BASE; i++) {
-			res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-			if (res == NULL) {
-				mtk_v4l2_err("get memory resource failed.");
-				ret = -ENXIO;
-				goto err_res;
-			}
-			dev->enc_reg_base[i] =
-				devm_ioremap_resource(&pdev->dev, res);
-			if (IS_ERR((__force void *)dev->enc_reg_base[i])) {
-				ret = PTR_ERR(
-					(__force void *)dev->enc_reg_base[i]);
-				goto err_res;
-			}
-			mtk_v4l2_debug(2, "reg[%d] base=0x%p",
-				i, dev->enc_reg_base[i]);
-		}
-	} else {
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (res == NULL) {
-			mtk_v4l2_err("get memory resource failed\n");
-			ret = -ENXIO;
+
+	for (i = VENC_SYS, j = 0; i < NUM_MAX_VCODEC_REG_BASE; i++, j++) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, j);
+		dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR((__force void *)dev->reg_base[i])) {
+			ret = PTR_ERR((__force void *)dev->reg_base[i]);
 			goto err_res;
 		}
-		dev->enc_reg_base[VENC_SYS] =
-			devm_ioremap_resource(&pdev->dev, res);
-		if (IS_ERR((__force void *)dev->enc_reg_base[VENC_SYS])) {
-			ret = PTR_ERR(
-				(__force void *)dev->enc_reg_base[VENC_SYS]);
-			goto err_res;
-		}
-		mtk_v4l2_debug(2, "reg[%d] base=0x%p",
-			VENC_SYS, dev->enc_reg_base[VENC_SYS]);
+		mtk_v4l2_debug(2, "reg[%d] base=0x%p", i, dev->reg_base[i]);
 	}
+
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (res == NULL) {
 		dev_err(&pdev->dev, "failed to get irq resource");
@@ -389,27 +295,23 @@
 		ret = -EINVAL;
 		goto err_res;
 	}
-	disable_irq(dev->enc_irq);
 
-	if (dev->venc_pdata->supports_vp8) {
-		dev->enc_lt_irq = platform_get_irq(pdev, 1);
-		ret = devm_request_irq(&pdev->dev,
-				       dev->enc_lt_irq,
-				       mtk_vcodec_enc_lt_irq_handler,
-				       0, pdev->name, dev);
-		if (ret) {
-			dev_err(&pdev->dev,
-				"Failed to install dev->enc_lt_irq %d (%d)",
-				dev->enc_lt_irq, ret);
-			ret = -EINVAL;
-			goto err_res;
-		}
-		disable_irq(dev->enc_lt_irq); /* VENC_LT */
+	dev->enc_lt_irq = platform_get_irq(pdev, 1);
+	ret = devm_request_irq(&pdev->dev,
+			       dev->enc_lt_irq, mtk_vcodec_enc_lt_irq_handler,
+			       0, pdev->name, dev);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Failed to install dev->enc_lt_irq %d (%d)",
+			dev->enc_lt_irq, ret);
+		ret = -EINVAL;
+		goto err_res;
 	}
 
+	disable_irq(dev->enc_irq);
+	disable_irq(dev->enc_lt_irq); /* VENC_LT */
+	mutex_init(&dev->enc_mutex);
 	mutex_init(&dev->dev_mutex);
-	sema_init(&dev->enc_sem, 1);
-	mutex_init(&dev->enc_dvfs_mutex);
 	spin_lock_init(&dev->irqlock);
 
 	snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s",
@@ -471,9 +373,6 @@
 	mtk_v4l2_debug(0, "encoder registered as /dev/video%d",
 			vfd_enc->num);
 
-	pm_notifier(mtk_vcodec_enc_suspend_notifier, 0);
-	dev->is_codec_suspending = 0;
-	venc_dev = dev;
 	return 0;
 
 err_enc_reg:
@@ -489,26 +388,8 @@
 	return ret;
 }
 
-static const struct mtk_vcodec_enc_pdata mt8173_pdata = {
-	.supports_vp8 = true,
-};
-
-static const struct mtk_vcodec_enc_pdata mt8183_pdata = {
-	.uses_ext = true,
-};
-
-static const struct mtk_vcodec_enc_pdata mt6779_pdata = {
-	.uses_ext = false,
-};
-static const struct mtk_vcodec_enc_pdata mt2712_pdata = {
-	.uses_ext = false,
-};
-
 static const struct of_device_id mtk_vcodec_enc_match[] = {
-	{.compatible = "mediatek,mt8173-vcodec-enc", .data = &mt8173_pdata},
-	{.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata},
-	{.compatible = "mediatek,mt2712-vcodec-enc", .data = &mt2712_pdata},
-	{.compatible = "mediatek,venc_gcon", .data = &mt6779_pdata},
+	{.compatible = "mediatek,mt8173-vcodec-enc",},
 	{},
 };
 MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match);
@@ -531,16 +412,11 @@
 	return 0;
 }
 
-static const struct dev_pm_ops mtk_vcodec_enc_pm_ops = {
-	.suspend = mtk_vcodec_enc_suspend,
-	.resume = mtk_vcodec_enc_resume,
-};
 static struct platform_driver mtk_vcodec_enc_driver = {
 	.probe	= mtk_vcodec_probe,
 	.remove	= mtk_vcodec_enc_remove,
 	.driver	= {
 		.name	= MTK_VCODEC_ENC_NAME,
-		.pm	= &mtk_vcodec_enc_pm_ops,
 		.of_match_table = mtk_vcodec_enc_match,
 	},
 };
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
old mode 100644
new mode 100755
index 6dbcfad..7c02504
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
@@ -1,33 +1,35 @@
 /*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Tiffany Lin <tiffany.lin@mediatek.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
+* Copyright (c) 2016 MediaTek Inc.
+* Author: Tiffany Lin <tiffany.lin@mediatek.com>
+*
+* 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.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
 
 #include <linux/clk.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
+#include <soc/mediatek/smi.h>
 
 #include "mtk_vcodec_enc_pm.h"
 #include "mtk_vcodec_util.h"
+#include "mtk_vpu.h"
+
 
 int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
 {
+	struct device_node *node;
 	struct platform_device *pdev;
-	struct mtk_vcodec_pm *pm;
-	struct mtk_vcodec_clk *enc_clk;
-	struct mtk_vcodec_clk_info *clk_info;
-	int ret = 0, i = 0;
 	struct device *dev;
+	struct mtk_vcodec_pm *pm;
+	int ret = 0;
 
 	pdev = mtkdev->plat_dev;
 	pm = &mtkdev->pm;
@@ -35,84 +37,103 @@
 	pm->mtkdev = mtkdev;
 	pm->dev = &pdev->dev;
 	dev = &pdev->dev;
-	enc_clk = &pm->venc_clk;
+
+	node = of_parse_phandle(dev->of_node, "mediatek,larb", 0);
+	if (!node) {
+		mtk_v4l2_err("no mediatek,larb found");
+		return -ENODEV;
+	}
+	pdev = of_find_device_by_node(node);
+	of_node_put(node);
+	if (!pdev) {
+		mtk_v4l2_err("no mediatek,larb device found");
+		return -ENODEV;
+	}
+	pm->larbvenc = &pdev->dev;
+
+	node = of_parse_phandle(dev->of_node, "mediatek,larb", 1);
+	if (!node) {
+		mtk_v4l2_err("no mediatek,larb found");
+		return -ENODEV;
+	}
+
+	pdev = of_find_device_by_node(node);
+	of_node_put(node);
+	if (!pdev) {
+		mtk_v4l2_err("no mediatek,larb device found");
+		return -ENODEV;
+	}
+
+	pm->larbvenclt = &pdev->dev;
 	pdev = mtkdev->plat_dev;
 	pm->dev = &pdev->dev;
 
-	enc_clk->clk_num = of_property_count_strings(pdev->dev.of_node,
-		"clock-names");
-	if (enc_clk->clk_num > 0) {
-		enc_clk->clk_info = devm_kcalloc(&pdev->dev,
-			enc_clk->clk_num, sizeof(*clk_info),
-			GFP_KERNEL);
-		if (!enc_clk->clk_info)
-			return -ENOMEM;
-	} else {
-		mtk_v4l2_err("Failed to get venc clock count");
-		return -EINVAL;
+	pm->vencpll_d2 = devm_clk_get(&pdev->dev, "venc_sel_src");
+	if (IS_ERR(pm->vencpll_d2)) {
+		mtk_v4l2_err("devm_clk_get vencpll_d2 fail");
+		ret = PTR_ERR(pm->vencpll_d2);
 	}
 
-	for (i = 0; i < enc_clk->clk_num; i++) {
-		clk_info = &enc_clk->clk_info[i];
-		ret = of_property_read_string_index(pdev->dev.of_node,
-			"clock-names", i, &clk_info->clk_name);
-		if (ret) {
-			mtk_v4l2_err("venc failed to get clk name %d", i);
-			return ret;
-		}
-		clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
-			clk_info->clk_name);
-		if (IS_ERR(clk_info->vcodec_clk)) {
-			mtk_v4l2_err("venc devm_clk_get (%d)%s fail", i,
-				clk_info->clk_name);
-			return PTR_ERR(clk_info->vcodec_clk);
-		}
+	pm->venc_sel = devm_clk_get(&pdev->dev, "venc_sel");
+	if (IS_ERR(pm->venc_sel)) {
+		mtk_v4l2_err("devm_clk_get venc_sel fail");
+		ret = PTR_ERR(pm->venc_sel);
 	}
 
-	pm_runtime_enable(&pdev->dev);
+	pm->univpll1_d2 = devm_clk_get(&pdev->dev, "venc_lt_sel_src");
+	if (IS_ERR(pm->univpll1_d2)) {
+		mtk_v4l2_err("devm_clk_get univpll1_d2 fail");
+		ret = PTR_ERR(pm->univpll1_d2);
+	}
+
+	pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel");
+	if (IS_ERR(pm->venc_lt_sel)) {
+		mtk_v4l2_err("devm_clk_get venc_lt_sel fail");
+		ret = PTR_ERR(pm->venc_lt_sel);
+	}
+
 	return ret;
 }
 
-void mtk_vcodec_release_enc_pm(struct mtk_vcodec_dev *dev)
+void mtk_vcodec_release_enc_pm(struct mtk_vcodec_dev *mtkdev)
 {
-	pm_runtime_disable(dev->pm.dev);
 }
 
 
 void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm)
 {
-	struct mtk_vcodec_clk *enc_clk = &pm->venc_clk;
-	int ret, i = 0;
+	int ret;
 
-	ret = pm_runtime_get_sync(pm->dev);
+	ret = clk_prepare_enable(pm->venc_sel);
 	if (ret)
-		mtk_v4l2_err("pm_runtime_get_sync fail %d", ret);
+		mtk_v4l2_err("clk_prepare_enable fail %d", ret);
 
-	for (i = 0; i < enc_clk->clk_num; i++) {
-		ret = clk_prepare_enable(enc_clk->clk_info[i].vcodec_clk);
-		if (ret) {
-			mtk_v4l2_err("venc clk_prepare_enable %d %s fail %d", i,
-				enc_clk->clk_info[i].clk_name, ret);
-			goto clkerr;
-		}
-	}
+	ret = clk_set_parent(pm->venc_sel, pm->vencpll_d2);
+	if (ret)
+		mtk_v4l2_err("clk_set_parent fail %d", ret);
 
-	return;
-clkerr:
-	for (i -= 1; i >= 0; i--)
-		clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk);
-	return;
+	ret = clk_prepare_enable(pm->venc_lt_sel);
+	if (ret)
+		mtk_v4l2_err("clk_prepare_enable fail %d", ret);
+
+	ret = clk_set_parent(pm->venc_lt_sel, pm->univpll1_d2);
+	if (ret)
+		mtk_v4l2_err("clk_set_parent fail %d", ret);
+
+	ret = mtk_smi_larb_get(pm->larbvenc);
+	if (ret)
+		mtk_v4l2_err("mtk_smi_larb_get larb3 fail %d", ret);
+
+	ret = mtk_smi_larb_get(pm->larbvenclt);
+	if (ret)
+		mtk_v4l2_err("mtk_smi_larb_get larb4 fail %d", ret);
+
 }
 
 void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm)
 {
-	struct mtk_vcodec_clk *enc_clk = &pm->venc_clk;
-	int ret, i = 0;
-
-	ret = pm_runtime_put_sync(pm->dev);
-	if (ret)
-		mtk_v4l2_err("pm_runtime_put_sync fail %d", ret);
-
-	for (i = enc_clk->clk_num - 1; i >= 0; i--)
-		clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk);
+	mtk_smi_larb_put(pm->larbvenc);
+	mtk_smi_larb_put(pm->larbvenclt);
+	clk_disable_unprepare(pm->venc_lt_sel);
+	clk_disable_unprepare(pm->venc_sel);
 }
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
old mode 100644
new mode 100755
index 3d22167..0c28d0b
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
@@ -17,6 +17,7 @@
 
 #include "mtk_vcodec_drv.h"
 #include "mtk_vcodec_util.h"
+#include "mtk_vpu.h"
 
 /* For encoder, this will enable logs in venc/*/
 bool mtk_vcodec_dbg;
@@ -33,25 +34,13 @@
 {
 	struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
 
-	if (!data || reg_idx >= NUM_MAX_VDEC_REG_BASE) {
+	if (!data || reg_idx >= NUM_MAX_VCODEC_REG_BASE) {
 		mtk_v4l2_err("Invalid arguments, reg_idx=%d", reg_idx);
 		return NULL;
 	}
 	return ctx->dev->reg_base[reg_idx];
 }
 EXPORT_SYMBOL(mtk_vcodec_get_reg_addr);
-void __iomem *mtk_vcodec_get_enc_reg_addr(struct mtk_vcodec_ctx *data,
-	unsigned int reg_idx)
-{
-	struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
-
-	if (!data || reg_idx >= NUM_MAX_VENC_REG_BASE) {
-		mtk_v4l2_err("Invalid arguments, reg_idx=%d", reg_idx);
-		return NULL;
-	}
-	return ctx->dev->enc_reg_base[reg_idx];
-}
-EXPORT_SYMBOL(mtk_vcodec_get_enc_reg_addr);
 
 int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
 			struct mtk_vcodec_mem *mem)
@@ -61,12 +50,15 @@
 	struct device *dev = &ctx->dev->plat_dev->dev;
 
 	mem->va = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL);
+
 	if (!mem->va) {
 		mtk_v4l2_err("%s dma_alloc size=%ld failed!", dev_name(dev),
 			     size);
 		return -ENOMEM;
 	}
 
+	memset(mem->va, 0, size);
+
 	mtk_v4l2_debug(3, "[%d]  - va      = %p", ctx->id, mem->va);
 	mtk_v4l2_debug(3, "[%d]  - dma     = 0x%lx", ctx->id,
 		       (unsigned long)mem->dma_addr);
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
old mode 100644
new mode 100755
index 5e5b865..06c254f
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
@@ -20,32 +20,9 @@
 #include <linux/dma-direction.h>
 
 struct mtk_vcodec_mem {
-	size_t length;
 	size_t size;
-	size_t data_offset;
 	void *va;
 	dma_addr_t dma_addr;
-	struct dma_buf *dmabuf;
-	__u32 flags;
-	__u32 index;
-};
-
-struct mtk_vcodec_fb {
-	size_t size;
-	dma_addr_t dma_addr;
-};
-/**
- * enum flags  - decoder different operation types
- * @NO_CAHCE_FLUSH	: no need to proceed cache flush
- * @NO_CAHCE_INVALIDATE	: no need to proceed cache invalidate
- * @CROP_CHANGED	: frame buffer crop changed
- * @REF_FREED	: frame buffer is reference freed
- */
-enum mtk_vcodec_flags {
-	NO_CAHCE_CLEAN = 1,
-	NO_CAHCE_INVALIDATE = 1 << 1,
-	CROP_CHANGED = 1 << 2,
-	REF_FREED = 1 << 3
 };
 
 struct mtk_vcodec_ctx;
@@ -63,7 +40,7 @@
 	pr_err("[MTK_VCODEC][ERROR][%d]: %s() " fmt "\n",		\
 	       ((struct mtk_vcodec_ctx *)h->ctx)->id, __func__, ##args)
 
-#define DEBUG   1
+
 #if defined(DEBUG)
 
 #define mtk_v4l2_debug(level, fmt, args...)				 \
@@ -101,8 +78,6 @@
 
 void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data,
 				unsigned int reg_idx);
-void __iomem *mtk_vcodec_get_enc_reg_addr(struct mtk_vcodec_ctx *data,
-	unsigned int reg_idx);
 int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
 				struct mtk_vcodec_mem *mem);
 void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
old mode 100644
new mode 100755
index 0bc8b9a..aa3ce41
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
@@ -55,7 +55,7 @@
 
 /**
  * struct h264_ring_fb_list - ring frame buffer list
- * @fb_list   : frame buffer array
+ * @fb_list   : frame buffer arrary
  * @read_idx  : read index
  * @write_idx : write index
  * @count     : buffer count in list
@@ -72,7 +72,7 @@
 /**
  * struct vdec_h264_dec_info - decode information
  * @dpb_sz		: decoding picture buffer size
- * @resolution_changed  : resolution change happen
+ * @resolution_changed  : resoltion change happen
  * @realloc_mv_buf	: flag to notify driver to re-allocate mv buffer
  * @reserved		: for 8 bytes alignment
  * @bs_dma		: Input bit-stream buffer dma address
@@ -238,8 +238,7 @@
 		}
 
 		mtk_vcodec_debug(inst, "[FB] put fb into free_list @(%p, %llx)",
-				 fb->fb_base[0].va,
-				 (u64)fb->fb_base[0].dma_addr);
+				 fb->base_y.va, (u64)fb->base_y.dma_addr);
 
 		list->fb_list[list->write_idx].vdec_fb_va = (u64)(uintptr_t)fb;
 		list->write_idx = (list->write_idx == H264_MAX_FB_NUM - 1) ?
@@ -254,8 +253,8 @@
 	*pic = inst->vsi->pic;
 	mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
 			 pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
-	mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
-			 pic->fb_sz[0], pic->fb_sz[1]);
+	mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz,
+			 pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz);
 }
 
 static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr)
@@ -275,7 +274,7 @@
 	mtk_vcodec_debug(inst, "sz=%d", *dpb_sz);
 }
 
-static int vdec_h264_init(struct mtk_vcodec_ctx *ctx)
+static int vdec_h264_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
 {
 	struct vdec_h264_inst *inst = NULL;
 	int err;
@@ -287,6 +286,7 @@
 	inst->ctx = ctx;
 
 	inst->vpu.id = IPI_VDEC_H264;
+	inst->vpu.dev = ctx->dev->vpu_plat_dev;
 	inst->vpu.ctx = ctx;
 	inst->vpu.handler = vpu_dec_ipi_handler;
 
@@ -303,7 +303,7 @@
 
 	mtk_vcodec_debug(inst, "H264 Instance >> %p", inst);
 
-	ctx->drv_handle = inst;
+	*h_vdec = (unsigned long)inst;
 	return 0;
 
 error_deinit:
@@ -314,7 +314,7 @@
 	return err;
 }
 
-static void vdec_h264_deinit(void *h_vdec)
+static void vdec_h264_deinit(unsigned long h_vdec)
 {
 	struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
 
@@ -339,8 +339,8 @@
 	return -1;
 }
 
-static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
-			    struct vdec_fb *fb, unsigned int  *res_chg)
+static int vdec_h264_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
+			    struct vdec_fb *fb, bool *res_chg)
 {
 	struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
 	struct vdec_vpu_inst *vpu = &inst->vpu;
@@ -352,9 +352,8 @@
 	unsigned int buf_sz;
 	unsigned int data[2];
 	uint64_t vdec_fb_va = (u64)(uintptr_t)fb;
-	uint64_t y_fb_dma = fb ? (u64)fb->fb_base[0].dma_addr : 0;
-	uint64_t c_fb_dma = fb ? (u64)fb->fb_base[1].dma_addr : 0;
-	*res_chg = VDEC_NO_CHANGE;
+	uint64_t y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
+	uint64_t c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
 
 	mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p",
 			 ++inst->num_nalu, y_fb_dma, c_fb_dma, fb);
@@ -394,9 +393,9 @@
 	if (err)
 		goto err_free_fb_out;
 
-	if (inst->vsi->dec.resolution_changed) {
+	*res_chg = inst->vsi->dec.resolution_changed;
+	if (*res_chg) {
 		struct vdec_pic_info pic;
-		*res_chg = VDEC_RES_CHANGE;
 
 		mtk_vcodec_debug(inst, "- resolution changed -");
 		get_pic_info(inst, &pic);
@@ -460,8 +459,8 @@
 	list->count--;
 }
 
-static int vdec_h264_get_param(void *h_vdec, enum vdec_get_param_type type,
-			       void *out)
+static int vdec_h264_get_param(unsigned long h_vdec,
+			       enum vdec_get_param_type type, void *out)
 {
 	struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
 
@@ -494,10 +493,16 @@
 	return 0;
 }
 
-const struct vdec_common_if vdec_h264_if = {
+static struct vdec_common_if vdec_h264_if = {
 	.init		= vdec_h264_init,
 	.decode		= vdec_h264_decode,
 	.get_param	= vdec_h264_get_param,
-	.set_param	= NULL,
 	.deinit		= vdec_h264_deinit,
 };
+
+struct vdec_common_if *get_h264_dec_comm_if(void);
+
+struct vdec_common_if *get_h264_dec_comm_if(void)
+{
+	return &vdec_h264_if;
+}
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
old mode 100644
new mode 100755
index 59a7eeb..3e84a76
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
@@ -120,7 +120,7 @@
 /**
  * struct vdec_vp8_vpu_inst - VPU instance for VP8 decode
  * @wq_hd	: Wait queue to wait VPU message ack
- * @signaled	: 1 - Host has received ack message from VPU, 0 - not receive
+ * @signaled	: 1 - Host has received ack message from VPU, 0 - not recevie
  * @failure	: VPU execution result status 0 - success, others - fail
  * @inst_addr	: VPU decoder instance address
  */
@@ -294,8 +294,8 @@
 
 	mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
 			 pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
-	mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
-			 pic->fb_sz[0], pic->fb_sz[1]);
+	mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz,
+			 pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz);
 }
 
 static void vp8_dec_finish(struct vdec_vp8_inst *inst)
@@ -310,7 +310,7 @@
 		list_for_each_entry(node, &inst->fb_use_list, list) {
 			struct vdec_fb *fb = (struct vdec_fb *)node->fb;
 
-			if (prev_y_dma == (uint64_t)fb->fb_base[0].dma_addr) {
+			if (prev_y_dma == (uint64_t)fb->base_y.dma_addr) {
 				list_move_tail(&node->list,
 					       &inst->fb_free_list);
 				break;
@@ -396,7 +396,7 @@
 	inst->vsi->dec.working_buf_dma = 0;
 }
 
-static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx)
+static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
 {
 	struct vdec_vp8_inst *inst;
 	int err;
@@ -408,6 +408,7 @@
 	inst->ctx = ctx;
 
 	inst->vpu.id = IPI_VDEC_VP8;
+	inst->vpu.dev = ctx->dev->vpu_plat_dev;
 	inst->vpu.ctx = ctx;
 	inst->vpu.handler = vpu_dec_ipi_handler;
 
@@ -426,7 +427,7 @@
 	get_hw_reg_base(inst);
 	mtk_vcodec_debug(inst, "VP8 Instance >> %p", inst);
 
-	ctx->drv_handle = inst;
+	*h_vdec = (unsigned long)inst;
 	return 0;
 
 error_deinit:
@@ -436,8 +437,8 @@
 	return err;
 }
 
-static int vdec_vp8_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
-			   struct vdec_fb *fb, unsigned int  *res_chg)
+static int vdec_vp8_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
+			   struct vdec_fb *fb, bool *res_chg)
 {
 	struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
 	struct vdec_vp8_dec_info *dec = &inst->vsi->dec;
@@ -447,7 +448,6 @@
 	int err = 0;
 	uint64_t y_fb_dma;
 	uint64_t c_fb_dma;
-	*res_chg = VDEC_NO_CHANGE;
 
 	/* bs NULL means flush decoder */
 	if (bs == NULL) {
@@ -455,8 +455,8 @@
 		return vpu_dec_reset(vpu);
 	}
 
-	y_fb_dma = fb ? (u64)fb->fb_base[0].dma_addr : 0;
-	c_fb_dma = fb ? (u64)fb->fb_base[1].dma_addr : 0;
+	y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
+	c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
 
 	mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx fb=%p",
 			 inst->frm_cnt, y_fb_dma, c_fb_dma, fb);
@@ -491,7 +491,7 @@
 
 	if (dec->resolution_changed) {
 		mtk_vcodec_debug(inst, "- resolution_changed -");
-		*res_chg = VDEC_RES_CHANGE;
+		*res_chg = true;
 		add_fb_to_free_list(inst, fb);
 		return 0;
 	}
@@ -513,7 +513,7 @@
 	mtk_vcodec_debug(inst, "\n - FRAME[%d] - show=%d\n", inst->frm_cnt,
 			 dec->show_frame);
 	inst->frm_cnt++;
-	*res_chg = VDEC_NO_CHANGE;
+	*res_chg = false;
 	return 0;
 
 error:
@@ -573,8 +573,8 @@
 			 cr->left, cr->top, cr->width, cr->height);
 }
 
-static int vdec_vp8_get_param(void *h_vdec, enum vdec_get_param_type type,
-			      void *out)
+static int vdec_vp8_get_param(unsigned long h_vdec,
+			      enum vdec_get_param_type type, void *out)
 {
 	struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
 
@@ -607,7 +607,7 @@
 	return 0;
 }
 
-static void vdec_vp8_deinit(void *h_vdec)
+static void vdec_vp8_deinit(unsigned long h_vdec)
 {
 	struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
 
@@ -618,10 +618,16 @@
 	kfree(inst);
 }
 
-const struct vdec_common_if vdec_vp8_if = {
+static struct vdec_common_if vdec_vp8_if = {
 	.init		= vdec_vp8_init,
 	.decode		= vdec_vp8_decode,
 	.get_param	= vdec_vp8_get_param,
-	.set_param	= NULL,
 	.deinit		= vdec_vp8_deinit,
 };
+
+struct vdec_common_if *get_vp8_dec_comm_if(void);
+
+struct vdec_common_if *get_vp8_dec_comm_if(void)
+{
+	return &vdec_vp8_if;
+}
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
old mode 100644
new mode 100755
index 232cade..bc8349b
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
@@ -227,7 +227,7 @@
 
 	list_for_each_entry(node, &inst->fb_use_list, list) {
 		fb = (struct vdec_fb *)node->fb;
-		if (fb->fb_base[0].va == addr) {
+		if (fb->base_y.va == addr) {
 			list_move_tail(&node->list,
 				       &inst->available_fb_node_list);
 			break;
@@ -275,11 +275,9 @@
 			if (!vp9_is_sf_ref_fb(inst,
 					      vsi->frm_bufs[ref_idx].buf.fb)) {
 				struct vdec_fb *fb;
-				struct vdec_fb *temp_fb;
 
-				temp_fb = vsi->frm_bufs[ref_idx].buf.fb;
 				fb = vp9_rm_from_fb_use_list(inst,
-				     temp_fb->fb_base[0].va);
+				     vsi->frm_bufs[ref_idx].buf.fb->base_y.va);
 				vp9_add_to_fb_free_list(inst, fb);
 			} else
 				vp9_free_sf_ref_fb(
@@ -297,11 +295,11 @@
 	struct vdec_vp9_vsi *vsi = inst->vsi;
 
 	for (i = 0; i < ARRAY_SIZE(vsi->sf_ref_fb); i++) {
-		if (vsi->sf_ref_fb[i].fb.fb_base[0].va) {
+		if (vsi->sf_ref_fb[i].fb.base_y.va) {
 			mtk_vcodec_mem_free(inst->ctx,
-				&vsi->sf_ref_fb[i].fb.fb_base[0]);
+				&vsi->sf_ref_fb[i].fb.base_y);
 			mtk_vcodec_mem_free(inst->ctx,
-				&vsi->sf_ref_fb[i].fb.fb_base[1]);
+				&vsi->sf_ref_fb[i].fb.base_c);
 			vsi->sf_ref_fb[i].used = 0;
 		}
 	}
@@ -322,7 +320,7 @@
 	for (idx = 0;
 		idx < ARRAY_SIZE(vsi->sf_ref_fb);
 		idx++) {
-		if (vsi->sf_ref_fb[idx].fb.fb_base[0].va &&
+		if (vsi->sf_ref_fb[idx].fb.base_y.va &&
 		    vsi->sf_ref_fb[idx].used == 0) {
 			return idx;
 		}
@@ -331,7 +329,7 @@
 	for (idx = 0;
 		idx < ARRAY_SIZE(vsi->sf_ref_fb);
 		idx++) {
-		if (vsi->sf_ref_fb[idx].fb.fb_base[0].va == NULL)
+		if (vsi->sf_ref_fb[idx].fb.base_y.va == NULL)
 			break;
 	}
 
@@ -340,7 +338,7 @@
 		return -1;
 	}
 
-	mem_basy_y = &vsi->sf_ref_fb[idx].fb.fb_base[0];
+	mem_basy_y = &vsi->sf_ref_fb[idx].fb.base_y;
 	mem_basy_y->size = vsi->buf_sz_y_bs +
 		vsi->buf_len_sz_y;
 
@@ -349,7 +347,7 @@
 		return -1;
 	}
 
-	mem_basy_c = &vsi->sf_ref_fb[idx].fb.fb_base[1];
+	mem_basy_c = &vsi->sf_ref_fb[idx].fb.base_c;
 	mem_basy_c->size = vsi->buf_sz_c_bs +
 		vsi->buf_len_sz_c;
 
@@ -482,14 +480,14 @@
 		 * buffer
 		 */
 		if ((frm_to_show->fb != NULL) &&
-			(inst->cur_fb->fb_base[0].size >=
-			frm_to_show->fb->fb_base[0].size)) {
-			memcpy((void *)inst->cur_fb->fb_base[0].va,
-				(void *)frm_to_show->fb->fb_base[0].va,
+			(inst->cur_fb->base_y.size >=
+			frm_to_show->fb->base_y.size)) {
+			memcpy((void *)inst->cur_fb->base_y.va,
+				(void *)frm_to_show->fb->base_y.va,
 				vsi->buf_w *
 				vsi->buf_h);
-			memcpy((void *)inst->cur_fb->fb_base[1].va,
-				(void *)frm_to_show->fb->fb_base[1].va,
+			memcpy((void *)inst->cur_fb->base_c.va,
+				(void *)frm_to_show->fb->base_c.va,
 				vsi->buf_w *
 				vsi->buf_h / 2);
 		} else {
@@ -499,9 +497,9 @@
 			 */
 			if (frm_to_show->fb != NULL)
 				mtk_vcodec_err(inst,
-					"inst->cur_fb->fb_base[0].size=%zu, frm_to_show->fb.fb_base[0].size=%zu",
-					inst->cur_fb->fb_base[0].size,
-					frm_to_show->fb->fb_base[0].size);
+					"inst->cur_fb->base_y.size=%zu, frm_to_show->fb.base_y.size=%zu",
+					inst->cur_fb->base_y.size,
+					frm_to_show->fb->base_y.size);
 		}
 		if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) {
 			if (vsi->show_frame)
@@ -523,7 +521,7 @@
 			struct vdec_fb *fb;
 
 			fb = vp9_rm_from_fb_use_list(inst,
-			vsi->frm_bufs[vsi->new_fb_idx].buf.fb->fb_base[0].va);
+			vsi->frm_bufs[vsi->new_fb_idx].buf.fb->base_y.va);
 
 			vp9_add_to_fb_free_list(inst, fb);
 		} else {
@@ -704,8 +702,10 @@
 
 static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic)
 {
-	pic->fb_sz[0] = inst->vsi->buf_sz_y_bs + inst->vsi->buf_len_sz_y;
-	pic->fb_sz[1] = inst->vsi->buf_sz_c_bs + inst->vsi->buf_len_sz_c;
+	pic->y_bs_sz = inst->vsi->buf_sz_y_bs;
+	pic->c_bs_sz = inst->vsi->buf_sz_c_bs;
+	pic->y_len_sz = inst->vsi->buf_len_sz_y;
+	pic->c_len_sz = inst->vsi->buf_len_sz_c;
 
 	pic->pic_w = inst->vsi->pic_w;
 	pic->pic_h = inst->vsi->pic_h;
@@ -714,9 +714,8 @@
 
 	mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
 		 pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
-	mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
-		pic->fb_sz[0],
-		pic->fb_sz[1]);
+	mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz,
+		 pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz);
 }
 
 static void get_disp_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb)
@@ -767,7 +766,7 @@
 	return 0;
 }
 
-static void vdec_vp9_deinit(void *h_vdec)
+static void vdec_vp9_deinit(unsigned long h_vdec)
 {
 	struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
 	struct mtk_vcodec_mem *mem;
@@ -789,7 +788,7 @@
 	vp9_free_inst(inst);
 }
 
-static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx)
+static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
 {
 	struct vdec_vp9_inst *inst;
 
@@ -801,6 +800,7 @@
 	inst->ctx = ctx;
 
 	inst->vpu.id = IPI_VDEC_VP9;
+	inst->vpu.dev = ctx->dev->vpu_plat_dev;
 	inst->vpu.ctx = ctx;
 	inst->vpu.handler = vpu_dec_ipi_handler;
 
@@ -812,7 +812,7 @@
 	inst->vsi = (struct vdec_vp9_vsi *)inst->vpu.vsi;
 	init_all_fb_lists(inst);
 
-	ctx->drv_handle = inst;
+	(*h_vdec) = (unsigned long)inst;
 	return 0;
 
 err_deinit_inst:
@@ -821,8 +821,8 @@
 	return -EINVAL;
 }
 
-static int vdec_vp9_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
-		   struct vdec_fb *fb, unsigned int  *res_chg)
+static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
+		   struct vdec_fb *fb, bool *res_chg)
 {
 	int ret = 0;
 	struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
@@ -830,7 +830,7 @@
 	u32 data[3];
 	int i;
 
-	*res_chg = VDEC_NO_CHANGE;
+	*res_chg = false;
 
 	if ((bs == NULL) && (fb == NULL)) {
 		mtk_vcodec_debug(inst, "[EOS]");
@@ -944,7 +944,7 @@
 		}
 
 		if (vsi->resolution_changed) {
-			*res_chg = VDEC_RES_CHANGE;
+			*res_chg = true;
 			mtk_vcodec_debug(inst, "VDEC_ST_RESOLUTION_CHANGED");
 
 			ret = 0;
@@ -980,8 +980,8 @@
 			 cr->left, cr->top, cr->width, cr->height);
 }
 
-static int vdec_vp9_get_param(void *h_vdec, enum vdec_get_param_type type,
-			      void *out)
+static int vdec_vp9_get_param(unsigned long h_vdec,
+		enum vdec_get_param_type type, void *out)
 {
 	struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
 	int ret = 0;
@@ -1011,10 +1011,16 @@
 	return ret;
 }
 
-const struct vdec_common_if vdec_vp9_if = {
+static struct vdec_common_if vdec_vp9_if = {
 	.init		= vdec_vp9_init,
 	.decode		= vdec_vp9_decode,
 	.get_param	= vdec_vp9_get_param,
-	.set_param  = NULL,
 	.deinit		= vdec_vp9_deinit,
 };
+
+struct vdec_common_if *get_vp9_dec_comm_if(void);
+
+struct vdec_common_if *get_vp9_dec_comm_if(void)
+{
+	return &vdec_vp9_if;
+}
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
old mode 100644
new mode 100755
index c0f921a..7e4c1a9
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
@@ -15,6 +15,8 @@
 #ifndef _VDEC_DRV_BASE_
 #define _VDEC_DRV_BASE_
 
+#include "mtk_vcodec_drv.h"
+
 #include "vdec_drv_if.h"
 
 struct vdec_common_if {
@@ -23,7 +25,7 @@
 	 * @ctx     : [in] mtk v4l2 context
 	 * @h_vdec  : [out] driver handle
 	 */
-	int (*init)(struct mtk_vcodec_ctx *ctx);
+	int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec);
 
 	/**
 	 * (*decode)() - trigger decode
@@ -32,8 +34,8 @@
 	 * @fb      : [in] frame buffer to store decoded frame
 	 * @res_chg : [out] resolution change happen
 	 */
-	int (*decode)(void *h_vdec, struct mtk_vcodec_mem *bs,
-		      struct vdec_fb *fb, unsigned int  *res_chg);
+	int (*decode)(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
+		      struct vdec_fb *fb, bool *res_chg);
 
 	/**
 	 * (*get_param)() - get driver's parameter
@@ -41,23 +43,14 @@
 	 * @type   : [in] input parameter type
 	 * @out    : [out] buffer to store query result
 	 */
-	int (*get_param)(void *h_vdec, enum vdec_get_param_type type,
+	int (*get_param)(unsigned long h_vdec, enum vdec_get_param_type type,
 			 void *out);
 
 	/**
-	 * (*set_param)() - set driver's parameter
-	 * @h_vdec : [in] driver handle
-	 * @type   : [in] input parameter type
-	 * @in     : [in] buffer to store query
-	 */
-	int (*set_param)(void  *h_vdec, enum vdec_set_param_type type,
-					 void *in);
-
-	/**
 	 * (*deinit)() - deinitialize driver.
 	 * @h_vdec : [in] driver handle to be deinit
 	 */
-	void (*deinit)(void *h_vdec);
+	void (*deinit)(unsigned long h_vdec);
 };
 
 #endif
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
old mode 100644
new mode 100755
index 2b281eb..5ffc468
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
@@ -21,78 +21,33 @@
 #include "mtk_vcodec_dec.h"
 #include "vdec_drv_base.h"
 #include "mtk_vcodec_dec_pm.h"
-
-#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCU)
-#include "mtk_vcu.h"
-const struct vdec_common_if *get_dec_common_if(void);
-#endif
-
-#ifdef CONFIG_VIDEO_MEDIATEK_VPU
 #include "mtk_vpu.h"
-extern const struct vdec_common_if vdec_h264_if;
-extern const struct vdec_common_if vdec_vp8_if;
-extern const struct vdec_common_if vdec_vp9_if;
-extern const struct vdec_common_if vdec_h264_slice_if;
-#endif
 
+const struct vdec_common_if *get_h264_dec_comm_if(void);
+const struct vdec_common_if *get_vp8_dec_comm_if(void);
+const struct vdec_common_if *get_vp9_dec_comm_if(void);
 
 int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
 {
 	int ret = 0;
 
-#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCU)
 	switch (fourcc) {
 	case V4L2_PIX_FMT_H264:
-	case V4L2_PIX_FMT_H265:
-	case V4L2_PIX_FMT_HEIF:
-	case V4L2_PIX_FMT_MPEG1:
-	case V4L2_PIX_FMT_MPEG2:
-	case V4L2_PIX_FMT_MPEG4:
-	case V4L2_PIX_FMT_H263:
-	case V4L2_PIX_FMT_S263:
-	case V4L2_PIX_FMT_XVID:
-	case V4L2_PIX_FMT_DIVX:
-	case V4L2_PIX_FMT_DIVX3:
-	case V4L2_PIX_FMT_DIVX4:
-	case V4L2_PIX_FMT_DIVX5:
-	case V4L2_PIX_FMT_DIVX6:
+		ctx->dec_if = get_h264_dec_comm_if();
+		break;
 	case V4L2_PIX_FMT_VP8:
+		ctx->dec_if = get_vp8_dec_comm_if();
+		break;
 	case V4L2_PIX_FMT_VP9:
-	case V4L2_PIX_FMT_WMV1:
-	case V4L2_PIX_FMT_WMV2:
-	case V4L2_PIX_FMT_WMV3:
-	case V4L2_PIX_FMT_WVC1:
-	case V4L2_PIX_FMT_WMVA:
-	case V4L2_PIX_FMT_RV30:
-	case V4L2_PIX_FMT_RV40:
-		ctx->dec_if = get_dec_common_if();
+		ctx->dec_if = get_vp9_dec_comm_if();
 		break;
 	default:
 		return -EINVAL;
 	}
-#endif
-#ifdef CONFIG_VIDEO_MEDIATEK_VPU
-	switch (fourcc) {
-	case V4L2_PIX_FMT_H264_SLICE:
-		ctx->dec_if = &vdec_h264_slice_if;
-		break;
-	case V4L2_PIX_FMT_H264:
-		ctx->dec_if = &vdec_h264_if;
-		break;
-	case V4L2_PIX_FMT_VP8:
-		ctx->dec_if = &vdec_vp8_if;
-		break;
-	case V4L2_PIX_FMT_VP9:
-		ctx->dec_if = &vdec_vp9_if;
-		break;
-	default:
-		return -EINVAL;
-	}
-#endif
 
 	mtk_vdec_lock(ctx);
 	mtk_vcodec_dec_clock_on(&ctx->dev->pm);
-	ret = ctx->dec_if->init(ctx);
+	ret = ctx->dec_if->init(ctx, &ctx->drv_handle);
 	mtk_vcodec_dec_clock_off(&ctx->dev->pm);
 	mtk_vdec_unlock(ctx);
 
@@ -100,10 +55,10 @@
 }
 
 int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
-		   struct vdec_fb *fb, unsigned int  *res_chg)
+		   struct vdec_fb *fb, bool *res_chg)
 {
 	int ret = 0;
-	int i = 0;
+
 	if (bs) {
 		if ((bs->dma_addr & 63) != 0) {
 			mtk_v4l2_err("bs dma_addr should 64 byte align");
@@ -112,21 +67,17 @@
 	}
 
 	if (fb) {
-		for (i = 0; i < fb->num_planes; i++) {
-			if ((fb->fb_base[i].dma_addr & 511UL) != 0UL) {
-				mtk_v4l2_err("fb addr should 512 byte align");
-				return -EINVAL;
-			}
+		if (((fb->base_y.dma_addr & 511) != 0) ||
+		    ((fb->base_c.dma_addr & 511) != 0)) {
+			mtk_v4l2_err("frame buffer dma_addr should 512 byte align");
+			return -EINVAL;
 		}
 	}
 
-
 	if (ctx->drv_handle == 0)
 		return -EIO;
 
-	mtk_vdec_pmqos_prelock(ctx);
 	mtk_vdec_lock(ctx);
-	mtk_vdec_pmqos_begin_frame(ctx);
 
 	mtk_vcodec_set_curr_ctx(ctx->dev, ctx);
 	mtk_vcodec_dec_clock_on(&ctx->dev->pm);
@@ -136,7 +87,6 @@
 	mtk_vcodec_dec_clock_off(&ctx->dev->pm);
 	mtk_vcodec_set_curr_ctx(ctx->dev, NULL);
 
-	mtk_vdec_pmqos_end_frame(ctx);
 	mtk_vdec_unlock(ctx);
 
 	return ret;
@@ -146,50 +96,14 @@
 		      void *out)
 {
 	int ret = 0;
-#ifdef CONFIG_VIDEO_MEDIATEK_VPU
+
 	if (ctx->drv_handle == 0)
 		return -EIO;
-#endif
 
-#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCU)
-	struct vdec_inst *inst = NULL;
-	int drv_handle_exist = 1;
-
-	if (!ctx->drv_handle) {
-		inst = kzalloc(sizeof(struct vdec_inst), GFP_KERNEL);
-		inst->ctx = ctx;
-		ctx->drv_handle = (void *)(inst);
-		ctx->dec_if = get_dec_common_if();
-		drv_handle_exist = 0;
-	}
-#endif
 	mtk_vdec_lock(ctx);
 	ret = ctx->dec_if->get_param(ctx->drv_handle, type, out);
 	mtk_vdec_unlock(ctx);
 
-#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCU)
-	if (!drv_handle_exist) {
-		kfree(inst);
-		ctx->drv_handle = 0;
-		ctx->dec_if = NULL;
-	}
-#endif
-	return ret;
-}
-
-int vdec_if_set_param(struct mtk_vcodec_ctx *ctx, enum vdec_set_param_type type,
-					  void *in)
-{
-	int ret = 0;
-
-	if (ctx->drv_handle == 0)
-		return -EIO;
-
-	mtk_vdec_lock(ctx);
-	if (ctx->dec_if->set_param)
-		ret = ctx->dec_if->set_param(ctx->drv_handle, type, in);
-	mtk_vdec_unlock(ctx);
-
 	return ret;
 }
 
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_if.h
old mode 100644
new mode 100755
index 682f50b..ded1154
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_if.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_drv_if.h
@@ -19,24 +19,6 @@
 #include "mtk_vcodec_drv.h"
 #include "mtk_vcodec_dec.h"
 #include "mtk_vcodec_util.h"
-#include "vdec_ipi_msg.h"
-#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCU)
-#include "vdec_vcu_if.h"
-
-/**
- * struct vdec_inst - decoder instance
- * @num_nalu : how many nalus be decoded
- * @ctx      : point to mtk_vcodec_ctx
- * @vcu      : VCU instance
- * @vsi      : VCU shared information
- */
-struct vdec_inst {
-	unsigned int num_nalu;
-	struct mtk_vcodec_ctx *ctx;
-	struct vdec_vcu_inst vcu;
-	struct vdec_vsi *vsi;
-};
-#endif
 
 
 /**
@@ -51,6 +33,24 @@
 	FB_ST_FREE		= (1 << 1)
 };
 
+/* For GET_PARAM_DISP_FRAME_BUFFER and GET_PARAM_FREE_FRAME_BUFFER,
+ * the caller does not own the returned buffer. The buffer will not be
+ *				released before vdec_if_deinit.
+ * GET_PARAM_DISP_FRAME_BUFFER	: get next displayable frame buffer,
+ *				struct vdec_fb**
+ * GET_PARAM_FREE_FRAME_BUFFER	: get non-referenced framebuffer, vdec_fb**
+ * GET_PARAM_PIC_INFO		: get picture info, struct vdec_pic_info*
+ * GET_PARAM_CROP_INFO		: get crop info, struct v4l2_crop*
+ * GET_PARAM_DPB_SIZE		: get dpb size, unsigned int*
+ */
+enum vdec_get_param_type {
+	GET_PARAM_DISP_FRAME_BUFFER,
+	GET_PARAM_FREE_FRAME_BUFFER,
+	GET_PARAM_PIC_INFO,
+	GET_PARAM_CROP_INFO,
+	GET_PARAM_DPB_SIZE
+};
+
 /**
  * struct vdec_fb_node  - decoder frame buffer node
  * @list	: list to hold this node
@@ -89,7 +89,7 @@
  * Return: 0 on success. -EIO on unrecoverable error.
  */
 int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
-		   struct vdec_fb *fb, unsigned int  *res_chg);
+		   struct vdec_fb *fb, bool *res_chg);
 
 /**
  * vdec_if_get_param() - get driver's parameter
@@ -100,14 +100,4 @@
 int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
 		      void *out);
 
-/*
- * vdec_if_set_param - Set parameter to driver
- * @ctx : [in] v4l2 context
- * @type        : [in] input parameter type
- * @out : [in] input parameter
- * Return: 0 if setting param successfully, otherwise it is failed.
- */
-int vdec_if_set_param(struct mtk_vcodec_ctx *ctx,
-					  enum vdec_set_param_type type,
-					  void *in);
 #endif
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
old mode 100644
new mode 100755
index 627a0e1..5a8a629
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
@@ -16,56 +16,6 @@
 #ifndef _VDEC_IPI_MSG_H_
 #define _VDEC_IPI_MSG_H_
 
-#define MTK_MAX_DEC_CODECS_SUPPORT       (128)
-#define DEC_MAX_FB_NUM              VIDEO_MAX_FRAME
-#define DEC_MAX_BS_NUM              VIDEO_MAX_FRAME
-/**
- * enum vdec_src_chg_type - decoder src change type
- * @VDEC_NO_CHANGE      : no change
- * @VDEC_RES_CHANGE     : resolution change
- * @VDEC_REALLOC_MV_BUF : realloc mv buf
- * @VDEC_HW_NOT_SUPPORT : hw not support
- * @VDEC_NEED_MORE_OUTPUT_BUF: bs need more fm buffer to decode
- *          kernel should send the same bs buffer again with new fm buffer
- * @VDEC_CROP_CHANGED: notification to update frame crop info
- */
-enum vdec_src_chg_type {
-	VDEC_NO_CHANGE              = (0 << 0),
-	VDEC_RES_CHANGE             = (1 << 0),
-	VDEC_REALLOC_MV_BUF         = (1 << 1),
-	VDEC_HW_NOT_SUPPORT         = (1 << 2),
-	VDEC_NEED_SEQ_HEADER        = (1 << 3),
-	VDEC_NEED_MORE_OUTPUT_BUF   = (1 << 4),
-	VDEC_CROP_CHANGED           = (1 << 5),
-};
-
-/*
- * enum vdec_set_param_type -
- *                  The type of set parameter used in vdec_if_set_param()
- * (VCU related: If you change the order, you must also update the VCU codes.)
- * SET_PARAM_DECODE_MODE: set decoder mode
- * SET_PARAM_FRAME_SIZE: set container frame size
- * SET_PARAM_SET_FIXED_MAX_OUTPUT_BUFFER: set fixed maximum buffer size
- * SET_PARAM_UFO_MODE: set UFO mode
- * SET_PARAM_CRC_PATH: set CRC path used for UT
- * SET_PARAM_GOLDEN_PATH: set Golden YUV path used for UT
- * SET_PARAM_FB_NUM_PLANES                      : frame buffer plane count
- */
-enum vdec_set_param_type {
-	SET_PARAM_DECODE_MODE,
-	SET_PARAM_FRAME_SIZE,
-	SET_PARAM_SET_FIXED_MAX_OUTPUT_BUFFER,
-	SET_PARAM_UFO_MODE,
-	SET_PARAM_CRC_PATH,
-	SET_PARAM_GOLDEN_PATH,
-	SET_PARAM_FB_NUM_PLANES,
-	SET_PARAM_WAIT_KEY_FRAME,
-	SET_PARAM_NAL_SIZE_LENGTH,
-	SET_PARAM_OPERATING_RATE,
-	SET_PARAM_FREE_FRAME_BUFQ_COUNT,
-	SET_PARAM_TOTAL_FRAME_BUFQ_COUNT
-};
-
 /**
  * enum vdec_ipi_msgid - message id between AP and VPU
  * @AP_IPIMSG_XXX	: AP to VPU cmd message id
@@ -77,56 +27,14 @@
 	AP_IPIMSG_DEC_END = 0xA002,
 	AP_IPIMSG_DEC_DEINIT = 0xA003,
 	AP_IPIMSG_DEC_RESET = 0xA004,
-	AP_IPIMSG_DEC_SET_PARAM = 0xA005,
-	AP_IPIMSG_DEC_QUERY_CAP = 0xA006,
 
 	VPU_IPIMSG_DEC_INIT_ACK = 0xB000,
 	VPU_IPIMSG_DEC_START_ACK = 0xB001,
 	VPU_IPIMSG_DEC_END_ACK = 0xB002,
 	VPU_IPIMSG_DEC_DEINIT_ACK = 0xB003,
 	VPU_IPIMSG_DEC_RESET_ACK = 0xB004,
-	VPU_IPIMSG_DEC_SET_PARAM_ACK = 0xB005,
-	VPU_IPIMSG_DEC_QUERY_CAP_ACK = 0xB006,
-
-	VPU_IPIMSG_DEC_WAITISR = 0xC000,
-	VPU_IPIMSG_DEC_GET_FRAME_BUFFER = 0xC001,
-	VPU_IPIMSG_DEC_CLOCK_ON = 0xC002,
-	VPU_IPIMSG_DEC_CLOCK_OFF = 0xC003
 };
 
-/* For GET_PARAM_DISP_FRAME_BUFFER and GET_PARAM_FREE_FRAME_BUFFER,
- * the caller does not own the returned buffer. The buffer will not be
- *                              released before vdec_if_deinit.
- * GET_PARAM_DISP_FRAME_BUFFER  : get next displayable frame buffer,
- *                              struct vdec_fb**
- * GET_PARAM_FREE_FRAME_BUFFER  : get non-referenced framebuffer, vdec_fb**
- * GET_PARAM_PIC_INFO           : get picture info, struct vdec_pic_info*
- * GET_PARAM_CROP_INFO          : get crop info, struct v4l2_crop*
- * GET_PARAM_DPB_SIZE           : get dpb size, __s32*
- * GET_PARAM_FRAME_INTERVAL     : get frame interval info*
- * GET_PARAM_ERRORMB_MAP        : get error mocroblock when decode error*
- * GET_PARAM_CAPABILITY_SUPPORTED_FORMATS: get codec supported format capability
- * GET_PARAM_CAPABILITY_FRAME_SIZES:
- *                       get codec supported frame size & alignment info
- */
-enum vdec_get_param_type {
-	GET_PARAM_DISP_FRAME_BUFFER,
-	GET_PARAM_FREE_FRAME_BUFFER,
-	GET_PARAM_FREE_BITSTREAM_BUFFER,
-	GET_PARAM_PIC_INFO,
-	GET_PARAM_CROP_INFO,
-	GET_PARAM_DPB_SIZE,
-	GET_PARAM_FRAME_INTERVAL,
-	GET_PARAM_ERRORMB_MAP,
-	GET_PARAM_CAPABILITY_SUPPORTED_FORMATS,
-	GET_PARAM_CAPABILITY_FRAME_SIZES,
-	GET_PARAM_COLOR_DESC,
-	GET_PARAM_ASPECT_RATIO,
-	GET_PARAM_PLATFORM_SUPPORTED_FIX_BUFFERS,
-	GET_PARAM_PLATFORM_SUPPORTED_FIX_BUFFERS_SVP,
-	GET_PARAM_INTERLACING,
-	GET_PARAM_CODEC_TYPE
-};
 /**
  * struct vdec_ap_ipi_cmd - generic AP to VPU ipi command format
  * @msg_id	: vdec_ipi_msgid
@@ -191,192 +99,5 @@
 	uint64_t ap_inst_addr;
 	uint32_t vpu_inst_addr;
 };
-/**
- * struct vdec_ap_ipi_set_param - for AP_IPIMSG_DEC_SET_PARAM
- * @msg_id        : AP_IPIMSG_DEC_SET_PARAM
- * @vpu_inst_addr : VPU decoder instance address
- * @id            : set param  type
- * @data          : param data
- */
-struct vdec_ap_ipi_set_param {
-	uint32_t msg_id;
-	uint32_t vpu_inst_addr;
-	uint32_t id;
-	uint32_t data[8];
-};
 
-/**
- * struct vdec_ap_ipi_query_cap - for AP_IPIMSG_DEC_QUERY_CAP
- * @msg_id        : AP_IPIMSG_DEC_QUERY_CAP
- * @id      : query capability type
- * @vdec_inst     : AP query data address
- */
-struct vdec_ap_ipi_query_cap {
-	uint32_t msg_id;
-	uint32_t id;
-#ifndef CONFIG_64BIT
-	union {
-		uint64_t ap_inst_addr_64;
-		uint32_t ap_inst_addr;
-	};
-	union {
-		uint64_t ap_data_addr_64;
-		uint32_t ap_data_addr;
-	};
-#else
-	uint64_t ap_inst_addr;
-	uint64_t ap_data_addr;
-#endif
-};
-
-/**
- * struct vdec_vpu_ipi_query_cap_ack - for VCU_IPIMSG_DEC_QUERY_CAP_ACK
- * @msg_id      : VPU_IPIMSG_DEC_QUERY_CAP_ACK
- * @status      : VPU exeuction result
- * @ap_data_addr   : AP query data address
- * @vpu_data_addr  : VCU query data address
- */
-struct vdec_vpu_ipi_query_cap_ack {
-	uint32_t msg_id;
-	int32_t status;
-#ifndef CONFIG_64BIT
-	union {
-		uint64_t ap_inst_addr_64;
-		uint32_t ap_inst_addr;
-	};
-	uint32_t id;
-	union {
-		uint64_t ap_data_addr_64;
-		uint32_t ap_data_addr;
-	};
-#else
-	uint64_t ap_inst_addr;
-	uint32_t id;
-	uint64_t ap_data_addr;
-#endif
-	uint32_t vpu_data_addr;
-};
-/*
- * struct vdec_ipi_fb - decoder frame buffer information
- * @vdec_fb_va  : virtual address of struct vdec_fb
- * @y_fb_dma    : dma address of Y frame buffer
- * @c_fb_dma    : dma address of C frame buffer
- * @poc         : picture order count of frame buffer
- * @reserved    : for 8 bytes alignment
- */
-struct vdec_ipi_fb {
-	uint64_t vdec_fb_va;
-	uint64_t y_fb_dma;
-	uint64_t c_fb_dma;
-	int32_t poc;
-	uint32_t reserved;
-};
-
-/**
- * struct ring_bs_list - ring bitstream buffer list
- * @vdec_bs_va_list   : bitstream buffer arrary
- * @read_idx  : read index
- * @write_idx : write index
- * @count	  : buffer count in list
- */
-struct ring_bs_list {
-	uint64_t vdec_bs_va_list[DEC_MAX_BS_NUM];
-	int32_t read_idx;
-	int32_t write_idx;
-	int32_t count;
-	int32_t reserved;
-};
-
-/**
- * struct ring_fb_list - ring frame buffer list
- * @fb_list   : frame buffer arrary
- * @read_idx  : read index
- * @write_idx : write index
- * @count     : buffer count in list
- */
-struct ring_fb_list {
-	struct vdec_ipi_fb fb_list[DEC_MAX_FB_NUM];
-	int32_t read_idx;
-	int32_t write_idx;
-	int32_t count;
-	int32_t reserved;
-};
-/**
- * struct vdec_dec_info - decode information
- * @dpb_sz		: decoding picture buffer size
- * @vdec_changed_info  : some changed flags
- * @bs_dma		: Input bit-stream buffer dma address
- * @bs_fd               : Input bit-stream buffer dmabuf fd
- * @fb_dma		: Y frame buffer dma address
- * @fb_fd             : Y frame buffer dmabuf fd
- * @vdec_bs_va		: VDEC bitstream buffer struct virtual address
- * @vdec_fb_va		: VDEC frame buffer struct virtual address
- * @fb_num_planes	: frame buffer plane count
- * @reserved		: reserved variable for 64bit align
- */
-struct vdec_dec_info {
-	__u32 dpb_sz;
-	__u32 vdec_changed_info;
-	__u64 bs_dma;
-	__u64 bs_fd;
-	__u64 fb_dma[VIDEO_MAX_PLANES];
-	__u64 fb_fd[VIDEO_MAX_PLANES];
-	__u64 vdec_bs_va;
-	__u64 vdec_fb_va;
-	__u32 fb_num_planes;
-	__u32 index;
-	__u32 wait_key_frame;
-	__u32 error_map;
-	__u32 timestamp;
-	__u32 queued_frame_buf_count;
-};
-
-struct mtk_color_desc {
-	__u32	full_range;
-	__u32	color_primaries;
-	__u32	transform_character;
-	__u32	matrix_coeffs;
-	__u32	display_primaries_x[3];
-	__u32	display_primaries_y[3];
-	__u32	white_point_x;
-	__u32	white_point_y;
-	__u32	max_display_mastering_luminance;
-	__u32	min_display_mastering_luminance;
-	__u32	max_content_light_level;
-	__u32	max_pic_light_level;
-	__u32	is_hdr;
-};
-/**
- * struct vdec_vsi - shared memory for decode information exchange
- *                        between VCU and Host.
- *                        The memory is allocated by VCU and mapping to Host
- *                        in vpu_dec_init()
- * @ppl_buf_dma : HW working buffer ppl dma address
- * @mv_buf_dma  : HW working buffer mv dma address
- * @list_free   : free frame buffer ring list
- * @list_disp   : display frame buffer ring list
- * @dec         : decode information
- * @pic         : picture information
- * @crop        : crop information
- * @video_formats        : codec supported format info
- * @vdec_framesizes    : codec supported resolution info
- */
-struct vdec_vsi {
-	struct ring_bs_list list_free_bs;
-	struct ring_fb_list list_free;
-	struct ring_fb_list list_disp;
-	struct vdec_dec_info dec;
-	struct vdec_pic_info pic;
-	struct mtk_color_desc color_desc;
-	struct v4l2_rect crop;
-	struct mtk_video_fmt video_formats[MTK_MAX_DEC_CODECS_SUPPORT];
-	struct mtk_codec_framesizes vdec_framesizes[MTK_MAX_DEC_CODECS_SUPPORT];
-	uint32_t aspect_ratio;
-	uint32_t fix_buffers;
-	uint32_t fix_buffers_svp;
-	uint32_t interlacing;
-	uint32_t codec_type;
-	uint8_t crc_path[256];
-	uint8_t golden_path[256];
-};
 #endif
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
old mode 100644
new mode 100755
index be226c7..1abd14e
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
@@ -16,7 +16,6 @@
 #include "mtk_vcodec_util.h"
 #include "vdec_ipi_msg.h"
 #include "vdec_vpu_if.h"
-#include "mtk_vcodec_fw.h"
 
 static void handle_init_ack_msg(struct vdec_vpu_ipi_init_ack *msg)
 {
@@ -27,7 +26,7 @@
 
 	/* mapping VPU address to kernel virtual address */
 	/* the content in vsi is initialized to 0 in VPU */
-	vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->ipi_msg_handle, msg->vpu_inst_addr);
+	vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr);
 	vpu->inst_addr = msg->vpu_inst_addr;
 
 	mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr);
@@ -77,7 +76,7 @@
 	vpu->failure = 0;
 	vpu->signaled = 0;
 
-	err = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->ipi_msg_handle, vpu->id, msg, len, 2000);
+	err = vpu_ipi_send(vpu->dev, vpu->id, msg, len);
 	if (err) {
 		mtk_vcodec_err(vpu, "send fail vpu_id=%d msg_id=%X status=%d",
 			       vpu->id, *(uint32_t *)msg, err);
@@ -112,8 +111,7 @@
 
 	init_waitqueue_head(&vpu->wq);
 
-	err = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->ipi_msg_handle, vpu->id, vpu->handler,
-					 "vdec", NULL);
+	err = vpu_ipi_register(vpu->dev, vpu->id, vpu->handler, "vdec", NULL);
 	if (err != 0) {
 		mtk_vcodec_err(vpu, "vpu_ipi_register fail status=%d", err);
 		return err;
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
old mode 100644
new mode 100755
index 0c48003..cd37bb2
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
@@ -15,13 +15,11 @@
 #ifndef _VDEC_VPU_IF_H_
 #define _VDEC_VPU_IF_H_
 
-#include "mtk_vcodec_fw.h"
-
-struct mtk_vcodec_ctx;
+#include "mtk_vpu.h"
 
 /**
  * struct vdec_vpu_inst - VPU instance for video codec
- * @id      : ipi msg id for each decoder
+ * @ipi_id      : ipi id for each decoder
  * @vsi         : driver structure allocated by VPU side and shared to AP side
  *                for control and info share
  * @failure     : VPU execution result status, 0: success, others: fail
@@ -33,14 +31,15 @@
  * @handler     : ipi handler for each decoder
  */
 struct vdec_vpu_inst {
-	int id;
+	enum ipi_id id;
 	void *vsi;
 	int32_t failure;
 	uint32_t inst_addr;
 	unsigned int signaled;
 	struct mtk_vcodec_ctx *ctx;
+	struct platform_device *dev;
 	wait_queue_head_t wq;
-	mtk_vcodec_ipi_handler handler;
+	ipi_handler_t handler;
 };
 
 /**
@@ -63,7 +62,7 @@
 /**
  * vpu_dec_end - end decoding, basically the function will be invoked once
  *               when HW decoding done interrupt received successfully. The
- *               decoder in VPU will continue to do reference frame management
+ *               decoder in VPU will continute to do referene frame management
  *               and check if there is a new decoded frame available to display.
  *
  * @vpu : instance for vdec_vpu_inst
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
old mode 100644
new mode 100755
index c3dd18f..6cf31b3
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
@@ -27,23 +27,14 @@
 #include "../venc_drv_base.h"
 #include "../venc_ipi_msg.h"
 #include "../venc_vpu_if.h"
+#include "mtk_vpu.h"
 
 static const char h264_filler_marker[] = {0x0, 0x0, 0x0, 0x1, 0xc};
 
 #define H264_FILLER_MARKER_SIZE ARRAY_SIZE(h264_filler_marker)
 #define VENC_PIC_BITSTREAM_BYTE_CNT 0x0098
 
-/**
- * enum venc_h264_frame_type - h264 encoder output bitstream frame type
- */
-enum venc_h264_frame_type {
-	VENC_H264_IDR_FRM,
-	VENC_H264_I_FRM,
-	VENC_H264_P_FRM,
-	VENC_H264_B_FRM,
-};
-
-/**
+/*
  * enum venc_h264_vpu_work_buf - h264 encoder buffer index
  */
 enum venc_h264_vpu_work_buf {
@@ -59,7 +50,7 @@
 	VENC_H264_VPU_WORK_BUF_MAX,
 };
 
-/**
+/*
  * enum venc_h264_bs_mode - for bs_mode argument in h264_enc_vpu_encode
  */
 enum venc_h264_bs_mode {
@@ -157,7 +148,6 @@
 	struct mtk_vcodec_mem pps_buf;
 	bool work_buf_allocated;
 	unsigned int frm_cnt;
-	unsigned int skip_frm_cnt;
 	unsigned int prepend_hdr;
 	struct venc_vpu_inst vpu_inst;
 	struct venc_h264_vsi *vsi;
@@ -276,7 +266,8 @@
 		 */
 		inst->work_bufs[i].size = wb[i].size;
 		if (i == VENC_H264_VPU_WORK_BUF_SKIP_FRAME) {
-			inst->work_bufs[i].va = mtk_vcodec_fw_map_dm_addr(inst->vpu_inst.ctx->dev->ipi_msg_handle, wb[i].vpua);
+			inst->work_bufs[i].va = vpu_mapping_dm_addr(
+				inst->vpu_inst.dev, wb[i].vpua);
 			inst->work_bufs[i].dma_addr = 0;
 		} else {
 			ret = mtk_vcodec_mem_alloc(inst->ctx,
@@ -295,7 +286,7 @@
 			if (i == VENC_H264_VPU_WORK_BUF_RC_CODE) {
 				void *tmp_va;
 
-				tmp_va = mtk_vcodec_fw_map_dm_addr(inst->vpu_inst.ctx->dev->ipi_msg_handle,
+				tmp_va = vpu_mapping_dm_addr(inst->vpu_inst.dev,
 							     wb[i].vpua);
 				memcpy(inst->work_bufs[i].va, tmp_va,
 				       wb[i].size);
@@ -341,22 +332,6 @@
 	return irq_status;
 }
 
-static int h264_frame_type(struct venc_h264_inst *inst)
-{
-	if ((inst->vsi->config.gop_size != 0 &&
-		(inst->frm_cnt % inst->vsi->config.gop_size) == 0) ||
-		(inst->frm_cnt == 0 && inst->vsi->config.gop_size == 0)) {
-		/* IDR frame */
-		return VENC_H264_IDR_FRM;
-	} else if ((inst->vsi->config.intra_period != 0 &&
-		(inst->frm_cnt % inst->vsi->config.intra_period) == 0) ||
-		(inst->frm_cnt == 0 && inst->vsi->config.intra_period == 0)) {
-		/* I frame */
-		return VENC_H264_I_FRM;
-	} else {
-		return VENC_H264_P_FRM;  //mt8183 only support I and P frame
-	}
-}
 static int h264_encode_sps(struct venc_h264_inst *inst,
 			   struct mtk_vcodec_mem *bs_buf,
 			   unsigned int *bs_size)
@@ -366,8 +341,8 @@
 
 	mtk_vcodec_debug_enter(inst);
 
-	ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_SPS, NULL, bs_buf,
-			     bs_size, NULL);
+	ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_SPS, NULL,
+			     bs_buf, bs_size);
 	if (ret)
 		return ret;
 
@@ -394,7 +369,7 @@
 	mtk_vcodec_debug_enter(inst);
 
 	ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_PPS, NULL,
-			     bs_buf, bs_size, NULL);
+			     bs_buf, bs_size);
 	if (ret)
 		return ret;
 
@@ -440,28 +415,13 @@
 {
 	int ret = 0;
 	unsigned int irq_status;
-	struct venc_frame_info frame_info;
 
 	mtk_vcodec_debug_enter(inst);
-	if (inst->frm_cnt == 0xFFFFFFFF) {
-		inst->frm_cnt = 0;
-		mtk_vcodec_debug(inst, "init frm_cnt to %d \n", inst->frm_cnt);
-	} else {
-		inst->frm_cnt++;
-		mtk_vcodec_debug(inst, "frm_cnt++ = %d \n ", inst->frm_cnt);
-	}
-	frame_info.frm_cnt = inst->frm_cnt;
-	frame_info.skip_frm_cnt = inst->skip_frm_cnt;
-	frame_info.frm_type = h264_frame_type(inst);
-	mtk_vcodec_debug(inst, "frm_cnt++ = %d,skip_frm_cnt =%d,frm_type=%d. \n",
-		frame_info.frm_cnt, frame_info.skip_frm_cnt,
-		frame_info.frm_type);
+
 	ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_FRAME, frm_buf,
-			     bs_buf, bs_size, &frame_info);
-	if (ret) {
-		inst->frm_cnt--;
+			     bs_buf, bs_size);
+	if (ret)
 		return ret;
-	}
 
 	/*
 	 * skip frame case: The skip frame buffer is composed by vpu side only,
@@ -472,19 +432,19 @@
 		memcpy(bs_buf->va,
 		       inst->work_bufs[VENC_H264_VPU_WORK_BUF_SKIP_FRAME].va,
 		       *bs_size);
-		++inst->skip_frm_cnt;
+		++inst->frm_cnt;
 		return ret;
 	}
 
 	irq_status = h264_enc_wait_venc_done(inst);
 	if (irq_status != MTK_VENC_IRQ_STATUS_FRM) {
 		mtk_vcodec_err(inst, "irq_status=%d failed", irq_status);
-		inst->frm_cnt--;
 		return -EIO;
 	}
 
 	*bs_size = h264_read_reg(inst, VENC_PIC_BITSTREAM_BYTE_CNT);
 
+	++inst->frm_cnt;
 	mtk_vcodec_debug(inst, "frm %d bs_size %d key_frm %d <-",
 			 inst->frm_cnt, *bs_size, inst->vpu_inst.is_key_frm);
 
@@ -507,7 +467,7 @@
 	memset(p, 0xff, size);
 }
 
-static int h264_enc_init(struct mtk_vcodec_ctx *ctx)
+static int h264_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle)
 {
 	int ret = 0;
 	struct venc_h264_inst *inst;
@@ -518,10 +478,9 @@
 
 	inst->ctx = ctx;
 	inst->vpu_inst.ctx = ctx;
-	inst->vpu_inst.id = SCP_IPI_VENC_H264;
+	inst->vpu_inst.dev = ctx->dev->vpu_plat_dev;
+	inst->vpu_inst.id = IPI_VENC_H264;
 	inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_SYS);
-	inst->frm_cnt = 0xFFFFFFFF;
-	mtk_v4l2_err("h264_enc_init =%d!!",IPI_VENC_H264);
 
 	mtk_vcodec_debug_enter(inst);
 
@@ -534,12 +493,12 @@
 	if (ret)
 		kfree(inst);
 	else
-		ctx->drv_handle = inst;
+		(*handle) = (unsigned long)inst;
 
 	return ret;
 }
 
-static int h264_enc_encode(void *handle,
+static int h264_enc_encode(unsigned long handle,
 			   enum venc_start_opt opt,
 			   struct venc_frm_buf *frm_buf,
 			   struct mtk_vcodec_mem *bs_buf,
@@ -634,13 +593,15 @@
 	return ret;
 }
 
-static int h264_enc_set_param(void *handle,
+static int h264_enc_set_param(unsigned long handle,
 			      enum venc_set_param_type type,
 			      struct venc_enc_param *enc_prm)
 {
 	int ret = 0;
 	struct venc_h264_inst *inst = (struct venc_h264_inst *)handle;
 
+	mtk_vcodec_debug(inst, "->type=%d", type);
+
 	switch (type) {
 	case VENC_SET_PARAM_ENC:
 		inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt;
@@ -653,9 +614,9 @@
 		inst->vsi->config.framerate = enc_prm->frm_rate;
 		inst->vsi->config.intra_period = enc_prm->intra_period;
 		inst->vsi->config.profile =
-			h264_get_profile(inst, enc_prm->profile);
+			h264_get_profile(inst, enc_prm->h264_profile);
 		inst->vsi->config.level =
-			h264_get_level(inst, enc_prm->level);
+			h264_get_level(inst, enc_prm->h264_level);
 		inst->vsi->config.wfd = 0;
 		ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
 		if (ret)
@@ -674,11 +635,7 @@
 		inst->prepend_hdr = 1;
 		mtk_vcodec_debug(inst, "set prepend header mode");
 		break;
-	case VENC_SET_PARAM_FORCE_INTRA:
-	case VENC_SET_PARAM_GOP_SIZE:
-	case VENC_SET_PARAM_INTRA_PERIOD:
-		inst->frm_cnt = 0xFFFFFFFF;
-		inst->skip_frm_cnt = 0;
+
 	default:
 		ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
 		break;
@@ -689,7 +646,7 @@
 	return ret;
 }
 
-static int h264_enc_deinit(void *handle)
+static int h264_enc_deinit(unsigned long handle)
 {
 	int ret = 0;
 	struct venc_h264_inst *inst = (struct venc_h264_inst *)handle;
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
old mode 100644
new mode 100755
index 1129caf..957420d
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
@@ -26,6 +26,7 @@
 #include "../venc_drv_base.h"
 #include "../venc_ipi_msg.h"
 #include "../venc_vpu_if.h"
+#include "mtk_vpu.h"
 
 #define VENC_BITSTREAM_FRAME_SIZE 0x0098
 #define VENC_BITSTREAM_HEADER_LEN 0x00e8
@@ -200,7 +201,7 @@
 		    i == VENC_VP8_VPU_WORK_BUF_RC_CODE3) {
 			void *tmp_va;
 
-			tmp_va = mtk_vcodec_fw_map_dm_addr(inst->vpu_inst.ctx->dev->ipi_msg_handle,
+			tmp_va = vpu_mapping_dm_addr(inst->vpu_inst.dev,
 						     wb[i].vpua);
 			memcpy(inst->work_bufs[i].va, tmp_va, wb[i].size);
 		}
@@ -309,8 +310,7 @@
 
 	mtk_vcodec_debug(inst, "->frm_cnt=%d", inst->frm_cnt);
 
-	ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, bs_size,
-			     NULL);
+	ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, bs_size);
 	if (ret)
 		return ret;
 
@@ -332,7 +332,7 @@
 	return ret;
 }
 
-static int vp8_enc_init(struct mtk_vcodec_ctx *ctx)
+static int vp8_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle)
 {
 	int ret = 0;
 	struct venc_vp8_inst *inst;
@@ -343,6 +343,7 @@
 
 	inst->ctx = ctx;
 	inst->vpu_inst.ctx = ctx;
+	inst->vpu_inst.dev = ctx->dev->vpu_plat_dev;
 	inst->vpu_inst.id = IPI_VENC_VP8;
 	inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_LT_SYS);
 
@@ -357,12 +358,12 @@
 	if (ret)
 		kfree(inst);
 	else
-		ctx->drv_handle = inst;
+		(*handle) = (unsigned long)inst;
 
 	return ret;
 }
 
-static int vp8_enc_encode(void *handle,
+static int vp8_enc_encode(unsigned long handle,
 			  enum venc_start_opt opt,
 			  struct venc_frm_buf *frm_buf,
 			  struct mtk_vcodec_mem *bs_buf,
@@ -399,7 +400,7 @@
 	return ret;
 }
 
-static int vp8_enc_set_param(void *handle,
+static int vp8_enc_set_param(unsigned long handle,
 			     enum venc_set_param_type type,
 			     struct venc_enc_param *enc_prm)
 {
@@ -450,7 +451,7 @@
 	return ret;
 }
 
-static int vp8_enc_deinit(void *handle)
+static int vp8_enc_deinit(unsigned long handle)
 {
 	int ret = 0;
 	struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_base.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_base.h
old mode 100644
new mode 100755
index 95a1bf0..6308d44
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_base.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_base.h
@@ -28,7 +28,7 @@
 	 * @ctx:	[in] mtk v4l2 context
 	 * @handle: [out] driver handle
 	 */
-	int (*init)(struct mtk_vcodec_ctx *ctx);
+	int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *handle);
 
 	/**
 	 * (*encode)() - trigger encode
@@ -38,34 +38,25 @@
 	 * @bs_buf: [in] bitstream buffer to store output bitstream
 	 * @result: [out] encode result
 	 */
-	int (*encode)(void *handle, enum venc_start_opt opt,
+	int (*encode)(unsigned long handle, enum venc_start_opt opt,
 		      struct venc_frm_buf *frm_buf,
 		      struct mtk_vcodec_mem *bs_buf,
 		      struct venc_done_result *result);
 
 	/**
-	 * (*get_param)() - set driver's parameter
-	 * @handle: [in] driver handle
-	 * @type: [in] parameter type
-	 * @in: [in] buffer to store the parameter
-	 */
-	int (*get_param)(void *handle, enum venc_get_param_type type,
-					 void *out);
-
-	/**
 	 * (*set_param)() - set driver's parameter
 	 * @handle: [in] driver handle
 	 * @type: [in] parameter type
 	 * @in: [in] buffer to store the parameter
 	 */
-	int (*set_param)(void *handle, enum venc_set_param_type type,
+	int (*set_param)(unsigned long handle, enum venc_set_param_type type,
 			 struct venc_enc_param *in);
 
 	/**
 	 * (*deinit)() - deinitialize driver.
 	 * @handle: [in] driver handle
 	 */
-	int (*deinit)(void *handle);
+	int (*deinit)(unsigned long handle);
 };
 
 #endif
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_if.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_if.c
old mode 100644
new mode 100755
index b560d71..d02d5f1
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_if.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_if.c
@@ -1,6 +1,18 @@
-// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2016 MediaTek Inc.
+ * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
+ *	Jungchang Tsao <jungchang.tsao@mediatek.com>
+ *	Tiffany Lin <tiffany.lin@mediatek.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  */
 
 #include <linux/interrupt.h>
@@ -12,38 +24,15 @@
 
 #include "mtk_vcodec_enc.h"
 #include "mtk_vcodec_enc_pm.h"
-
-#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCU)
-#include "mtk_vcu.h"
-const struct venc_common_if *get_enc_common_if(void);
-#endif
-
-#ifdef CONFIG_VIDEO_MEDIATEK_VPU
 #include "mtk_vpu.h"
+
 const struct venc_common_if *get_h264_enc_comm_if(void);
 const struct venc_common_if *get_vp8_enc_comm_if(void);
-#endif
 
 int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
 {
 	int ret = 0;
 
-	ctx->oal_vcodec = 0;
-	ctx->slowmotion = 0;
-#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCU)
-	switch (fourcc) {
-	case V4L2_PIX_FMT_H264:
-	case V4L2_PIX_FMT_H265:
-	case V4L2_PIX_FMT_MPEG4:
-	case V4L2_PIX_FMT_H263:
-		ctx->enc_if = get_enc_common_if();
-		ctx->oal_vcodec = 0;
-		break;
-	default:
-		return -EINVAL;
-	}
-#endif
-#ifdef CONFIG_VIDEO_MEDIATEK_VPU
 	switch (fourcc) {
 	case V4L2_PIX_FMT_VP8:
 		ctx->enc_if = get_vp8_enc_comm_if();
@@ -54,45 +43,12 @@
 	default:
 		return -EINVAL;
 	}
-#endif
 
-	if (!ctx->oal_vcodec) {
-		mtk_venc_lock(ctx);
-		mtk_vcodec_enc_clock_on(&ctx->dev->pm);
-	}
-	ret = ctx->enc_if->init(ctx);
-	if (!ctx->oal_vcodec) {
-		mtk_vcodec_enc_clock_off(&ctx->dev->pm);
-		mtk_venc_unlock(ctx);
-	}
-	return ret;
-}
-int venc_if_get_param(struct mtk_vcodec_ctx *ctx, enum venc_get_param_type type,
-					  void *out)
-{
-	struct venc_inst *inst = NULL;
-	int ret = 0;
-	int drv_handle_exist = 1;
-
-	if (!ctx->drv_handle) {
-		inst = kzalloc(sizeof(struct venc_inst), GFP_KERNEL);
-		inst->ctx = ctx;
-		ctx->drv_handle = (void *)(inst);
-		#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCU)
-		ctx->enc_if = get_enc_common_if();
-		#endif
-		drv_handle_exist = 0;
-	}
-	if (!ctx->slowmotion)
-		mtk_venc_lock(ctx);
-	ret = ctx->enc_if->get_param(ctx->drv_handle, type, out);
-	if (!ctx->slowmotion)
-		mtk_venc_unlock(ctx);
-	if (!drv_handle_exist) {
-		kfree(inst);
-		ctx->drv_handle = 0;
-		ctx->enc_if = NULL;
-	}
+	mtk_venc_lock(ctx);
+	mtk_vcodec_enc_clock_on(&ctx->dev->pm);
+	ret = ctx->enc_if->init(ctx, (unsigned long *)&ctx->drv_handle);
+	mtk_vcodec_enc_clock_off(&ctx->dev->pm);
+	mtk_venc_unlock(ctx);
 
 	return ret;
 }
@@ -102,39 +58,14 @@
 {
 	int ret = 0;
 
-	if (!ctx->oal_vcodec) {
-		mtk_venc_lock(ctx);
-		mtk_vcodec_enc_clock_on(&ctx->dev->pm);
-	}
+	mtk_venc_lock(ctx);
+	mtk_vcodec_enc_clock_on(&ctx->dev->pm);
 	ret = ctx->enc_if->set_param(ctx->drv_handle, type, in);
-	if (!ctx->oal_vcodec) {
-		mtk_vcodec_enc_clock_off(&ctx->dev->pm);
-		mtk_venc_unlock(ctx);
-	}
+	mtk_vcodec_enc_clock_off(&ctx->dev->pm);
+	mtk_venc_unlock(ctx);
+
 	return ret;
 }
-void venc_encode_prepare(void *ctx_prepare, unsigned long *flags)
-{
-	struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)ctx_prepare;
-
-	mtk_venc_lock(ctx);
-	spin_lock_irqsave(&ctx->dev->irqlock, *flags);
-	ctx->dev->curr_ctx = ctx;
-	spin_unlock_irqrestore(&ctx->dev->irqlock, *flags);
-	mtk_vcodec_enc_clock_on(&ctx->dev->pm);
-}
-EXPORT_SYMBOL_GPL(venc_encode_prepare);
-void venc_encode_unprepare(void *ctx_unprepare, unsigned long *flags)
-{
-	struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)ctx_unprepare;
-
-	mtk_vcodec_enc_clock_off(&ctx->dev->pm);
-	spin_lock_irqsave(&ctx->dev->irqlock, *flags);
-	ctx->dev->curr_ctx = NULL;
-	spin_unlock_irqrestore(&ctx->dev->irqlock, *flags);
-	mtk_venc_unlock(ctx);
-}
-EXPORT_SYMBOL_GPL(venc_encode_unprepare);
 
 int venc_if_encode(struct mtk_vcodec_ctx *ctx,
 		   enum venc_start_opt opt, struct venc_frm_buf *frm_buf,
@@ -144,16 +75,22 @@
 	int ret = 0;
 	unsigned long flags;
 
-	if (ctx->oal_vcodec == 0 && ctx->slowmotion == 0)
+	mtk_venc_lock(ctx);
 
-		venc_encode_prepare(ctx, &flags);
+	spin_lock_irqsave(&ctx->dev->irqlock, flags);
+	ctx->dev->curr_ctx = ctx;
+	spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
 
+	mtk_vcodec_enc_clock_on(&ctx->dev->pm);
 	ret = ctx->enc_if->encode(ctx->drv_handle, opt, frm_buf,
 				  bs_buf, result);
+	mtk_vcodec_enc_clock_off(&ctx->dev->pm);
 
-	if (ctx->oal_vcodec == 0 && ctx->slowmotion == 0)
-		venc_encode_unprepare(ctx, &flags);
+	spin_lock_irqsave(&ctx->dev->irqlock, flags);
+	ctx->dev->curr_ctx = NULL;
+	spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
 
+	mtk_venc_unlock(ctx);
 	return ret;
 }
 
@@ -161,18 +98,15 @@
 {
 	int ret = 0;
 
-	if (!ctx->drv_handle)
+	if (ctx->drv_handle == 0)
 		return 0;
 
-	if (!ctx->oal_vcodec) {
-		mtk_venc_lock(ctx);
-		mtk_vcodec_enc_clock_on(&ctx->dev->pm);
-	}
+	mtk_venc_lock(ctx);
+	mtk_vcodec_enc_clock_on(&ctx->dev->pm);
 	ret = ctx->enc_if->deinit(ctx->drv_handle);
-	if (!ctx->oal_vcodec) {
-		mtk_vcodec_enc_clock_off(&ctx->dev->pm);
-		mtk_venc_unlock(ctx);
-	}
+	mtk_vcodec_enc_clock_off(&ctx->dev->pm);
+	mtk_venc_unlock(ctx);
+
 	ctx->drv_handle = 0;
 
 	return ret;
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_if.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_if.h
old mode 100644
new mode 100755
index f6ed09b..a6e7d32
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_if.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_drv_if.h
@@ -20,10 +20,6 @@
 
 #include "mtk_vcodec_drv.h"
 #include "mtk_vcodec_util.h"
-#include "venc_ipi_msg.h"
-#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCU)
-#include "venc_vcu_if.h"
-#endif
 
 /*
  * enum venc_yuv_fmt - The type of input yuv format
@@ -33,17 +29,11 @@
  * @VENC_YUV_FORMAT_NV12: NV12 YUV format
  * @VENC_YUV_FORMAT_NV21: NV21 YUV format
  */
-struct venc_inst {
-	void __iomem *hw_base;
-	struct mtk_vcodec_mem pps_buf;
-	bool work_buf_allocated;
-	unsigned int frm_cnt;
-	unsigned int prepend_hdr;
-	#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCU)
-	struct venc_vcu_inst vcu_inst;
-	#endif
-	struct venc_vsi *vsi;
-	struct mtk_vcodec_ctx *ctx;
+enum venc_yuv_fmt {
+	VENC_YUV_FORMAT_I420 = 3,
+	VENC_YUV_FORMAT_YV12 = 5,
+	VENC_YUV_FORMAT_NV12 = 6,
+	VENC_YUV_FORMAT_NV21 = 7,
 };
 
 /*
@@ -54,6 +44,7 @@
 enum venc_start_opt {
 	VENC_START_OPT_ENCODE_SEQUENCE_HEADER,
 	VENC_START_OPT_ENCODE_FRAME,
+};
 
 /*
  * enum venc_set_param_type - The type of set parameter used in
@@ -69,7 +60,16 @@
  * @VENC_SET_PARAM_PREPEND_HEADER: set H264 prepend SPS/PPS before IDR
  * @VENC_SET_PARAM_TS_MODE: set VP8 temporal scalability mode
  */
-	VENC_START_OPT_ENCODE_FRAME_FINAL
+enum venc_set_param_type {
+	VENC_SET_PARAM_ENC,
+	VENC_SET_PARAM_FORCE_INTRA,
+	VENC_SET_PARAM_ADJUST_BITRATE,
+	VENC_SET_PARAM_ADJUST_FRAMERATE,
+	VENC_SET_PARAM_GOP_SIZE,
+	VENC_SET_PARAM_INTRA_PERIOD,
+	VENC_SET_PARAM_SKIP_FRAME,
+	VENC_SET_PARAM_PREPEND_HEADER,
+	VENC_SET_PARAM_TS_MODE,
 };
 
 /*
@@ -87,12 +87,27 @@
  * @bitrate: target bitrate in bps
  * @gop_size: group of picture size
  */
-
+struct venc_enc_param {
+	enum venc_yuv_fmt input_yuv_fmt;
+	unsigned int h264_profile;
+	unsigned int h264_level;
+	unsigned int width;
+	unsigned int height;
+	unsigned int buf_width;
+	unsigned int buf_height;
+	unsigned int frm_rate;
+	unsigned int intra_period;
+	unsigned int bitrate;
+	unsigned int gop_size;
+};
 
 /*
  * struct venc_frm_buf - frame buffer information used in venc_if_encode()
  * @fb_addr: plane frame buffer addresses
  */
+struct venc_frm_buf {
+	struct mtk_vcodec_mem fb_addr[MTK_VCODEC_MAX_PLANES];
+};
 
 /*
  * struct venc_done_result - This is return information used in venc_if_encode()
@@ -100,10 +115,8 @@
  * @is_key_frm: output is key frame or not
  */
 struct venc_done_result {
-	__u32 bs_size;
-	__u32 is_key_frm;
-	__u64 bs_va;
-	__u64 frm_va;
+	unsigned int bs_size;
+	bool is_key_frm;
 };
 
 /*
@@ -120,8 +133,6 @@
  * Return: 0 if releasing handle successfully, otherwise it is failed.
  */
 int venc_if_deinit(struct mtk_vcodec_ctx *ctx);
-int venc_if_get_param(struct mtk_vcodec_ctx *ctx, enum venc_get_param_type type,
-					  void *out);
 
 /*
  * venc_if_set_param - Set parameter to driver
@@ -149,6 +160,4 @@
 		   struct mtk_vcodec_mem *bs_buf,
 		   struct venc_done_result *result);
 
-void venc_encode_prepare(void *ctx_prepare, unsigned long *flags);
-void venc_encode_unprepare(void *ctx_unprepare, unsigned long *flags);
 #endif /* _VENC_DRV_IF_H_ */
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
old mode 100644
new mode 100755
index 272a33d..4c869cb
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
@@ -17,13 +17,9 @@
 
 #ifndef _VENC_IPI_MSG_H_
 #define _VENC_IPI_MSG_H_
-#include <linux/videodev2.h>
 
-#define MTK_MAX_ENC_CODECS_SUPPORT       (32)
 #define AP_IPIMSG_VENC_BASE 0xC000
 #define VPU_IPIMSG_VENC_BASE 0xD000
-#define VENC_MAX_FB_NUM              VIDEO_MAX_FRAME
-#define VENC_MAX_BS_NUM              VIDEO_MAX_FRAME
 
 /**
  * enum venc_ipi_msg_id - message id between AP and VPU
@@ -36,60 +32,13 @@
 	AP_IPIMSG_ENC_SET_PARAM,
 	AP_IPIMSG_ENC_ENCODE,
 	AP_IPIMSG_ENC_DEINIT,
-	AP_IPIMSG_ENC_QUERY_CAP,
 
 	VPU_IPIMSG_ENC_INIT_DONE = VPU_IPIMSG_VENC_BASE,
 	VPU_IPIMSG_ENC_SET_PARAM_DONE,
 	VPU_IPIMSG_ENC_ENCODE_DONE,
 	VPU_IPIMSG_ENC_DEINIT_DONE,
-	VPU_IPIMSG_ENC_QUERY_CAP_ACK,
-	VPU_IPIMSG_ENC_POWER_ON,
-	VPU_IPIMSG_ENC_POWER_OFF,
-	VPU_IPIMSG_ENC_WAIT_ISR,
-	VPU_IPIMSG_ENC_ENCODE_ACK
 };
 
-enum venc_get_param_type {
-	GET_PARAM_CAPABILITY_SUPPORTED_FORMATS,
-	GET_PARAM_CAPABILITY_FRAME_SIZES,
-	GET_PARAM_FREE_BUFFERS,
-	GET_PARAM_ROI_RC_QP
-};
-/*
- * enum venc_set_param_type - The type of set parameter used in
- *                                                    venc_if_set_param()
- * (VCU related: If you change the order, you must also update the VCU codes.)
- * @VENC_SET_PARAM_ENC: set encoder parameters
- * @VENC_SET_PARAM_FORCE_INTRA: force an intra frame
- * @VENC_SET_PARAM_ADJUST_BITRATE: adjust bitrate (in bps)
- * @VENC_SET_PARAM_ADJUST_FRAMERATE: set frame rate
- * @VENC_SET_PARAM_GOP_SIZE: set IDR interval
- * @VENC_SET_PARAM_INTRA_PERIOD: set I frame interval
- * @VENC_SET_PARAM_SKIP_FRAME: set H264 skip one frame
- * @VENC_SET_PARAM_PREPEND_HEADER: set H264 prepend SPS/PPS before IDR
- * @VENC_SET_PARAM_TS_MODE: set VP8 temporal scalability mode
- * @VENC_SET_PARAM_SCENARIO: set encoder scenario mode for different RC control
- * @VENC_SET_PARAM_NONREFP: set encoder non reference P period
- */
-enum venc_set_param_type {
-	VENC_SET_PARAM_ENC,
-	VENC_SET_PARAM_FORCE_INTRA,
-	VENC_SET_PARAM_ADJUST_BITRATE,
-	VENC_SET_PARAM_ADJUST_FRAMERATE,
-	VENC_SET_PARAM_GOP_SIZE,
-	VENC_SET_PARAM_INTRA_PERIOD,
-	VENC_SET_PARAM_SKIP_FRAME,
-	VENC_SET_PARAM_PREPEND_HEADER,
-	VENC_SET_PARAM_TS_MODE,
-	VENC_SET_PARAM_SCENARIO,
-	VENC_SET_PARAM_NONREFP,
-	VENC_SET_PARAM_DETECTED_FRAMERATE,
-	VENC_SET_PARAM_RFS_ON,
-	VENC_SET_PARAM_PREPEND_SPSPPS_TO_IDR,
-	VENC_SET_PARAM_OPERATION_RATE,
-	VENC_SET_PARAM_BITRATE_MODE,
-	VENC_SET_PARAM_ROI_ON
-};
 /**
  * struct venc_ap_ipi_msg_init - AP to VPU init cmd structure
  * @msg_id:	message id (AP_IPIMSG_XXX_ENC_INIT)
@@ -106,57 +55,6 @@
 };
 
 /**
- * struct venc_ap_ipi_query_cap - for AP_IPIMSG_ENC_QUERY_CAP
- * @msg_id        : AP_IPIMSG_ENC_QUERY_CAP
- * @id      : query capability type
- * @vdec_inst     : AP query data address
- */
-struct venc_ap_ipi_query_cap {
-	__u32 msg_id;
-	__u32 id;
-#ifndef CONFIG_64BIT
-	union {
-		__u64 ap_inst_addr_64;
-		__u32 ap_inst_addr;
-	};
-	union {
-		__u64 ap_data_addr_64;
-		__u32 ap_data_addr;
-	};
-#else
-	__u64 ap_inst_addr;
-	__u64 ap_data_addr;
-#endif
-};
-
-/**
- * struct venc_vcu_ipi_query_cap_ack - for VCU_IPIMSG_ENC_QUERY_CAP_ACK
- * @msg_id      : VCU_IPIMSG_ENC_QUERY_CAP_ACK
- * @status      : VCU exeuction result
- * @ap_data_addr   : AP query data address
- * @vcu_data_addr  : VCU query data address
- */
-struct venc_vcu_ipi_query_cap_ack {
-	__u32 msg_id;
-	__s32 status;
-#ifndef CONFIG_64BIT
-	union {
-		__u64 ap_inst_addr_64;
-		__u32 ap_inst_addr;
-	};
-	__u32 id;
-	union {
-		__u64 ap_data_addr_64;
-		__u32 ap_data_addr;
-	};
-#else
-	__u64 ap_inst_addr;
-	__u32 id;
-	__u64 ap_data_addr;
-#endif
-	__u32 vcu_data_addr;
-};
-/**
  * struct venc_ap_ipi_msg_set_param - AP to VPU set_param cmd structure
  * @msg_id:	message id (AP_IPIMSG_XXX_ENC_SET_PARAM)
  * @vpu_inst_addr:	VPU encoder instance addr
@@ -173,12 +71,6 @@
 	uint32_t data[8];
 };
 
-struct venc_ap_ipi_msg_set_param_ext {
-	struct venc_ap_ipi_msg_set_param base;
-	uint32_t data_ext[24];
-};
-
-
 /**
  * struct venc_ap_ipi_msg_enc - AP to VPU enc cmd structure
  * @msg_id:	message id (AP_IPIMSG_XXX_ENC_ENCODE)
@@ -193,21 +85,10 @@
 struct venc_ap_ipi_msg_enc {
 	uint32_t msg_id;
 	uint32_t vpu_inst_addr;
+	uint32_t bs_mode;
 	uint32_t input_addr[3];
-	uint32_t input_size[3];
 	uint32_t bs_addr;
 	uint32_t bs_size;
-	__u32 data_offset[3];
-	__s16 input_fd[3];
-	__s16 bs_fd;
-	__u8 fb_num_planes;
-	__u8 bs_mode;
-};
-
-struct venc_ap_ipi_msg_enc_ext {
-	struct venc_ap_ipi_msg_enc base;
-	uint32_t data_item;
-	uint32_t data[32];
 };
 
 /**
@@ -222,22 +103,6 @@
 };
 
 /**
- * struct venc_vcu_ipi_msg_waitisr - VCU ack AP wait isr cmd structure
- * @msg_id:   message id (VCU_IPIMSG_XXX_ENC_DEINIT_DONE)
- * @status:   cmd status (venc_ipi_msg_status)
- * @venc_inst:	AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
- * @irq_status: encoder irq status
- * @timeout: 1 indicate encode timeout, 0 indicate no error
- */
-struct venc_vpu_ipi_msg_waitisr {
-	__u32 msg_id;
-	__s32 status;
-	__u64 venc_inst;
-	__u32 irq_status;
-	__u32 timeout;
-};
-
-/**
  * enum venc_ipi_msg_status - VPU ack AP cmd status
  */
 enum venc_ipi_msg_status {
@@ -251,7 +116,7 @@
  * @status:	cmd status (venc_ipi_msg_status)
  * @venc_inst:	AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
  */
-struct venc_vcu_ipi_msg_common {
+struct venc_vpu_ipi_msg_common {
 	uint32_t msg_id;
 	uint32_t status;
 	uint64_t venc_inst;
@@ -268,7 +133,7 @@
  *		this reserved field, if kernel run in 64bit. this struct size
  *		will be different between kernel and vpu
  */
-struct venc_vcu_ipi_msg_init {
+struct venc_vpu_ipi_msg_init {
 	uint32_t msg_id;
 	uint32_t status;
 	uint64_t venc_inst;
@@ -285,7 +150,7 @@
  * @data_item:	number of items in the data array
  * @data[6]:	data array to store the return result
  */
-struct venc_vcu_ipi_msg_set_param {
+struct venc_vpu_ipi_msg_set_param {
 	uint32_t msg_id;
 	uint32_t status;
 	uint64_t venc_inst;
@@ -320,7 +185,7 @@
  *		this reserved field, if kernel run in 64bit. this struct size
  *		will be different between kernel and vpu
  */
-struct venc_vcu_ipi_msg_enc {
+struct venc_vpu_ipi_msg_enc {
 	uint32_t msg_id;
 	uint32_t status;
 	uint64_t venc_inst;
@@ -336,125 +201,10 @@
  * @status:   cmd status (venc_ipi_msg_status)
  * @venc_inst:	AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
  */
-struct venc_vcu_ipi_msg_deinit {
+struct venc_vpu_ipi_msg_deinit {
 	uint32_t msg_id;
 	uint32_t status;
 	uint64_t venc_inst;
 };
 
-/*
- * struct venc_vcu_config - Structure for encoder configuration
- *                               AP-W/R : AP is writer/reader on this item
- *                               VCU-W/R: VCU is write/reader on this item
- * @input_fourcc: input fourcc
- * @bitrate: target bitrate (in bps)
- * @pic_w: picture width. Picture size is visible stream resolution, in pixels,
- *         to be used for display purposes; must be smaller or equal to buffer
- *         size.
- * @pic_h: picture height
- * @buf_w: buffer width. Buffer size is stream resolution in pixels aligned to
- *         hardware requirements.
- * @buf_h: buffer height
- * @gop_size: group of picture size (idr frame)
- * @intra_period: intra frame period
- * @framerate: frame rate in fps
- * @profile: as specified in standard
- * @level: as specified in standard
- * @wfd: WFD mode 1:on, 0:off
- */
-struct venc_vcu_config {
-	__u32 input_fourcc;
-	__u32 bitrate;
-	__u32 pic_w;
-	__u32 pic_h;
-	__u32 buf_w;
-	__u32 buf_h;
-	__u32 gop_size;
-	__u32 intra_period;
-	__u32 framerate;
-	__u32 profile;
-	__u32 level;
-	__u32 wfd;
-	__u32 operationrate;
-	__u32 scenario;
-	__u32 prependheader;
-	__u32 bitratemode;
-	__u32 roi_rc_qp;
-	__u32 roion;
-};
-
-/**
- * enum venc_bs_mode - for bs_mode argument in venc_bs_mode
- */
-enum venc_bs_mode {
-	VENC_BS_MODE_SPS = 0,
-	VENC_BS_MODE_PPS,
-	VENC_BS_MODE_SEQ_HDR,
-	VENC_BS_MODE_FRAME,
-	VENC_BS_MODE_FRAME_FINAL,
-	VENC_BS_MODE_MAX
-};
-/**
- * struct venc_info - encode information
- * @bs_dma		: Input bit-stream buffer dma address
- * @bs_fd           : Input bit-stream buffer dmabuf fd
- * @fb_dma		    : Y frame buffer dma address
- * @fb_fd           : Y frame buffer dmabuf fd
- * @venc_bs_va		: VDEC bitstream buffer struct virtual address
- * @venc_fb_va		: VDEC frame buffer struct virtual address
- * @fb_num_planes	: frame buffer plane count
- * @reserved		: reserved variable for 64bit align
- */
-struct venc_info {
-	__u64 bs_dma;
-	__u64 bs_fd;
-	__u64 fb_dma[VIDEO_MAX_PLANES];
-	__u64 fb_fd[VIDEO_MAX_PLANES];
-	__u64 venc_bs_va;
-	__u64 venc_fb_va;
-	__u32 fb_num_planes;
-	__u32 index;
-	__u64 timestamp;
-	__u32 roimap;
-	__u32 reserved;
-};
-
-/**
- * struct ring_input_list - ring input buffer list
- * @venc_bs_va_list   : bitstream buffer arrary
- * @venc_fb_va_list   : frame buffer arrary
- * @read_idx  : read index
- * @write_idx : write index
- * @count     : buffer count in list
- */
-struct ring_input_list {
-	__u64 venc_bs_va_list[VENC_MAX_FB_NUM];
-	__u64 venc_fb_va_list[VENC_MAX_FB_NUM];
-	__u32 bs_size[VENC_MAX_FB_NUM];
-	__u32 is_key_frm[VENC_MAX_FB_NUM];
-	__s32 read_idx;
-	__s32 write_idx;
-	__s32 count;
-	__s32 reserved;
-};
-/*
- * struct venc_vsi - Structure for VCU driver control and info share
- *                        AP-W/R : AP is writer/reader on this item
- *                        VCU-W/R: VCU is write/reader on this item
- * This structure is allocated in VCU side and shared to AP side.
- * @config: h264 encoder configuration
- * @work_bufs: working buffer information in VCU side
- * The work_bufs here is for storing the 'size' info shared to AP side.
- * The similar item in struct venc_inst is for memory allocation
- * in AP side. The AP driver will copy the 'size' from here to the one in
- * struct mtk_vcodec_mem, then invoke mtk_vcodec_mem_alloc to allocate
- * the buffer. After that, bypass the 'dma_addr' to the 'iova' field here for
- * register setting in VCU side.
- */
-struct venc_vsi {
-	struct venc_vcu_config config;
-	__u32  sizeimage[VIDEO_MAX_PLANES];
-	struct ring_input_list list_free;
-	struct venc_info       venc;
-};
 #endif /* _VENC_IPI_MSG_H_ */
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
old mode 100644
new mode 100755
index 8ad22f8..0d882ac
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
@@ -13,7 +13,7 @@
  * GNU General Public License for more details.
  */
 
-#include "mtk_vcodec_fw.h"
+#include "mtk_vpu.h"
 #include "venc_ipi_msg.h"
 #include "venc_vpu_if.h"
 
@@ -22,7 +22,7 @@
 	struct venc_vpu_ipi_msg_init *msg = data;
 
 	vpu->inst_addr = msg->vpu_inst_addr;
-	vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->ipi_msg_handle, msg->vpu_inst_addr);
+	vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr);
 }
 
 static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, void *data)
@@ -72,12 +72,12 @@
 
 	mtk_vcodec_debug_enter(vpu);
 
-	if (!vpu->ctx->dev->ipi_msg_handle) {
+	if (!vpu->dev) {
 		mtk_vcodec_err(vpu, "inst dev is NULL");
 		return -EINVAL;
 	}
 
-	status = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->ipi_msg_handle, vpu->id, msg, len, 2000);
+	status = vpu_ipi_send(vpu->dev, vpu->id, msg, len);
 	if (status) {
 		mtk_vcodec_err(vpu, "vpu_ipi_send msg_id %x len %d fail %d",
 			       *(uint32_t *)msg, len, status);
@@ -102,9 +102,8 @@
 	vpu->signaled = 0;
 	vpu->failure = 0;
 
-	status = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->ipi_msg_handle, vpu->id,
-		vpu_enc_ipi_handler, "venc", NULL);
-
+	status = vpu_ipi_register(vpu->dev, vpu->id, vpu_enc_ipi_handler,
+				  NULL, NULL);
 	if (status) {
 		mtk_vcodec_err(vpu, "vpu_ipi_register fail %d", status);
 		return -EINVAL;
@@ -123,85 +122,49 @@
 	return 0;
 }
 
-static unsigned int venc_enc_param_crop_right(struct venc_vpu_inst *vpu,
-					      struct venc_enc_param *enc_prm)
-{
-	unsigned int img_crop_right = enc_prm->buf_width - enc_prm->width;
-	if (img_crop_right > 16) {
-		img_crop_right -= 16;
-		if (img_crop_right > 16)
-			mtk_vcodec_err(vpu,  "input not supported crop %d\n",
-			enc_prm->buf_width - enc_prm->width);
-	} else if (img_crop_right == 16) {
-			img_crop_right = 0;
-	}
-
-	return img_crop_right;
-}
-
-static unsigned int venc_enc_param_crop_bottom(struct venc_enc_param *enc_prm) {
-	return (((enc_prm->height + 15) / 16) * 16) - enc_prm->height;
-}
-
-#define ROUND_16(X) (((X) + 0xF) & (~0xF))
-static unsigned int venc_enc_param_num_mb(struct venc_enc_param *enc_prm) {
-	return (ROUND_16(enc_prm->width) >> 4) * (ROUND_16(enc_prm->height) >> 4);
-}
-
 int vpu_enc_set_param(struct venc_vpu_inst *vpu,
 		      enum venc_set_param_type id,
 		      struct venc_enc_param *enc_param)
 {
-	const bool is_ext = vpu->ctx->dev->venc_pdata->uses_ext;
-	size_t msg_size = is_ext ?
-		sizeof(struct venc_ap_ipi_msg_set_param_ext) :
-		sizeof(struct venc_ap_ipi_msg_set_param);
-	struct venc_ap_ipi_msg_set_param_ext out;
+	struct venc_ap_ipi_msg_set_param out;
 
 	mtk_vcodec_debug(vpu, "id %d ->", id);
 
 	memset(&out, 0, sizeof(out));
-	out.base.msg_id = AP_IPIMSG_ENC_SET_PARAM;
-	out.base.vpu_inst_addr = vpu->inst_addr;
-	out.base.param_id = id;
+	out.msg_id = AP_IPIMSG_ENC_SET_PARAM;
+	out.vpu_inst_addr = vpu->inst_addr;
+	out.param_id = id;
 	switch (id) {
 	case VENC_SET_PARAM_ENC:
-		if (is_ext) {
-			out.base.data_item = 3;
-			out.base.data[0] = venc_enc_param_crop_right(vpu, enc_param);
-			out.base.data[1] = venc_enc_param_crop_bottom(enc_param);
-			out.base.data[2] = venc_enc_param_num_mb(enc_param);
-		} else {
-			out.base.data_item = 0;
-		}
+		out.data_item = 0;
 		break;
 	case VENC_SET_PARAM_FORCE_INTRA:
-		out.base.data_item = 0;
+		out.data_item = 0;
 		break;
 	case VENC_SET_PARAM_ADJUST_BITRATE:
-		out.base.data_item = 1;
-		out.base.data[0] = enc_param->bitrate;
+		out.data_item = 1;
+		out.data[0] = enc_param->bitrate;
 		break;
 	case VENC_SET_PARAM_ADJUST_FRAMERATE:
-		out.base.data_item = 1;
-		out.base.data[0] = enc_param->frm_rate;
+		out.data_item = 1;
+		out.data[0] = enc_param->frm_rate;
 		break;
 	case VENC_SET_PARAM_GOP_SIZE:
-		out.base.data_item = 1;
-		out.base.data[0] = enc_param->gop_size;
+		out.data_item = 1;
+		out.data[0] = enc_param->gop_size;
 		break;
 	case VENC_SET_PARAM_INTRA_PERIOD:
-		out.base.data_item = 1;
-		out.base.data[0] = enc_param->intra_period;
+		out.data_item = 1;
+		out.data[0] = enc_param->intra_period;
 		break;
 	case VENC_SET_PARAM_SKIP_FRAME:
-		out.base.data_item = 0;
+		out.data_item = 0;
 		break;
 	default:
 		mtk_vcodec_err(vpu, "id %d not supported", id);
 		return -EINVAL;
 	}
-	if (vpu_enc_send_msg(vpu, &out, msg_size)) {
+	if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
 		mtk_vcodec_err(vpu,
 			       "AP_IPIMSG_ENC_SET_PARAM %d fail", id);
 		return -EINVAL;
@@ -215,45 +178,33 @@
 int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode,
 		   struct venc_frm_buf *frm_buf,
 		   struct mtk_vcodec_mem *bs_buf,
-		   unsigned int *bs_size,
-		   struct venc_frame_info *frame_info)
+		   unsigned int *bs_size)
 {
-	const bool is_ext = vpu->ctx->dev->venc_pdata->uses_ext;
-	size_t msg_size = is_ext ?
-		sizeof(struct venc_ap_ipi_msg_enc_ext) :
-		sizeof(struct venc_ap_ipi_msg_enc);
-	struct venc_ap_ipi_msg_enc_ext out;
+	struct venc_ap_ipi_msg_enc out;
 
 	mtk_vcodec_debug(vpu, "bs_mode %d ->", bs_mode);
 
 	memset(&out, 0, sizeof(out));
-	out.base.msg_id = AP_IPIMSG_ENC_ENCODE;
-	out.base.vpu_inst_addr = vpu->inst_addr;
-	out.base.bs_mode = bs_mode;
+	out.msg_id = AP_IPIMSG_ENC_ENCODE;
+	out.vpu_inst_addr = vpu->inst_addr;
+	out.bs_mode = bs_mode;
 	if (frm_buf) {
 		if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) &&
 		    (frm_buf->fb_addr[1].dma_addr % 16 == 0) &&
 		    (frm_buf->fb_addr[2].dma_addr % 16 == 0)) {
-			out.base.input_addr[0] = frm_buf->fb_addr[0].dma_addr;
-			out.base.input_addr[1] = frm_buf->fb_addr[1].dma_addr;
-			out.base.input_addr[2] = frm_buf->fb_addr[2].dma_addr;
+			out.input_addr[0] = frm_buf->fb_addr[0].dma_addr;
+			out.input_addr[1] = frm_buf->fb_addr[1].dma_addr;
+			out.input_addr[2] = frm_buf->fb_addr[2].dma_addr;
 		} else {
 			mtk_vcodec_err(vpu, "dma_addr not align to 16");
 			return -EINVAL;
 		}
 	}
 	if (bs_buf) {
-		out.base.bs_addr = bs_buf->dma_addr;
-		out.base.bs_size = bs_buf->size;
+		out.bs_addr = bs_buf->dma_addr;
+		out.bs_size = bs_buf->size;
 	}
-	if (is_ext && frame_info)
-	{
-		out.data_item = 3;
-		out.data[0] = frame_info->frm_cnt;
-		out.data[1] = frame_info->skip_frm_cnt;
-		out.data[2] = frame_info->frm_type;
-	}
-	if (vpu_enc_send_msg(vpu, &out, msg_size)) {
+	if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
 		mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_ENCODE %d fail",
 			       bs_mode);
 		return -EINVAL;
diff --git a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_vpu_if.h b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_vpu_if.h
old mode 100644
new mode 100755
index 638f9b1..215d1e0
--- a/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_vpu_if.h
+++ b/src/kernel/linux/v4.19/drivers/media/platform/mtk-vcodec/venc_vpu_if.h
@@ -16,7 +16,7 @@
 #ifndef _VENC_VPU_IF_H_
 #define _VENC_VPU_IF_H_
 
-#include "mtk_vcodec_fw.h"
+#include "mtk_vpu.h"
 #include "venc_drv_if.h"
 
 /*
@@ -43,8 +43,9 @@
 	int is_key_frm;
 	unsigned int inst_addr;
 	void *vsi;
-	int id;
+	enum ipi_id id;
 	struct mtk_vcodec_ctx *ctx;
+	struct platform_device *dev;
 };
 
 int vpu_enc_init(struct venc_vpu_inst *vpu);
@@ -54,8 +55,7 @@
 int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode,
 		   struct venc_frm_buf *frm_buf,
 		   struct mtk_vcodec_mem *bs_buf,
-		   unsigned int *bs_size,
-		   struct venc_frame_info *frame_info);
+		   unsigned int *bs_size);
 int vpu_enc_deinit(struct venc_vpu_inst *vpu);
 
 #endif
diff --git a/src/kernel/linux/v4.19/drivers/mfd/mt6330-irq.c b/src/kernel/linux/v4.19/drivers/mfd/mt6330-irq.c
old mode 100644
new mode 100755
index ddc045d..e223c36
--- a/src/kernel/linux/v4.19/drivers/mfd/mt6330-irq.c
+++ b/src/kernel/linux/v4.19/drivers/mfd/mt6330-irq.c
@@ -26,6 +26,7 @@
 	unsigned int sta_reg;
 	unsigned int sta_reg_shift;
 	unsigned int top_offset;
+	unsigned int top_mask_offset;
 };
 
 struct pmic_irq_data {
@@ -34,6 +35,8 @@
 	unsigned int reg_width;
 	unsigned short top_int_status_reg_l;
 	unsigned short top_int_status_reg_h;
+	unsigned short top_int_mask_set_reg;
+	unsigned short top_int_mask_clr_reg;
 	bool *enable_hwirq;
 	bool *cache_hwirq;
 	struct irq_top_t *pmic_ints;
@@ -203,8 +206,17 @@
 	if (!top_irq_status)
 		spmi_dump_spmimst_all_reg();
 	for (i = 0; i < irqd->num_top; i++) {
-		if (top_irq_status & BIT(irqd->pmic_ints[i].top_offset))
+		if (top_irq_status & BIT(irqd->pmic_ints[i].top_offset)) {
+			/* Mask top INT */
+			regmap_write(chip->regmap, irqd->top_int_mask_set_reg,
+				BIT(irqd->pmic_ints[i].top_mask_offset));
+
 			mt6330_irq_sp_handler(chip, i);
+
+			/* Umask top INT */
+			regmap_write(chip->regmap, irqd->top_int_mask_clr_reg,
+				BIT(irqd->pmic_ints[i].top_mask_offset));
+		}
 	}
 
 	return IRQ_HANDLED;
@@ -245,6 +257,8 @@
 	irqd->reg_width = MT6330_REG_WIDTH;
 	irqd->top_int_status_reg_l = MT6330_TOP_INT_STATUS0;
 	irqd->top_int_status_reg_h = MT6330_TOP_INT_STATUS1;
+	irqd->top_int_mask_set_reg = MT6330_TOP_INT_MASK_CON0_SET;
+	irqd->top_int_mask_clr_reg = MT6330_TOP_INT_MASK_CON0_CLR;
 	irqd->pmic_ints = mt6330_ints;
 
 	dev_info(chip->dev, "mt6330_irq_init +++\n");
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/Makefile b/src/kernel/linux/v4.19/drivers/misc/mediatek/Makefile
old mode 100644
new mode 100755
index 05f9404..5d0f05e
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/Makefile
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/Makefile
@@ -70,6 +70,7 @@
 obj-$(CONFIG_USB) += usb_boost/
 obj-$(CONFIG_MTK_ECCCI_C2K) += c2k_usb/
 obj-y +=eint_debug/
+obj-$(CONFIG_HSM_SUPPORT) += hsm/
 obj-y +=wakeup_gpio/
 #tianyan@2021.10.28 modify for DTR/RI gpio start
 obj-y += wakeup_dtr/
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/aee/mrdump/mrdump_panic.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/aee/mrdump/mrdump_panic.c
index 0483cb7..7654c17 100755
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/aee/mrdump/mrdump_panic.c
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/aee/mrdump/mrdump_panic.c
@@ -242,43 +242,77 @@
 	.notifier_call = ipanic_die,
 };
 
+/********* patchback for compatible with 2735 LK *********/
+// mrdump_cb info from lk
+static unsigned long cbaddr, cbsize;
+static int __init mrdump_get_cb(char *p)
+{
+	int ret;
+
+	ret = sscanf(p, "0x%lx,0x%lx", &cbaddr, &cbsize);
+	if (ret != 2) {
+		pr_notice("%s: no mrdump_sram_cb. (ret=%d, p=%s)\n",
+				__func__, ret, p);
+	} else {
+		pr_notice("%s: mrdump_cbaddr=0x%lx, mrdump_cbsize=0x%lx\n",
+			__func__, cbaddr, cbsize);
+	}
+
+	return 0;
+}
+early_param("mrdump_cb", mrdump_get_cb);
+
+// ddr reserve flag from lk
+static char mrdump_lk_ddr_reserve_ready[4];
+
+static int __init mrdump_get_ddr_reserve_status(char *str)
+{
+	strlcpy(mrdump_lk_ddr_reserve_ready, str,
+			sizeof(mrdump_lk_ddr_reserve_ready));
+	return 0;
+}
+
+early_param("mrdump_ddrsv", mrdump_get_ddr_reserve_status);
+static bool mrdump_ddr_reserve_is_ready(void)
+{
+	if (strncmp(mrdump_lk_ddr_reserve_ready, "yes", 3) == 0)
+		return true;
+	else
+		return false;
+}
+
+static char mrdump_lk_version[12];
+static int __init mrdump_get_lk_version(char *str)
+{
+	strlcpy(mrdump_lk_version, str,
+			sizeof(mrdump_lk_version));
+	return 0;
+}
+
+early_param("mrdump.lk", mrdump_get_lk_version);
+/********* end patchback for compatible with 2735 LK *********/
+
 static __init int mrdump_parse_chosen(struct mrdump_params *mparams)
 {
-	struct device_node *node;
-	u32 reg[2];
-	const char *lkver, *ddr_rsv;
-
+	// 2735 lk pass parameters from kernel cmdline
 	memset(mparams, 0, sizeof(struct mrdump_params));
 
-	node = of_find_node_by_path("/chosen");
-	if (node) {
-		if (of_property_read_u32_array(node, "mrdump,cblock",
-					       reg, ARRAY_SIZE(reg)) == 0) {
-			mparams->cb_addr = reg[0];
-			mparams->cb_size = reg[1];
-			//pr_notice("%s: mrdump_cbaddr=%x, mrdump_cbsize=%x\n",
-			//	  __func__, mparams->cb_addr, mparams->cb_size);
-		}
+	mparams->cb_addr = (phys_addr_t)cbaddr;
+	mparams->cb_size = (phys_addr_t)cbsize;
+	pr_notice("%s: mrdump_cbaddr=0x%llx, mrdump_cbsize=0x%llx\n",
+			__func__, mparams->cb_addr, mparams->cb_size);
 
-		if (of_property_read_string(node, "mrdump,lk", &lkver) == 0) {
-			strlcpy(mparams->lk_version, lkver,
-				sizeof(mparams->lk_version));
-			pr_notice("%s: lk version %s\n", __func__, lkver);
-		}
+	strlcpy(mparams->lk_version, mrdump_lk_version,
+			sizeof(mparams->lk_version));
+	pr_notice("%s: lk version %s\n", __func__, mrdump_lk_version);
 
-		if (of_property_read_string(node, "mrdump,ddr_rsv",
-					    &ddr_rsv) == 0) {
-			if (strcmp(ddr_rsv, "yes") == 0)
-				mparams->drm_ready = true;
-			pr_notice("%s: ddr reserve mode %s\n", __func__,
-				  ddr_rsv);
-		}
-
-		return 0;
+	if (mrdump_ddr_reserve_is_ready()) {
+		mparams->drm_ready = true;
+		pr_notice("%s: ddr reserve mode %s\n", __func__,
+				mrdump_lk_ddr_reserve_ready);
 	}
-	of_node_put(node);
-	pr_notice("%s: Can't find chosen node\n", __func__);
-	return -1;
+
+	return 0;
 }
 
 static int __init mrdump_panic_init(void)
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/aee/mrdump/mrdump_panic_wdt.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/aee/mrdump/mrdump_panic_wdt.c
index 87c755c..a47de22 100755
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/aee/mrdump/mrdump_panic_wdt.c
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/aee/mrdump/mrdump_panic_wdt.c
@@ -391,7 +391,7 @@
 #ifdef CONFIG_ARM64
 	int i;
 #endif
-	void *regs;
+	void *regs = NULL;
 	struct pt_regs pregs;
 	char zaplog[64] = {0};
 	int cpu = get_HW_cpuid();
@@ -430,6 +430,7 @@
 				(cpu * sizeof(struct atf_aee_regs)));
 
 #ifdef CONFIG_ARM64
+		pregs.orig_x0 = 0;
 		pregs.pstate = ((struct atf_aee_regs *)regs)->pstate;
 		pregs.pc = ((struct atf_aee_regs *)regs)->pc;
 		pregs.sp = ((struct atf_aee_regs *)regs)->sp;
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/eccci/port/port_sysmsg.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/eccci/port/port_sysmsg.c
old mode 100644
new mode 100755
index 231a543..2a11083
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/eccci/port/port_sysmsg.c
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/eccci/port/port_sysmsg.c
@@ -180,14 +180,30 @@
 	return 0;
 }
 
+#define MAX_THERMAL_MSG_NUM 15
+static int thermal_msg_count;  // log reduction
+
 static void sys_msg_handler(struct port_t *port, struct sk_buff *skb)
 {
 	struct ccci_header *ccci_h = (struct ccci_header *)skb->data;
 	int md_id = port->md_id;
 
-	CCCI_NORMAL_LOG(md_id, SYS, "system message (%x %x %x %x)\n",
-		ccci_h->data[0], ccci_h->data[1],
-		ccci_h->channel, ccci_h->reserved);
+	if (ccci_h->data[1] != MD_RF_MAX_TEMPERATURE_SUB6) {
+		CCCI_NORMAL_LOG(md_id, SYS, "system message (%x %x %x %x)\n",
+			ccci_h->data[0], ccci_h->data[1],
+			ccci_h->channel, ccci_h->reserved);
+	} else if (ccci_h->data[1] == MD_RF_MAX_TEMPERATURE_SUB6) {
+		if (thermal_msg_count < MAX_THERMAL_MSG_NUM) {
+			thermal_msg_count++;
+		} else {
+			CCCI_NORMAL_LOG(md_id, SYS,
+				"system message (%x %x %x %x) msg_count:%d\n",
+				ccci_h->data[0], ccci_h->data[1],
+				ccci_h->channel, ccci_h->reserved,
+				thermal_msg_count);
+			thermal_msg_count = 0;
+		}
+	}
 	switch (ccci_h->data[1]) {
 	case MD_WDT_MONITOR:
 		/* abandoned */
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/hsm/hsm.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/hsm/hsm.c
old mode 100644
new mode 100755
index 778112d..78857e2
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/hsm/hsm.c
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/hsm/hsm.c
@@ -74,15 +74,11 @@
 static int hsm_suspend(struct platform_device *pdev, pm_message_t mesg)
 {
 	hsm_clock_off();
-	pm_runtime_put_sync(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
 	return 0;
 }
 
 static int hsm_resume(struct platform_device *pdev)
 {
-	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
 	hsm_reset();
 	hsm_clock_on();
 	return 0;
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/pmic/common/upmu.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/pmic/common/upmu.c
old mode 100644
new mode 100755
index 037d08f..51eb17d
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/pmic/common/upmu.c
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/pmic/common/upmu.c
@@ -83,7 +83,7 @@
 		pr_notice("[%s] regmap not ready\n", __func__);
 		return -ENODEV;
 	}
-	ret = regmap_update_bits(map, RegNum, (MASK << SHIFT), (val << SHIFT));
+	ret = regmap_write_bits(map, RegNum, (MASK << SHIFT), (val << SHIFT));
 	if (ret) {
 		dev_notice(chip->dev,
 			"[%s]ret=%d Reg=0x%x val=0x%x MASK=0x%x SHIFT=%d\n",
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/pmic/mt6330/v1/pmic_debugfs.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/pmic/mt6330/v1/pmic_debugfs.c
old mode 100644
new mode 100755
index 9efeda3..aa463be
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/pmic/mt6330/v1/pmic_debugfs.c
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/pmic/mt6330/v1/pmic_debugfs.c
@@ -219,21 +219,21 @@
 
 	PMICLOG("dump PMIC register\n");
 
-	for (i = 0; i < pFlag->offset; i = i + 10) {
+	for (i = 0; i < pFlag->offset; i = i + 5) {
 		pr_notice("Reg[0x%x]=0x%x Reg[0x%x]=0x%x Reg[0x%x]=0x%x Reg[0x%x]=0x%x Reg[0x%x]=0x%x\n"
 			  , i, upmu_get_reg_value(i)
+			  , i + 1, upmu_get_reg_value(i + 1)
 			  , i + 2, upmu_get_reg_value(i + 2)
-			  , i + 4, upmu_get_reg_value(i + 4)
-			  , i + 6, upmu_get_reg_value(i + 6)
-			  , i + 8, upmu_get_reg_value(i + 8));
+			  , i + 3, upmu_get_reg_value(i + 3)
+			  , i + 4, upmu_get_reg_value(i + 4));
 		if (m != NULL) {
 			seq_printf(m,
 				"Reg[0x%x]=0x%x Reg[0x%x]=0x%x Reg[0x%x]=0x%x Reg[0x%x]=0x%x Reg[0x%x]=0x%x\n"
 				, i, upmu_get_reg_value(i)
+				, i + 1, upmu_get_reg_value(i + 1)
 				, i + 2, upmu_get_reg_value(i + 2)
-				, i + 4, upmu_get_reg_value(i + 4)
-				, i + 6, upmu_get_reg_value(i + 6)
-				, i + 8, upmu_get_reg_value(i + 8));
+				, i + 3, upmu_get_reg_value(i + 3)
+				, i + 4, upmu_get_reg_value(i + 4));
 		}
 	}
 }
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/Kconfig b/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/Kconfig
old mode 100644
new mode 100755
index 6bfe8d0..d0205ab
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/Kconfig
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/Kconfig
@@ -6,13 +6,4 @@
 	  with mediatek sensor architecture.
 	  If unsure, say N.
 
-config MTK_SENSOR_ARCHITECTURE
-	string "MTK SENSOR ARCHITECTURE"
-	default "dummy"
-	help
-	  Sensor config for sensor architecture in project.
-	  Please set 1.0/2.0/3.0 etc if you want to support sensor
-	  with mediatek sensor architecture.
-	  If unsure, set dummy.
-
-source "drivers/misc/mediatek/sensor/2.0/Kconfig"
+source "drivers/misc/mediatek/sensor/iio/Kconfig"
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/Makefile b/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/Makefile
old mode 100644
new mode 100755
index 31c6d23..3bd9bfc
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/Makefile
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/Makefile
@@ -1 +1 @@
-obj-y += $(subst ",,$(CONFIG_MTK_SENSOR_ARCHITECTURE))/
+obj-y += iio/
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/iio/Kconfig b/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/iio/Kconfig
new file mode 100755
index 0000000..5314271
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/iio/Kconfig
@@ -0,0 +1,9 @@
+config MTK_BMP380_IIO_SUPPORT
+	bool "MTK_BMP380_IIO_SUPPORT for MediaTek package"
+	default n
+	help
+	  Enable MTK BMP380 IIO subsystem support.
+	  BMP380 is a low-power and low-noise
+	  barometric pressure sensor.
+	  If in doubt, say N here.
+
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/iio/Makefile b/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/iio/Makefile
new file mode 100755
index 0000000..5d69b53
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/iio/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MTK_BMP380_IIO_SUPPORT) += bmp380_iio.o
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/iio/bmp380_iio.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/iio/bmp380_iio.c
new file mode 100755
index 0000000..28b0047
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/sensor/iio/bmp380_iio.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+
+#define CHECK_CHIP_ID_TIME_MAX          0x05
+#define C_I2C_FIFO_SIZE                 0x08
+#define PRESSURE_SENSOR_NAME            "bmp380"
+#define BOSCH_BMP380_ID                 0x50
+
+#define BOSCH_BMP380_REG_RESET          0x7e
+#define BOSCH_BMP380_REG_DIG_T1         0x31
+#define BOSCH_BMP380_REG_ID             0x00
+#define BOSCH_BMP380_REG_CTRL_ODR       0x1d  //Control the Output Data Rate
+#define BOSCH_BMP380_REG_CTRL_OSR       0x1c  //Control the OverSampling
+#define BOSCH_BMP380_REG_CTRL_PWR       0x1b
+#define BOSCH_BMP380_REG_CONFIG         0x1f  //iir filter coefficents
+#define BOSCH_BMP380_REG_PRESS_LSB      0x04
+#define BOSCH_BMP380_REG_FIFO_WTM_1     0x16
+#define BOSCH_BMP380_REG_FIFO_WTM_0     0x15
+#define BOSCH_BMP380_REG_FIFO_CONFIG_1  0x17
+#define BOSCH_BMP380_REG_FIFO_CONFIG_2  0x18
+
+#define BOSCH_BMP380_GAIN_VALUE         100
+
+struct BMP380CompParams {
+	uint16_t par_t1;
+	uint16_t par_t2;
+	int8_t par_t3;
+
+	int16_t par_p1;
+	int16_t par_p2;
+	int8_t par_p3;
+	int8_t par_p4;
+	u16 par_p5;
+	u16 par_p6;
+	int8_t par_p7;
+	int8_t par_p8;
+	int16_t par_p9;
+	int8_t par_p10;
+	int8_t par_p11;
+	s64 t_lin;
+} __packed;
+
+struct bmp380_device_priv {
+	uint32_t i2c_num;
+	uint32_t i2c_addr;
+	struct i2c_client *client;
+	struct BMP380CompParams comp;
+	atomic_t raw_enable;
+};
+
+static const struct iio_chan_spec bmp380_channels[] = {
+	{
+		.type = IIO_PRESSURE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+	},
+};
+
+
+/* I2C operation functions */
+static int bmp_i2c_read_block(struct i2c_client *client,
+				uint8_t addr, uint8_t *data, uint8_t len)
+{
+	int err = 0;
+	uint8_t beg = addr;
+	struct i2c_msg msgs[2] = {
+		{/*.addr = client->addr,*/
+		.flags = 0,
+		.len = 1,
+		.buf = &beg},
+		{
+			/*.addr = client->addr*/
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = data,
+		} };
+	if (!client)
+		return -EINVAL;
+	msgs[0].addr = client->addr;
+	msgs[1].addr = client->addr;
+
+	err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (err != 2) {
+		pr_err_ratelimited("bmp380 i2c_trans err:%x %x (%d %p %d) %d\n",
+				msgs[0].addr, client->addr, addr, data, len,
+				err);
+		err = -EIO;
+	} else {
+		err = 0; /*no error*/
+	}
+	return err;
+}
+
+static int bmp_i2c_write_block(struct i2c_client *client,
+				uint8_t addr, uint8_t *data, uint8_t len)
+{
+	/* because address also occupies one byte,
+	 * the maximum length for write is 7 bytes
+	 */
+	int err = 0, idx = 0, num = 0;
+	char buf[32];
+
+	if (!client)
+		return -EINVAL;
+	else if (len > C_I2C_FIFO_SIZE) {
+		pr_err_ratelimited("bmp380 len %d fi %d\n", len,
+				   C_I2C_FIFO_SIZE);
+		return -EINVAL;
+	}
+	buf[num++] = addr;
+	for (idx = 0; idx < len; idx++)
+		buf[num++] = data[idx];
+
+	err = i2c_master_send(client, buf, num);
+	if (err < 0) {
+		pr_err_ratelimited("bmp380 send command error!!\n");
+		return -EFAULT;
+	}
+
+	return err;
+}
+
+static int bmp380_soft_reset(struct i2c_client *client)
+{
+	uint8_t data = 0xb6;
+
+	return bmp_i2c_write_block(client, BOSCH_BMP380_REG_RESET, &data, 1);
+}
+
+static int bmp380_check_chip_id(struct i2c_client *client)
+{
+	int err = -1;
+	uint8_t chip_id = 0;
+	uint8_t read_count = 0;
+
+	while (read_count++ < CHECK_CHIP_ID_TIME_MAX) {
+		bmp_i2c_read_block(client, BOSCH_BMP380_REG_ID,
+				   &chip_id, 1);
+
+		if (chip_id != BOSCH_BMP380_ID) {
+			mdelay(1);
+			pr_err("%s fail(0x%2x).\n",
+				__func__, chip_id);
+		} else {
+			err = 0;
+			pr_info("%s success(0x%2x).\n",
+				__func__, chip_id);
+			break;
+		}
+	}
+	return err;
+}
+
+static int bmp380_init_device(struct i2c_client *client,
+		struct bmp380_device_priv *priv)
+{
+	int err = -1;
+	uint8_t tx_buf[2] = {0};
+	uint8_t rx_buf[8] = {0};
+
+	err = bmp380_soft_reset(client);
+	if (err < 0) {
+		pr_err("bmp380 soft reset fail,exit probe!\n");
+		goto i2c_fail;
+	}
+
+	mdelay(2);
+
+	tx_buf[0] = BOSCH_BMP380_REG_DIG_T1;
+	err = bmp_i2c_read_block(client, tx_buf[0], rx_buf, 0x08);
+	if (err < 0) {
+		pr_err("bmp380 read block BOSCH_BMP380_REG_DIG_T1 fail\n");
+		goto i2c_fail;
+	}
+	memcpy((uint8_t *)&priv->comp, rx_buf, 8);
+
+	tx_buf[0] = BOSCH_BMP380_REG_DIG_T1 + 8;
+	err = bmp_i2c_read_block(client, tx_buf[0], rx_buf, 0x08);
+	if (err < 0) {
+		pr_err("bmp380 read block BOSCH_BMP380_REG_DIG_T1+8 fail\n");
+		goto i2c_fail;
+	}
+	memcpy((uint8_t *)((uint8_t *)&priv->comp + 8), rx_buf, 8);
+
+	tx_buf[0] = BOSCH_BMP380_REG_DIG_T1 + 16;
+	err = bmp_i2c_read_block(client, tx_buf[0], rx_buf, 0x05);
+	if (err < 0) {
+		pr_err("bmp380 read block BOSCH_BMP380_REG_DIG_T1+16 fail\n");
+		goto i2c_fail;
+	}
+	memcpy((uint8_t *)((uint8_t *)&priv->comp + 16), rx_buf, 5);
+
+	//config oversampling: baro:16x, temp:2x
+	tx_buf[0] = ((4 << 3) | (1 << 0));
+	err = bmp_i2c_write_block(client, BOSCH_BMP380_REG_CTRL_OSR,
+				  tx_buf, 0x01);
+	if (err < 0)
+		pr_err("bmp380 write block BOSCH_BMP380_REG_CTRL_OSR fail!\n");
+
+	tx_buf[0] = 4;//config standy time: 62.5ms
+	err = bmp_i2c_write_block(client, BOSCH_BMP380_REG_CTRL_ODR,
+				  tx_buf, 0x01);
+	if (err < 0) {
+		pr_err("bmp380 write block BOSCH_BMP380_REG_CTRL_ODR fail!\n");
+		goto i2c_fail;
+	}
+
+i2c_fail:
+	return err;
+}
+
+static int64_t compensate_temp(struct bmp380_device_priv *priv,
+				uint32_t uncomp_temp)
+{
+
+	uint64_t partial_data1;
+	uint64_t partial_data2;
+	uint64_t partial_data3;
+	int64_t partial_data4;
+	int64_t partial_data5;
+	int64_t partial_data6;
+	int64_t comp_temp;
+
+	partial_data1 = uncomp_temp - (256 * priv->comp.par_t1);
+	partial_data2 = priv->comp.par_t2 * partial_data1;
+	partial_data3 = partial_data1 * partial_data1;
+	partial_data4 = (int64_t)partial_data3 * priv->comp.par_t3;
+	partial_data5 = ((int64_t)(partial_data2 * 262144) + partial_data4);
+	partial_data6 = partial_data5 / 4294967296;
+	priv->comp.t_lin = partial_data6;
+	comp_temp = (int64_t)((partial_data6 * 25) / 16384);
+
+	//return the tempeature in the unit of 0.01 centigrade.
+	return comp_temp;
+}
+
+static int64_t compensate_baro(struct bmp380_device_priv *priv,
+					uint32_t uncomp_press)
+{
+	int64_t partial_data1;
+	int64_t partial_data2;
+	int64_t partial_data3;
+	int64_t partial_data4;
+	int64_t partial_data5;
+	int64_t partial_data6;
+	int64_t offset;
+	int64_t sensitivity;
+	uint64_t comp_press;
+
+	partial_data1 = priv->comp.t_lin * priv->comp.t_lin;
+	partial_data2 = partial_data1 / 64;
+	partial_data3 = (partial_data2 * priv->comp.t_lin) / 256;
+	partial_data4 = (priv->comp.par_p8 * partial_data3) / 32;
+	partial_data5 = (priv->comp.par_p7 * partial_data1) * 16;
+	partial_data6 = (priv->comp.par_p6 * priv->comp.t_lin)
+		* 4194304;
+	offset = (priv->comp.par_p5 * 140737488355328) + partial_data4
+		+ partial_data5 + partial_data6;
+
+	partial_data2 = (priv->comp.par_p4 * partial_data3) / 32;
+	partial_data4 = (priv->comp.par_p3 * partial_data1) * 4;
+	partial_data5 = (priv->comp.par_p2 - 16384)
+		* priv->comp.t_lin * 2097152;
+	sensitivity = ((priv->comp.par_p1 - 16384) * 70368744177664)
+		+ partial_data2 + partial_data4	+ partial_data5;
+
+	partial_data1 = (sensitivity / 16777216) * uncomp_press;
+	partial_data2 = priv->comp.par_p10 * priv->comp.t_lin;
+	partial_data3 = partial_data2 + (65536 * priv->comp.par_p9);
+	partial_data4 = (partial_data3 * uncomp_press) / 8192;
+	partial_data5 = (partial_data4 * uncomp_press / 10) / 512 * 10;
+	partial_data6 = (int64_t)((uint64_t)uncomp_press
+		* (uint64_t)uncomp_press);
+	partial_data2 = (priv->comp.par_p11 * partial_data6) / 65536;
+	partial_data3 = (partial_data2 * uncomp_press) / 128;
+	partial_data4 = (offset / 4) + partial_data1 + partial_data5
+		+ partial_data3;
+	comp_press = (((uint64_t)partial_data4 * 25)
+		/ (uint64_t)1099511627776);
+
+	//return the press in the unit of the 0.01 Pa.
+	return comp_press;
+}
+
+static int bmp_get_pressure(struct bmp380_device_priv *priv, s32 *p_buf)
+{
+	uint32_t press_adc;
+	uint32_t temp_adc;
+	int ret = 0;
+	uint32_t data_xlsb;
+	uint32_t data_lsb;
+	uint32_t data_msb;
+	uint8_t tx_buf[1] = {0};
+	uint8_t rx_buf[6] = {0};
+	int64_t temp = 0, press = 0;
+	struct i2c_client *client = priv->client;
+
+	tx_buf[0] = BOSCH_BMP380_REG_PRESS_LSB;
+	ret = bmp_i2c_read_block(client, tx_buf[0], rx_buf, 6);
+	if (ret < 0) {
+		pr_err("%s failed\n", __func__);
+		return ret;
+	}
+
+	data_xlsb = (uint32_t)rx_buf[0];
+	data_lsb = (uint32_t)rx_buf[1] << 8;
+	data_msb = (uint32_t)rx_buf[2] << 16;
+	press_adc  = data_msb | data_lsb | data_xlsb;
+
+	data_xlsb = (uint32_t)rx_buf[3];
+	data_lsb = (uint32_t)rx_buf[4] << 8;
+	data_msb = (uint32_t)rx_buf[5] << 16;
+	temp_adc = data_msb | data_lsb | data_xlsb;
+
+	temp = compensate_temp(priv, temp_adc);
+	press = compensate_baro(priv, press_adc);
+	*p_buf = (s32)press * BOSCH_BMP380_GAIN_VALUE / 10000;
+
+	return 0;
+}
+
+static int bmp380_sample(struct bmp380_device_priv *priv)
+{
+	s32 value = 0;
+	int err = 0;
+
+	if (!priv) {
+		pr_err("bmp380 sample failed:invalid bmp380_device_priv\n");
+		return -1;
+	}
+
+	err = bmp_get_pressure(priv, &value);
+	if (err) {
+		pr_err("bmp_get_pressure failed\n");
+		return err;
+	}
+
+	//pr_info("%s successfully get sample: %d\n", __func__, value);
+	return value;
+}
+
+static int bmp380_enable(struct bmp380_device_priv *priv, int en)
+{
+	int ret = 0;
+	struct i2c_client *client;
+	uint8_t tx_buf[1] = {0};
+	int retry = 0;
+
+	client = priv->client;
+
+	if (en)
+		tx_buf[0] = (3 << 4 | 1 << 1 | 1 << 0);
+	else
+		tx_buf[0] = (2 << 5 | 5 << 2);
+
+	for (retry = 0; retry < 3; retry++) {
+		ret = bmp_i2c_write_block(client,
+					BOSCH_BMP380_REG_CTRL_PWR,
+					tx_buf, 0x01);
+		if (ret >= 0) {
+			pr_debug("%s (%d) done(retry:%d)\n", __func__,
+				en, retry);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int bmp380_read_raw(struct iio_dev *indio_dev,
+			 struct iio_chan_spec const *chan,
+			 int *val, int *val2, long mask)
+{
+	struct bmp380_device_priv *priv = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_PRESSURE:
+			bmp380_enable(priv, 1);
+			*val = bmp380_sample(priv);
+			bmp380_enable(priv, 0);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info bmp380_info = {
+	.read_raw   = &bmp380_read_raw,
+};
+
+static int bmp380_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int err = 0;
+	struct device *dev = &client->dev;
+	struct iio_dev *indio_dev;
+	struct bmp380_device_priv *priv;
+	int ret;
+
+	err = bmp380_check_chip_id(client);
+	if (err < 0) {
+		pr_err("bmp380 chip id mismatch,exit probe!\n");
+		goto findHW_fail;
+	}
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+	if (!indio_dev) {
+		err = -ENOMEM;
+		goto malloc_fail;
+	}
+
+	priv = iio_priv(indio_dev);
+	priv->client = client;
+
+	indio_dev->dev.parent = dev;
+	indio_dev->name = id->name;
+	indio_dev->channels = bmp380_channels;
+	indio_dev->num_channels = ARRAY_SIZE(bmp380_channels);
+	indio_dev->info = &bmp380_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(dev, "Failed to register IIO device\n");
+		goto init_fail;
+	}
+
+	i2c_set_clientdata(client, indio_dev);
+
+	err = bmp380_init_device(client, priv);
+	if (err < 0) {
+		pr_err("%s fail\n", __func__);
+		goto init_fail;
+	}
+
+	bmp380_enable(priv, 1);
+	ret = bmp380_sample(priv);
+	bmp380_enable(priv, 0);
+
+	pr_info("%s success! Pressure value: %d\n", __func__, ret);
+	return 0;
+
+init_fail:
+//create_manager_fail:
+	kfree(indio_dev);
+malloc_fail:
+findHW_fail:
+	pr_err("%s fail!\n", __func__);
+	return err;
+}
+
+static int bmp380_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+	kfree(indio_dev);
+	return 0;
+}
+
+static const struct i2c_device_id bmp380_id[] = {
+	{PRESSURE_SENSOR_NAME, 0},
+	{},
+};
+
+static const struct of_device_id bmp380_of_match[] = {
+	{.compatible = "mediatek,barometer"},
+	{},
+};
+
+static struct i2c_driver bmp380_driver = {
+	.driver = {
+		.name = PRESSURE_SENSOR_NAME,
+		.bus = &i2c_bus_type,
+		.owner = THIS_MODULE,
+		.of_match_table = bmp380_of_match,
+	},
+	.probe = bmp380_probe,
+	.remove = bmp380_remove,
+	.id_table = bmp380_id
+};
+
+module_i2c_driver(bmp380_driver);
+
+MODULE_DESCRIPTION("bmp380 driver");
+MODULE_AUTHOR("Mediatek");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/Kconfig b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/Kconfig
old mode 100644
new mode 100755
index e90930a..eed09a4
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/Kconfig
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/Kconfig
@@ -26,3 +26,23 @@
 	depends on ARCH_MEDIATEK
 	---help---
 	  Customer special config for multicast ODU support
+
+config MTK_SGMII_NETSYS
+	bool "sgmii for netsys"
+	default n
+	help
+	  Set the PHY sgmii for netsys
+
+	  This selects the sgmii as Netsys ethernet driver
+	  interface. SNPS ethernet driver can only use rgmii
+	  with this configuration.
+
+config MTK_SGMII_SNPS
+	bool "sgmii for snps"
+	default n
+	help
+	  Set the PHY sgmii for snps
+
+	  This selects the sgmii as SNPS ethernet driver
+	  interface. Netsys ethernet driver can only use
+	  another sgmii with this configuration.
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_edma.c b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_edma.c
old mode 100644
new mode 100755
index 3a3242b..10a6735
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_edma.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_edma.c
@@ -661,7 +661,7 @@
 	ring->data = kcalloc(rx_dma_size, sizeof(*ring->data),
 			     GFP_KERNEL);
 	if (!ring->data) {
-		//pr_info("%s: kcalloc error\n", __func__);
+		pr_info("%s: kcalloc error\n", __func__);
 		return -ENOMEM;
 	}
 
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_dbg.c b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
index 2afe494..9a98183 100755
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
@@ -31,19 +31,27 @@
 
 void mt7530_mdio_w32(struct mtk_eth *eth, u32 reg, u32 val)
 {
+	mutex_lock(&eth->mii_bus->mdio_lock);
+
 	_mtk_mdio_write(eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
 	_mtk_mdio_write(eth, 0x1f, (reg >> 2) & 0xf,  val & 0xffff);
 	_mtk_mdio_write(eth, 0x1f, 0x10, val >> 16);
+
+	mutex_unlock(&eth->mii_bus->mdio_lock);
 }
 
 u32 mt7530_mdio_r32(struct mtk_eth *eth, u32 reg)
 {
 	u16 high, low;
 
+	mutex_lock(&eth->mii_bus->mdio_lock);
+
 	_mtk_mdio_write(eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
 	low = _mtk_mdio_read(eth, 0x1f, (reg >> 2) & 0xf);
 	high = _mtk_mdio_read(eth, 0x1f, 0x10);
 
+	mutex_unlock(&eth->mii_bus->mdio_lock);
+
 	return (high << 16) | (low & 0xffff);
 }
 
@@ -351,21 +359,27 @@
 void mii_mgr_read_combine(struct mtk_eth *eth, u32 phy_addr, u32 phy_register,
 			  u32 *read_data)
 {
-	if (mt7530_exist(eth) && phy_addr == 31)
+	if (mt7530_exist(eth) && phy_addr == 31) {
 		*read_data = mt7530_mdio_r32(eth, phy_register);
 
-	else
+	} else {
+		mutex_lock(&eth->mii_bus->mdio_lock);
 		*read_data = _mtk_mdio_read(eth, phy_addr, phy_register);
+		mutex_unlock(&eth->mii_bus->mdio_lock);
+	}
 }
 
 void mii_mgr_write_combine(struct mtk_eth *eth, u32 phy_addr, u32 phy_register,
 			   u32 write_data)
 {
-	if (mt7530_exist(eth) && phy_addr == 31)
+	if (mt7530_exist(eth) && phy_addr == 31) {
 		mt7530_mdio_w32(eth, phy_register, write_data);
 
-	else
+	} else {
+		mutex_lock(&eth->mii_bus->mdio_lock);
 		_mtk_mdio_write(eth, phy_addr, phy_register, write_data);
+		mutex_unlock(&eth->mii_bus->mdio_lock);
+	}
 }
 
 static void mii_mgr_read_cl45(struct mtk_eth *eth, u32 port, u32 devad, u32 reg, u32 *data)
@@ -585,10 +599,10 @@
 	u32 i, j;
 
 	seq_puts(seq, "		<<SCH CONFIG>>\n");
-	seq_printf(seq, "SCH1_SCH2:\t0x%08x\n",
+	seq_printf(seq, "SCH1 2:0x%08x\n",
 		   mtk_r32(eth, MTK_QDMA_TX_SCH1_SCH2));
-	seq_printf(seq, "SCH3_SCH4:\t0x%08x\n",
-		   mtk_r32(eth, MTK_QDMA_TX_SCH1_SCH2));
+	seq_printf(seq, "SCH3 4:0x%08x\n",
+		   mtk_r32(eth, MTK_QDMA_TX_SCH3_SCH4));
 
 	mtk_w32(eth, 0, MTK_QDMA_SEL);
 	seq_puts(seq, "		<<TXQ SCH>>\n");
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_path.c b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_path.c
index a5cf48d..4a3942d 100755
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_path.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_path.c
@@ -236,7 +236,7 @@
 
 	/* Setup SGMIISYS with the determined property */
 	if (MTK_HAS_FLAGS(eth->sgmii->flags[sid], MTK_SGMII_PHYSPEED_AN))
-		err = mtk_sgmii_setup_mode_an(eth->sgmii, sid);
+		err = mtk_sgmii_setup_mode_an(eth->sgmii, sid, eth);
 	else
 		err = mtk_sgmii_setup_mode_force(eth->sgmii, sid, eth);
 
@@ -245,7 +245,6 @@
 
 	regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
 			   SYSCFG0_SGMII_MASK, 0x3 << 8);
-			   
 
 	return 0;
 }
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index e634475..cd34f12 100755
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -65,6 +65,64 @@
 	"wed_mcu_sel", "net_2x_sel", "sgmii_sel", "sgmii_sbus_sel",
 };
 
+#if defined(CONFIG_HW_NAT)
+static struct net_device *mtk_fast_path[MAX_IF_NUM] = {0};
+
+/* The fast paths transmit skb to PPE via Netsys eth.
+ * We register them to HWNAT module only when at least one Netsys eth is up.
+ * Confirm the fast paths were hooked before Netsys eth goes up.
+ */
+
+void mtk_hook_fast_path(struct net_device *dev)
+{
+	int i = 0;
+
+	for (i = 0; i < MAX_IF_NUM; i++) {
+		if (mtk_fast_path[i] == dev) {
+			pr_notice("%s : %s fast path hooked(%d)\n",
+				  __func__, dev->name, i);
+			return;
+		}
+		if (!mtk_fast_path[i]) {
+			mtk_fast_path[i] = dev;
+			pr_notice("%s : %s fast path(%d)\n",
+				  __func__, dev->name, i);
+			return;
+		}
+	}
+}
+
+static void mtk_register_fast_path(void)
+{
+	int i = 0;
+
+	if (ppe_dev_register_hook) {
+		for (i = 0; i < MAX_IF_NUM; i++) {
+			if (mtk_fast_path[i]) {
+				ppe_dev_register_hook(mtk_fast_path[i]);
+				pr_notice("%s : %s fast path(%d)",
+					  __func__, mtk_fast_path[i]->name, i);
+			}
+		}
+	}
+}
+
+static void mtk_unregister_fast_path(void)
+{
+	int i = 0;
+
+	if (ppe_dev_register_hook) {
+		for (i = 0; i < MAX_IF_NUM; i++) {
+			if (mtk_fast_path[i]) {
+				ppe_dev_unregister_hook(mtk_fast_path[i]);
+				pr_notice("%s : %s fast path(%d)",
+					  __func__, mtk_fast_path[i]->name, i);
+			}
+		}
+	}
+}
+#endif
+
 void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
 {
 	__raw_writel(val, eth->base + reg);
@@ -281,12 +339,19 @@
 		return;
 
 	switch (dev->phydev->speed) {
+	case SPEED_2500:
 	case SPEED_1000:
 		mcr |= MAC_MCR_SPEED_1000;
 		break;
 	case SPEED_100:
 		mcr |= MAC_MCR_SPEED_100;
 		break;
+	case SPEED_10: // bit[3:2] is 0
+		break;
+	default:
+		netif_dbg(mac->hw, link, dev, "unsupported speed %d\n",
+			  dev->phydev->speed);
+		break;
 	};
 
 	if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) &&
@@ -320,10 +385,13 @@
 			  flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
 			  flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
 	}
-	mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
 
-	mtk_w32(mac->hw, 0x0104f33b, MTK_MAC_MCR(0));
-	mtk_w32(mac->hw, 0x0104e33b, MTK_MAC_MCR(1));
+	if (MTK_HAS_FLAGS(mac->hw->sgmii->flags[mac->id],
+			  MTK_SGMII_PHYSPEED_AN))
+		mcr = 0x21057300;
+
+	mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
+	pr_notice("mac %d MAC_MCR = %x\n", mac->id, mcr);
 
 	if (dev->phydev->link)
 		netif_carrier_on(dev);
@@ -374,6 +442,10 @@
 	if (!np && of_phy_is_fixed_link(mac->of_node))
 		if (!of_phy_register_fixed_link(mac->of_node))
 			np = of_node_get(mac->of_node);
+
+	if (!np)
+		np = of_node_get(mac->of_node);
+
 	if (!np)
 		return -ENODEV;
 
@@ -443,6 +515,15 @@
 	return -EINVAL;
 }
 
+static void mtk_phy_disconnect(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+
+	phy_disconnect(dev->phydev);
+	if (of_phy_is_fixed_link(mac->of_node))
+		of_phy_deregister_fixed_link(mac->of_node);
+}
+
 static int mtk_mdio_init(struct mtk_eth *eth)
 {
 	struct device_node *mii_np;
@@ -642,7 +723,6 @@
 		hw_stats->tx_bytes += (stats << 32);
 	hw_stats->tx_packets += mtk_r32(mac->hw, base + 0x38);
 	u64_stats_update_end(&hw_stats->syncp);
-
 }
 
 static void mtk_stats_update(struct mtk_eth *eth)
@@ -818,9 +898,8 @@
 
 	itxd = ring->next_free;
 
-	if (itxd == ring->last_free) {
+	if (itxd == ring->last_free)
 		return -ENOMEM;
-	}
 
 	/* set the forward port */
 	fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT;
@@ -876,6 +955,7 @@
 	/* TX SG offload */
 	txd = itxd;
 	nr_frags = skb_shinfo(skb)->nr_frags;
+
 	for (i = 0; i < nr_frags; i++) {
 		struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
 		unsigned int offset = 0;
@@ -1108,7 +1188,10 @@
 	struct mtk_rx_ring *ring;
 	int i;
 
-	if (eth->hwlro) {
+	if (!eth->hwlro) {
+		ring = &eth->rx_ring[0];
+		mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
+	} else {
 		for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
 			ring = &eth->rx_ring[i];
 			if (ring->calc_idx_update) {
@@ -1116,9 +1199,6 @@
 				mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
 			}
 		}
-	} else {
-		ring = &eth->rx_ring[0];
-		mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
 	}
 }
 
@@ -1156,8 +1236,9 @@
 		mac--;
 
 #if defined(CONFIG_HW_NAT)
+		/* fast path FP is QDMA. default uses mac1(eth0) */
 		if (mac > 1)
-			mac = 1;
+			mac = netif_running(eth->netdev[1]) ? 1 : 0;
 #endif
 		if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||
 			     !eth->netdev[mac]))
@@ -1977,11 +2058,11 @@
 	int tx_done = 0;
 
 	mtk_handle_status_irq(eth);
-	mtk_w32(eth, MTK_TX_DONE_INT | MTK_TX_DONE_INT0, MTK_QMTK_INT_STATUS);
+	mtk_w32(eth, MTK_TX_DONE_INT | MTK_TX_DONE_INT0, MTK_QDMA_INT_STATUS);
 	tx_done = mtk_poll_tx(eth, budget);
 
 	if (unlikely(netif_msg_intr(eth))) {
-		status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+		status = mtk_r32(eth, MTK_QDMA_INT_STATUS);
 		mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
 		dev_info(eth->dev,
 			 "done tx %d, intr 0x%08x/0x%x\n",
@@ -1991,7 +2072,7 @@
 	if (tx_done == budget)
 		return budget;
 
-	status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+	status = mtk_r32(eth, MTK_QDMA_INT_STATUS);
 	if (status & MTK_TX_DONE_INT)
 		return budget;
 
@@ -2195,9 +2276,9 @@
 		goto no_tx_mem;
 
 	ring->dma = dma_alloc_coherent(eth->dev,
-					  MTK_DMA_SIZE * sz,
-					  &ring->phys,
-					  GFP_ATOMIC | __GFP_ZERO);
+				       MTK_DMA_SIZE * sz,
+				       &ring->phys,
+				       GFP_ATOMIC | __GFP_ZERO);
 	if (!ring->dma)
 		goto no_tx_mem;
 
@@ -2288,27 +2369,21 @@
 	ring->buf_size = mtk_max_buf_size(ring->frag_size);
 	ring->data = kcalloc(rx_dma_size, sizeof(*ring->data),
 			     GFP_KERNEL);
-	if (!ring->data) {
-		//pr_notice(" data no mem\n");
+	if (!ring->data)
 		return -ENOMEM;
-	}
 
 	for (i = 0; i < rx_dma_size; i++) {
 		ring->data[i] = netdev_alloc_frag(ring->frag_size);
-		if (!ring->data[i]) {
-			//pr_notice(" data no mem 11\n");
+		if (!ring->data[i])
 			return -ENOMEM;
-		}
 	}
 
 	ring->dma = dma_alloc_coherent(eth->dev,
 				       rx_dma_size * sizeof(*ring->dma),
 				       &ring->phys,
 				       GFP_ATOMIC | __GFP_ZERO);
-	if (!ring->dma) {
-		//pr_notice(" dma no mem\n");
+	if (!ring->dma)
 		return -ENOMEM;
-	}
 
 	for (i = 0; i < rx_dma_size; i++) {
 		dma_addr_t dma_addr = dma_map_single(eth->dev,
@@ -3098,7 +3173,7 @@
 {
 	int i;
 
-	for (i = 0; i < 2; i++) {
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
 		u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
 
 		/* default setup the forward port to send frame to PDMA */
@@ -3111,7 +3186,7 @@
 
 		mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
 	}
-	/*Reset and enable PSE*/
+	/* Reset and enable PSE */
 	mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
 	mtk_w32(eth, 0, MTK_RST_GL);
 }
@@ -3122,14 +3197,20 @@
 	struct mtk_eth *eth = mac->hw;
 	int err;
 
-	pr_info("1!!!!! RX desc = %x\n", cpu_to_le32((u32)(4200 - 1)));
+	pr_info("%s in mac[%d]\n", __func__, mac->id);
 
-	regulator_set_voltage(eth->dvfsrc_vcore_power, SGMII_VCORE_OPS, INT_MAX);
+	if (eth->soc->sgmii_pm)
+		regulator_set_voltage(eth->dvfsrc_vcore_power,
+				      SGMII_VCORE_OPS, INT_MAX);
+
 	/* we run 2 netdevs on the same dma ring so we only bring it up once */
 	if (!refcount_read(&eth->dma_refcnt)) {
 		err = mtk_start_dma(eth);
-		if (err)
+
+		if (err) {
+			dev_err(eth->dev, "%s: mtk_start_dma err\n", __func__);
 			return err;
+		}
 		mtk_gdma_config(eth, MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN);
 		napi_enable(&eth->tx_napi);
 
@@ -3156,12 +3237,18 @@
 			mtk_rx_irq_enable_edma_all(eth);
 		}
 
+#if defined(CONFIG_HW_NAT)
+		mtk_register_fast_path();
+#endif
+
 		refcount_set(&eth->dma_refcnt, 1);
 	}
 	else
 		refcount_inc(&eth->dma_refcnt);
 
-	phy_start(dev->phydev);
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY))
+		phy_start(dev->phydev);
+
 	netif_start_queue(dev);
 
 	return 0;
@@ -3196,11 +3283,14 @@
 	struct mtk_eth *eth = mac->hw;
 
 	netif_tx_disable(dev);
-	phy_stop(dev->phydev);
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY))
+		phy_stop(dev->phydev);
 
 	/* only shutdown DMA if this is the last user */
 	if (!refcount_dec_and_test(&eth->dma_refcnt))
 		return 0;
+
 	mtk_gdma_config(eth, MTK_GDMA_DROP_ALL);
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
@@ -3239,7 +3329,14 @@
 	}
 
 	mtk_dma_free(eth);
-	regulator_set_voltage(eth->dvfsrc_vcore_power, SGMII_VCORE_NON_OPS, INT_MAX);
+
+	if (eth->soc->sgmii_pm)
+		regulator_set_voltage(eth->dvfsrc_vcore_power,
+				      SGMII_VCORE_NON_OPS, INT_MAX);
+
+#if defined(CONFIG_HW_NAT)
+	mtk_unregister_fast_path();
+#endif
 
 	return 0;
 }
@@ -3530,6 +3627,7 @@
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	const char *mac_addr;
+	int ret = 0;
 
 	mac_addr = of_get_mac_address(mac->of_node);
 	if (mac_addr)
@@ -3542,7 +3640,10 @@
 			dev->dev_addr);
 	}
 
-	return mtk_phy_connect(dev);
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY))
+		ret = mtk_phy_connect(dev);
+
+	return ret;
 }
 
 static void mtk_uninit(struct net_device *dev)
@@ -3550,20 +3651,25 @@
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 
-	phy_disconnect(dev->phydev);
-	if (of_phy_is_fixed_link(mac->of_node))
-		of_phy_deregister_fixed_link(mac->of_node);
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY))
+		mtk_phy_disconnect(dev);
+
 	mtk_tx_irq_disable(eth, ~0);
 	mtk_rx_irq_disable(eth, ~0);
 }
 
 static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+
 	switch (cmd) {
 	case SIOCGMIIPHY:
 	case SIOCGMIIREG:
 	case SIOCSMIIREG:
-		return phy_mii_ioctl(dev->phydev, ifr, cmd);
+		if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY))
+			return phy_mii_ioctl(dev->phydev, ifr, cmd);
+		break;
 	default:
 		/* default invoke the mtk_eth_dbg handler */
 		return mtk_do_priv_ioctl(dev, ifr, cmd);
@@ -3676,11 +3782,13 @@
 				  struct ethtool_link_ksettings *cmd)
 {
 	struct mtk_mac *mac = netdev_priv(ndev);
+	struct mtk_eth *eth = mac->hw;
 
 	if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
 		return -EBUSY;
 
-	phy_ethtool_ksettings_get(ndev->phydev, cmd);
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY))
+		phy_ethtool_ksettings_get(ndev->phydev, cmd);
 
 	return 0;
 }
@@ -3689,11 +3797,16 @@
 				  const struct ethtool_link_ksettings *cmd)
 {
 	struct mtk_mac *mac = netdev_priv(ndev);
+	struct mtk_eth *eth = mac->hw;
+	int ret = 0;
 
 	if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
 		return -EBUSY;
 
-	return phy_ethtool_ksettings_set(ndev->phydev, cmd);
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY))
+		ret = phy_ethtool_ksettings_set(ndev->phydev, cmd);
+
+	return ret;
 }
 
 static void mtk_get_drvinfo(struct net_device *dev,
@@ -3723,26 +3836,36 @@
 static int mtk_nway_reset(struct net_device *dev)
 {
 	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int ret = 0;
 
 	if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
 		return -EBUSY;
 
-	return genphy_restart_aneg(dev->phydev);
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY))
+		ret = genphy_restart_aneg(dev->phydev);
+
+	return ret;
 }
 
 static u32 mtk_get_link(struct net_device *dev)
 {
 	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
 	int err;
 
 	if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
 		return -EBUSY;
 
-	err = genphy_update_link(dev->phydev);
-	if (err)
-		return ethtool_op_get_link(dev);
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY)) {
+		err = genphy_update_link(dev->phydev);
+		if (err)
+			return ethtool_op_get_link(dev);
 
-	return dev->phydev->link;
+		return dev->phydev->link;
+	}
+
+	return 0;
 }
 
 static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -3867,7 +3990,7 @@
 	.get_sset_count		= mtk_get_sset_count,
 	.get_ethtool_stats	= mtk_get_ethtool_stats,
 	.get_rxnfc		= mtk_get_rxnfc,
-	.set_rxnfc              = mtk_set_rxnfc,
+	.set_rxnfc		= mtk_set_rxnfc,
 };
 
 static const struct net_device_ops mtk_netdev_ops = {
@@ -3880,7 +4003,7 @@
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_do_ioctl		= mtk_do_ioctl,
 	//.ndo_tx_timeout		= mtk_tx_timeout,
-	.ndo_get_stats64        = mtk_get_stats64,
+	.ndo_get_stats64	= mtk_get_stats64,
 	.ndo_fix_features	= mtk_fix_features,
 	.ndo_set_features	= mtk_set_features,
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -4030,9 +4153,9 @@
 		eth->dvfsrc_vcore_power = regulator_get(&pdev->dev, "dvfsrc-vcore");
 		regulator_set_voltage(eth->dvfsrc_vcore_power, SGMII_VCORE_OPS, INT_MAX);
 
+		/* sgmii0 */
 		eth->sgmii_node0 = of_find_compatible_node(NULL, NULL,
 						"mediatek,colgin-sgmiisys_0");
-
 		if (IS_ERR(eth->sgmii_node0)) {
 			dev_err(&pdev->dev, "no eth->sgmii_node0 regmap found\n");
 			return PTR_ERR(eth->sgmii_node0);
@@ -4040,34 +4163,35 @@
 		sgmii_pdev = of_find_device_by_node(eth->sgmii_node0);
 		eth->sgmii_dev0 = &sgmii_pdev->dev;
 
+		/* sgmii1 */
 		eth->sgmii_node1 = of_find_compatible_node(NULL, NULL,
 						"mediatek,colgin-sgmiisys_1");
-		sgmii_pdev = of_find_device_by_node(eth->sgmii_node1);
-		eth->sgmii_dev1 = &sgmii_pdev->dev;
-
 		if (IS_ERR(eth->sgmii_node1)) {
 			dev_err(&pdev->dev, "no eth->sgmii_node1 regmap found\n");
 			return PTR_ERR(eth->sgmii_node1);
 		}
+		sgmii_pdev = of_find_device_by_node(eth->sgmii_node1);
+		eth->sgmii_dev1 = &sgmii_pdev->dev;
 
+		/* sgmii0 phy */
 		eth->sgmii_phy_node0 = of_find_compatible_node(NULL, NULL,
 						"mediatek,colgin-sgmiisys_phy_0");
-		sgmii_pdev = of_find_device_by_node(eth->sgmii_phy_node0);
-		eth->sgmii_phy_dev0 = &sgmii_pdev->dev;
 		if (IS_ERR(eth->sgmii_phy_node0)) {
 			dev_err(&pdev->dev, "no eth->sgmii_phy_node0 regmap found\n");
 			return PTR_ERR(eth->sgmii_phy_node0);
 		}
+		sgmii_pdev = of_find_device_by_node(eth->sgmii_phy_node0);
+		eth->sgmii_phy_dev0 = &sgmii_pdev->dev;
 
-
+		/* sgmii1 phy */
 		eth->sgmii_phy_node1 = of_find_compatible_node(NULL, NULL,
 						"mediatek,colgin-sgmiisys_phy_1");
-		sgmii_pdev = of_find_device_by_node(eth->sgmii_phy_node1);
-		eth->sgmii_phy_dev1 = &sgmii_pdev->dev;
 		if (IS_ERR(eth->sgmii_phy_node1)) {
 			dev_err(&pdev->dev, "no eth->sgmii_phy_node1 regmap found\n");
 			return PTR_ERR(eth->sgmii_phy_node1);
 		}
+		sgmii_pdev = of_find_device_by_node(eth->sgmii_phy_node1);
+		eth->sgmii_phy_dev1 = &sgmii_pdev->dev;
 	}
 
 	if (eth->soc->pinctrl) {
@@ -4293,7 +4417,7 @@
 	struct platform_device *pdev = to_platform_device(device);
 	struct mtk_eth *eth;
 	u32 val = 0;
-	int ret;
+	int i, ret;
 	static int enable_hw_idle = 0;
 
 	if (pdev == NULL) {
@@ -4302,10 +4426,23 @@
 	}
 
 	eth = platform_get_drvdata(pdev);
-        netif_stop_queue(eth->netdev[0]);
-        netif_stop_queue(eth->netdev[1]);
-	phy_stop(eth->netdev[0]->phydev);
-	phy_stop(eth->netdev[1]->phydev);
+
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!eth->netdev[i])
+			continue;
+
+		netif_stop_queue(eth->netdev[i]);
+	}
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY)) {
+		for (i = 0; i < MTK_MAC_COUNT; i++) {
+			if (!eth->netdev[i])
+				continue;
+
+			phy_stop(eth->netdev[i]->phydev);
+		}
+	}
+
 #if 0
 	regmap_update_bits(eth->ethsys, MTK_PPE_TB_CFG,
 			   SCAN_MODE_MASK,
@@ -4316,7 +4453,11 @@
 #endif
 	mtk_w32(eth, 0x7fb5, MTK_PPE_TB_CFG);
 	mtk_w32(eth, 0x7fb5, MTK_PPE1_TB_CFG);
-	regulator_set_voltage(eth->dvfsrc_vcore_power, SGMII_VCORE_NON_OPS, INT_MAX);
+
+	if (eth->soc->sgmii_pm)
+		regulator_set_voltage(eth->dvfsrc_vcore_power,
+				      SGMII_VCORE_NON_OPS, INT_MAX);
+
 	mtk_gdma_config(eth, MTK_GDMA_DROP_ALL);
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
 	if (eth->hwrss) {
@@ -4379,7 +4520,7 @@
 	struct platform_device *pdev = to_platform_device(device);
 	struct device_node *np;
 	struct mtk_eth *eth;
-	int err;
+	int i, err;
 	const char *str;
 
 //	if (pdev == NULL) {
@@ -4400,20 +4541,37 @@
 	mtk_w32(eth, 0x27fb5, MTK_PPE_TB_CFG);
 	mtk_w32(eth, 0x27fb5, MTK_PPE1_TB_CFG);
 
-	np = of_parse_phandle(pdev->dev.of_node, "mediatek,sgmiisys", 0);
-	err = of_property_read_string(np, "mediatek,physpeed", &str);
-	if (err)
-		return err;
+	if (eth->soc->sgmii_pm) {
+		np = of_parse_phandle(pdev->dev.of_node,
+				      "mediatek,sgmiisys", 0);
 
-	if (refcount_read(&eth->dma_refcnt)) {
-		if (!strcmp(str, "auto"))
-			regulator_set_voltage(eth->dvfsrc_vcore_power, SGMII_VCORE_1G, INT_MAX);
-		 else
-			regulator_set_voltage(eth->dvfsrc_vcore_power, SGMII_VCORE_OPS, INT_MAX);
+		err = of_property_read_string(np, "mediatek,physpeed", &str);
+		if (err)
+			return err;
+
+		if (refcount_read(&eth->dma_refcnt)) {
+			if (!strcmp(str, "auto"))
+				regulator_set_voltage(eth->dvfsrc_vcore_power,
+						      SGMII_VCORE_1G, INT_MAX);
+			else
+				regulator_set_voltage(eth->dvfsrc_vcore_power,
+						      SGMII_VCORE_OPS, INT_MAX);
+		}
 	}
-	//mtk_clk_enable(eth);
-	mtk_sgmii_setup_mode_force(eth->sgmii, 0, eth);
-	mtk_sgmii_setup_mode_force(eth->sgmii, 1, eth);
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY)) {
+		for (i = 0; i < MTK_MAC_COUNT; i++) {
+			if (!eth->netdev[i])
+				continue;
+
+			if (MTK_HAS_FLAGS(eth->sgmii->flags[i],
+					  MTK_SGMII_PHYSPEED_AN))
+				mtk_sgmii_setup_mode_an(eth->sgmii, i, eth);
+			else
+				mtk_sgmii_setup_mode_force(eth->sgmii, i, eth);
+		}
+	}
+
 	//napi_enable(&eth->tx_napi);
 	//napi_enable(&eth->rx_napi);
 	mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
@@ -4443,10 +4601,22 @@
 	else
 		mtk_w32(eth, 0x00200081, MTK_PDMA_LRO_CTRL_DW0);
 	mtk_w32(eth, 0x80001c04, MTK_PDMA_GLO_CFG);
-	phy_start(eth->netdev[0]->phydev);
-	phy_start(eth->netdev[1]->phydev);
-	netif_start_queue(eth->netdev[0]);
-	netif_start_queue(eth->netdev[1]);
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY)) {
+		for (i = 0; i < MTK_MAC_COUNT; i++) {
+			if (!eth->netdev[i])
+				continue;
+
+			phy_start(eth->netdev[i]->phydev);
+		}
+	}
+
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!eth->netdev[i])
+			continue;
+
+		netif_start_queue(eth->netdev[i]);
+	}
 	//pr_notice("netsys resume_noirq done\n");
 
 	return 0;
@@ -4503,12 +4673,27 @@
 	.sgmii_pm = true,
 };
 
+static const struct mtk_soc_data mt2735_data = {
+	.ana_rgc3 = 0x128,
+	.irq_num = 9,
+#if defined(CONFIG_EDMA_RX)
+	.caps = MT2735_CAPS | MTK_HWLRO | MTK_EDMA_RX,
+#else
+	.caps = MT2735_CAPS | MTK_HWLRO,
+#endif
+	.required_clks = MT2735_CLKS_BITMAP,
+	.required_pctl = false,
+	.pinctrl = false,
+	.sgmii_pm = false,
+};
+
 const struct of_device_id of_mtk_match[] = {
 	{ .compatible = "mediatek,mt2701-eth", .data = &mt2701_data},
 	{ .compatible = "mediatek,mt7622-eth", .data = &mt7622_data},
 	{ .compatible = "mediatek,mt7623-eth", .data = &mt7623_data},
 	{ .compatible = "mediatek,mt7629-eth", .data = &mt7629_data},
 	{ .compatible = "mediatek,mt6890-eth", .data = &mt6890_data},
+	{ .compatible = "mediatek,mt2735-eth", .data = &mt2735_data},
 	{ .compatible = "mediatek,fpga-eth", .data = &fpga_data},
 	{},
 };
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 5597e0c..4e89135 100755
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -299,7 +299,7 @@
 #define FC_THRES_MIN		0x4444
 
 /* QDMA Interrupt Status Register */
-#define MTK_QMTK_INT_STATUS	0x1A18
+#define MTK_QDMA_INT_STATUS	0x1A18
 #define MTK_RX_DONE_DLY		BIT(30)
 #define MTK_RX_DONE_DLY3	BIT(27)
 #define MTK_RX_DONE_DLY2	BIT(26)
@@ -412,6 +412,7 @@
 
 /* Mac control registers */
 #define MTK_MAC_MCR(x)		(0x10100 + (x * 0x100))
+#define MTK_MAC_PPSC		0x10000
 
 #define MAC_MCR_MAX_RX_1536	BIT(24)
 #define MAC_MCR_IPG_CFG		BIT(18)
@@ -504,6 +505,7 @@
 /* Register to auto-negotiation restart */
 #define SGMSYS_PCS_CONTROL_1	0x0
 #define SGMII_AN_RESTART	BIT(9)
+#define SGMII_AN_ENABLE		BIT(12)
 
 /* Register to programmable link timer, the unit in 2 * 8ns */
 #define SGMSYS_PCS_LINK_TIMER	0x18
@@ -760,27 +762,35 @@
 				 BIT(MTK_CLK_SGMII_CK) | \
 				 BIT(MTK_CLK_ETH2PLL))
 #define LEOPARD_CLKS_BITMAP	(BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) |  \
-				BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \
-				BIT(MTK_CLK_GP2) | BIT(MTK_CLK_FE) | \
-				BIT(MTK_CLK_SGMII_TX_250M) | \
-				BIT(MTK_CLK_SGMII_RX_250M) | \
-				BIT(MTK_CLK_SGMII_CDR_REF) | \
-				BIT(MTK_CLK_SGMII_CDR_FB) | \
-				BIT(MTK_CLK_SGMII2_TX_250M) | \
-				BIT(MTK_CLK_SGMII2_RX_250M) | \
-				BIT(MTK_CLK_SGMII2_CDR_REF) | \
-				BIT(MTK_CLK_SGMII2_CDR_FB) | \
-				BIT(MTK_CLK_SGMII_CK) | \
-				BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP))
+				 BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \
+				 BIT(MTK_CLK_GP2) | BIT(MTK_CLK_FE) | \
+				 BIT(MTK_CLK_SGMII_TX_250M) | \
+				 BIT(MTK_CLK_SGMII_RX_250M) | \
+				 BIT(MTK_CLK_SGMII_CDR_REF) | \
+				 BIT(MTK_CLK_SGMII_CDR_FB) | \
+				 BIT(MTK_CLK_SGMII2_TX_250M) | \
+				 BIT(MTK_CLK_SGMII2_RX_250M) | \
+				 BIT(MTK_CLK_SGMII2_CDR_REF) | \
+				 BIT(MTK_CLK_SGMII2_CDR_FB) | \
+				 BIT(MTK_CLK_SGMII_CK) | \
+				 BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP))
 
 #define MT6890_CLKS_BITMAP	(BIT(MTK_CLK_NETSYS_SEL) | \
-				BIT(MTK_CLK_MEDSYS_SEL) | \
-				BIT(MTK_CLK_NETSYS_500M_SEL) | \
-				BIT(MTK_CLK_NETSYS_MED_MCU_SEL) | \
-				BIT(MTK_CLK_NETSYS_WED_MCU_SEL) | \
-				BIT(MTK_CLK_NETSYS_2X_SEL) | \
-				BIT(MTK_CLK_SGMII_SEL) | \
-				BIT(MTK_CLK_SGMII_SBUS_SEL))
+				 BIT(MTK_CLK_MEDSYS_SEL) | \
+				 BIT(MTK_CLK_NETSYS_500M_SEL) | \
+				 BIT(MTK_CLK_NETSYS_MED_MCU_SEL) | \
+				 BIT(MTK_CLK_NETSYS_WED_MCU_SEL) | \
+				 BIT(MTK_CLK_NETSYS_2X_SEL) | \
+				 BIT(MTK_CLK_SGMII_SEL) | \
+				 BIT(MTK_CLK_SGMII_SBUS_SEL))
+
+#define MT2735_CLKS_BITMAP	(BIT(MTK_CLK_NETSYS_SEL) | \
+				 BIT(MTK_CLK_MEDSYS_SEL) | \
+				 BIT(MTK_CLK_NETSYS_500M_SEL) | \
+				 BIT(MTK_CLK_NETSYS_MED_MCU_SEL) | \
+				 BIT(MTK_CLK_NETSYS_WED_MCU_SEL) | \
+				 BIT(MTK_CLK_NETSYS_2X_SEL))
+
 enum mtk_dev_state {
 	MTK_HW_INIT,
 	MTK_RESETTING
@@ -831,7 +841,6 @@
 	MTK_RX_FLAGS_QDMA,
 	MTK_RX_FLAGS_EDMA0,
 	MTK_RX_FLAGS_EDMA1,
-
 };
 
 /* struct mtk_rx_ring -	This struct holds info describing a RX ring
@@ -891,7 +900,7 @@
 #define MTK_FPGA_CLK			BIT(12)
 #define MTK_HWRSS			BIT(13)
 #define MTK_EDMA_RX			BIT(14)
-
+#define MTK_DISABLE_PHY			BIT(15)
 
 /* Capability for features on SoCs */
 #define MTK_PATH_BIT(x)         BIT((x) + 20)
@@ -960,16 +969,19 @@
 
 #define MT6890_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
 		      MTK_SGMII_PHY)
+
+#define MT2735_CAPS  (MTK_DISABLE_PHY)
+
 /* struct mtk_eth_data -	This is the structure holding all differences
-*				among various plaforms
-* @ana_rgc3:                   The offset for register ANA_RGC3 related to
-*				sgmiisys syscon
-* @caps			Flags shown the extra capability for the SoC
-* @required_clks		Flags shown the bitmap for required clocks on
-*				the target SoC
-* @required_pctl		A bool value to show whether the SoC requires
-*				the extra setup for those pins used by GMAC.
-*/
+ *				among various plaforms
+ * @ana_rgc3:                   The offset for register ANA_RGC3 related to
+ *				sgmiisys syscon
+ * @caps			Flags shown the extra capability for the SoC
+ * @required_clks		Flags shown the bitmap for required clocks on
+ *				the target SoC
+ * @required_pctl		A bool value to show whether the SoC requires
+ *				the extra setup for those pins used by GMAC.
+ */
 struct mtk_soc_data {
 	u32             ana_rgc3;
 	u32		caps;
@@ -988,9 +1000,11 @@
 };
 
 #define MTK_SGMII_PHYSPEED_AN          BIT(31)
-#define MTK_SGMII_PHYSPEED_MASK        GENMASK(2, 0)
+#define MTK_SGMII_PHYSPEED_MASK        GENMASK(3, 0)
 #define MTK_SGMII_PHYSPEED_1000        BIT(0)
 #define MTK_SGMII_PHYSPEED_2500        BIT(1)
+#define MTK_SGMII_PHYSPEED_100         BIT(2)
+#define MTK_SGMII_PHYSPEED_10          BIT(3)
 #define MTK_HAS_FLAGS(flags, _x)       (((flags) & (_x)) == (_x))
 
 /* struct mtk_sgmii -  This is the structure holding sgmii regmap and its
@@ -1140,8 +1154,8 @@
 u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
 
 int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np,
-			u32 ana_rgc3);
-int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id);
+		   u32 ana_rgc3);
+int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id, struct mtk_eth *eth);
 int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id,
 					struct mtk_eth *eth);
 int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode);
@@ -1149,6 +1163,8 @@
 #if defined(CONFIG_HW_NAT)
 extern int (*ppe_hook_rx_eth)(struct sk_buff *skb);
 extern int (*ppe_hook_tx_eth)(struct sk_buff *skb, int gmac_no);
+extern void (*ppe_dev_register_hook)(struct net_device *dev);
+extern void (*ppe_dev_unregister_hook)(struct net_device *dev);
 #endif
 
 #define MTK_EDMA0_GLO_CFG	0x3A04
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_sgmii.c b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_sgmii.c
index ddbacb9..5648633 100755
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -381,6 +381,10 @@
 			ss->flags[i] |= MTK_SGMII_PHYSPEED_2500;
 		else if (!strcmp(str, "1000"))
 			ss->flags[i] |= MTK_SGMII_PHYSPEED_1000;
+		else if (!strcmp(str, "100"))
+			ss->flags[i] |= MTK_SGMII_PHYSPEED_100;
+		else if (!strcmp(str, "10"))
+			ss->flags[i] |= MTK_SGMII_PHYSPEED_10;
 		else if (!strcmp(str, "auto"))
 			ss->flags[i] |= MTK_SGMII_PHYSPEED_AN;
 		else
@@ -398,28 +402,34 @@
 	return 0;
 }
 
-int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id)
+int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id, struct mtk_eth *eth)
 {
 	unsigned int val = 0;
 
 	if (!ss->regmap[id])
 		return -EINVAL;
 
-	/* Setup the link timer and QPHY power up inside SGMIISYS */
-	regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER,
-		  SGMII_LINK_TIMER_DEFAULT);
+	pr_info("%s\n", __func__);
+	mtk_sgmii_setup_mode_force(ss, id, eth);
 
-	regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val);
-	val |= SGMII_REMOTE_FAULT_DIS;
-	regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
+	regmap_update_bits(ss->regmap[id], 0x128, GENMASK(3, 2), 0x0 << 2);
+	mtk_w32(eth, 0x21057300, MTK_MAC_MCR(id));
+	regmap_update_bits(ss->regmap[id], 0x0, GENMASK(31, 0), 0x41140);
+	regmap_update_bits(ss->regmap[id], 0x20, GENMASK(31, 0), 0x3112000B);
+
+	// TODO: MTK_MAC_PPSC phy id should move to dts
+	mtk_w32(eth, 0xc5000605, MTK_MAC_PPSC);
 
 	regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
-	val |= SGMII_AN_RESTART;
-	regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
+	pr_info("AN PCS_control[%d] = %x\n", id, val);
 
-	regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
-	val &= ~SGMII_PHYA_PWD;
-	regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val);
+	//debug info
+	regmap_read(ss->regmap[id], 0x128, &val);
+	pr_info("AN 0x128[%d] = %x\n", id, val);
+	regmap_read(ss->regmap[id], 0x20, &val);
+	pr_info("AN 0x020[%d] = %x\n", id, val);
+	regmap_read(ss->regmap[id], 0x0, &val);
+	pr_info("AN 0x000[%d] = %x\n", id, val);
 
 	return 0;
 }
@@ -432,19 +442,34 @@
 	if (!ss->regmap[id])
 		return -EINVAL;
 
+	mode = ss->flags[id] & MTK_SGMII_PHYSPEED_MASK;
+
+	/* SGMII clock */
 	regmap_read(ss->regmap[id], ss->ana_rgc3, &val);
 	val &= ~GENMASK(3, 2);
-	mode = ss->flags[id] & MTK_SGMII_PHYSPEED_MASK;
-	val |= (mode == MTK_SGMII_PHYSPEED_1000) ? 0 : BIT(2);
+	val |= (mode == MTK_SGMII_PHYSPEED_2500) ? BIT(2) : 0;
 	regmap_write(ss->regmap[id], ss->ana_rgc3, val);
 
 	/* disable SGMII AN */
 	regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
-	val &= ~BIT(12);
+	val &= ~SGMII_AN_ENABLE;
 	regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
 
 	/* SGMII force mode setting */
-	val = 0x31120009;
+	val = 0x31120001;
+	switch (mode) {
+	case MTK_SGMII_PHYSPEED_2500:
+	case MTK_SGMII_PHYSPEED_1000:
+		val |= BIT(3);
+		break;
+	case MTK_SGMII_PHYSPEED_100:
+		val |= BIT(2);
+		break;
+	case MTK_SGMII_PHYSPEED_10: // bit[3:2] is 0
+		break;
+	default:
+		pr_info("unsupported sgmii mode %d", mode);
+	};
 	regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
 
 	/* Release PHYA power down state */
@@ -455,7 +480,7 @@
 	/*SET SGMII PHY parameter*/
 	pr_info("sgmii phy caps[%d] = %x \n", id, eth->soc->caps);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII_PHY)) {
-		if(mode == MTK_SGMII_PHYSPEED_2500)
+		if (mode == MTK_SGMII_PHYSPEED_2500)
 			mtk_sgmii_phy_gen2(ss, id);
 		else
 			mtk_sgmii_phy_gen1(ss, id);
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
old mode 100644
new mode 100755
index 7d0d374..d3746da
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
@@ -104,7 +104,7 @@
 #define MTK_USE_SGMII		1
 
 /*SGMII require vcore*/
-#define SGMII_VCORE_OPS		750000
+#define SGMII_VCORE_OPS		650000
 
 struct mac_delay_struct {
 	u32 tx_delay;
@@ -158,6 +158,9 @@
 /* list of clocks required for mac */
 static const char * const mt2735_dwmac_clk_l[] = {
 	"mac_main", "ptp_ref", "eth_cg", "eth_rmii"
+#if defined(CONFIG_MTK_SGMII_SNPS)
+	, "sgmii_sel", "sgmii_sbus_sel"
+#endif
 };
 
 static int eth_smt_result = 2;
@@ -946,6 +949,8 @@
 		mac_delay->tx_delay /= 80;
 		mac_delay->rx_delay /= 80;
 		break;
+	case PHY_INTERFACE_MODE_SGMII:
+		break;
 	default:
 		dev_err(plat->dev, "phy interface not supported\n");
 		break;
@@ -965,6 +970,8 @@
 		mac_delay->tx_delay *= 80;
 		mac_delay->rx_delay *= 80;
 		break;
+	case PHY_INTERFACE_MODE_SGMII:
+		break;
 	default:
 		dev_err(plat->dev, "phy interface not supported\n");
 		break;
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac.h
old mode 100644
new mode 100755
index 301c01d..36d6b80
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -172,6 +172,7 @@
 	int synopsys_id;
 	u32 msg_enable;
 	int wolopts;
+	int phy_wolopts;
 	int wol_irq;
 	int clk_csr;
 	struct timer_list eee_ctrl_timer;
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
old mode 100644
new mode 100755
index a43e1e6..a57df0c
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -637,15 +637,18 @@
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
 
-	if (!priv->plat->pmt)
-		return phy_ethtool_get_wol(dev->phydev, wol);
+	phy_ethtool_get_wol(dev->phydev, wol);
 
-	mutex_lock(&priv->lock);
-	if (device_can_wakeup(priv->device)) {
-		wol->supported = WAKE_MAGIC | WAKE_UCAST;
-		wol->wolopts = priv->wolopts;
+	if (!!wol->supported) {
+		return;
+	} else if (priv->plat->pmt) {
+		mutex_lock(&priv->lock);
+		if (device_can_wakeup(priv->device)) {
+			wol->supported = WAKE_MAGIC | WAKE_UCAST;
+			wol->wolopts = priv->wolopts;
+		}
+		mutex_unlock(&priv->lock);
 	}
-	mutex_unlock(&priv->lock);
 }
 
 static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -653,40 +656,46 @@
 	struct stmmac_priv *priv = netdev_priv(dev);
 	u32 support = WAKE_MAGIC | WAKE_UCAST;
 
-	if (!priv->plat->pmt) {
-		int ret = phy_ethtool_set_wol(dev->phydev, wol);
+	int ret = phy_ethtool_set_wol(dev->phydev, wol);
 
-		if (!ret)
-			device_set_wakeup_enable(priv->device, !!wol->wolopts);
+	if (!ret && (wol->wolopts & WAKE_MAGIC)) {
+		device_set_wakeup_enable(priv->device, !!wol->wolopts);
+		priv->phy_wolopts = WAKE_MAGIC;
 		return ret;
-	}
-
-	/* By default almost all GMAC devices support the WoL via
-	 * magic frame but we can disable it if the HW capability
-	 * register shows no support for pmt_magic_frame. */
-	if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame))
-		wol->wolopts &= ~WAKE_MAGIC;
-
-	if (!device_can_wakeup(priv->device))
-		return -EINVAL;
-
-	if (wol->wolopts & ~support)
-		return -EINVAL;
-
-	if (wol->wolopts) {
-		pr_info("stmmac: wakeup enable\n");
-		device_set_wakeup_enable(priv->device, 1);
-		enable_irq_wake(priv->wol_irq);
 	} else {
-		device_set_wakeup_enable(priv->device, 0);
-		disable_irq_wake(priv->wol_irq);
+		priv->phy_wolopts = 0;
 	}
 
-	mutex_lock(&priv->lock);
-	priv->wolopts = wol->wolopts;
-	mutex_unlock(&priv->lock);
+	if (priv->plat->pmt) {
+		/* By default almost all GMAC devices support the WoL via
+		 * magic frame but we can disable it if the HW capability
+		 * register shows no support for pmt_magic_frame.
+		 */
+		if (priv->hw_cap_support && !priv->dma_cap.pmt_magic_frame)
+			wol->wolopts &= ~WAKE_MAGIC;
 
-	return 0;
+		if (!device_can_wakeup(priv->device))
+			return -EINVAL;
+
+		if (wol->wolopts & ~support)
+			return -EINVAL;
+
+		if (wol->wolopts) {
+			pr_info("stmmac: wakeup enable\n");
+			device_set_wakeup_enable(priv->device, 1);
+			enable_irq_wake(priv->wol_irq);
+		} else {
+			device_set_wakeup_enable(priv->device, 0);
+			disable_irq_wake(priv->wol_irq);
+		}
+
+		mutex_lock(&priv->lock);
+		priv->wolopts = wol->wolopts;
+		mutex_unlock(&priv->lock);
+		ret = 0;
+	}
+
+	return ret;
 }
 
 static int stmmac_ethtool_op_get_eee(struct net_device *dev,
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
old mode 100644
new mode 100755
index ba75fdd..b34725d
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -964,7 +964,6 @@
 	char bus_id[MII_BUS_ID_SIZE];
 	int interface = priv->plat->interface;
 	int max_speed = priv->plat->max_speed;
-	int ret;
 	priv->oldlink = false;
 	priv->speed = SPEED_UNKNOWN;
 	priv->oldduplex = DUPLEX_UNKNOWN;
@@ -1039,11 +1038,6 @@
 	if (priv->plat->phy_intr_irq > 0) {
 		phy_ethtool_get_wol(phydev, &wol);
 		device_set_wakeup_capable(priv->device, !!wol.supported);
-		wol.wolopts = WAKE_MAGIC;
-		ret = phy_ethtool_set_wol(phydev, &wol);
-
-		if (!ret)
-			device_set_wakeup_enable(priv->device, !!wol.wolopts);
 	}
 
 	return 0;
@@ -4566,6 +4560,10 @@
 		goto error_netdev_register;
 	}
 
+#if defined(CONFIG_HW_NAT)
+	mtk_hook_fast_path(ndev);
+#endif
+
 #ifdef CONFIG_DEBUG_FS
 	ret = stmmac_init_fs(ndev);
 	if (ret < 0)
@@ -4664,7 +4662,7 @@
 	stmmac_stop_all_dma(priv);
 
 	/* Enable Power down mode by programming the PMT regs */
-	if (device_may_wakeup(priv->device) && priv->plat->pmt) {
+	if (device_may_wakeup(priv->device) && priv->wolopts) {
 		stmmac_pmt(priv, priv->hw, priv->wolopts);
 		priv->irq_wake = 1;
 	} else {
@@ -4676,7 +4674,7 @@
 		clk_disable_unprepare(priv->plat->pclk);
 		clk_disable_unprepare(priv->plat->stmmac_clk);
 
-		if (priv->plat->phy_intr_irq > 0)
+		if (priv->plat->phy_intr_irq > 0 && priv->phy_wolopts)
 			enable_irq_wake(priv->plat->phy_intr_irq);
 	}
 	mutex_unlock(&priv->lock);
@@ -4745,7 +4743,7 @@
 	 * this bit because it can generate problems while resuming
 	 * from another devices (e.g. serial console).
 	 */
-	if (device_may_wakeup(priv->device) && priv->plat->pmt) {
+	if (device_may_wakeup(priv->device) && priv->wolopts) {
 		mutex_lock(&priv->lock);
 		stmmac_pmt(priv, priv->hw, 0);
 		mutex_unlock(&priv->lock);
@@ -4772,7 +4770,7 @@
 			phy_init_hw(priv->dev->phydev);
 		}
 
-		if (priv->plat->phy_intr_irq > 0) {
+		if (priv->plat->phy_intr_irq > 0 && priv->phy_wolopts) {
 			disable_irq_wake(priv->plat->phy_intr_irq);
 			err = phy_ethtool_set_wol(priv->dev->phydev, &wol);
 
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
old mode 100644
new mode 100755
index 37c0bc6..cc1895a
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -314,7 +314,12 @@
 
 		priv->plat->tx_queues_cfg[queue].mode_to_use = MTL_QUEUE_AVB;
 	} else if (!qopt->enable) {
-		return stmmac_dma_qmode(priv, priv->ioaddr, queue, MTL_QUEUE_DCB);
+		ret = stmmac_dma_qmode(priv, priv->ioaddr, queue,
+				       MTL_QUEUE_DCB);
+		if (ret)
+			return ret;
+
+		priv->plat->tx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB;
 	}
 
 	/* Port Transmit Rate and Speed Divider */
diff --git a/src/kernel/linux/v4.19/drivers/net/phy/marvell-88q.c b/src/kernel/linux/v4.19/drivers/net/phy/marvell-88q.c
old mode 100644
new mode 100755
index 6fb740a..297a56b
--- a/src/kernel/linux/v4.19/drivers/net/phy/marvell-88q.c
+++ b/src/kernel/linux/v4.19/drivers/net/phy/marvell-88q.c
@@ -169,7 +169,6 @@
 	return 0;
 }
 
-
 static int q2110_read_status(struct phy_device *phydev)
 {
 	int val;
@@ -177,10 +176,19 @@
 	phydev->duplex = 1;
 	phydev->pause = 0;
 
+	if (!phy_polling_mode(phydev) || !phydev->link) {
+		val = phy_read(phydev, Q2110_T1_AN_STATUS);
+		if (val < 0)
+			return val;
+		else if (val & Q2110_T1_LINK_STATUS)
+			goto done;
+	}
+
 	val = phy_read(phydev, Q2110_T1_AN_STATUS);
 	if (val < 0)
 		return val;
 
+done:
 	if (val & Q2110_T1_LINK_STATUS)
 		phydev->link = 1;
 	else
diff --git a/src/kernel/linux/v4.19/drivers/net/phy/micrel.c b/src/kernel/linux/v4.19/drivers/net/phy/micrel.c
old mode 100644
new mode 100755
index 3957ada..2a367bc
--- a/src/kernel/linux/v4.19/drivers/net/phy/micrel.c
+++ b/src/kernel/linux/v4.19/drivers/net/phy/micrel.c
@@ -710,6 +710,13 @@
 	else if (ret & 0xff)
 		return 0;
 
+	ret = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
+			   KSZ9131RN_WAKE_ON_LAN_CONTROL);
+	if (ret < 0)
+		return ret;
+	else if (!(ret & KSZ9131RN_WOL_ENABLE_MAGIC_PKT))
+		return 0;
+
 	ret = phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
 			     KSZ9131RN_WAKE_ON_LAN_CONTROL,
 			     KSZ9131RN_WOL_ENABLE_MAGIC_PKT, 0);
diff --git a/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk-scpsys.c b/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk-scpsys.c
index c4c151d..20ebc23 100755
--- a/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk-scpsys.c
+++ b/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk-scpsys.c
@@ -37,6 +37,7 @@
 #define MTK_SCPD_ALWAYS_ON		BIT(3)
 #define MTK_SCPD_MD_OPS			BIT(4)
 #define MTK_SCPD_NETSYS_OPS		BIT(5)
+#define MTK_SCPD_HSM_OPS		BIT(6)
 #define MTK_SCPD_CAPS(_scpd, _x)	((_scpd)->data->caps & (_x))
 
 #define SPM_VDE_PWR_CON			0x0210
@@ -169,6 +170,10 @@
 #define MT6890_TOP_AXI_PROT_EN_INFRA_VDNR_1_MSDC	(BIT(3) | BIT(16))
 #define MT6890_TOP_AXI_PROT_EN_INFRA_VDNR_1_SSUSB	(BIT(1) | BIT(2))
 #define MT6890_TOP_AXI_PROT_EN_INFRA_VDNR_3_SSUSB	(BIT(11))
+#define MT6890_TOP_AXI_PROT_EN_2_HSM		(BIT(19) | BIT(21))
+#define MT6890_TOP_AXI_PROT_EN_HSM		(BIT(2) | BIT(3))
+#define MT6890_TOP_AXI_PROT_EN_HSM_2ND		(BIT(4))
+#define MT6890_TOP_AXI_PROT_EN_2_HSM_2ND	(BIT(16) | BIT(17))
 
 enum clk_id {
 	CLK_NONE,
@@ -186,6 +191,7 @@
 	CLK_ETH3,
 	CLK_ETH4,
 	CLK_EIP97,
+	CLK_HSM,
 	CLK_MAX,
 };
 
@@ -205,6 +211,7 @@
 	"snps_ptp_sel",
 	"snps_rmii_sel",
 	"eip97_sel",
+	"hsm_sel",
 	NULL,
 };
 
@@ -636,8 +643,18 @@
 		writel(val, ctl_addr);
 	}
 
-	val |= PWR_RST_B_BIT;
-	writel(val, ctl_addr);
+	/* HSM have two special points:
+	 * a. Request bus protect before PWR_RST_B.
+	 * b. Move the RST_B after SRAM_PDN.
+	 */
+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_HSM_OPS)) {
+		ret = scpsys_bus_protect_disable(scpd);
+		if (ret < 0)
+			goto err_pwr_ack;
+	} else { /* !HSM */
+		val |= PWR_RST_B_BIT;
+		writel(val, ctl_addr);
+	}
 
 	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_STRICT_BUSP)) {
 		/*
@@ -665,9 +682,16 @@
 		if (ret < 0)
 			goto err_sram;
 
-		ret = scpsys_bus_protect_disable(scpd);
-		if (ret < 0)
-			goto err_sram;
+		/* HSM Move RST_B after SRAM_PDN to 0. */
+		if (MTK_SCPD_CAPS(scpd, MTK_SCPD_HSM_OPS)) {
+			val = readl(ctl_addr);
+			val |= PWR_RST_B_BIT;
+			writel(val, ctl_addr);
+		} else { /* !HSM */
+			ret = scpsys_bus_protect_disable(scpd);
+			if (ret < 0)
+				goto err_sram;
+		}
 	}
 
 	return 0;
@@ -2032,6 +2056,22 @@
 		.ctl_offs = 0x344,
 		.sram_pdn_bits = GENMASK(8, 8),
 		.sram_pdn_ack_bits = GENMASK(12, 12),
+		.caps = MTK_SCPD_HSM_OPS,
+		.clk_id = {CLK_HSM},
+		.bp_table = {
+			BUS_PROT(IFR_TYPE, 0x0714, 0x0718, 0x0710, 0x0724,
+				 MT6890_TOP_AXI_PROT_EN_2_HSM,
+				 MT6890_TOP_AXI_PROT_EN_2_HSM, 0),
+			BUS_PROT(IFR_TYPE, 0x02A0, 0x02A4, 0x0220, 0x0228,
+				 MT6890_TOP_AXI_PROT_EN_HSM,
+				 MT6890_TOP_AXI_PROT_EN_HSM, 0),
+			BUS_PROT(IFR_TYPE, 0x02A0, 0x02A4, 0x0220, 0x0228,
+				 MT6890_TOP_AXI_PROT_EN_HSM_2ND,
+				 MT6890_TOP_AXI_PROT_EN_HSM_2ND, 0),
+			BUS_PROT(IFR_TYPE, 0x0714, 0x0718, 0x0710, 0x0724,
+				 MT6890_TOP_AXI_PROT_EN_2_HSM_2ND,
+				 MT6890_TOP_AXI_PROT_EN_2_HSM_2ND, 0),
+		},
 	},
 	[MT6890_POWER_DOMAIN_SSUSB] = {
 		.name = "ssusb",
diff --git a/src/kernel/linux/v4.19/drivers/spmi/mtk-pmif.c b/src/kernel/linux/v4.19/drivers/spmi/mtk-pmif.c
old mode 100644
new mode 100755
index b254a88..062cbe4
--- a/src/kernel/linux/v4.19/drivers/spmi/mtk-pmif.c
+++ b/src/kernel/linux/v4.19/drivers/spmi/mtk-pmif.c
@@ -1608,18 +1608,20 @@
 
 	for (i = 0; i < SPMI_MAX_SLAVE_ID; i++) {
 		slv_irq_sta = mtk_spmi_readl(arb, SPMI_SLV_3_0_EINT + (i / 4));
-		slv_irq_sta >>= (((i % 4) * 8) & 0xFF);
+		// Need to use 0xFF to clear SPMI_SLV_x_x_EINT before
+		// callback to pmic, since pmic may rcs to master again in the
+		// callback function, and we also need to deal this request.
+		// If we clear after the callback,
+		// then we may miss this request.
+		mtk_spmi_writel(arb, (0xFF << ((i % 4) * 8)),
+		    SPMI_SLV_3_0_EINT + (i / 4));
+
+		slv_irq_sta = (slv_irq_sta >> ((i % 4) * 8)) & 0xFF;
 		if (arb->rcs_enable_hwirq[i] && slv_irq_sta) {
 			dev_info(&arb->spmic->dev,
 				 "hwirq=%d, sta=0x%x\n", i, slv_irq_sta);
 			handle_nested_irq(irq_find_mapping(arb->domain, i));
 		}
-		/* need to clear using 0xFF to avoid new irq happen
-		 * after read SPMI_SLV_3_0_EINT + (i/4) value then use
-		 * this value to clean
-		 */
-		mtk_spmi_writel(arb, (0xFF << ((i % 4) * 8)),
-				SPMI_SLV_3_0_EINT + (i / 4));
 	}
 	return IRQ_HANDLED;
 }
diff --git a/src/kernel/linux/v4.19/drivers/usb/gadget/function/f_ncm.c b/src/kernel/linux/v4.19/drivers/usb/gadget/function/f_ncm.c
old mode 100644
new mode 100755
index 5780fba..d2b32d1
--- a/src/kernel/linux/v4.19/drivers/usb/gadget/function/f_ncm.c
+++ b/src/kernel/linux/v4.19/drivers/usb/gadget/function/f_ncm.c
@@ -23,6 +23,7 @@
 #include "u_ether.h"
 #include "u_ether_configfs.h"
 #include "u_ncm.h"
+#include "configfs.h"
 
 /*
  * This function is a "CDC Network Control Model" (CDC NCM) Ethernet link.
@@ -35,9 +36,7 @@
 
 /* to trigger crc/non-crc ndp signature */
 
-#define NCM_NDP_HDR_CRC_MASK	0x01000000
 #define NCM_NDP_HDR_CRC		0x01000000
-#define NCM_NDP_HDR_NOCRC	0x00000000
 
 enum ncm_notify_state {
 	NCM_NOTIFY_NONE,		/* don't notify */
@@ -54,6 +53,7 @@
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 	u8				notify_state;
+	atomic_t			notify_count;
 	bool				is_open;
 
 	const struct ndp_parser_opts	*parser_opts;
@@ -85,8 +85,10 @@
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 static inline unsigned ncm_bitrate(struct usb_gadget *g)
 {
-	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
-		return 13 * 1024 * 8 * 1000 * 8;
+	if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS)
+		return 4250000000U;
+	else if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+		return 3750000000U;
 	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
 		return 13 * 512 * 8 * 1000 * 8;
 	else
@@ -526,6 +528,7 @@
 {
 	ncm->parser_opts = &ndp16_opts;
 	ncm->is_crc = false;
+	ncm->ndp_sign = ncm->parser_opts->ndp_sign;
 	ncm->port.cdc_filter = DEFAULT_FILTER;
 
 	/* doesn't make sense for ncm, fixed size used */
@@ -547,7 +550,7 @@
 	int				status;
 
 	/* notification already in flight? */
-	if (!req)
+	if (atomic_read(&ncm->notify_count))
 		return;
 
 	event = req->buf;
@@ -564,8 +567,10 @@
 		event->wLength = 0;
 		req->length = sizeof *event;
 
-		DBG(cdev, "notify connect %s\n",
-				ncm->is_open ? "true" : "false");
+		//DBG(cdev, "notify connect %s\n",
+		//		ncm->is_open ? "true" : "false");
+		LOGI("NCM_NOTIFY_CONNECT is_open %s\n",
+			ncm->is_open ? "true" : "false");
 		ncm->notify_state = NCM_NOTIFY_NONE;
 		break;
 
@@ -580,14 +585,16 @@
 		data[0] = cpu_to_le32(ncm_bitrate(cdev->gadget));
 		data[1] = data[0];
 
-		DBG(cdev, "notify speed %d\n", ncm_bitrate(cdev->gadget));
+		//DBG(cdev, "notify speed %u\n", ncm_bitrate(cdev->gadget));
+		LOGI("NCM_NOTIFY_SPEED speed %u\n", ncm_bitrate(cdev->gadget));
 		ncm->notify_state = NCM_NOTIFY_CONNECT;
 		break;
 	}
 	event->bmRequestType = 0xA1;
 	event->wIndex = cpu_to_le16(ncm->ctrl_id);
 
-	ncm->notify_req = NULL;
+	atomic_inc(&ncm->notify_count);
+
 	/*
 	 * In double buffering if there is a space in FIFO,
 	 * completion callback can be called right after the call,
@@ -597,8 +604,9 @@
 	status = usb_ep_queue(ncm->notify, req, GFP_ATOMIC);
 	spin_lock(&ncm->lock);
 	if (status < 0) {
-		ncm->notify_req = req;
-		DBG(cdev, "notify --> %d\n", status);
+		atomic_dec(&ncm->notify_count);
+		//DBG(cdev, "notify --> %d\n", status);
+		LOGE("usb_ep_queue() fail status %d\n", status);
 	}
 }
 
@@ -632,17 +640,19 @@
 	case 0:
 		VDBG(cdev, "Notification %02x sent\n",
 		     event->bNotificationType);
+		atomic_dec(&ncm->notify_count);
 		break;
 	case -ECONNRESET:
 	case -ESHUTDOWN:
+		atomic_set(&ncm->notify_count, 0);
 		ncm->notify_state = NCM_NOTIFY_NONE;
 		break;
 	default:
 		DBG(cdev, "event %02x --> %d\n",
 			event->bNotificationType, req->status);
+		atomic_dec(&ncm->notify_count);
 		break;
 	}
-	ncm->notify_req = req;
 	ncm_do_notify(ncm);
 	spin_unlock(&ncm->lock);
 }
@@ -700,7 +710,8 @@
 		 */
 		if (w_length != 0 || w_index != ncm->ctrl_id)
 			goto invalid;
-		DBG(cdev, "packet filter %02x\n", w_value);
+		//DBG(cdev, "packet filter %02x\n", w_value);
+		LOGI("packet filter %02x\n", w_value);
 		/*
 		 * REVISIT locking of cdc_filter.  This assumes the UDC
 		 * driver won't have a concurrent packet TX irq running on
@@ -727,7 +738,8 @@
 		value = w_length > sizeof ntb_parameters ?
 			sizeof ntb_parameters : w_length;
 		memcpy(req->buf, &ntb_parameters, value);
-		VDBG(cdev, "Host asked NTB parameters\n");
+		//VDBG(cdev, "Host asked NTB parameters\n");
+		LOGI("Host asked NTB parameters\n");
 		break;
 
 	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
@@ -737,8 +749,10 @@
 			goto invalid;
 		put_unaligned_le32(ncm->port.fixed_in_len, req->buf);
 		value = 4;
-		VDBG(cdev, "Host asked INPUT SIZE, sending %d\n",
-		     ncm->port.fixed_in_len);
+		//VDBG(cdev, "Host asked INPUT SIZE, sending %d\n",
+		//     ncm->port.fixed_in_len);
+		LOGI("Host asked INPUT SIZE, sending %d\n",
+			ncm->port.fixed_in_len);
 		break;
 
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
@@ -764,7 +778,8 @@
 		format = (ncm->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
 		put_unaligned_le16(format, req->buf);
 		value = 2;
-		VDBG(cdev, "Host asked NTB FORMAT, sending %d\n", format);
+		//VDBG(cdev, "Host asked NTB FORMAT, sending %d\n", format);
+		LOGI("Host asked NTB FORMAT, sending %d\n", format);
 		break;
 	}
 
@@ -776,11 +791,13 @@
 		switch (w_value) {
 		case 0x0000:
 			ncm->parser_opts = &ndp16_opts;
-			DBG(cdev, "NCM16 selected\n");
+			//DBG(cdev, "NCM16 selected\n");
+			LOGI("NCM16 selected\n");
 			break;
 		case 0x0001:
 			ncm->parser_opts = &ndp32_opts;
-			DBG(cdev, "NCM32 selected\n");
+			//DBG(cdev, "NCM32 selected\n");
+			LOGI("NCM32 selected\n");
 			break;
 		default:
 			goto invalid;
@@ -798,32 +815,30 @@
 		is_crc = ncm->is_crc ? 0x0001 : 0x0000;
 		put_unaligned_le16(is_crc, req->buf);
 		value = 2;
-		VDBG(cdev, "Host asked CRC MODE, sending %d\n", is_crc);
+		//VDBG(cdev, "Host asked CRC MODE, sending %d\n", is_crc);
+		LOGI("Host asked CRC MODE, sending %d\n", is_crc);
 		break;
 	}
 
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 		| USB_CDC_SET_CRC_MODE:
 	{
-		int ndp_hdr_crc = 0;
-
 		if (w_length != 0 || w_index != ncm->ctrl_id)
 			goto invalid;
 		switch (w_value) {
 		case 0x0000:
 			ncm->is_crc = false;
-			ndp_hdr_crc = NCM_NDP_HDR_NOCRC;
-			DBG(cdev, "non-CRC mode selected\n");
+			//DBG(cdev, "non-CRC mode selected\n");
+			LOGI("non-CRC mode selected\n");
 			break;
 		case 0x0001:
 			ncm->is_crc = true;
-			ndp_hdr_crc = NCM_NDP_HDR_CRC;
-			DBG(cdev, "CRC mode selected\n");
+			//DBG(cdev, "CRC mode selected\n");
+			LOGI("CRC mode selected\n");
 			break;
 		default:
 			goto invalid;
 		}
-		ncm->ndp_sign = ncm->parser_opts->ndp_sign | ndp_hdr_crc;
 		value = 0;
 		break;
 	}
@@ -836,23 +851,34 @@
 
 	default:
 invalid:
-		DBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+		//DBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+		//	ctrl->bRequestType, ctrl->bRequest,
+		//	w_value, w_index, w_length);
+		LOGI("invalid control req%02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
 			w_value, w_index, w_length);
 	}
+	ncm->ndp_sign = ncm->parser_opts->ndp_sign |
+		(ncm->is_crc ? NCM_NDP_HDR_CRC : 0);
 
 	/* respond with data transfer or status phase? */
 	if (value >= 0) {
-		DBG(cdev, "ncm req%02x.%02x v%04x i%04x l%d\n",
+		//DBG(cdev, "ncm req%02x.%02x v%04x i%04x l%d\n",
+		//	ctrl->bRequestType, ctrl->bRequest,
+		//	w_value, w_index, w_length);
+		LOGI("ncm req%02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
 			w_value, w_index, w_length);
 		req->zero = 0;
 		req->length = value;
 		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0)
-			ERROR(cdev, "ncm req %02x.%02x response err %d\n",
-					ctrl->bRequestType, ctrl->bRequest,
-					value);
+			//ERROR(cdev, "ncm req %02x.%02x response err %d\n",
+			//		ctrl->bRequestType, ctrl->bRequest,
+			//		value);
+			LOGE("ncm req %02x.%02x response err %d\n",
+				ctrl->bRequestType, ctrl->bRequest,
+				value);
 	}
 
 	/* device either stalls (value < 0) or reports success */
@@ -865,6 +891,9 @@
 	struct f_ncm		*ncm = func_to_ncm(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
+	LOGI("intf=%d (ctrl=%d data=%d) alt=%d\n",
+		intf, ncm->ctrl_id, ncm->data_id, alt);
+
 	/* Control interface has only altsetting 0 */
 	if (intf == ncm->ctrl_id) {
 		if (alt != 0)
@@ -922,8 +951,10 @@
 			ncm->port.cdc_filter = DEFAULT_FILTER;
 			DBG(cdev, "activate ncm\n");
 			net = gether_connect(&ncm->port);
-			if (IS_ERR(net))
+			if (IS_ERR(net)) {
+				LOGE("gether_connect fail\n");
 				return PTR_ERR(net);
+			}
 			ncm->netdev = net;
 			ncm->timer_stopping = false;
 		}
@@ -1018,6 +1049,12 @@
 	__le16		*ntb_data;
 	__le16		*ntb_ndp;
 	int		dgram_pad;
+	struct skb_shared_info	*pinfo = NULL;
+	skb_frag_t		*frag = NULL;
+	unsigned int	frag_cnt = 0;
+	unsigned int	frag_idx = 0;
+	unsigned int	frag_data_len = 0;
+	char			*frag_data_addr;
 
 	unsigned	max_size = ncm->port.fixed_in_len;
 	const struct ndp_parser_opts *opts = ncm->parser_opts;
@@ -1026,8 +1063,10 @@
 	const int rem = le16_to_cpu(ntb_parameters.wNdpInPayloadRemainder);
 	const int dgram_idx_len = 2 * 2 * opts->dgram_item_len;
 
-	if (!skb && !ncm->skb_tx_data)
+	if (!skb && !ncm->skb_tx_data) {
+		LOGE("skb and skb_tx_data are NULL\n");
 		return NULL;
+	}
 
 	if (skb) {
 		/* Add the CRC if required up front */
@@ -1054,8 +1093,10 @@
 		    ncm->skb_tx_ndp->len + ndp_align + (2 * dgram_idx_len))
 		    > max_size)) {
 			skb2 = package_for_tx(ncm);
-			if (!skb2)
+			if (!skb2) {
+				LOGE("skb2 is NULL\n");
 				goto err;
+			}
 		}
 
 		if (!ncm->skb_tx_data) {
@@ -1065,8 +1106,10 @@
 
 			/* Create a new skb for the NTH and datagrams. */
 			ncm->skb_tx_data = alloc_skb(max_size, GFP_ATOMIC);
-			if (!ncm->skb_tx_data)
+			if (!ncm->skb_tx_data) {
+				LOGE("skb_tx_data alloc fail\n");
 				goto err;
+			}
 
 			ncm->skb_tx_data->dev = ncm->netdev;
 			ntb_data = skb_put_zero(ncm->skb_tx_data, ncb_len);
@@ -1084,8 +1127,10 @@
 						    + opts->dpe_size
 						    * TX_MAX_NUM_DPE),
 						    GFP_ATOMIC);
-			if (!ncm->skb_tx_ndp)
+			if (!ncm->skb_tx_ndp) {
+				LOGE("skb_tx_ndp alloc fail\n");
 				goto err;
+			}
 
 			ncm->skb_tx_ndp->dev = ncm->netdev;
 			ntb_ndp = skb_put(ncm->skb_tx_ndp, opts->ndp_size);
@@ -1098,11 +1143,11 @@
 			ncm->ndp_dgram_count = 1;
 
 			/* Note: we skip opts->next_ndp_index */
-		}
 
-		/* Delay the timer. */
-		hrtimer_start(&ncm->task_timer, TX_TIMEOUT_NSECS,
-			      HRTIMER_MODE_REL_SOFT);
+			/* Start the timer. */
+			hrtimer_start(&ncm->task_timer, TX_TIMEOUT_NSECS,
+				      HRTIMER_MODE_REL_SOFT);
+		}
 
 		/* Add the datagram position entries */
 		ntb_ndp = skb_put_zero(ncm->skb_tx_ndp, dgram_idx_len);
@@ -1119,15 +1164,37 @@
 
 		/* Add the new data to the skb */
 		skb_put_zero(ncm->skb_tx_data, dgram_pad);
-		skb_put_data(ncm->skb_tx_data, skb->data, skb->len);
+
+		if (ncm->netdev->features & NETIF_F_GSO) {
+			pinfo = skb_shinfo(skb);
+			frag_cnt = pinfo->nr_frags;
+		}
+		if (frag_cnt == 0) {
+			skb_put_data(ncm->skb_tx_data, skb->data, skb->len);
+		} else {
+			skb_put_data(ncm->skb_tx_data, skb->data,
+				skb->len - skb->data_len);
+
+			for (frag_idx = 0; frag_idx < frag_cnt; frag_idx++) {
+				frag = pinfo->frags + frag_idx;
+				frag_data_len = skb_frag_size(frag);
+				frag_data_addr = skb_frag_address(frag);
+
+				skb_put_data(ncm->skb_tx_data, frag_data_addr,
+					frag_data_len);
+			}
+		}
+
 		dev_consume_skb_any(skb);
 		skb = NULL;
 
 	} else if (ncm->skb_tx_data && ncm->timer_force_tx) {
 		/* If the tx was requested because of a timeout then send */
 		skb2 = package_for_tx(ncm);
-		if (!skb2)
+		if (!skb2) {
+			LOGE("skb and skb2 are null\n");
 			goto err;
+		}
 	}
 
 	return skb2;
@@ -1180,9 +1247,11 @@
 	int		ndp_index;
 	unsigned	dg_len, dg_len2;
 	unsigned	ndp_len;
+	unsigned	block_len;
 	struct sk_buff	*skb2;
 	int		ret = -EINVAL;
-	unsigned	max_size = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
+	unsigned	ntb_max = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
+	unsigned	frame_max = le16_to_cpu(ecm_desc.wMaxSegmentSize);
 	const struct ndp_parser_opts *opts = ncm->parser_opts;
 	unsigned	crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
 	int		dgram_counter;
@@ -1193,7 +1262,6 @@
 			skb->len);
 		print_hex_dump(KERN_INFO, "HEAD:", DUMP_PREFIX_ADDRESS, 32, 1,
 			       skb->data, 32, false);
-
 		goto err;
 	}
 	tmp += 2;
@@ -1204,8 +1272,9 @@
 	}
 	tmp++; /* skip wSequence */
 
+	block_len = get_ncm(&tmp, opts->block_length);
 	/* (d)wBlockLength */
-	if (get_ncm(&tmp, opts->block_length) > max_size) {
+	if (block_len > ntb_max) {
 		INFO(port->func.config->cdev, "OUT size exceeded\n");
 		goto err;
 	}
@@ -1214,15 +1283,23 @@
 
 	/* Run through all the NDP's in the NTB */
 	do {
-		/* NCM 3.2 */
-		if (((ndp_index % 4) != 0) &&
-				(ndp_index < opts->nth_size)) {
+		/*
+		 * NCM 3.2
+		 * dwNdpIndex
+		 */
+		if (((ndp_index % 4) != 0) ||
+				(ndp_index < opts->nth_size) ||
+				(ndp_index > (block_len -
+					      opts->ndp_size))) {
 			INFO(port->func.config->cdev, "Bad index: %#X\n",
 			     ndp_index);
 			goto err;
 		}
 
-		/* walk through NDP */
+		/*
+		 * walk through NDP
+		 * dwSignature
+		 */
 		tmp = (void *)(skb->data + ndp_index);
 		if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
 			INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
@@ -1233,14 +1310,15 @@
 		ndp_len = get_unaligned_le16(tmp++);
 		/*
 		 * NCM 3.3.1
+		 * wLength
 		 * entry is 2 items
 		 * item size is 16/32 bits, opts->dgram_item_len * 2 bytes
 		 * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry
 		 * Each entry is a dgram index and a dgram length.
 		 */
 		if ((ndp_len < opts->ndp_size
-				+ 2 * 2 * (opts->dgram_item_len * 2))
-				|| (ndp_len % opts->ndplen_align != 0)) {
+				+ 2 * 2 * (opts->dgram_item_len * 2)) ||
+				(ndp_len % opts->ndplen_align != 0)) {
 			INFO(port->func.config->cdev, "Bad NDP length: %#X\n",
 			     ndp_len);
 			goto err;
@@ -1257,8 +1335,21 @@
 
 		do {
 			index = index2;
+			/* wDatagramIndex[0] */
+			if ((index < opts->nth_size) ||
+					(index > block_len - opts->dpe_size)) {
+				INFO(port->func.config->cdev,
+				     "Bad index: %#X\n", index);
+				goto err;
+			}
+
 			dg_len = dg_len2;
-			if (dg_len < 14 + crc_len) { /* ethernet hdr + crc */
+			/*
+			 * wDatagramLength[0]
+			 * ethernet hdr + crc or larger than max frame size
+			 */
+			if ((dg_len < 14 + crc_len) ||
+					(dg_len > frame_max)) {
 				INFO(port->func.config->cdev,
 				     "Bad dgram length: %#X\n", dg_len);
 				goto err;
@@ -1282,14 +1373,23 @@
 			index2 = get_ncm(&tmp, opts->dgram_item_len);
 			dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
 
+			/* wDatagramIndex[1] */
+			if (index2 > block_len - opts->dpe_size) {
+				INFO(port->func.config->cdev,
+				     "Bad index: %#X\n", index2);
+				goto err;
+			}
+
 			/*
 			 * Copy the data into a new skb.
 			 * This ensures the truesize is correct
 			 */
 			skb2 = netdev_alloc_skb_ip_align(ncm->netdev,
 							 dg_len - crc_len);
-			if (skb2 == NULL)
+			if (skb2 == NULL) {
+				LOGE("skb2 alloc fail\n");
 				goto err;
+			}
 			skb_put_data(skb2, skb->data + index,
 				     dg_len - crc_len);
 
@@ -1298,7 +1398,6 @@
 			ndp_len -= 2 * (opts->dgram_item_len * 2);
 
 			dgram_counter++;
-
 			if (index2 == 0 || dg_len2 == 0)
 				break;
 		} while (ndp_len > 2 * (opts->dgram_item_len * 2));
@@ -1318,9 +1417,10 @@
 static void ncm_disable(struct usb_function *f)
 {
 	struct f_ncm		*ncm = func_to_ncm(f);
-	struct usb_composite_dev *cdev = f->config->cdev;
+	//struct usb_composite_dev *cdev = f->config->cdev;
 
-	DBG(cdev, "ncm deactivated\n");
+	//DBG(cdev, "ncm deactivated\n");
+	LOGI("\n");
 
 	if (ncm->port.in_ep->enabled) {
 		ncm->timer_stopping = true;
@@ -1358,7 +1458,8 @@
 {
 	struct f_ncm		*ncm = func_to_ncm(&geth->func);
 
-	DBG(ncm->port.func.config->cdev, "%s\n", __func__);
+	//DBG(ncm->port.func.config->cdev, "%s\n", __func__);
+	LOGI("\n");
 
 	spin_lock(&ncm->lock);
 	ncm->is_open = true;
@@ -1370,7 +1471,8 @@
 {
 	struct f_ncm		*ncm = func_to_ncm(&geth->func);
 
-	DBG(ncm->port.func.config->cdev, "%s\n", __func__);
+	//DBG(ncm->port.func.config->cdev, "%s\n", __func__);
+	LOGI("\n");
 
 	spin_lock(&ncm->lock);
 	ncm->is_open = false;
@@ -1391,10 +1493,22 @@
 	struct usb_ep		*ep;
 	struct f_ncm_opts	*ncm_opts;
 
+	LOGI("\n");
+
 	if (!can_support_ecm(cdev->gadget))
 		return -EINVAL;
 
 	ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
+
+	if (cdev->use_os_string) {
+		f->os_desc_table = kzalloc(sizeof(*f->os_desc_table),
+					   GFP_KERNEL);
+		if (!f->os_desc_table)
+			return -ENOMEM;
+		f->os_desc_n = 1;
+		f->os_desc_table[0].os_desc = &ncm_opts->ncm_os_desc;
+	}
+
 	/*
 	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
 	 * configurations are bound in sequence with list_for_each_entry,
@@ -1408,13 +1522,15 @@
 		status = gether_register_netdev(ncm_opts->net);
 		mutex_unlock(&ncm_opts->lock);
 		if (status)
-			return status;
+			goto fail;
 		ncm_opts->bound = true;
 	}
 	us = usb_gstrings_attach(cdev, ncm_strings,
 				 ARRAY_SIZE(ncm_string_defs));
-	if (IS_ERR(us))
-		return PTR_ERR(us);
+	if (IS_ERR(us)) {
+		status = PTR_ERR(us);
+		goto fail;
+	}
 	ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id;
 	ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id;
 	ncm_data_intf.iInterface = us[STRING_DATA_IDX].id;
@@ -1431,6 +1547,10 @@
 	ncm_control_intf.bInterfaceNumber = status;
 	ncm_union_desc.bMasterInterface0 = status;
 
+	if (cdev->use_os_string)
+		f->os_desc_table[0].if_id =
+			ncm_iad_desc.bFirstInterface;
+
 	status = usb_interface_id(c, f);
 	if (status < 0)
 		goto fail;
@@ -1486,7 +1606,7 @@
 		fs_ncm_notify_desc.bEndpointAddress;
 
 	status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function,
-			ncm_ss_function, NULL);
+			ncm_ss_function, ncm_ss_function);
 	if (status)
 		goto fail;
 
@@ -1502,7 +1622,12 @@
 	hrtimer_init(&ncm->task_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
 	ncm->task_timer.function = ncm_tx_timeout;
 
-	DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+	//DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+	//		gadget_is_superspeed(c->cdev->gadget) ? "super" :
+	//		gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+	//		ncm->port.in_ep->name, ncm->port.out_ep->name,
+	//		ncm->notify->name);
+	LOGI("CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
 			gadget_is_superspeed(c->cdev->gadget) ? "super" :
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			ncm->port.in_ep->name, ncm->port.out_ep->name,
@@ -1510,12 +1635,16 @@
 	return 0;
 
 fail:
+	kfree(f->os_desc_table);
+	f->os_desc_n = 0;
+
 	if (ncm->notify_req) {
 		kfree(ncm->notify_req->buf);
 		usb_ep_free_request(ncm->notify, ncm->notify_req);
 	}
 
-	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
+	//ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
+	LOGE("%s: can't bind, err %d\n", f->name, status);
 
 	return status;
 }
@@ -1564,26 +1693,51 @@
 		gether_cleanup(netdev_priv(opts->net));
 	else
 		free_netdev(opts->net);
+	kfree(opts->ncm_interf_group);
 	kfree(opts);
 }
 
 static struct usb_function_instance *ncm_alloc_inst(void)
 {
 	struct f_ncm_opts *opts;
+	struct usb_os_desc *descs[1];
+	char *names[1];
+	struct config_group *ncm_interf_group;
+
+	LOGI("\n");
 
 	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
-	if (!opts)
+	if (!opts) {
+		LOGE("opts alloc fail\n");
 		return ERR_PTR(-ENOMEM);
+	}
+	opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id;
+
 	mutex_init(&opts->lock);
 	opts->func_inst.free_func_inst = ncm_free_inst;
-	opts->net = gether_setup_default();
+	//opts->net = gether_setup_default();
+	opts->net = gether_setup_name_default("ncm");
 	if (IS_ERR(opts->net)) {
 		struct net_device *net = opts->net;
 		kfree(opts);
+		LOGE("gether_setup_name_default fail\n");
 		return ERR_CAST(net);
 	}
+	INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop);
+
+	descs[0] = &opts->ncm_os_desc;
+	names[0] = "ncm";
 
 	config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type);
+	ncm_interf_group =
+		usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs,
+					       names, THIS_MODULE);
+	if (IS_ERR(ncm_interf_group)) {
+		LOGE("usb_os_desc_prepare_interf_dir fail\n");
+		ncm_free_inst(&opts->func_inst);
+		return ERR_CAST(ncm_interf_group);
+	}
+	opts->ncm_interf_group = ncm_interf_group;
 
 	return &opts->func_inst;
 }
@@ -1593,6 +1747,8 @@
 	struct f_ncm *ncm;
 	struct f_ncm_opts *opts;
 
+	LOGI("\n");
+
 	ncm = func_to_ncm(f);
 	opts = container_of(f->fi, struct f_ncm_opts, func_inst);
 	kfree(ncm);
@@ -1605,13 +1761,22 @@
 {
 	struct f_ncm *ncm = func_to_ncm(f);
 
-	DBG(c->cdev, "ncm unbind\n");
+	//DBG(c->cdev, "ncm unbind\n");
+	LOGI("\n");
 
 	hrtimer_cancel(&ncm->task_timer);
 
+	kfree(f->os_desc_table);
+	f->os_desc_n = 0;
+
 	ncm_string_defs[0].id = 0;
 	usb_free_all_descriptors(f);
 
+	if (atomic_read(&ncm->notify_count)) {
+		usb_ep_dequeue(ncm->notify, ncm->notify_req);
+		atomic_set(&ncm->notify_count, 0);
+	}
+
 	kfree(ncm->notify_req->buf);
 	usb_ep_free_request(ncm->notify, ncm->notify_req);
 }
@@ -1622,10 +1787,14 @@
 	struct f_ncm_opts	*opts;
 	int status;
 
+	LOGI("\n");
+
 	/* allocate and initialize one new instance */
 	ncm = kzalloc(sizeof(*ncm), GFP_KERNEL);
-	if (!ncm)
+	if (!ncm) {
+		LOGE("ncm alloc fail\n");
 		return ERR_PTR(-ENOMEM);
+	}
 
 	opts = container_of(fi, struct f_ncm_opts, func_inst);
 	mutex_lock(&opts->lock);
@@ -1635,6 +1804,7 @@
 	status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr,
 				      sizeof(ncm->ethaddr));
 	if (status < 12) { /* strlen("01234567890a") */
+		LOGE("host addr len < 12 is unexpected\n");
 		kfree(ncm);
 		mutex_unlock(&opts->lock);
 		return ERR_PTR(-EINVAL);
diff --git a/src/kernel/linux/v4.19/drivers/usb/gadget/function/rndis.c b/src/kernel/linux/v4.19/drivers/usb/gadget/function/rndis.c
old mode 100644
new mode 100755
index 8d8f528..402fc83
--- a/src/kernel/linux/v4.19/drivers/usb/gadget/function/rndis.c
+++ b/src/kernel/linux/v4.19/drivers/usb/gadget/function/rndis.c
@@ -1175,7 +1175,7 @@
 		skb_pull(skb, data_offset + 8);
 		num_pkts++;
 
-		if (msg_len == skb->len || data_len == (skb->len -1)) {
+		if (msg_len == skb->len || data_len == skb->len) {
 			skb_trim(skb, data_len);
 			break;
 		}
diff --git a/src/kernel/linux/v4.19/drivers/usb/gadget/function/u_ether.c b/src/kernel/linux/v4.19/drivers/usb/gadget/function/u_ether.c
index 184fcb9..ce6a15e 100755
--- a/src/kernel/linux/v4.19/drivers/usb/gadget/function/u_ether.c
+++ b/src/kernel/linux/v4.19/drivers/usb/gadget/function/u_ether.c
@@ -606,6 +606,9 @@
 	U_ETHER_DBG("%s: to_usb=%d, net->name=%s\n",
 			__func__, to_usb, net->name);
 
+	if (skb == NULL)
+		return 1;
+
 	skb->dev = net;
 
 	if (to_usb) {
@@ -934,7 +937,8 @@
 		return NETDEV_TX_OK;
 	}
 
-	iph = skb->encapsulation ? inner_ip_hdr(skb): ip_hdr(skb);
+	if (skb)
+		iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
 
 	if (uether_tx_rtt_profile)	{
 		rtt_tx_start_time = ktime_get();
@@ -972,7 +976,7 @@
 	}
 
 	/* apply outgoing CDC or RNDIS filters */
-	if (!is_promisc(cdc_filter)) {
+	if (skb && !is_promisc(cdc_filter)) {
 		u8		*dest = skb->data;
 
 		if (is_multicast_ether_addr(dest)) {
diff --git a/src/kernel/linux/v4.19/drivers/usb/gadget/function/u_ncm.h b/src/kernel/linux/v4.19/drivers/usb/gadget/function/u_ncm.h
old mode 100644
new mode 100755
index 67324f9..aac3082
--- a/src/kernel/linux/v4.19/drivers/usb/gadget/function/u_ncm.h
+++ b/src/kernel/linux/v4.19/drivers/usb/gadget/function/u_ncm.h
@@ -7,7 +7,7 @@
  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
- * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
  */
 
 #ifndef U_NCM_H
@@ -15,11 +15,26 @@
 
 #include <linux/usb/composite.h>
 
+#define NCM_VER "1.00"
+//1.00 initial version
+
+#define LOGD(fmt, args...) \
+	pr_emerg("%s NCM DBG, %s, " fmt, NCM_VER, __func__, ## args)
+
+#define LOGI(fmt, args...) \
+	pr_emerg("%s NCM LOG, %s, " fmt, NCM_VER, __func__, ## args)
+
+#define LOGE(fmt, args...) \
+	pr_emerg("%s NCM ERR, %s, " fmt, NCM_VER, __func__, ## args)
+
 struct f_ncm_opts {
 	struct usb_function_instance	func_inst;
 	struct net_device		*net;
 	bool				bound;
 
+	struct config_group		*ncm_interf_group;
+	struct usb_os_desc		ncm_os_desc;
+	char				ncm_ext_compat_id[16];
 	/*
 	 * Read/write access to configfs attributes is handled by configfs.
 	 *
diff --git a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3.h b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3.h
index dc334b1..9606963 100755
--- a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3.h
+++ b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3.h
@@ -508,6 +508,8 @@
 void mtu3_gadget_resume(struct mtu3 *mtu);
 void mtu3_gadget_disconnect(struct mtu3 *mtu);
 
+int mtu3_usb_vbus_detect_init(struct ssusb_mtk *ssusb);//tianyan@2021.11.29 modify for usb otg
+
 irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu);
 extern const struct usb_ep_ops mtu3_ep0_ops;
 
diff --git a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_core.c b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_core.c
index e0ce587..c45daca 100755
--- a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_core.c
+++ b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_core.c
@@ -287,8 +287,12 @@
 void mtu3_dev_on_off(struct mtu3 *mtu, int is_on)
 {
 #ifndef CONFIG_MTU3_MD_USB_EP0_CTRL
-	if (mtu->is_u3_ip && mtu->max_speed >= USB_SPEED_SUPER)
+	if (mtu->is_u3_ip && mtu->max_speed >= USB_SPEED_SUPER){
 		mtu3_ss_func_set(mtu, is_on);
+		dev_dbg(mtu->dev, "%s\n", usb_speed_string(mtu->g.speed));
+		if (!is_on && mtu->g.speed < USB_SPEED_SUPER)
+			mtu3_hs_softconn_set(mtu, is_on);
+	}
 	else
 		mtu3_hs_softconn_set(mtu, is_on);
 #endif
@@ -368,7 +372,8 @@
 
 static irqreturn_t mtu3_vbus_detect_eint_isr(int irq, void *data)
 {
-	struct mtu3 *mtu = data;
+	struct ssusb_mtk *ssusb = data;//tianyan@2021.11.29 modify for usb otg
+	struct mtu3 *mtu = ssusb->u3d;//tianyan@2021.11.29 modify for usb otg
 
 	disable_irq_nosync(irq);
 
@@ -376,19 +381,24 @@
 		dev_info(mtu->dev, "low-level, vbus plug out\n");
 		ssusb_set_force_vbus(mtu->ssusb, false);
 		irq_set_irq_type(irq, IRQF_TRIGGER_HIGH);
+		ssusb->otg_switch.vbus_nb.notifier_call(&ssusb->otg_switch.vbus_nb,false,NULL);//tianyan@2021.11.29 modify for usb otg
 	} else {
 		dev_info(mtu->dev, "high-level, vbus plug in\n");
 		ssusb_set_force_vbus(mtu->ssusb, true);
 		irq_set_irq_type(irq, IRQF_TRIGGER_LOW);
+		ssusb->otg_switch.vbus_nb.notifier_call(&ssusb->otg_switch.vbus_nb,true,NULL);//tianyan@2021.11.29 modify for usb otg
 	}
 	enable_irq(irq);
 	return IRQ_HANDLED;
 }
 
-static int mtu3_usb_vbus_detect_init(struct mtu3 *mtu)
+int mtu3_usb_vbus_detect_init(struct ssusb_mtk *ssusb)//tianyan@2021.11.29 modify for usb otg
 {
 	struct device_node *node;
 	int ret;
+	struct mtu3 *mtu = ssusb->u3d;//tianyan@2021.11.29 modify for usb otg
+	
+	return 0;//tianyan@2021.11.29 modify for usb otg
 
 	node = of_find_compatible_node(NULL, NULL,
 					"mediatek,mtu3");
@@ -435,7 +445,7 @@
 	}
 
 	ret = request_irq(mtu->detect_irq, mtu3_vbus_detect_eint_isr,
-				   IRQF_TRIGGER_LOW, "mtu_detect_eint", mtu);
+				   IRQF_TRIGGER_HIGH, "mtu_detect_eint", ssusb);//tianyan@2021.11.29 modify for usb otg
 	if (ret) {
 		dev_err(mtu->dev, "request eint(%d) fail (%d)\n",
 				   mtu->detect_irq, ret);
@@ -1109,7 +1119,7 @@
 		dev_err(dev, "mtu3 gadget init failed:%d\n", ret);
 		goto gadget_err;
 	}
-	mtu3_usb_vbus_detect_init(mtu);
+	
 	/* init as host mode, power down device IP for power saving */
 	if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
 		mtu3_stop(mtu);
diff --git a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_dr.c b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_dr.c
index 3a3ef38..6fb327d 100755
--- a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_dr.c
+++ b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_dr.c
@@ -42,12 +42,10 @@
 
 static void toggle_opstate(struct ssusb_mtk *ssusb)
 {
-	dev_info(ssusb->dev, "%s\n", __func__);
+     dev_info(ssusb->dev, "%s\n", __func__);
 	//if (!ssusb->otg_switch.is_u3_drd) {//zhengzhou 0318 usb otg */
-	if (!ssusb->otg_switch.is_u3_drd) {
 		mtu3_setbits(ssusb->mac_base, U3D_DEVICE_CONTROL, DC_SESSION);
 		mtu3_setbits(ssusb->mac_base, U3D_POWER_MANAGEMENT, SOFT_CONN);
-	}
 	//}
 }
 
@@ -257,7 +255,7 @@
 
 	if (otg_sx->id_event){
 		mdelay(500);
-		pm_stay_awake(ssusb->dev);
+		pm_stay_awake(ssusb->dev);//tianyan@2021.11.29 modify for usb otg
 		switch_port_to_on(ssusb, true);
 		ssusb_host_enable(ssusb);
 		/* register host driver */
@@ -273,7 +271,7 @@
 		of_platform_depopulate(ssusb->dev);
 		ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
 		switch_port_to_on(ssusb, false);
-		pm_relax(ssusb->dev);
+		pm_relax(ssusb->dev);//tianyan@2021.11.29 modify for usb otg
 		}
 		//zhengzhou 0318 usb otg end*/
 }
diff --git a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_plat.c b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_plat.c
index b3e4b08..3005550 100755
--- a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_plat.c
+++ b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_plat.c
@@ -755,6 +755,7 @@
 			dev_err(dev, "failed to initialize switch\n");
 			goto host_exit;
 		}
+		mtu3_usb_vbus_detect_init(ssusb);//tianyan@2021.11.29 modify for usb otg
 		break;
 	default:
 		dev_err(dev, "unsupported mode: %d\n", ssusb->dr_mode);
@@ -836,9 +837,13 @@
 
 	dev_info(dev, "%s\n", __func__);
 
+	//enable_irq_wake(ssusb->u3d->detect_irq);//tianyan@2021.11.29 modify for usb otg
 	/* REVISIT: disconnect it for only device mode? */
-	if (!ssusb->is_host)
+	if (!ssusb->is_host){//tianyan@2021.11.29 modify for usb otg
+		ssusb_phy_power_off(ssusb);
+		ssusb_clks_disable(ssusb);
 		return 0;
+	}
 
 	ssusb_host_disable(ssusb, true);
 	ssusb_phy_power_off(ssusb);
@@ -854,9 +859,17 @@
 	int ret;
 
 	dev_info(dev, "%s\n", __func__);
-
-	if (!ssusb->is_host)
+	//disable_irq_wake(ssusb->u3d->detect_irq);//tianyan@2021.11.29 modify for usb otg
+	
+	if (!ssusb->is_host){//tianyan@2021.11.29 modify for usb otg
+		ret = ssusb_clks_enable(ssusb);
+		if (ret)
+			goto clks_err;
+		ret = ssusb_phy_power_on(ssusb);
+		if (ret)
+			goto phy_err;
 		return 0;
+	}
 
 	ssusb_wakeup_set(ssusb, false);
 	ret = ssusb_clks_enable(ssusb);
diff --git a/src/kernel/linux/v4.19/include/dt-bindings/clock/mt6890-clk.h b/src/kernel/linux/v4.19/include/dt-bindings/clock/mt6890-clk.h
index b55fac6..b345ae8 100755
--- a/src/kernel/linux/v4.19/include/dt-bindings/clock/mt6890-clk.h
+++ b/src/kernel/linux/v4.19/include/dt-bindings/clock/mt6890-clk.h
@@ -215,7 +215,7 @@
 #define CLK_TOP_NETSYS_SEL		202
 #define CLK_TOP_MEDSYS_SEL		203
 #define CLK_TOP_HSM_CRYPTO_SEL		204 /* no use */
-#define CLK_TOP_HSM_ARC_SEL		205 /* no use */
+#define CLK_TOP_HSM_ARC_SEL		205
 #define CLK_TOP_EIP97_SEL		206
 #define CLK_TOP_SNPS_ETH_312P5M_SEL	207
 #define CLK_TOP_SNPS_ETH_250M_SEL	208
diff --git a/src/kernel/linux/v4.19/include/linux/mfd/mt6330/core.h b/src/kernel/linux/v4.19/include/linux/mfd/mt6330/core.h
old mode 100644
new mode 100755
index aebf8c6..a2596a6
--- a/src/kernel/linux/v4.19/include/linux/mfd/mt6330/core.h
+++ b/src/kernel/linux/v4.19/include/linux/mfd/mt6330/core.h
@@ -29,6 +29,14 @@
 	MT6330_SCK_TOP = 13,
 };
 
+enum mt6330_irq_top_mask_shift {
+	MT6330_BUCK_TOP_MASK = 0,
+	MT6330_LDO_TOP_MASK = 1,
+	MT6330_PSC_TOP_MASK = 2,
+	MT6330_MISC_TOP_MASK = 3,
+	MT6330_SCK_TOP_MASK = 5,
+};
+
 enum mt6330_irq_numbers {
 	MT6330_IRQ_VCORE_OC = 0,
 	MT6330_IRQ_VMD11_OC = 1,
@@ -115,6 +123,7 @@
 	.sta_reg = MT6330_##sp##_TOP_INT_STATUS0,		\
 	.sta_reg_shift = 0x1,	\
 	.top_offset = MT6330_##sp##_TOP,	\
+	.top_mask_offset = MT6330_##sp##_TOP_MASK,	\
 }
 
 struct mt6330_chip {
diff --git a/src/kernel/linux/v4.19/include/net/ra_nat.h b/src/kernel/linux/v4.19/include/net/ra_nat.h
old mode 100644
new mode 100755
index 5963011..189e119
--- a/src/kernel/linux/v4.19/include/net/ra_nat.h
+++ b/src/kernel/linux/v4.19/include/net/ra_nat.h
@@ -544,5 +544,8 @@
 #define QDMA_RX		5
 #define PDMA_RX		0
 
+#if defined(CONFIG_HW_NAT)
+void mtk_hook_fast_path(struct net_device *dev);
+#endif
 
 #endif
diff --git a/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_RATEEST.h b/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_RATEEST.h
old mode 100644
new mode 100755
index 2b87a71..52a37bd
--- a/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_RATEEST.h
+++ b/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_RATEEST.h
@@ -1,17 +1,39 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _XT_RATEEST_TARGET_H
-#define _XT_RATEEST_TARGET_H
+#ifndef _XT_RATEEST_MATCH_H
+#define _XT_RATEEST_MATCH_H
 
 #include <linux/types.h>
 #include <linux/if.h>
 
-struct xt_rateest_target_info {
-	char			name[IFNAMSIZ];
-	__s8			interval;
-	__u8		ewma_log;
-
-	/* Used internally by the kernel */
-	struct xt_rateest	*est __attribute__((aligned(8)));
+enum xt_rateest_match_flags {
+	XT_RATEEST_MATCH_INVERT	= 1<<0,
+	XT_RATEEST_MATCH_ABS	= 1<<1,
+	XT_RATEEST_MATCH_REL	= 1<<2,
+	XT_RATEEST_MATCH_DELTA	= 1<<3,
+	XT_RATEEST_MATCH_BPS	= 1<<4,
+	XT_RATEEST_MATCH_PPS	= 1<<5,
 };
 
-#endif /* _XT_RATEEST_TARGET_H */
+enum xt_rateest_match_mode {
+	XT_RATEEST_MATCH_NONE,
+	XT_RATEEST_MATCH_EQ,
+	XT_RATEEST_MATCH_LT,
+	XT_RATEEST_MATCH_GT,
+};
+
+struct xt_rateest_match_info {
+	char			name1[IFNAMSIZ];
+	char			name2[IFNAMSIZ];
+	__u16		flags;
+	__u16		mode;
+	__u32		bps1;
+	__u32		pps1;
+	__u32		bps2;
+	__u32		pps2;
+
+	/* Used internally by the kernel */
+	struct xt_rateest	*est1 __attribute__((aligned(8)));
+	struct xt_rateest	*est2 __attribute__((aligned(8)));
+};
+
+#endif /* _XT_RATEEST_MATCH_H */
diff --git a/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_TCPMSS.h b/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_TCPMSS.h
old mode 100644
new mode 100755
index 65ea6c9..2268f58
--- a/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_TCPMSS.h
+++ b/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_TCPMSS.h
@@ -1,13 +1,12 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _XT_TCPMSS_H
-#define _XT_TCPMSS_H
+#ifndef _XT_TCPMSS_MATCH_H
+#define _XT_TCPMSS_MATCH_H
 
 #include <linux/types.h>
 
-struct xt_tcpmss_info {
-	__u16 mss;
+struct xt_tcpmss_match_info {
+    __u16 mss_min, mss_max;
+    __u8 invert;
 };
 
-#define XT_TCPMSS_CLAMP_PMTU 0xffff
-
-#endif /* _XT_TCPMSS_H */
+#endif /*_XT_TCPMSS_MATCH_H*/
diff --git a/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_dscp.h b/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_dscp.h
old mode 100644
new mode 100755
index 7594e4d..223d635
--- a/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_dscp.h
+++ b/src/kernel/linux/v4.19/include/uapi/linux/netfilter/xt_dscp.h
@@ -1,32 +1,27 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/* x_tables module for matching the IPv4/IPv6 DSCP field
+/* x_tables module for setting the IPv4/IPv6 DSCP field
  *
  * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
  * This software is distributed under GNU GPL v2, 1991
  *
  * See RFC2474 for a description of the DSCP field within the IP Header.
  *
- * xt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp
+ * xt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
 */
-#ifndef _XT_DSCP_H
-#define _XT_DSCP_H
-
+#ifndef _XT_DSCP_TARGET_H
+#define _XT_DSCP_TARGET_H
+#include <linux/netfilter/xt_dscp.h>
 #include <linux/types.h>
 
-#define XT_DSCP_MASK	0xfc	/* 11111100 */
-#define XT_DSCP_SHIFT	2
-#define XT_DSCP_MAX	0x3f	/* 00111111 */
-
-/* match info */
-struct xt_dscp_info {
+/* target info */
+struct xt_DSCP_info {
 	__u8 dscp;
-	__u8 invert;
 };
 
-struct xt_tos_match_info {
-	__u8 tos_mask;
+struct xt_tos_target_info {
 	__u8 tos_value;
-	__u8 invert;
+	__u8 tos_mask;
 };
 
-#endif /* _XT_DSCP_H */
+#endif /* _XT_DSCP_TARGET_H */
diff --git a/src/kernel/linux/v4.19/include/uapi/linux/netfilter_ipv4/ipt_TTL.h b/src/kernel/linux/v4.19/include/uapi/linux/netfilter_ipv4/ipt_TTL.h
old mode 100644
new mode 100755
index 57d2fc6..ad0226a
--- a/src/kernel/linux/v4.19/include/uapi/linux/netfilter_ipv4/ipt_TTL.h
+++ b/src/kernel/linux/v4.19/include/uapi/linux/netfilter_ipv4/ipt_TTL.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/* TTL modification module for IP tables
- * (C) 2000 by Harald Welte <laforge@netfilter.org> */
+/* IP tables module for matching the value of the TTL
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
 
 #ifndef _IPT_TTL_H
 #define _IPT_TTL_H
@@ -8,14 +8,14 @@
 #include <linux/types.h>
 
 enum {
-	IPT_TTL_SET = 0,
-	IPT_TTL_INC,
-	IPT_TTL_DEC
+	IPT_TTL_EQ = 0,		/* equals */
+	IPT_TTL_NE,		/* not equals */
+	IPT_TTL_LT,		/* less than */
+	IPT_TTL_GT,		/* greater than */
 };
 
-#define IPT_TTL_MAXMODE	IPT_TTL_DEC
 
-struct ipt_TTL_info {
+struct ipt_ttl_info {
 	__u8	mode;
 	__u8	ttl;
 };
diff --git a/src/kernel/linux/v4.19/include/uapi/linux/netfilter_ipv4/ipt_ecn.h b/src/kernel/linux/v4.19/include/uapi/linux/netfilter_ipv4/ipt_ecn.h
old mode 100644
new mode 100755
index 8121bec..e3630fd
--- a/src/kernel/linux/v4.19/include/uapi/linux/netfilter_ipv4/ipt_ecn.h
+++ b/src/kernel/linux/v4.19/include/uapi/linux/netfilter_ipv4/ipt_ecn.h
@@ -1,16 +1,34 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _IPT_ECN_H
-#define _IPT_ECN_H
+/* Header file for iptables ipt_ECN target
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * ipt_ECN.h,v 1.3 2002/05/29 12:17:40 laforge Exp
+*/
+#ifndef _IPT_ECN_TARGET_H
+#define _IPT_ECN_TARGET_H
 
-#include <linux/netfilter/xt_ecn.h>
-#define ipt_ecn_info xt_ecn_info
+#include <linux/types.h>
+#include <linux/netfilter/xt_DSCP.h>
 
-enum {
-	IPT_ECN_IP_MASK       = XT_ECN_IP_MASK,
-	IPT_ECN_OP_MATCH_IP   = XT_ECN_OP_MATCH_IP,
-	IPT_ECN_OP_MATCH_ECE  = XT_ECN_OP_MATCH_ECE,
-	IPT_ECN_OP_MATCH_CWR  = XT_ECN_OP_MATCH_CWR,
-	IPT_ECN_OP_MATCH_MASK = XT_ECN_OP_MATCH_MASK,
+#define IPT_ECN_IP_MASK	(~XT_DSCP_MASK)
+
+#define IPT_ECN_OP_SET_IP	0x01	/* set ECN bits of IPv4 header */
+#define IPT_ECN_OP_SET_ECE	0x10	/* set ECE bit of TCP header */
+#define IPT_ECN_OP_SET_CWR	0x20	/* set CWR bit of TCP header */
+
+#define IPT_ECN_OP_MASK		0xce
+
+struct ipt_ECN_info {
+	__u8 operation;	/* bitset of operations */
+	__u8 ip_ect;	/* ECT codepoint of IPv4 header, pre-shifted */
+	union {
+		struct {
+			__u8 ece:1, cwr:1; /* TCP ECT bits */
+		} tcp;
+	} proto;
 };
 
-#endif /* IPT_ECN_H */
+#endif /* _IPT_ECN_TARGET_H */
diff --git a/src/kernel/linux/v4.19/net/netfilter/xt_TCPMSS.c b/src/kernel/linux/v4.19/net/netfilter/xt_TCPMSS.c
old mode 100644
new mode 100755
index 98efb20..c53d4d1
--- a/src/kernel/linux/v4.19/net/netfilter/xt_TCPMSS.c
+++ b/src/kernel/linux/v4.19/net/netfilter/xt_TCPMSS.c
@@ -1,348 +1,110 @@
-/*
- * This is a module which is used for setting the MSS option in TCP packets.
- *
- * Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
- * Copyright (C) 2007 Patrick McHardy <kaber@trash.net>
+/* Kernel module to match TCP MSS values. */
+
+/* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
+ * Portions (C) 2005 by Harald Welte <laforge@netfilter.org>
  *
  * 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.
  */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <linux/gfp.h>
-#include <linux/ipv6.h>
-#include <linux/tcp.h>
-#include <net/dst.h>
-#include <net/flow.h>
-#include <net/ipv6.h>
-#include <net/route.h>
 #include <net/tcp.h>
 
+#include <linux/netfilter/xt_tcpmss.h>
+#include <linux/netfilter/x_tables.h>
+
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter/xt_tcpudp.h>
-#include <linux/netfilter/xt_TCPMSS.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("Xtables: TCP Maximum Segment Size (MSS) adjustment");
-MODULE_ALIAS("ipt_TCPMSS");
-MODULE_ALIAS("ip6t_TCPMSS");
+MODULE_DESCRIPTION("Xtables: TCP MSS match");
+MODULE_ALIAS("ipt_tcpmss");
+MODULE_ALIAS("ip6t_tcpmss");
 
-static inline unsigned int
-optlen(const u_int8_t *opt, unsigned int offset)
+static bool
+tcpmss_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
-	/* Beware zero-length options: make finite progress */
-	if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
-		return 1;
-	else
-		return opt[offset+1];
-}
+	const struct xt_tcpmss_match_info *info = par->matchinfo;
+	const struct tcphdr *th;
+	struct tcphdr _tcph;
+	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
+	const u_int8_t *op;
+	u8 _opt[15 * 4 - sizeof(_tcph)];
+	unsigned int i, optlen;
 
-static u_int32_t tcpmss_reverse_mtu(struct net *net,
-				    const struct sk_buff *skb,
-				    unsigned int family)
-{
-	struct flowi fl;
-	struct rtable *rt = NULL;
-	u_int32_t mtu     = ~0U;
+	/* If we don't have the whole header, drop packet. */
+	th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
+	if (th == NULL)
+		goto dropit;
 
-	if (family == PF_INET) {
-		struct flowi4 *fl4 = &fl.u.ip4;
-		memset(fl4, 0, sizeof(*fl4));
-		fl4->daddr = ip_hdr(skb)->saddr;
-	} else {
-		struct flowi6 *fl6 = &fl.u.ip6;
+	/* Malformed. */
+	if (th->doff*4 < sizeof(*th))
+		goto dropit;
 
-		memset(fl6, 0, sizeof(*fl6));
-		fl6->daddr = ipv6_hdr(skb)->saddr;
-	}
+	optlen = th->doff*4 - sizeof(*th);
+	if (!optlen)
+		goto out;
 
-	nf_route(net, (struct dst_entry **)&rt, &fl, false, family);
-	if (rt != NULL) {
-		mtu = dst_mtu(&rt->dst);
-		dst_release(&rt->dst);
-	}
-	return mtu;
-}
+	/* Truncated options. */
+	op = skb_header_pointer(skb, par->thoff + sizeof(*th), optlen, _opt);
+	if (op == NULL)
+		goto dropit;
 
-static int
-tcpmss_mangle_packet(struct sk_buff *skb,
-		     const struct xt_action_param *par,
-		     unsigned int family,
-		     unsigned int tcphoff,
-		     unsigned int minlen)
-{
-	const struct xt_tcpmss_info *info = par->targinfo;
-	struct tcphdr *tcph;
-	int len, tcp_hdrlen;
-	unsigned int i;
-	__be16 oldval;
-	u16 newmss;
-	u8 *opt;
+	for (i = 0; i < optlen; ) {
+		if (op[i] == TCPOPT_MSS
+		    && (optlen - i) >= TCPOLEN_MSS
+		    && op[i+1] == TCPOLEN_MSS) {
+			u_int16_t mssval;
 
-	/* This is a fragment, no TCP header is available */
-	if (par->fragoff != 0)
-		return 0;
+			mssval = (op[i+2] << 8) | op[i+3];
 
-	if (!skb_make_writable(skb, skb->len))
-		return -1;
-
-	len = skb->len - tcphoff;
-	if (len < (int)sizeof(struct tcphdr))
-		return -1;
-
-	tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
-	tcp_hdrlen = tcph->doff * 4;
-
-	if (len < tcp_hdrlen || tcp_hdrlen < sizeof(struct tcphdr))
-		return -1;
-
-	if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
-		struct net *net = xt_net(par);
-		unsigned int in_mtu = tcpmss_reverse_mtu(net, skb, family);
-		unsigned int min_mtu = min(dst_mtu(skb_dst(skb)), in_mtu);
-
-		if (min_mtu <= minlen) {
-			net_err_ratelimited("unknown or invalid path-MTU (%u)\n",
-					    min_mtu);
-			return -1;
+			return (mssval >= info->mss_min &&
+				mssval <= info->mss_max) ^ info->invert;
 		}
-		newmss = min_mtu - minlen;
-	} else
-		newmss = info->mss;
-
-	opt = (u_int8_t *)tcph;
-	for (i = sizeof(struct tcphdr); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen(opt, i)) {
-		if (opt[i] == TCPOPT_MSS && opt[i+1] == TCPOLEN_MSS) {
-			u_int16_t oldmss;
-
-			oldmss = (opt[i+2] << 8) | opt[i+3];
-
-			/* Never increase MSS, even when setting it, as
-			 * doing so results in problems for hosts that rely
-			 * on MSS being set correctly.
-			 */
-			if (oldmss <= newmss)
-				return 0;
-
-			opt[i+2] = (newmss & 0xff00) >> 8;
-			opt[i+3] = newmss & 0x00ff;
-
-			inet_proto_csum_replace2(&tcph->check, skb,
-						 htons(oldmss), htons(newmss),
-						 false);
-			return 0;
-		}
+		if (op[i] < 2)
+			i++;
+		else
+			i += op[i+1] ? : 1;
 	}
+out:
+	return info->invert;
 
-	/* There is data after the header so the option can't be added
-	 * without moving it, and doing so may make the SYN packet
-	 * itself too large. Accept the packet unmodified instead.
-	 */
-	if (len > tcp_hdrlen)
-		return 0;
-
-	/* tcph->doff has 4 bits, do not wrap it to 0 */
-	if (tcp_hdrlen >= 15 * 4)
-		return 0;
-
-	/*
-	 * MSS Option not found ?! add it..
-	 */
-	if (skb_tailroom(skb) < TCPOLEN_MSS) {
-		if (pskb_expand_head(skb, 0,
-				     TCPOLEN_MSS - skb_tailroom(skb),
-				     GFP_ATOMIC))
-			return -1;
-		tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
-	}
-
-	skb_put(skb, TCPOLEN_MSS);
-
-	/*
-	 * IPv4: RFC 1122 states "If an MSS option is not received at
-	 * connection setup, TCP MUST assume a default send MSS of 536".
-	 * IPv6: RFC 2460 states IPv6 has a minimum MTU of 1280 and a minimum
-	 * length IPv6 header of 60, ergo the default MSS value is 1220
-	 * Since no MSS was provided, we must use the default values
-	 */
-	if (xt_family(par) == NFPROTO_IPV4)
-		newmss = min(newmss, (u16)536);
-	else
-		newmss = min(newmss, (u16)1220);
-
-	opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
-	memmove(opt + TCPOLEN_MSS, opt, len - sizeof(struct tcphdr));
-
-	inet_proto_csum_replace2(&tcph->check, skb,
-				 htons(len), htons(len + TCPOLEN_MSS), true);
-	opt[0] = TCPOPT_MSS;
-	opt[1] = TCPOLEN_MSS;
-	opt[2] = (newmss & 0xff00) >> 8;
-	opt[3] = newmss & 0x00ff;
-
-	inet_proto_csum_replace4(&tcph->check, skb, 0, *((__be32 *)opt), false);
-
-	oldval = ((__be16 *)tcph)[6];
-	tcph->doff += TCPOLEN_MSS/4;
-	inet_proto_csum_replace2(&tcph->check, skb,
-				 oldval, ((__be16 *)tcph)[6], false);
-	return TCPOLEN_MSS;
-}
-
-static unsigned int
-tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
-{
-	struct iphdr *iph = ip_hdr(skb);
-	__be16 newlen;
-	int ret;
-
-	ret = tcpmss_mangle_packet(skb, par,
-				   PF_INET,
-				   iph->ihl * 4,
-				   sizeof(*iph) + sizeof(struct tcphdr));
-	if (ret < 0)
-		return NF_DROP;
-	if (ret > 0) {
-		iph = ip_hdr(skb);
-		newlen = htons(ntohs(iph->tot_len) + ret);
-		csum_replace2(&iph->check, iph->tot_len, newlen);
-		iph->tot_len = newlen;
-	}
-	return XT_CONTINUE;
-}
-
-#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
-static unsigned int
-tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
-{
-	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
-	u8 nexthdr;
-	__be16 frag_off, oldlen, newlen;
-	int tcphoff;
-	int ret;
-
-	nexthdr = ipv6h->nexthdr;
-	tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off);
-	if (tcphoff < 0)
-		return NF_DROP;
-	ret = tcpmss_mangle_packet(skb, par,
-				   PF_INET6,
-				   tcphoff,
-				   sizeof(*ipv6h) + sizeof(struct tcphdr));
-	if (ret < 0)
-		return NF_DROP;
-	if (ret > 0) {
-		ipv6h = ipv6_hdr(skb);
-		oldlen = ipv6h->payload_len;
-		newlen = htons(ntohs(oldlen) + ret);
-		if (skb->ip_summed == CHECKSUM_COMPLETE)
-			skb->csum = csum_add(csum_sub(skb->csum, oldlen),
-					     newlen);
-		ipv6h->payload_len = newlen;
-	}
-	return XT_CONTINUE;
-}
-#endif
-
-/* Must specify -p tcp --syn */
-static inline bool find_syn_match(const struct xt_entry_match *m)
-{
-	const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
-
-	if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
-	    tcpinfo->flg_cmp & TCPHDR_SYN &&
-	    !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
-		return true;
-
+dropit:
+	par->hotdrop = true;
 	return false;
 }
 
-static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
-{
-	const struct xt_tcpmss_info *info = par->targinfo;
-	const struct ipt_entry *e = par->entryinfo;
-	const struct xt_entry_match *ematch;
-
-	if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
-	    (par->hook_mask & ~((1 << NF_INET_FORWARD) |
-			   (1 << NF_INET_LOCAL_OUT) |
-			   (1 << NF_INET_POST_ROUTING))) != 0) {
-		pr_info_ratelimited("path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
-		return -EINVAL;
-	}
-	if (par->nft_compat)
-		return 0;
-
-	xt_ematch_foreach(ematch, e)
-		if (find_syn_match(ematch))
-			return 0;
-	pr_info_ratelimited("Only works on TCP SYN packets\n");
-	return -EINVAL;
-}
-
-#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
-static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
-{
-	const struct xt_tcpmss_info *info = par->targinfo;
-	const struct ip6t_entry *e = par->entryinfo;
-	const struct xt_entry_match *ematch;
-
-	if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
-	    (par->hook_mask & ~((1 << NF_INET_FORWARD) |
-			   (1 << NF_INET_LOCAL_OUT) |
-			   (1 << NF_INET_POST_ROUTING))) != 0) {
-		pr_info_ratelimited("path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
-		return -EINVAL;
-	}
-	if (par->nft_compat)
-		return 0;
-
-	xt_ematch_foreach(ematch, e)
-		if (find_syn_match(ematch))
-			return 0;
-	pr_info_ratelimited("Only works on TCP SYN packets\n");
-	return -EINVAL;
-}
-#endif
-
-static struct xt_target tcpmss_tg_reg[] __read_mostly = {
+static struct xt_match tcpmss_mt_reg[] __read_mostly = {
 	{
+		.name		= "tcpmss",
 		.family		= NFPROTO_IPV4,
-		.name		= "TCPMSS",
-		.checkentry	= tcpmss_tg4_check,
-		.target		= tcpmss_tg4,
-		.targetsize	= sizeof(struct xt_tcpmss_info),
+		.match		= tcpmss_mt,
+		.matchsize	= sizeof(struct xt_tcpmss_match_info),
 		.proto		= IPPROTO_TCP,
 		.me		= THIS_MODULE,
 	},
-#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 	{
+		.name		= "tcpmss",
 		.family		= NFPROTO_IPV6,
-		.name		= "TCPMSS",
-		.checkentry	= tcpmss_tg6_check,
-		.target		= tcpmss_tg6,
-		.targetsize	= sizeof(struct xt_tcpmss_info),
+		.match		= tcpmss_mt,
+		.matchsize	= sizeof(struct xt_tcpmss_match_info),
 		.proto		= IPPROTO_TCP,
 		.me		= THIS_MODULE,
 	},
-#endif
 };
 
-static int __init tcpmss_tg_init(void)
+static int __init tcpmss_mt_init(void)
 {
-	return xt_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
+	return xt_register_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
 }
 
-static void __exit tcpmss_tg_exit(void)
+static void __exit tcpmss_mt_exit(void)
 {
-	xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
+	xt_unregister_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
 }
 
-module_init(tcpmss_tg_init);
-module_exit(tcpmss_tg_exit);
+module_init(tcpmss_mt_init);
+module_exit(tcpmss_mt_exit);
diff --git a/src/kernel/linux/v4.19/net/netfilter/xt_rateest.c b/src/kernel/linux/v4.19/net/netfilter/xt_rateest.c
old mode 100644
new mode 100755
index bf77326..9e05c86
--- a/src/kernel/linux/v4.19/net/netfilter/xt_rateest.c
+++ b/src/kernel/linux/v4.19/net/netfilter/xt_rateest.c
@@ -8,149 +8,225 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/gen_stats.h>
+#include <linux/jhash.h>
+#include <linux/rtnetlink.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <net/gen_stats.h>
+#include <net/netlink.h>
+#include <net/netns/generic.h>
 
 #include <linux/netfilter/x_tables.h>
-#include <linux/netfilter/xt_rateest.h>
+#include <linux/netfilter/xt_RATEEST.h>
 #include <net/netfilter/xt_rateest.h>
 
+#define RATEEST_HSIZE	16
 
-static bool
-xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par)
+struct xt_rateest_net {
+	struct mutex hash_lock;
+	struct hlist_head hash[RATEEST_HSIZE];
+};
+
+static unsigned int xt_rateest_id;
+
+static unsigned int jhash_rnd __read_mostly;
+
+static unsigned int xt_rateest_hash(const char *name)
 {
-	const struct xt_rateest_match_info *info = par->matchinfo;
-	struct gnet_stats_rate_est64 sample = {0};
-	u_int32_t bps1, bps2, pps1, pps2;
-	bool ret = true;
+	return jhash(name, FIELD_SIZEOF(struct xt_rateest, name), jhash_rnd) &
+	       (RATEEST_HSIZE - 1);
+}
 
-	gen_estimator_read(&info->est1->rate_est, &sample);
+static void xt_rateest_hash_insert(struct xt_rateest_net *xn,
+				   struct xt_rateest *est)
+{
+	unsigned int h;
 
-	if (info->flags & XT_RATEEST_MATCH_DELTA) {
-		bps1 = info->bps1 >= sample.bps ? info->bps1 - sample.bps : 0;
-		pps1 = info->pps1 >= sample.pps ? info->pps1 - sample.pps : 0;
-	} else {
-		bps1 = sample.bps;
-		pps1 = sample.pps;
-	}
+	h = xt_rateest_hash(est->name);
+	hlist_add_head(&est->list, &xn->hash[h]);
+}
 
-	if (info->flags & XT_RATEEST_MATCH_ABS) {
-		bps2 = info->bps2;
-		pps2 = info->pps2;
-	} else {
-		gen_estimator_read(&info->est2->rate_est, &sample);
+static struct xt_rateest *__xt_rateest_lookup(struct xt_rateest_net *xn,
+					      const char *name)
+{
+	struct xt_rateest *est;
+	unsigned int h;
 
-		if (info->flags & XT_RATEEST_MATCH_DELTA) {
-			bps2 = info->bps2 >= sample.bps ? info->bps2 - sample.bps : 0;
-			pps2 = info->pps2 >= sample.pps ? info->pps2 - sample.pps : 0;
-		} else {
-			bps2 = sample.bps;
-			pps2 = sample.pps;
+	h = xt_rateest_hash(name);
+	hlist_for_each_entry(est, &xn->hash[h], list) {
+		if (strcmp(est->name, name) == 0) {
+			est->refcnt++;
+			return est;
 		}
 	}
 
-	switch (info->mode) {
-	case XT_RATEEST_MATCH_LT:
-		if (info->flags & XT_RATEEST_MATCH_BPS)
-			ret &= bps1 < bps2;
-		if (info->flags & XT_RATEEST_MATCH_PPS)
-			ret &= pps1 < pps2;
-		break;
-	case XT_RATEEST_MATCH_GT:
-		if (info->flags & XT_RATEEST_MATCH_BPS)
-			ret &= bps1 > bps2;
-		if (info->flags & XT_RATEEST_MATCH_PPS)
-			ret &= pps1 > pps2;
-		break;
-	case XT_RATEEST_MATCH_EQ:
-		if (info->flags & XT_RATEEST_MATCH_BPS)
-			ret &= bps1 == bps2;
-		if (info->flags & XT_RATEEST_MATCH_PPS)
-			ret &= pps1 == pps2;
-		break;
-	}
-
-	ret ^= info->flags & XT_RATEEST_MATCH_INVERT ? true : false;
-	return ret;
+	return NULL;
 }
 
-static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
+struct xt_rateest *xt_rateest_lookup(struct net *net, const char *name)
 {
-	struct xt_rateest_match_info *info = par->matchinfo;
-	struct xt_rateest *est1, *est2;
-	int ret = -EINVAL;
+	struct xt_rateest_net *xn = net_generic(net, xt_rateest_id);
+	struct xt_rateest *est;
 
-	if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS |
-				     XT_RATEEST_MATCH_REL)) != 1)
-		goto err1;
+	mutex_lock(&xn->hash_lock);
+	est = __xt_rateest_lookup(xn, name);
+	mutex_unlock(&xn->hash_lock);
+	return est;
+}
+EXPORT_SYMBOL_GPL(xt_rateest_lookup);
 
-	if (!(info->flags & (XT_RATEEST_MATCH_BPS | XT_RATEEST_MATCH_PPS)))
-		goto err1;
+void xt_rateest_put(struct net *net, struct xt_rateest *est)
+{
+	struct xt_rateest_net *xn = net_generic(net, xt_rateest_id);
 
-	switch (info->mode) {
-	case XT_RATEEST_MATCH_EQ:
-	case XT_RATEEST_MATCH_LT:
-	case XT_RATEEST_MATCH_GT:
-		break;
-	default:
-		goto err1;
+	mutex_lock(&xn->hash_lock);
+	if (--est->refcnt == 0) {
+		hlist_del(&est->list);
+		gen_kill_estimator(&est->rate_est);
+		/*
+		 * gen_estimator est_timer() might access est->lock or bstats,
+		 * wait a RCU grace period before freeing 'est'
+		 */
+		kfree_rcu(est, rcu);
+	}
+	mutex_unlock(&xn->hash_lock);
+}
+EXPORT_SYMBOL_GPL(xt_rateest_put);
+
+static unsigned int
+xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+	const struct xt_rateest_target_info *info = par->targinfo;
+	struct gnet_stats_basic_packed *stats = &info->est->bstats;
+
+	spin_lock_bh(&info->est->lock);
+	stats->bytes += skb->len;
+	stats->packets++;
+	spin_unlock_bh(&info->est->lock);
+
+	return XT_CONTINUE;
+}
+
+static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
+{
+	struct xt_rateest_net *xn = net_generic(par->net, xt_rateest_id);
+	struct xt_rateest_target_info *info = par->targinfo;
+	struct xt_rateest *est;
+	struct {
+		struct nlattr		opt;
+		struct gnet_estimator	est;
+	} cfg;
+	int ret;
+
+	net_get_random_once(&jhash_rnd, sizeof(jhash_rnd));
+
+	mutex_lock(&xn->hash_lock);
+	est = __xt_rateest_lookup(xn, info->name);
+	if (est) {
+		mutex_unlock(&xn->hash_lock);
+		/*
+		 * If estimator parameters are specified, they must match the
+		 * existing estimator.
+		 */
+		if ((!info->interval && !info->ewma_log) ||
+		    (info->interval != est->params.interval ||
+		     info->ewma_log != est->params.ewma_log)) {
+			xt_rateest_put(par->net, est);
+			return -EINVAL;
+		}
+		info->est = est;
+		return 0;
 	}
 
-	ret  = -ENOENT;
-	est1 = xt_rateest_lookup(par->net, info->name1);
-	if (!est1)
+	ret = -ENOMEM;
+	est = kzalloc(sizeof(*est), GFP_KERNEL);
+	if (!est)
 		goto err1;
 
-	est2 = NULL;
-	if (info->flags & XT_RATEEST_MATCH_REL) {
-		est2 = xt_rateest_lookup(par->net, info->name2);
-		if (!est2)
-			goto err2;
-	}
+	strlcpy(est->name, info->name, sizeof(est->name));
+	spin_lock_init(&est->lock);
+	est->refcnt		= 1;
+	est->params.interval	= info->interval;
+	est->params.ewma_log	= info->ewma_log;
 
-	info->est1 = est1;
-	info->est2 = est2;
+	cfg.opt.nla_len		= nla_attr_size(sizeof(cfg.est));
+	cfg.opt.nla_type	= TCA_STATS_RATE_EST;
+	cfg.est.interval	= info->interval;
+	cfg.est.ewma_log	= info->ewma_log;
+
+	ret = gen_new_estimator(&est->bstats, NULL, &est->rate_est,
+				&est->lock, NULL, &cfg.opt);
+	if (ret < 0)
+		goto err2;
+
+	info->est = est;
+	xt_rateest_hash_insert(xn, est);
+	mutex_unlock(&xn->hash_lock);
 	return 0;
 
 err2:
-	xt_rateest_put(par->net, est1);
+	kfree(est);
 err1:
+	mutex_unlock(&xn->hash_lock);
 	return ret;
 }
 
-static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par)
+static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
 {
-	struct xt_rateest_match_info *info = par->matchinfo;
+	struct xt_rateest_target_info *info = par->targinfo;
 
-	xt_rateest_put(par->net, info->est1);
-	if (info->est2)
-		xt_rateest_put(par->net, info->est2);
+	xt_rateest_put(par->net, info->est);
 }
 
-static struct xt_match xt_rateest_mt_reg __read_mostly = {
-	.name       = "rateest",
+static struct xt_target xt_rateest_tg_reg __read_mostly = {
+	.name       = "RATEEST",
 	.revision   = 0,
 	.family     = NFPROTO_UNSPEC,
-	.match      = xt_rateest_mt,
-	.checkentry = xt_rateest_mt_checkentry,
-	.destroy    = xt_rateest_mt_destroy,
-	.matchsize  = sizeof(struct xt_rateest_match_info),
-	.usersize   = offsetof(struct xt_rateest_match_info, est1),
+	.target     = xt_rateest_tg,
+	.checkentry = xt_rateest_tg_checkentry,
+	.destroy    = xt_rateest_tg_destroy,
+	.targetsize = sizeof(struct xt_rateest_target_info),
+	.usersize   = offsetof(struct xt_rateest_target_info, est),
 	.me         = THIS_MODULE,
 };
 
-static int __init xt_rateest_mt_init(void)
+static __net_init int xt_rateest_net_init(struct net *net)
 {
-	return xt_register_match(&xt_rateest_mt_reg);
+	struct xt_rateest_net *xn = net_generic(net, xt_rateest_id);
+	int i;
+
+	mutex_init(&xn->hash_lock);
+	for (i = 0; i < ARRAY_SIZE(xn->hash); i++)
+		INIT_HLIST_HEAD(&xn->hash[i]);
+	return 0;
 }
 
-static void __exit xt_rateest_mt_fini(void)
+static struct pernet_operations xt_rateest_net_ops = {
+	.init = xt_rateest_net_init,
+	.id   = &xt_rateest_id,
+	.size = sizeof(struct xt_rateest_net),
+};
+
+static int __init xt_rateest_tg_init(void)
 {
-	xt_unregister_match(&xt_rateest_mt_reg);
+	int err = register_pernet_subsys(&xt_rateest_net_ops);
+
+	if (err)
+		return err;
+	return xt_register_target(&xt_rateest_tg_reg);
 }
 
+static void __exit xt_rateest_tg_fini(void)
+{
+	xt_unregister_target(&xt_rateest_tg_reg);
+	unregister_pernet_subsys(&xt_rateest_net_ops);
+}
+
+
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("xtables rate estimator match");
-MODULE_ALIAS("ipt_rateest");
-MODULE_ALIAS("ip6t_rateest");
-module_init(xt_rateest_mt_init);
-module_exit(xt_rateest_mt_fini);
+MODULE_DESCRIPTION("Xtables: packet rate estimator");
+MODULE_ALIAS("ipt_RATEEST");
+MODULE_ALIAS("ip6t_RATEEST");
+module_init(xt_rateest_tg_init);
+module_exit(xt_rateest_tg_fini);
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/foe_fdb.c b/src/kernel/modules/netsys_driver/nat/hw_nat/foe_fdb.c
index a997bc2..708eadb 100755
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/foe_fdb.c
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/foe_fdb.c
@@ -278,12 +278,12 @@
 		else
 			ppe_mib_dump_ppe1(hash_index, &pkt_cnt, &byte_cnt);
 
-		if (fport >= 0 && fport < MAX_IF_NUM) {
+		if (fport < MAX_IF_NUM) {
 			hnat_if[fport].tx_byte_cnt += byte_cnt;
 			hnat_if[fport].tx_pkt_cnt += pkt_cnt;
 		}
 
-		if (sport >= 0 && sport < MAX_IF_NUM) {
+		if (sport < MAX_IF_NUM) {
 			hnat_if[sport].rx_byte_cnt += byte_cnt;
 			hnat_if[sport].rx_pkt_cnt += pkt_cnt;
 
@@ -303,7 +303,7 @@
 		}
 
 
-		if (debug_level == 6) {
+		if (debug_level == 6 && sport < MAX_IF_NUM && fport < MAX_IF_NUM) {
 
 			if (IS_IPV4_HNAPT(entry))
 				pr_notice("%s(%d)(%d), sport(%d), fport(%d): rx_byte:%llu, rx_pkt:%llu, tx_byte=%llu, tx_pkt=%llu, mcast=%llu, entry_pkt_cnt=%llu, entry_byte_cnt=%llu\n",
@@ -432,49 +432,44 @@
 		entry = &ppe_foe_base[hash_index];
 		entry1 = &ppe1_foe_base[hash_index];
 
-		if (entry->bfib1.state == BIND) {
+		fport = get_act_dp(entry);
+		sport = get_rxif_idx(entry);
+		mcast = is_foe_mcast_entry(entry);
 
-			fport = get_act_dp(entry);
-			sport = get_rxif_idx(entry);
-			mcast = is_foe_mcast_entry(entry);
+		if (dev_idx == fport || dev_idx == sport) {
+			ppe_mib_dump_ppe0(hash_index, &pkt_cnt, &byte_cnt);
+			if (dev_idx == fport) {
+				total_tx_pkt += pkt_cnt;
+				total_tx_byte += byte_cnt;
+			}
 
-			if (dev_idx == fport || dev_idx == sport) {
-				ppe_mib_dump_ppe0(hash_index, &pkt_cnt, &byte_cnt);
-				if (dev_idx == fport) {
-					total_tx_pkt += pkt_cnt;
-					total_tx_byte += byte_cnt;
-				}
-
-				if (dev_idx == sport) {
-					total_rx_pkt += pkt_cnt;
-					total_rx_byte += byte_cnt;
-					if (mcast)
-						mcast_rx_pkt += pkt_cnt;
-				}
+			if (dev_idx == sport) {
+				total_rx_pkt += pkt_cnt;
+				total_rx_byte += byte_cnt;
+				if (mcast)
+					mcast_rx_pkt += pkt_cnt;
 			}
 		}
 
-		if (entry1->bfib1.state == BIND) {
+		fport1 = get_act_dp(entry1);
+		sport1 = get_rxif_idx(entry1);
+		mcast1 = is_foe_mcast_entry(entry1);
 
-			fport1 = get_act_dp(entry1);
-			sport1 = get_rxif_idx(entry1);
-			mcast1 = is_foe_mcast_entry(entry1);
+		if (dev_idx == fport1 || dev_idx == sport1) {
+			ppe_mib_dump_ppe1(hash_index, &pkt_cnt1, &byte_cnt1);
+			if (dev_idx == fport1) {
+				total_tx_pkt += pkt_cnt1;
+				total_tx_byte += byte_cnt1;
+			}
 
-			if (dev_idx == fport1 || dev_idx == sport1) {
-				ppe_mib_dump_ppe1(hash_index, &pkt_cnt1, &byte_cnt1);
-				if (dev_idx == fport1) {
-					total_tx_pkt += pkt_cnt1;
-					total_tx_byte += byte_cnt1;
-				}
-
-				if (dev_idx == sport1) {
-					total_rx_pkt += pkt_cnt1;
-					total_rx_byte += byte_cnt1;
-					if (mcast1)
-						mcast_rx_pkt += pkt_cnt1;
-				}
+			if (dev_idx == sport1) {
+				total_rx_pkt += pkt_cnt1;
+				total_rx_byte += byte_cnt1;
+				if (mcast1)
+					mcast_rx_pkt += pkt_cnt1;
 			}
 		}
+
 	}
 
 
@@ -1244,8 +1239,10 @@
 		     IP_FORMAT3(entry->ipv4_dslite.new_dip), IP_FORMAT2(entry->ipv4_dslite.new_dip),
 		     IP_FORMAT1(entry->ipv4_dslite.new_dip), IP_FORMAT0(entry->ipv4_dslite.new_dip),
 		     entry->ipv4_dslite.new_dport);
- 	}else if (IS_IPV4_MAPT(entry)){
+ 	}
 #if(0)
+	else if (IS_IPV4_MAPT(entry)){
+
 		NAT_PRINT("Information Block 2: %08X\n", entry->ipv4_dslite.info_blk2);
 		NAT_PRINT("Create IPv4 MAP-T entry (4 to 6)\n");
 		NAT_PRINT
@@ -1271,7 +1268,7 @@
 		     entry->ipv4_dslite.dport);
 		NAT_PRINT
 		    ("L4 New Port: %d->%d\n", entry->ipv4_dslite.new_sport, entry->ipv4_dslite.new_dport);
-#else
+		// ------------------
 		NAT_PRINT("Information Block 2: %08X\n", entry->ipv6_6rd.info_blk2);
 		NAT_PRINT("Create MAP-T (6 to 4)\n");
 		if (IS_IPV6_FLAB_EBL()) {
@@ -1294,8 +1291,10 @@
 			     entry->ipv6_6rd.ipv6_dip3, entry->ipv6_6rd.dport);
 			NAT_PRINT ("L4 New Port: %d->%d\n", entry->ipv6_6rd.new_sport, entry->ipv6_6rd.new_dport);
 		}
-#endif	     		
-	} else if (IS_IPV6_3T_ROUTE(entry)) {
+
+	}
+#endif
+	else if (IS_IPV6_3T_ROUTE(entry)) {
 		NAT_PRINT("Information Block 2: %08X\n", entry->ipv6_3t_route.info_blk2);
 		NAT_PRINT("Create IPv6 3-Tuple entry\n");
 		NAT_PRINT
@@ -1412,7 +1411,7 @@
 		NAT_PRINT(" Remove tunnel = %u\n", entry->bfib1.rmt);
 		NAT_PRINT("=========================================\n\n");
 	}
-	
+
 }
 
 int foe_get_ppe_entries(struct hwnat_args *opt1, int count, struct foe_entry *foe_base)
@@ -1429,14 +1428,14 @@
 			/* Extra info */
 			opt1->entries[count].fport = opt1->entries[count].fqos = opt1->entries[count].qid = 0;
 			if (IS_IPV4_GRP(entry)) {
-				opt1->entries[count].fport = entry->ipv4_hnapt.iblk2.acnt;
-				opt1->entries[count].fqos =  ppe_force_port(entry);
+				opt1->entries[count].fport = ppe_force_port(entry);
+				opt1->entries[count].fqos = entry->ipv4_hnapt.iblk2.fqos;
 				opt1->entries[count].qid = ppe_qid(entry);
 			}
 			if (fe_feature & HNAT_IPV6) {
 				if (IS_IPV6_GRP(entry)) {
-					opt1->entries[count].fport = entry->ipv6_5t_route.iblk2.acnt;
-					opt1->entries[count].fqos = ppe_force_port(entry);
+					opt1->entries[count].fport = ppe_force_port(entry);
+					opt1->entries[count].fqos = entry->ipv6_3t_route.iblk2.fqos;
 					opt1->entries[count].qid =  ppe_qid(entry);
 				}
 			}
@@ -1538,7 +1537,7 @@
 
 int foe_get_all_entries(struct hwnat_args *opt1)
 {
-	int ppe_count, ppe1_count;		/* valid entry count */
+	int ppe_count, ppe1_count = 0;		/* valid entry count */
 
 	ppe_count = foe_get_ppe_entries(opt1, 0, ppe_foe_base);
 	if (ppe_count < 16 * 1024) {
@@ -1661,7 +1660,7 @@
 
 void hw_nat_l2_info(struct foe_entry *entry, struct hwnat_tuple *opt)
 {
-	if ((opt->pkt_type) == IPV4_NAPT) {
+	if (opt->pkt_type == IPV4_NAPT || opt->pkt_type == IPV4_NAT) {
 		foe_set_mac_hi_info(entry->ipv4_hnapt.dmac_hi, opt->dmac);
 		foe_set_mac_lo_info(entry->ipv4_hnapt.dmac_lo, opt->dmac);
 		foe_set_mac_hi_info(entry->ipv4_hnapt.smac_hi, opt->smac);
@@ -1719,7 +1718,7 @@
 	test.flow_lbl[1] = 0x12;
 	test.flow_lbl[2] = 0xab;
 
-	if ((opt->pkt_type) == IPV4_NAPT) {
+	if (opt->pkt_type == IPV4_NAPT || opt->pkt_type == IPV4_NAT) {
 		entry->ipv4_hnapt.sip = opt->ing_sipv4;
 		entry->ipv4_hnapt.dip = opt->ing_dipv4;
 		entry->ipv4_hnapt.new_sip = opt->eg_sipv4;
@@ -1812,8 +1811,8 @@
 
 	entry->ipv4_hnapt.bfib1.cah = 1;
 
-	if ((opt->pkt_type) == IPV4_NAPT) {
-		entry->ipv4_hnapt.bfib1.pkt_type = IPV4_NAPT;
+	if (opt->pkt_type == IPV4_NAPT || opt->pkt_type == IPV4_NAT) {
+		entry->ipv4_hnapt.bfib1.pkt_type = opt->pkt_type;
 		entry->ipv4_hnapt.bfib1.sta = 1;
 		entry->ipv4_hnapt.bfib1.udp = opt->is_udp; /* tcp/udp */
 		entry->ipv4_hnapt.bfib1.state = BIND;
@@ -1866,25 +1865,25 @@
 
 void hw_nat_ib2_info(struct foe_entry *entry, struct hwnat_tuple *opt)
 {
-	if ((opt->pkt_type) == IPV4_NAPT) {
+	if (opt->pkt_type == IPV4_NAPT || opt->pkt_type == IPV4_NAT) {
 		entry->ipv4_hnapt.iblk2.dp = (opt->dst_port) & 0x7; /* 0:cpu, 1:GE1 */
 		entry->ipv4_hnapt.iblk2.dscp = opt->dscp;
 
-#if defined(CONFIG_HNAT_V1)
-	if ((opt->dst_port) >= 8) {
-	    entry->ipv4_hnapt.iblk2.dp1 = 1;
-	} else {
-	    entry->ipv4_hnapt.iblk2.dp1 = 0;
-	}
-	entry->ipv4_hnapt.iblk2.qid1 = 0;
+	#if defined(CONFIG_HNAT_V1)
+		if ((opt->dst_port) >= 8) {
+		    entry->ipv4_hnapt.iblk2.dp1 = 1;
+		} else {
+		    entry->ipv4_hnapt.iblk2.dp1 = 0;
+		}
+		entry->ipv4_hnapt.iblk2.qid1 = 0;
 
-#endif /* CONFIG_HNAT_V1 */
-	entry->ipv4_hnapt.iblk2.qid = 0;	
-	entry->ipv4_hnapt.iblk2.fqos = 0;
+	#endif /* CONFIG_HNAT_V1 */
+		entry->ipv4_hnapt.iblk2.qid = 0;
+		entry->ipv4_hnapt.iblk2.fqos = 0;
 
-	entry->ipv4_hnapt.iblk2.acnt = opt->dst_port;
-	entry->ipv4_hnapt.iblk2.mcast = 0;
-	entry->ipv4_hnapt.iblk2.mibf = 1;
+		entry->ipv4_hnapt.iblk2.acnt = opt->dst_port;
+		entry->ipv4_hnapt.iblk2.mcast = 0;
+		entry->ipv4_hnapt.iblk2.mibf = 1;
 
 	} else if ((opt->pkt_type) == IPV6_ROUTING) {
 		if (fe_feature & HNAT_IPV6) {
@@ -2418,7 +2417,7 @@
 
 void set_qid(struct sk_buff *skb)
 {
-	struct foe_pri_key key;
+	struct foe_pri_key key = {0};
 	s32 hash_index;
 	struct foe_entry *entry = NULL;
 
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/foe_fdb.h b/src/kernel/modules/netsys_driver/nat/hw_nat/foe_fdb.h
index 1b5aef7..cf5a01f 100755
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/foe_fdb.h
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/foe_fdb.h
@@ -125,6 +125,7 @@
 	struct udphdr uh;
 
 	u32 pkt_type;
+	u16 gre_call_id;
 	u8 is_mcast;
 
 };
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.c b/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.c
index 2ecd8fa..e246473 100755
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.c
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.c
@@ -65,6 +65,8 @@
 #include <linux/inetdevice.h>
 #include <net/rtnetlink.h>
 #include <net/netevent.h>
+#include <net/gre.h>
+#include <net/pptp.h>
 #include <linux/platform_device.h>
 #include "ra_nat.h"
 #include "foe_fdb.h"
@@ -91,13 +93,15 @@
 u32 ppe_hw_fast;
 u8 set_fqos = 0;
 u8 xlat_enable = 1;
+u8 pptp_enable = 0;
 u32 rndis_bind_count = 0;
 u32 rndis_mod = 2;
+u8 second_path = 0;
 
 static const char *const mtk_hnat_feature_name[] = {
 	"GE2_SUPPORT", "HNAT_IPV6", "HNAT_VLAN_TX", "HNAT_MCAST", "HNAT_QDMA", "WARP_WHNAT", "WIFI_HNAT", "HNAT_WAN_P4", "WAN_TO_WLAN_QOS", "HNAT_SP_TAG",
 	"QDMA_TX_RX", "PPE_MIB", "PACKET_SAMPLING", "HNAT_OPENWRT", "HNAT_WLAN_QOS", "WLAN_OPTIMIZE", "UDP_FRAG", "AUTO_MODE", "SEMI_AUTO_MODE", "MANUAL_MODE",
-	"PRE_BIND", "HNAT_IPI", "DBG_IPV6_SIP", "DBG_IPV4_SIP", "DBG_SP", "ETH_QOS"
+	"PRE_BIND", "HNAT_IPI", "DBG_IPV6_SIP", "DBG_IPV4_SIP", "DBG_SP", "ETH_QOS", "SW_DVFS"
 };
 
 u8 USE_3T_UDP_FRAG;
@@ -304,7 +308,8 @@
 		hwnat_info_region = USE_HEAD_ROOM;
 
 		return USE_HEAD_ROOM;	/* use headroom */
-	} else if (IS_MAGIC_TAG_PROTECT_VALID_TAIL(skb) && IS_SPACE_AVAILABLE_TAIL(skb)) {
+	} else if (IS_MAGIC_TAG_PROTECT_VALID_TAIL(skb) && IS_SPACE_AVAILABLE_TAIL(skb) &&
+		   IS_SPACE_AVAILABLE_HEAD(skb)) {
 		FOE_INFO_START_ADDR(skb);
 		alg_tmp = FOE_ALG_TAIL(skb);;
 		sp_tmp = FOE_SP_TAIL(skb);
@@ -380,6 +385,7 @@
 	skb->protocol = eth->h_proto;
 	return vir_if_idx;
 }
+
 #ifdef CONFIG_MTK_TINYSYS_MEDMCU_SUPPORT
 extern void __iomem *medmcu_hnat_info_host_base_virt;
 void hnat_info_init(struct device *dev)
@@ -400,6 +406,7 @@
 
 }
 #endif
+
 static int foe_alloc_tbl(u32 num_of_entry, struct device *dev)
 {
 	u32 foe_tbl_size;
@@ -897,32 +904,31 @@
 	int i = 0;
 	int dev_match = 0;
 	struct ethhdr *eth = (struct ethhdr *)skb_mac_header(skb);
+	struct net_device *dst_dev;
 
-	if (debug_level >= 10)
-		pr_notice("%s, name = %s\n", __func__, skb->dev->name);
-
-		/* PPE can only handle IPv4/IPv6/PPP packets */
+	/* PPE can only handle IPv4/IPv6/PPP packets */
 	if (((skb->protocol != htons(ETH_P_8021Q)) &&
 	    (skb->protocol != htons(ETH_P_IP)) && (skb->protocol != htons(ETH_P_IPV6)) &&
 	    (skb->protocol != htons(ETH_P_PPP_SES)) && (skb->protocol != htons(ETH_P_PPP_DISC))) ||
-			is_multicast_ether_addr(&eth->h_dest[0])) {
+		is_multicast_ether_addr(&eth->h_dest[0])) {
 
-			if (debug_level >= 10)
-				pr_notice("%s not support, skb->protocol = 0x%x, multicase:%d\n", __func__, skb->protocol, is_multicast_ether_addr(&eth->h_dest[0]));
-			return 1;
+		if (debug_level >= 10)
+			pr_notice("%s not support, skb->protocol = 0x%x, multicast:%d\n", __func__, skb->protocol, is_multicast_ether_addr(&eth->h_dest[0]));
+		return 1;
 	}
 
 	if (debug_level >= 10)
-		pr_notice("%s enter, name = %s, protocol = 0x%x, skb-headroom=%d\n", __func__,
+		pr_notice("%s, name = %s, protocol = 0x%x, skb-headroom=%d\n", __func__,
 			skb->dev->name, skb->protocol, skb_headroom(skb));
 
 	skb_set_network_header(skb, 0);
 
 #ifdef CONFIG_SUPPORT_WLAN_OPTIMIZE
-		if (bridge_short_cut_rx(skb))
-			return 1;	/* Bridge ==> sw path (rps) */
+	if (bridge_short_cut_rx(skb))
+		return 1;	/* Bridge ==> sw path (rps) */
 #endif
 
+	/* Check the source interface is registered */
 	for (i = 0; i < MAX_IF_NUM; i++) {
 		if (dst_port[i] == skb->dev) {
 			vir_if_idx = i;
@@ -933,53 +939,58 @@
 		}
 	}
 
-#ifdef CONFIG_RAETH_EDMA
-	for (i = 1; i < MAX_IF_NUM; i++) {
-		if(dst_port[i]->name == NULL) {
-			pr_err("[HS-ethernet/HWNAT/RX] %s : dst_port[%d] name is NULL\n", __func__, i);
-			return 1;
-		}
-
-		if ((strcmp(dst_port[i]->name, DEV_NAME) == 0 && strcmp(skb->dev->name, AQR_DEV_NAME) == 0) ||
-		    (strcmp(dst_port[i]->name, DEV2_NAME) == 0 && strcmp(skb->dev->name, AQR_DEV2_NAME) == 0)) {
-			vir_if_idx = i;
-			dev_match = 1;
-			if (debug_level >= 7)
-				pr_notice("[HS-ethernet/HWNAT/RX] %s : dev_match ok Interfacess=%s, vir_if_idx=%x\n", __func__, skb->dev->name, vir_if_idx);
-			break;
-		}
-	}
-#endif
-
 	if (dev_match == 0) {
 		if (debug_level >= 1)
 			pr_notice("%s UnKnown Interface, vir_if_idx=%x\n", __func__, vir_if_idx);
 		return 1;
 	}
 
+	/* Check the destination interface is running */
+	if (FOE_MAGIC_TAG(skb) == FOE_MAGIC_EDMA0)
+		dst_dev = dst_port[DP_EDMA0];
+	else if (FOE_MAGIC_TAG(skb) == FOE_MAGIC_EDMA1)
+		dst_dev = dst_port[DP_EDMA1];
+	else
+		dst_dev = (second_path && !netif_running(dst_port[DP_GMAC1]))?
+			  dst_port[DP_GMAC2] : dst_port[DP_GMAC1];
+
+	if (!dst_dev || !netif_running(dst_dev)) {
+		if (debug_level >= 1)
+			pr_notice("%s Interface %s is Down\n", __func__, dst_dev->name);
+		return 1;
+	}
+
+	/* currently, skb->data points to layer 3 */
+	if (skb_headroom(skb) < FOE_INFO_LEN + ETH_HLEN + VLAN_HLEN) {
+		if (debug_level >= 3)
+			pr_notice("%s headroom isn't enough\n", __func__);
+		return 1;
+	}
+
 	/* push vlan tag to stand for actual incoming interface, */
 	/* so HNAT module can know the actual incoming interface from vlan id. */
 	skb_push(skb, ETH_HLEN);/* pointer to layer2 header before calling hard_start_xmit */
-
-#ifdef CONFIG_RAETH_EDMA
-		if (FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_EDMA0)
-			skb->dev = dst_port[DP_EDMA0];
-		else if (FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_EDMA1)
-			skb->dev = dst_port[DP_EDMA1];
-		else
-			skb->dev = dst_port[DP_GMAC1];	/* we use GMAC1 to send the packet to PPE */
-#else
-		if (FOE_MAGIC_TAG(skb) == FOE_MAGIC_EDMA0)
-			skb->dev = dst_port[DP_EDMA0];
-		else if (FOE_MAGIC_TAG(skb) == FOE_MAGIC_EDMA1)
-			skb->dev = dst_port[DP_EDMA1];
-		else
-			skb->dev = dst_port[DP_GMAC1];	/* we use GMAC1 to send the packet to PPE */
-#endif
+	skb->dev = dst_dev;
 
 #ifdef CONFIG_SUPPORT_WLAN_QOS
-		set_qid(skb);
+	set_qid(skb);
+	if ((!skb->dev) || ((skb->dev != dst_port[DP_GMAC2]) &&
+	    (skb->dev != dst_port[DP_GMAC1])))
+		skb->dev = dst_port[DP_GMAC1];	/* we use GMAC1 to send the packet to PPE */
 #endif
+
+	/* push the poped vlan back */
+	if (skb_vlan_tag_present(skb)) {
+		skb = vlan_insert_tag(skb, skb->vlan_proto, skb_vlan_tag_get(skb));
+		if (skb == NULL) {
+			if (debug_level >= 3)
+				pr_notice("%s, vlan_insert_tag() frees the skb\n", __func__);
+			return 0;
+		}
+		skb->vlan_tci = 0;
+	}
+
+	/* push the source interface */
 	skb->vlan_proto = htons(ETH_P_8021Q);
 #ifdef	CONFIG_RAETH_HW_VLAN_TX
 	skb->vlan_tci |= VLAN_TAG_PRESENT;
@@ -992,52 +1003,42 @@
 		return 0;
 	}
 #endif
-	if (IS_SPACE_AVAILABLE_HEAD(skb) && IS_SPACE_AVAILABLE_TAIL(skb)) {
-		/* redirect to PPE */
-#ifdef CONFIG_RAETH_EDMA
-		FOE_AI_TAIL(skb) = UN_HIT;
-		FOE_TAG_PROTECT_TAIL(skb) = TAG_PROTECT;
 
-		if (FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_EDMA0) {
-			FOE_MAGIC_TAG_TAIL(skb) = FOE_MAGIC_PPE0;
-		} else if (FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_EDMA1) {
-			FOE_MAGIC_TAG_TAIL(skb) = FOE_MAGIC_PPE1;
-		} else {
-			FOE_MAGIC_TAG_TAIL(skb) = FOE_MAGIC_PPE;
-		}
-#else
+	/* redirect to PPE */
+	if (IS_SPACE_AVAILABLE_HEAD(skb)) {
+
 		FOE_AI(skb) = UN_HIT;
-		FOE_AI_TAIL(skb) = UN_HIT;
 		FOE_TAG_PROTECT(skb) = TAG_PROTECT;
+
+		if (FOE_MAGIC_TAG(skb) == FOE_MAGIC_EDMA0)
+			FOE_MAGIC_TAG(skb) = FOE_MAGIC_PPE0;
+		else if (FOE_MAGIC_TAG(skb) == FOE_MAGIC_EDMA1)
+			FOE_MAGIC_TAG(skb) = FOE_MAGIC_PPE1;
+		else
+			FOE_MAGIC_TAG(skb) = FOE_MAGIC_PPE;
+
+	} else if (IS_SPACE_AVAILABLE_TAIL(skb)) {
+
+		FOE_AI_TAIL(skb) = UN_HIT;
 		FOE_TAG_PROTECT_TAIL(skb) = TAG_PROTECT;
 
-		if (FOE_MAGIC_TAG(skb) == FOE_MAGIC_EDMA0) {
-			FOE_MAGIC_TAG(skb) = FOE_MAGIC_PPE0;
+		if (FOE_MAGIC_TAG(skb) == FOE_MAGIC_EDMA0)
 			FOE_MAGIC_TAG_TAIL(skb) = FOE_MAGIC_PPE0;
-		} else if (FOE_MAGIC_TAG(skb) == FOE_MAGIC_EDMA1) {
-			FOE_MAGIC_TAG(skb) = FOE_MAGIC_PPE1;
+		else if (FOE_MAGIC_TAG(skb) == FOE_MAGIC_EDMA1)
 			FOE_MAGIC_TAG_TAIL(skb) = FOE_MAGIC_PPE1;
-		} else {
-			FOE_MAGIC_TAG(skb) = FOE_MAGIC_PPE;
+		else
 			FOE_MAGIC_TAG_TAIL(skb) = FOE_MAGIC_PPE;
-		}
-#endif
+
 	} else {
 		if (debug_level >= 3)
-			pr_notice("%s, can't fill FOE!\n",
-				__func__);
+			pr_notice("%s, check why! skb with vlan return to caller, headroom:%d, tailroom:%d\n",
+				__func__, skb_headroom(skb), skb_tailroom(skb));
 		return 1;
 	}
 
-#ifdef CONFIG_SUPPORT_WLAN_QOS
-		/*if (debug_level >= 2)*/
-			/*pr_notice("skb->dev = %s\n", skb->dev);*/
-		if ((!skb->dev) || ((skb->dev != dst_port[DP_GMAC2]) &&
-		    (skb->dev != dst_port[DP_GMAC1])))
-			skb->dev = dst_port[DP_GMAC1];	/* we use GMAC1 to send the packet to PPE */
-#endif
 	if (debug_level >= 10)
 		pr_notice("%s, send to ppe via ETH tx\n", __func__);
+
 	dev_queue_xmit(skb);
 
 	return 0;
@@ -1068,43 +1069,12 @@
   		pr_notice("%s, vir_if_idx is 65535\n", __func__);
   		return 1;
   	}
-#ifdef CONFIG_RAETH_EDMA
-	if (dst_port[vir_if_idx] != NULL) {
-		if (strcmp(dst_port[vir_if_idx]-> name, DEV_NAME) == 0) {
-			if (aqr_dev1 != NULL) {
-				aqr_dev = aqr_dev1;
-			} else {
-				aqr_dev1 = ra_dev_get_by_name(AQR_DEV_NAME);
-				aqr_dev = aqr_dev1;
-			}
-		} else if (strcmp(dst_port[vir_if_idx]-> name, DEV2_NAME) == 0) {
-			if (aqr_dev2 != NULL) {
-				aqr_dev = aqr_dev2;
-			} else {
-				aqr_dev2 = ra_dev_get_by_name(AQR_DEV2_NAME);
-				aqr_dev = aqr_dev2;
-			}
-		}
-	}
-#endif
+
 	/* recover to right incoming interface */
 	if (vir_if_idx < MAX_IF_NUM && dst_port[vir_if_idx]) {
-#ifdef CONFIG_RAETH_EDMA
-		if (aqr_dev != NULL) {
-			skb->dev = aqr_dev;
-			if (debug_level >= 7) {
-				pr_notice("[HS-ethernet/HWNAT/RX-pingpong] set the interface id back= %s (AQR)\n", aqr_dev->name);
-                        }
-		} else {
-			skb->dev = dst_port[vir_if_idx];
-			if (debug_level >= 7) {
-				pr_notice("[HS-ethernet/HWNAT/RX-pingpong] set the interface id back= %s \n", skb->dev->name);
-			}
-		}
-#else
+
 		if (dst_port[vir_if_idx] != NULL)
 			skb->dev = dst_port[vir_if_idx];
-#endif
 
 	} else {
 		if (debug_level >= 1)
@@ -1122,39 +1092,6 @@
 	} else {
 		skb->pkt_type = PACKET_OTHERHOST;
 
-#ifdef CONFIG_RAETH_EDMA
-		for (idx = 1; idx < MAX_IF_NUM; idx++) {
-			dev = dst_port[idx];
-			if (strcmp(dev-> name, DEV_NAME) == 0) {
-				if (aqr_dev1 != NULL) {
-					aqr_dev = aqr_dev1;
-				} else {
-					aqr_dev1 = ra_dev_get_by_name(AQR_DEV_NAME);
-					aqr_dev = aqr_dev1;
-				}
-
-				if (aqr_dev && ether_addr_equal(eth->h_dest, aqr_dev->dev_addr) == 0) {
-					//pr_notice("aqr0_dev_addr=%x:%x:%x:%x:%x:%x\n",aqr_dev->dev_addr[0],aqr_dev->dev_addr[1],aqr_dev->dev_addr[2],aqr_dev->dev_addr[3],aqr_dev->dev_addr[4],aqr_dev->dev_addr[5]);
-					skb->pkt_type = PACKET_HOST;
-					break;
-				}
-
-			} else if (strcmp(dev-> name, DEV2_NAME) == 0) {
-				if (aqr_dev2 != NULL) {
-					aqr_dev = aqr_dev2;
-				} else {
-					aqr_dev2 = ra_dev_get_by_name(AQR_DEV2_NAME);
-					aqr_dev = aqr_dev2;
-				}
-
-				if (aqr_dev && ether_addr_equal(eth->h_dest, aqr_dev->dev_addr) == 0) {
-					//pr_notice("aqr1_dev_addr=%x:%x:%x:%x:%x:%x\n",aqr_dev->dev_addr[0],aqr_dev->dev_addr[1],aqr_dev->dev_addr[2],aqr_dev->dev_addr[3],aqr_dev->dev_addr[4],aqr_dev->dev_addr[5]);
-					skb->pkt_type = PACKET_HOST;
-					break;
-				}
-			}
-		}
-#else
 		for (idx = 0; idx < MAX_IF_NUM; idx++) {
 			dev = dst_port[idx];
 			if (dev && ether_addr_equal(eth->h_dest, dev->dev_addr) == 0) {
@@ -1162,10 +1099,8 @@
 				break;
 			}
 		}
-#endif
 	}
 
-
 	if (debug_level >= 7)
 		pr_notice("%s, name = %s, vir_if_idx =%d, pkt_type:%d\n",
 			__func__, skb->dev->name, vir_if_idx, skb->pkt_type);
@@ -1308,7 +1243,6 @@
         if (debug_level >= 10)
 		pr_notice("%s, FOE_AI(skb):0x%x, FOE_SP(skb):%d\n", __func__, FOE_AI(skb), FOE_SP(skb));
 
-
 	if (skb == NULL) {
 		if (debug_level >= 7)
 			pr_notice("%s, skb == NULL\n", __func__);
@@ -1368,20 +1302,18 @@
 	/* interface is unknown */
 	if (!skb->dev) {
 		if (debug_level >= 1)
-			pr_notice("%s, interface is unknown\n", __func__);
+			pr_notice("%s, interface is unknown, act_dp = %d\n", __func__, act_dp);
 		kfree_skb(skb);
 		return 0;
 	}
 	skb_set_network_header(skb, 0);
 	skb_push(skb, ETH_HLEN);	/* pointer to layer2 header */
 
-
 	if (debug_level >= 7)
 		pr_notice("%s, bind to cpu done if name = %s\n",  __func__, skb->dev->name);
 
-
-
 	dev_queue_xmit(skb);
+
 	return 0;
 }
 
@@ -1502,6 +1434,11 @@
 #endif
 }
 
+bool is_same_subnet(uint32_t src_ip, uint32_t dst_ip) {
+
+	return ((src_ip & 0xFFFFFF) == (dst_ip & 0xFFFFFF));
+}
+
 int32_t ppe_parse_layer_med(struct sk_buff *skb, struct foe_entry *entry, struct pkt_parse_result *ppe_parse_result)
 {
 
@@ -1509,11 +1446,9 @@
 	struct ipv6hdr *ip6h = NULL;
 	struct tcphdr *th = NULL;
 	struct udphdr *uh = NULL;
+	struct pptp_gre_header *gh = NULL;
 	u8 ipv6_head_len = 0;
 
-	// dvt use
-	USE_3T_UDP_FRAG = 1;
-
 	memset(ppe_parse_result, 0, sizeof(*ppe_parse_result));
 	//hwnat_memcpy(ppe_parse_result->dmac, eth->h_dest, ETH_ALEN);
 	//hwnat_memcpy(ppe_parse_result->smac, eth->h_source, ETH_ALEN);
@@ -1563,11 +1498,14 @@
 			else
 				ppe_parse_result->pkt_type = IPV4_HNAPT;
 
-			if (iph->frag_off & htons(IP_MF | IP_OFFSET)) {
-		if (debug_level >= 6)
-			DD;
-				return 1;
-			}
+			/* L4 header checksum is wrong if bind */
+			if (iph != NULL && (iph->frag_off & htons(IP_MF | IP_OFFSET)))
+				if (!is_same_subnet(iph->saddr, iph->daddr)){
+					if (debug_level >= 7)
+						pr_notice("%s, 3T link on different subnet is not allowed to HWNAT !!\n", __func__);
+					return 1;
+				}
+
 		} else if (iph->protocol == IPPROTO_UDP) {
 			if (debug_level >= 6)
 				pr_notice("MD TX UDP!!!!!\n");
@@ -1580,15 +1518,29 @@
 			else
 				ppe_parse_result->pkt_type = IPV4_HNAPT;
 
-			if (iph->frag_off & htons(IP_MF | IP_OFFSET))
-				if (USE_3T_UDP_FRAG == 0) {
+			/* L4 header checksum is wrong if bind */
+			if (iph != NULL && (iph->frag_off & htons(IP_MF | IP_OFFSET)))
+				if (!is_same_subnet(iph->saddr, iph->daddr)){
+					if (debug_level >= 7)
+						pr_notice("%s, 3T link on different subnet is not allowed to HWNAT !!\n", __func__);
 					return 1;
 				}
+
 		} else if (iph->protocol == IPPROTO_GRE) {
-			/* do nothing */
-		if (debug_level >= 6)
-			DD;
-			return 1;
+			if (pptp_enable == 0)
+				return 1;
+			ppe_parse_result->pkt_type = IPV4_NAT;
+
+
+			skb_set_transport_header(skb, (iph->ihl * 4));
+			gh = (struct pptp_gre_header *)skb_transport_header(skb);
+
+			ppe_parse_result->gre_call_id = gh->call_id;
+
+			if (debug_level >= 7)
+				pr_notice("%s, gre call id:%d\n", __func__,
+					ppe_parse_result->gre_call_id);
+
 		}
 	} else {
 		ip6h = (struct ipv6hdr *)skb_network_header(skb);
@@ -1640,7 +1592,7 @@
 		}
 	}
 
-	if (debug_level >= 6) {
+	if (debug_level >= 11) {
 		pr_notice("--------------\n");
 		pr_notice("DMAC:%02X:%02X:%02X:%02X:%02X:%02X\n",
 			ppe_parse_result->dmac[0], ppe_parse_result->dmac[1],
@@ -1720,14 +1672,13 @@
 	struct ipv6hdr *ip6h = NULL;
 	struct tcphdr *th = NULL;
 	struct udphdr *uh = NULL;
+	struct pptp_gre_header *gh = NULL;
 	u8 ipv6_head_len = 0;
 #ifdef	CONFIG_RAETH_HW_VLAN_TX
 	struct vlan_hdr pseudo_vhdr;
 #endif
 	ppe_parse_result->vlan_layer = 0;
 	ppe_parse_result->vlan_tag = 0;
-	// dvt use
-	USE_3T_UDP_FRAG = 1;
 
 	memset(ppe_parse_result, 0, sizeof(*ppe_parse_result));
 	eth = (struct ethhdr *)skb->data;
@@ -1853,11 +1804,14 @@
 			else
 				ppe_parse_result->pkt_type = IPV4_HNAPT;
 
-			if (iph->frag_off & htons(IP_MF | IP_OFFSET)) {
-		if (debug_level >= 6)
-			DD;
-				return 1;
-			}
+			/* L4 header checksum is wrong if bind */
+			if (iph != NULL && (iph->frag_off & htons(IP_MF | IP_OFFSET)))
+				if (!is_same_subnet(iph->saddr, iph->daddr)){
+					if (debug_level >= 7)
+						pr_notice("%s, 3T link on different subnet is not allowed to HWNAT !!\n", __func__);
+					return 1;
+				}
+
 		} else if (iph->protocol == IPPROTO_UDP) {
 			skb_set_transport_header(skb, ETH_HLEN + ppe_parse_result->vlan1_gap +
 						 ppe_parse_result->vlan2_gap +
@@ -1870,17 +1824,29 @@
 			else
 				ppe_parse_result->pkt_type = IPV4_HNAPT;
 
-			if (iph->frag_off & htons(IP_MF | IP_OFFSET))
-				if (USE_3T_UDP_FRAG == 0) {
-		if (debug_level >= 6)
-			DD;
-				return 1;
+			/* L4 header checksum is wrong if bind */
+			if (iph != NULL && (iph->frag_off & htons(IP_MF | IP_OFFSET)))
+				if (!is_same_subnet(iph->saddr, iph->daddr)){
+					if (debug_level >= 7)
+						pr_notice("%s, 3T link on different subnet is not allowed to HWNAT !!\n", __func__);
+					return 1;
 				}
+
 		} else if (iph->protocol == IPPROTO_GRE) {
-			/* do nothing */
-		if (debug_level >= 6)
-			DD;
-			return 1;
+			if (pptp_enable == 0)
+				return 1;
+			ppe_parse_result->pkt_type = IPV4_NAT;
+
+			skb_set_transport_header(skb, ETH_HLEN + ppe_parse_result->vlan1_gap +
+						 ppe_parse_result->vlan2_gap +
+						 ppe_parse_result->pppoe_gap + (iph->ihl * 4));
+			gh = (struct pptp_gre_header *)skb_transport_header(skb);
+
+			ppe_parse_result->gre_call_id = gh->call_id;
+
+			if (debug_level >= 7)
+				pr_notice("%s, gre call id:%04x\n", __func__,
+					ppe_parse_result->gre_call_id);
 		}
 		if (fe_feature & HNAT_IPV6) {
 			if (iph->protocol == IPPROTO_IPV6) {
@@ -1960,7 +1926,7 @@
 				ppe_parse_result->pkt_type = IPV6_5T_ROUTE;
 
 		} else if (ip6h->nexthdr == NEXTHDR_IPIP) {
-			
+
 			skb_set_transport_header(skb, ETH_HLEN + ppe_parse_result->vlan1_gap +
 						 ppe_parse_result->vlan2_gap +
 						 ppe_parse_result->pppoe_gap +
@@ -1971,18 +1937,32 @@
 			       sizeof(struct iphdr));
 
 			if(SwitchDslMape == 1) {
-				if (ppe_parse_result->iph.protocol == IPPROTO_TCP) {	
+				if (ppe_parse_result->iph.protocol == IPPROTO_TCP) {
 					th = (struct tcphdr *)skb_transport_header(skb);
 					memcpy(&ppe_parse_result->th, th, sizeof(struct tcphdr));
-					if(ppe_parse_result->iph.frag_off & htons(IP_MF | IP_OFFSET)) {
-						return 1;
-					}
+
+					iph = (struct iphdr *)&ppe_parse_result->iph;
+					/* L4 header checksum is wrong if bind */
+					if (iph != NULL && (iph->frag_off & htons(IP_MF | IP_OFFSET)))
+						if (!is_same_subnet(iph->saddr, iph->daddr)){
+							if (debug_level >= 7)
+								pr_notice("%s, 3T link on different subnet is not allowed to HWNAT !!\n", __func__);
+							return 1;
+						}
+
 				} else if (ppe_parse_result->iph.protocol == IPPROTO_UDP) {
 					uh = (struct udphdr *)skb_transport_header(skb);
 					memcpy(&ppe_parse_result->uh, uh, sizeof(struct udphdr));
-					if(ppe_parse_result->iph.frag_off & htons(IP_MF|IP_OFFSET)) {
-						return 1;
-					}
+
+					iph = (struct iphdr *)&ppe_parse_result->iph;
+					/* L4 header checksum is wrong if bind */
+					if (iph != NULL && (iph->frag_off & htons(IP_MF | IP_OFFSET)))
+						if (!is_same_subnet(iph->saddr, iph->daddr)){
+							if (debug_level >= 7)
+								pr_notice("%s, 3T link on different subnet is not allowed to HWNAT !!\n", __func__);
+							return 1;
+						}
+
 				}
 				ppe_parse_result->pkt_type = IPV4_MAP_E;
 			} else {
@@ -1999,7 +1979,7 @@
 		return 1;
 	}
 
-	if (debug_level >= 6) {
+	if (debug_level >= 11) {
 		pr_notice("--------------\n");
 		pr_notice("DMAC:%02X:%02X:%02X:%02X:%02X:%02X\n",
 			ppe_parse_result->dmac[0], ppe_parse_result->dmac[1],
@@ -2080,7 +2060,7 @@
 	/* Set VLAN Info - VLAN1/VLAN2 */
 	/* Set Layer2 Info - DMAC, SMAC */
 	if ((ppe_parse_result->pkt_type == IPV4_HNAT) || (ppe_parse_result->pkt_type == IPV4_HNAPT)) {
-		if (entry->ipv4_hnapt.bfib1.pkt_type == IPV4_DSLITE || 
+		if (entry->ipv4_hnapt.bfib1.pkt_type == IPV4_DSLITE ||
 		    entry->ipv4_hnapt.bfib1.pkt_type == IPV4_MAP_E) {/* DS-Lite WAN->LAN */
 			if (fe_feature & HNAT_IPV6) {
 				foe_set_mac_hi_info(entry->ipv4_dslite.dmac_hi, ppe_parse_result->dmac);
@@ -2457,10 +2437,20 @@
 			entry->ipv4_hnapt.new_dport = ntohs(ppe_parse_result->uh.dest);
 			entry->ipv4_hnapt.bfib1.udp = UDP;
 		}
+	} else if (ppe_parse_result->pkt_type == IPV4_HNAT) {
+
+		if (ppe_parse_result->iph.protocol == IPPROTO_GRE) {
+
+			/* Keep the same GRE caller ID field */
+			entry->ipv4_hnapt.new_sport = ntohs(ppe_parse_result->gre_call_id);
+
+			if (debug_level >= 7)
+				pr_notice("%s, sport:%04x, gre call id:%04x\n",
+					__func__, entry->ipv4_hnapt.sport, entry->ipv4_hnapt.new_sport);
+		}
+
 	}
 
-	/*else if (ppe_parse_result.pkt_type == IPV4_HNAT)*/
-		/* do nothing */
 	/*else if (ppe_parse_result.pkt_type == IPV6_1T_ROUTE)*/
 		/* do nothing */
 	/*else if (ppe_parse_result.pkt_type == IPV6_3T_ROUTE)*/
@@ -2508,7 +2498,7 @@
 		iblk2->mcast = 0;
 	}
 #endif
-	
+
 #if defined(CONFIG_HNAT_V2)
 	iblk2->dp = fpidx & 0xf;
 #endif
@@ -2560,7 +2550,7 @@
 		entry->ipv6_3t_route.iblk2.qid = (qidx & 0x0f);
 #endif
 	}
-	
+
 }
 
 void set_warp_wifi_dp(struct sk_buff *skb, struct foe_entry *entry, struct pkt_parse_result *ppe_parse_result, int gmac_no)
@@ -2608,7 +2598,6 @@
 		if (FOE_SP(skb) == 5)
 			entry->ipv6_3t_route.iblk2.fqos = 0;	/* wifi to wifi not go to pse port6 */
 		else
-
 			entry->ipv6_3t_route.iblk2.fqos = set_fqos;
 	}
 }
@@ -2672,7 +2661,9 @@
 
 #endif /* CONFIG_EDMA_RX */
 
-	pr_info("%s, FOE_AI(skb):0x%x, FOE_SP(skb):%d, pse_port:%d\n", __func__, FOE_AI(skb), FOE_SP(skb), pse_port);
+	if (debug_level >= 1)
+		pr_info("%s, FOE_AI(skb):0x%x, FOE_SP(skb):%d, pse_port:%d\n",
+			__func__, FOE_AI(skb), FOE_SP(skb), pse_port);
 
 	if (fe_feature & HNAT_QDMA) {
 		set_ppe_qid(skb, entry);
@@ -2717,7 +2708,8 @@
 	}
         pse_port = ADMA_PSE_PORT;
 
-	pr_info("set_wifi_info, gmac_no:%d, pse_port:%d, sw_fast_path:%d\n", gmac_no, pse_port, sw_fast_path);
+	if (debug_level >= 1)
+		pr_info("set_wifi_info, gmac_no:%d, pse_port:%d, sw_fast_path:%d\n", gmac_no, pse_port, sw_fast_path);
 
 	if (fe_feature & WARP_WHNAT) {
 		if (!sw_fast_path) {
@@ -2851,7 +2843,6 @@
 		if ((entry->ipv4_hnapt.vlan1 & VLAN_VID_MASK) == 1) {
 			if ((bind_dir == UPSTREAM_ONLY) || (bind_dir == BIDIRECTION))
 				ppe_set_infoblk2(&entry->ipv6_5t_route.iblk2, 1, NO_USE, ETH1_ACG, ppe_parse_result);
-
 			else
 				return 1;
 		}
@@ -2883,7 +2874,6 @@
 				if ((bind_dir == UPSTREAM_ONLY) || (bind_dir == BIDIRECTION))
 					ppe_set_infoblk2(&entry->ipv4_hnapt.iblk2, 1, NO_USE, ETH1_ACG,
 							 ppe_parse_result);
-
 				else
 					return 1;
 			} else {/* one-arm */
@@ -2904,23 +2894,22 @@
 		}
 #else
 		if ((entry->ipv4_hnapt.vlan1 & VLAN_VID_MASK) == lan_vid) {
-				if ((bind_dir == DOWNSTREAM_ONLY) || (bind_dir == BIDIRECTION))
-					ppe_set_infoblk2(&entry->ipv4_hnapt.iblk2, 1, NO_USE, ETH0_ACG,
-							 ppe_parse_result);
-				else
-					return 1;
+			if ((bind_dir == DOWNSTREAM_ONLY) || (bind_dir == BIDIRECTION))
+				ppe_set_infoblk2(&entry->ipv4_hnapt.iblk2, 1, NO_USE, ETH0_ACG,
+						 ppe_parse_result);
+			else
+				return 1;
 		} else if ((entry->ipv4_hnapt.vlan1 & VLAN_VID_MASK) == wan_vid) {
 			if ((bind_dir == UPSTREAM_ONLY) || (bind_dir == BIDIRECTION))
 				ppe_set_infoblk2(&entry->ipv4_hnapt.iblk2, 1, NO_USE, ETH1_ACG,
-						ppe_parse_result);
-
+						 ppe_parse_result);
 			else
 				return 1;
 		} else/* one-arm */
 				ppe_set_infoblk2(&entry->ipv4_hnapt.iblk2, 1, NO_USE, ETH0_ACG,
-						ppe_parse_result);
+						 ppe_parse_result);
 	}
-	
+
 #endif
 	return 0;
 }
@@ -2928,11 +2917,10 @@
 int set_eth_dp_gmac2(struct foe_entry *entry, int gmac_no,
 		     struct pkt_parse_result *ppe_parse_result)
 {
-		/* RT3883/MT7621 with 2xGMAC - Assuming GMAC2=WAN  and GMAC1=LAN */
+	/* RT3883/MT7621 with 2xGMAC - Assuming GMAC2=WAN  and GMAC1=LAN */
 	if (gmac_no == 1) {
 		if ((bind_dir == DOWNSTREAM_ONLY) || (bind_dir == BIDIRECTION))
 			set_dst_port(entry, 1, 1, ppe_parse_result); /*pse port1,goup1*/
-
 		else
 			return 1;
 	} else if (gmac_no == 2) {
@@ -2947,34 +2935,22 @@
 void set_eth_fqos(struct sk_buff *skb, struct foe_entry *entry)
 {
 	if (IS_IPV4_GRP(entry)) {
-
-			if (FOE_SP(skb) == 5) {
+			if (fe_feature & ETH_QOS)
+				entry->ipv4_hnapt.iblk2.fqos = set_fqos;
+			else
 				entry->ipv4_hnapt.iblk2.fqos = 0;
-			} else {
-				if (fe_feature & ETH_QOS)
-					entry->ipv4_hnapt.iblk2.fqos = set_fqos;
-				else
-					entry->ipv4_hnapt.iblk2.fqos = 0;
-			}
 	}
 
 	if (fe_feature & HNAT_IPV6) {
 		if (IS_IPV6_GRP(entry)) {
-
-			if (FOE_SP(skb) == 5) {
+			if (fe_feature & ETH_QOS)
+				entry->ipv6_5t_route.iblk2.fqos = set_fqos;
+			else
 				entry->ipv6_5t_route.iblk2.fqos = 0;
-			} else{
-				if (fe_feature & ETH_QOS)
-					entry->ipv6_5t_route.iblk2.fqos = set_fqos;
-				else
-					entry->ipv6_5t_route.iblk2.fqos = 0;
-			}
-
 		}
 	}
 }
 
-
 uint32_t ppe_set_ext_if_num(struct sk_buff *skb, struct foe_entry *entry)
 {
 	u32 offset = 0;
@@ -3198,7 +3174,7 @@
 		}
 	}
 	if (i < MAX_IF_NUM)
-		pr_notice("%s : ineterface %s register (%d), accel. type(%d)\n", __func__, dev->name, i, dst_port_type[i]);
+		pr_notice("%s : interface %s register (%d), accel. type(%d)\n", __func__, dev->name, i, dst_port_type[i]);
 }
 
 void ppe_dev_unreg_handler(struct net_device *dev)
@@ -3207,6 +3183,7 @@
 
 	if (dev == NULL)
 		return;
+
 	if (strncmp(dev->name, "ccmni0", 6) == 0) {
 		if (dst_port[8] != NULL) {
 			dst_port[8] = NULL;
@@ -3273,6 +3250,7 @@
 	if (i < MAX_IF_NUM)
 		pr_notice("%s : ineterface %s set null (%d)\n", __func__, dev->name, i);
 }
+
 #ifdef CONFIG_HW_NAT_SEMI_AUTO_MODE
 int get_done_bit(struct sk_buff *skb, struct foe_entry *entry)
 {
@@ -3352,17 +3330,17 @@
 		ppe_flow_set |= (BIT_IPV4_NAPT_EN | BIT_IPV4_NAT_EN);
 		ppe_flow_set |= (BIT_IPV4_NAT_FRAG_EN | BIT_UDP_IP4F_NAT_EN);	/* ip fragment */
 		ppe_flow_set |= (BIT_IPV4_HASH_GREK);
-		
+
 		ppe_flow_set |= BIT_IPV6_6RD_EN | BIT_IPV6_3T_ROUTE_EN | BIT_IPV6_5T_ROUTE_EN;
 			/* ppe_flow_set |= (BIT_IPV6_HASH_FLAB); // flow label */
-		
+
 		ppe_flow_set |= (BIT_IPV6_HASH_GREK);
 		ppe_flow_set |= (BIT_IPV4_464XLAT_EN);
 #if defined(CONFIG_HNAT_V2)
 		ppe_flow_set |= (BIT_IPV4_MAPE_EN);
 #else
 		ppe_flow_set |= (BIT_IPV4_DSL_EN);
-#endif		
+#endif
 	} else {
 		ppe_flow_set &= ~(BIT_IPV4_NAPT_EN | BIT_IPV4_NAT_EN);
 		ppe_flow_set &= ~(BIT_IPV4_NAT_FRAG_EN);
@@ -3373,7 +3351,7 @@
 		ppe_flow_set &= ~(BIT_IPV4_MAPE_EN);
 #else
 		ppe_flow_set &= ~(BIT_IPV4_DSL_EN);
-#endif	
+#endif
 			/* ppe_flow_set &= ~(BIT_IPV6_HASH_FLAB); */
 
 		ppe_flow_set &= ~(BIT_IPV6_HASH_GREK);
@@ -3383,7 +3361,7 @@
 
 	if (ppe_flow_set & BIT_IPV4_MAPE_EN)
 		SwitchDslMape = 1;
-	else 
+	else
 		SwitchDslMape = 0;
 
 	reg_write(PPE_FLOW_SET, ppe_flow_set);
@@ -3809,6 +3787,12 @@
 	return dev_get_by_name(&init_net, name);
 }
 
+#define IS_FAST_PATH_UP \
+	(dst_port[DP_EDMA0] && netif_running(dst_port[DP_EDMA0])) || \
+	(dst_port[DP_EDMA1] && netif_running(dst_port[DP_EDMA1])) || \
+	(dst_port[DP_GMAC1] && netif_running(dst_port[DP_GMAC1])) || \
+	(second_path && dst_port[DP_GMAC2] && netif_running(dst_port[DP_GMAC2]))? 1 : 0
+
 void eth_register(void)
 {
 	struct net_device *dev;
@@ -3824,7 +3808,12 @@
 			break;
 		}
 	}
-	if (fe_feature & GE2_SUPPORT) {
+
+#ifndef CONFIG_MTK_SGMII_SNPS
+	second_path = (fe_feature & GE2_SUPPORT)? 1 : 0;
+#endif
+
+	if (second_path) {
 		dev = ra_dev_get_by_name(DEV_NAME_HNAT_WAN);
 		ppe_dev_reg_handler(dev);
 		for (i = 0; i < MAX_IF_NUM; i++) {
@@ -3836,12 +3825,11 @@
 			}
 		}
 	}
-
-
 }
-#if(0)
+
 void modem_if_register(void)
 {
+#if(0)
 	struct net_device *dev;
 
 	dev = ra_dev_get_by_name(DEV_NAME_HNAT_CCCI0);
@@ -3867,8 +3855,9 @@
 
 	dev = ra_dev_get_by_name(DEV_NAME_HNAT_CCCI7);
 	ppe_dev_reg_handler(dev);
-}
 #endif
+}
+
 void rndis_if_register(void)
 {
 	struct net_device *dev;
@@ -3919,15 +3908,16 @@
 			break;
 		}
 	}
-
 }
 
 void snps_if_register(void)
 {
 	struct net_device *dev;
 
-	dev = ra_dev_get_by_name(DEV_NAME_HNAT_SNPS);
-	ppe_dev_reg_handler(dev);
+	if (IS_FAST_PATH_UP) {
+		dev = ra_dev_get_by_name(DEV_NAME_HNAT_SNPS);
+		ppe_dev_reg_handler(dev);
+	}
 }
 
 void ppe_set_dst_port(uint32_t ebl)
@@ -3943,17 +3933,18 @@
 		eth_register();
 #endif
 		ext_if_register();
-		//modem_if_register();
+		modem_if_register();
 		wifi_if_register();
 		rndis_if_register();
 		snps_if_register();
 	} else {
-		 /* disable */
-		if(dst_port[DP_GMAC1] != NULL)
+		/* disable */
+		if (dst_port[DP_GMAC1] != NULL)
 			dev_put(dst_port[DP_GMAC1]);
 
-		if(dst_port[DP_GMAC2] != NULL)
-			dev_put(dst_port[DP_GMAC2]);
+		if (second_path)
+			if(dst_port[DP_GMAC2] != NULL)
+				dev_put(dst_port[DP_GMAC2]);
 
 		for (j = 0; j < MAX_IF_NUM; j++) {
 			if (dst_port[j])
@@ -4054,7 +4045,10 @@
 	 */
 	/* FIXME: enable it to support IP fragement */
 	reg_write(PPE_IP_PROT_CHK, 0xFFFFFFFF);	/* IPV4_NXTH_CHK and IPV6_NXTH_CHK */
-	/* reg_modify_bits(PPE_IP_PROT_0, IPPROTO_GRE, 0, 8); */
+
+	if (pptp_enable == 1)
+		reg_modify_bits(PPE_IP_PROT_0, IPPROTO_GRE, 0, 8);
+
 	/* reg_modify_bits(PPE_IP_PROT_0, IPPROTO_TCP, 8, 8); */
 	/* reg_modify_bits(PPE_IP_PROT_0, IPPROTO_UDP, 16, 8); */
 	/* reg_modify_bits(PPE_IP_PROT_0, IPPROTO_IPV6, 24, 8); */
@@ -4151,7 +4145,7 @@
 		//pr_notice(" which_region = %d\n", which_region);
 
 	if (which_region == ALL_INFO_ERROR) {
-		if (pr_debug_ratelimited())
+		if (debug_level >= 7)
 			pr_notice("ppe_tx_handler : ALL_INFO_ERROR\n");
 		return 1;
 	}
@@ -4324,9 +4318,9 @@
 	ppe_set_entry_bind(skb, entry); /* Enter binding state */
 
 #ifdef CONFIG_HW_NAT_SEMI_AUTO_MODE
-		set_ppe_table_done(entry);
-		/*make sure data write to dram*/
-		wmb();
+	set_ppe_table_done(entry);
+	/*make sure data write to dram*/
+	wmb();
 #endif
 }
 
@@ -4336,7 +4330,6 @@
 	int ret;
 
 	ret = ppe_common_part(skb, entry, gmac_no, ppe_parse_result);
-
 	if (ret)
 		return ret;
 
@@ -4352,6 +4345,7 @@
 
 	if (ret)
 		return ret;
+
 	/* For force to cpu handler, record if name */
 	if (ppe_set_ext_if_num(skb, entry)) {
 		memset(FOE_INFO_START_ADDR(skb), 0, FOE_INFO_LEN);
@@ -4368,7 +4362,6 @@
 	int ret;
 
 	ret = ppe_common_part(skb, entry, gmac_no, ppe_parse_result);
-
 	if (ret)
 		return ret;
 
@@ -4391,7 +4384,6 @@
 	int ret;
 
 	ret = ppe_common_part_med(skb, entry, gmac_no, ppe_parse_result);
-
 	if (ret)
 		return ret;
 
@@ -4413,7 +4405,6 @@
 	int ret;
 
 	ret = ppe_common_part(skb, entry, gmac_no, ppe_parse_result);
-
 	if (ret)
 		return ret;
 
@@ -4437,7 +4428,6 @@
 	int ret;
 
 	ret = ppe_common_part(skb, entry, gmac_no, ppe_parse_result);
-
 	if (ret)
 		return ret;
 
@@ -4504,7 +4494,7 @@
 			/*this is duplicate packet in keepalive new header mode*/
 			/*just drop it */
 		if (debug_level >= 3)
-			pr_notice("Wifi TxGot HITBIND_KEEPALIVE_DUP_OLD packe (%s,%d)\n", skb->dev->name,
+			pr_notice("USB TxGot HITBIND_KEEPALIVE_DUP_OLD packe (%s,%d)\n", skb->dev->name,
 				FOE_ENTRY_NUM(skb));
 		memset(FOE_INFO_START_ADDR(skb), 0, FOE_INFO_LEN);
 		return 0;
@@ -4588,6 +4578,7 @@
 	}
 	return 1;
 }
+
 int tx_cpu_handler_eth(struct sk_buff *skb, struct foe_entry *entry, int gmac_no)
 {
 	int ret;
@@ -4636,7 +4627,7 @@
 	struct pkt_parse_result ppe_parse_result;
 
 	if (debug_level >= 7) {
-	    pr_notice("[HS-ethernet/HWNAT/TX] tx_cpu_handler_ext enter! \n");
+	    pr_notice("%s enter!\n", __func__);
 	}
 
 	if (debug_level >= 7) {
@@ -4711,7 +4702,8 @@
 	entry = decide_which_ppe(skb);
 
 
-	if (FOE_AI(skb) == HIT_BIND_FORCE_TO_CPU) {
+	if (FOE_AI(skb) == HIT_BIND_FORCE_TO_CPU ||
+	    FOE_AI(skb) == PACKET_FORWARD_PATH_WITHOUT_PPE) {
 
 		return hitbind_force_to_cpu_handler(skb, entry);
 		/* handle the incoming packet which came back from PPE */
@@ -4759,7 +4751,7 @@
 	}
 
 	if((FOE_MAGIC_TAG(skb) == FOE_MAGIC_WED0) ||
-		(FOE_MAGIC_TAG(skb) == FOE_MAGIC_WED1))
+	   (FOE_MAGIC_TAG(skb) == FOE_MAGIC_WED1))
 		return 1;
 
 	/* the incoming packet is from PCI or WiFi interface */
@@ -4951,12 +4943,16 @@
 		entry = &ppe1_foe_base[FOE_ENTRY_NUM(skb)];
 	} else if(FOE_SP(skb) == MDMA_PSE_PORT) {
 		entry = &ppe1_foe_base[FOE_ENTRY_NUM(skb)];
-	} else if((FOE_SP(skb) == EDMA0_PSE_PORT)) {
+	} else if(FOE_SP(skb) == EDMA0_PSE_PORT) {
 		entry = &ppe_foe_base[FOE_ENTRY_NUM(skb)];
-	} else if((FOE_SP(skb) == EDMA1_PSE_PORT) ) {
+	} else if(FOE_SP(skb) == EDMA1_PSE_PORT) {
 		entry = &ppe1_foe_base[FOE_ENTRY_NUM(skb)];
- 	} else if((FOE_SP(skb) == ADMA_PSE_PORT) || (FOE_SP(skb) == QDMA_PSE_PORT)) {
+	} else if(FOE_SP(skb) == ADMA_PSE_PORT) {
 		entry = &ppe_foe_base[FOE_ENTRY_NUM(skb)];
+	} else if(FOE_SP(skb) == QDMA_PSE_PORT) { // QoS
+		entry = (FOE_AI(skb) == PACKET_FORWARD_PATH_WITHOUT_PPE)?
+			&ppe1_foe_base[FOE_ENTRY_NUM(skb)] : // MDMA
+			&ppe_foe_base[FOE_ENTRY_NUM(skb)];
 	} else {
 		entry = &ppe_foe_base[FOE_ENTRY_NUM(skb)];
 		if (debug_level >= 3) {
@@ -4980,7 +4976,7 @@
 	hnat_chip_name |= MT7623_HWNAT;
 	hnat_chip_name |= LEOPARD_HWNAT;
 
-	pr_notice("hnat_chip_name = %x\n", hnat_chip_name);
+	pr_notice("hnat_chip_name = 0x%x\n", hnat_chip_name);
 }
 
 void fe_feature_setting(void)
@@ -5015,7 +5011,7 @@
 	fe_feature |= ETH_QOS;
 	fe_feature |= SW_DVFS;
 
-	pr_notice("fe_feature = %x\n", fe_feature);
+	pr_notice("fe_feature = 0x%x\n", fe_feature);
 	for (i = 0; i < ARRAY_SIZE(mtk_hnat_feature_name); i++) {
 		if (fe_feature & BIT(i))
 			pr_notice("!! hwnat feature :%s\n", mtk_hnat_feature_name[i]);
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_config.h b/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_config.h
index 222ccc3..5a2643e 100755
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_config.h
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_config.h
@@ -69,12 +69,13 @@
 #define USE_UDP_FRAG
 #endif
 
+/* hnat_chip_name */
+
 #ifdef CONFIG_RALINK_MT7620
 #define MT7620_HWNAT	BIT(0)
 #else
 #define MT7620_HWNAT	(0)
 #endif
-
 #ifdef CONFIG_RALINK_MT7621
 #define MT7621_HWNAT	BIT(1)
 #else
@@ -96,8 +97,10 @@
 #define LEOPARD_HWNAT	(0)
 #endif
 
+/* fe_feature */
+
 #ifdef	CONFIG_RAETH_GMAC2
-#define GE2_SUPPORT	(1)
+#define GE2_SUPPORT	BIT(0)
 #else
 #define GE2_SUPPORT	(0)
 #endif
@@ -114,7 +117,7 @@
 #define HNAT_VLAN_TX	(0)
 #endif
 
-#ifdef	CONFIG_PPE_MCAST
+#if 0 /*def	CONFIG_PPE_MCAST */
 #define HNAT_MCAST	BIT(3)
 #else
 #define HNAT_MCAST	(0)
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_define.h b/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_define.h
old mode 100644
new mode 100755
index feb84dc..b69017b
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_define.h
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_define.h
@@ -127,14 +127,12 @@
 /*extern struct pkt_parse_result ppe_parse_result;*/
 extern int dbg_cpu_reason;
 
-#ifdef CONFIG_SUPPORT_OPENWRT
 #define DEV_NAME_HNAT_LAN	"eth0"
 #define DEV_NAME_HNAT_WAN	"eth1"
-#define DEV_NAME_HNAT_SNPS	"eth2"
+#ifdef CONFIG_MTK_SGMII_SNPS
+#define DEV_NAME_HNAT_SNPS	"eth1"
 #else
-#define DEV_NAME_HNAT_LAN	"eth2"
-#define DEV_NAME_HNAT_WAN	"eth3"
-#define DEV_NAME_HNAT_SNPS	"eth4"
+#define DEV_NAME_HNAT_SNPS	"eth2"
 #endif
 
 #define DEV_NAME_HNAT_EDMA0	"edma0"
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/hwnat_config.h b/src/kernel/modules/netsys_driver/nat/hw_nat/hwnat_config.h
old mode 100644
new mode 100755
index 5f72f3e..5a92292
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/hwnat_config.h
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/hwnat_config.h
@@ -103,7 +103,8 @@
 #define HNAT_VLAN_TX	(0)
 #endif
 
-#ifdef	CONFIG_PPE_MCAST
+/* disable mucast */
+#if 0 /*def	CONFIG_PPE_MCAST */
 #define HNAT_MCAST	BIT(3)
 #else
 #define HNAT_MCAST	(0)
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.c b/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.c
index 9466dc5..4f05d42 100755
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.c
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.c
@@ -427,10 +427,11 @@
 int32_t ppe_rx_eth_handler(struct sk_buff *skb)
 {
 	int ret;
+
+	foe_format_create(skb);
 	if (debug_level >= 10)
 		pr_info("%s, FOE_AI(skb):0x%x, FOE_SP(skb):%d\n", __func__, FOE_AI(skb), FOE_SP(skb));
 
-	foe_format_create(skb);
 	//FOE_INFO_DUMP(skb);
 	FOE_ALG(skb) = 0;
 	rx_debug_log(skb);
@@ -658,9 +659,8 @@
 		/* EDIA TX fast path is not ready */
 		ppe_hook_tx_ext = NULL;
 
-		/* Default off */
-		ppe_hook_rx_snps = NULL;
-		ppe_hook_tx_snps = NULL;
+		ppe_hook_rx_snps = ppe_rx_snps_handler;
+		ppe_hook_tx_snps = ppe_tx_snps_handler;
 
 		ppe_get_dev_stats = ppe_get_dev_stats_handler;
 
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.h b/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.h
index 0bed4d3..056f403 100755
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.h
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.h
@@ -140,7 +140,8 @@
 	HIT_BIND_MULTICAST_TO_CPU = 0x18,
 	/*  Switch clone multicast packet to GMAC1 & CPU */
 	HIT_BIND_MULTICAST_TO_GMAC_CPU = 0x19,
-	HIT_PRE_BIND = 0x1A	/*  Pre-bind */
+	HIT_PRE_BIND = 0x1A,	/*  Pre-bind */
+	PACKET_FORWARD_PATH_WITHOUT_PPE = 0x1E
 };
 
 
diff --git a/src/telephony/multi-user-test/src/cc.cpp b/src/telephony/multi-user-test/src/cc.cpp
old mode 100644
new mode 100755
index 6ef0924..e42ad38
--- a/src/telephony/multi-user-test/src/cc.cpp
+++ b/src/telephony/multi-user-test/src/cc.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -196,6 +197,7 @@
         ret = get_mixer_ctrl_value_int(g_mixer_name_bt);
     } else {
         RLOGE("mixer_check wrong mix %d", mix);
+        ret = -1;
     }
     RLOGD("The ctrl \"%s\" is set to %d ", g_mixer_name, ret);
     return ret;
diff --git a/src/telephony/multi-user-test/src/data/data_gdbus.cpp b/src/telephony/multi-user-test/src/data/data_gdbus.cpp
old mode 100644
new mode 100755
index 0073ad3..fa5ea12
--- a/src/telephony/multi-user-test/src/data/data_gdbus.cpp
+++ b/src/telephony/multi-user-test/src/data/data_gdbus.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/multi-user-test/src/em/em_hspa.cpp b/src/telephony/multi-user-test/src/em/em_hspa.cpp
old mode 100644
new mode 100755
index a2df7c5..1447b26
--- a/src/telephony/multi-user-test/src/em/em_hspa.cpp
+++ b/src/telephony/multi-user-test/src/em/em_hspa.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/multi-user-test/src/em/em_modemtest.cpp b/src/telephony/multi-user-test/src/em/em_modemtest.cpp
old mode 100644
new mode 100755
index 30b4906..64cbeb0
--- a/src/telephony/multi-user-test/src/em/em_modemtest.cpp
+++ b/src/telephony/multi-user-test/src/em/em_modemtest.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTest.cpp b/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTest.cpp
old mode 100644
new mode 100755
index 26759a1..b9c6cdc
--- a/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTest.cpp
+++ b/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTest.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -1004,6 +1005,7 @@
         std::shared_ptr<RfDesenseTxTestLte> tdd = std::make_shared<
                 RfDesenseTxTestLte>(utils::MODEM_LTE_TDD);
         tdd->show_default();
+#ifdef C2K_SUPPORT
     } else if ((standard == sub_tx_test[INDEX_CDMA_EVDO].name)
             && utils::isC2KSupport()) {
         //CDMA(EVDO)
@@ -1016,6 +1018,7 @@
         std::shared_ptr<RfDesenseTxTestCdma> cdma_1x = std::make_shared<
                 RfDesenseTxTestCdma>(utils::MODEM_CDMA_1X);
         cdma_1x->show_default();
+#endif
     } else {
         LOG_D(LOG_TAG, "invaild INPUT");
         return false;
@@ -1051,6 +1054,7 @@
     } else if (standard == sub_tx_test[INDEX_LTE_TDD].name) {
         //LTE(TDD)
         handle_lte_tdd_para(name, last_pos, sub_name);
+#ifdef C2K_SUPPORT
     } else if ((standard == sub_tx_test[INDEX_CDMA_EVDO].name)
             && utils::isC2KSupport()) {
         //CDMA(EVDO)
@@ -1059,6 +1063,7 @@
             && utils::isC2KSupport()) {
         //CDMA(1X)
         handle_cdma_1X_para(name, last_pos, sub_name);
+#endif
     } else {
         LOG_D(LOG_TAG, "invaild INPUT");
         return false;
@@ -1084,6 +1089,7 @@
     } else if (standard == sub_tx_test[INDEX_LTE_TDD].name) {
         //LTE(TDD)
         mRatList[INDEX_LTE_TDD]->setRatCheckState(true);
+#ifdef C2K_SUPPORT
     } else if ((standard == sub_tx_test[INDEX_CDMA_EVDO].name)
             && utils::isC2KSupport()) {
         //CDMA(EVDO)
@@ -1092,6 +1098,7 @@
             && utils::isC2KSupport()) {
         //CDMA(1X)
         mRatList[INDEX_CDMA_1X]->setRatCheckState(true);
+#endif
     } else {
         LOG_D(LOG_TAG, "invaild INPUT");
         return false;
diff --git a/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTestGsm.cpp b/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTestGsm.cpp
old mode 100644
new mode 100755
index 793e99f..8bbe469
--- a/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTestGsm.cpp
+++ b/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTestGsm.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -284,10 +285,15 @@
 
 void RfDesenseTxTestGsm::show_default() {
     int band_index = utils::find_index(band_values, band);
+    if (band_index > 5 || band_index < 0) {
+        LOG_W(LOG_TAG, "show_default, band_index=%d, out of range\n" , band_index);
+        band_index = 0;
+    }
+
     int pattern_index = std::stoi(pattern);
     std::string temp = "GSM parameter: Band: " + std::string(rfdesense_gsm_band[band_index].name) +
             ", Channel(ARFCN): " + channel + ", Power Level: " + power + ", AFC: " + afc + ", TSC: " + tsc +
-            ", PATTERN: " + std::string(rfdesense_gsm_pattern[pattern_index].name);
+            ", PATTERN: " + std::string(rfdesense_gsm_pattern[pattern_index > 6 ? 0 : pattern_index].name);
     emResultNotifyWithDone(temp);
 }
 
diff --git a/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTestTd.cpp b/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTestTd.cpp
old mode 100644
new mode 100755
index 3693061..2afe62e
--- a/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTestTd.cpp
+++ b/src/telephony/multi-user-test/src/em/rfdesense/RfDesenseTxTestTd.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/multi-user-test/src/network.cpp b/src/telephony/multi-user-test/src/network.cpp
old mode 100644
new mode 100755
index 4247837..cad74a3
--- a/src/telephony/multi-user-test/src/network.cpp
+++ b/src/telephony/multi-user-test/src/network.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/multi-user-test/src/sms/sms.cpp b/src/telephony/multi-user-test/src/sms/sms.cpp
old mode 100644
new mode 100755
index 35de3da..97e2c57
--- a/src/telephony/multi-user-test/src/sms/sms.cpp
+++ b/src/telephony/multi-user-test/src/sms/sms.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -71,6 +72,7 @@
         pdu = (char **)malloc(sizeof(char *) * msg_num);
         if(pdu == NULL){
             RLOGD("%s, %s, %d, allocate memory for pdu failed", __FILE__, __FUNCTION__, __LINE__);
+            return 0;
         } else {
             for(index = 0; index < msg_num; index++){
                 pdu[index] = (char *)malloc(sizeof(char)*MAX_PDU_SIZE);
@@ -104,20 +106,22 @@
                 android::Parcel p;
                 size_t pos = p.dataPosition();
                 RequestInfo *pRI_backup = (RequestInfo *)calloc(1, sizeof(RequestInfo));
-                pRI_backup->token = pRI->token;
-                pRI_backup->pCI = pRI->pCI;
-                pRI_backup->socket_id = pRI->socket_id;
-                pRI_backup->p_next = pRI->p_next;
-                constructGsmSendSmsRilRequest(p, smscPDU, pdu[index]);
-                p.setDataPosition(pos);
-                pRI->pCI->dispatchFunction(p, pRI_backup);
+                if(pRI_backup != NULL) {
+                    pRI_backup->token = pRI->token;
+                    pRI_backup->pCI = pRI->pCI;
+                    pRI_backup->socket_id = pRI->socket_id;
+                    pRI_backup->p_next = pRI->p_next;
+                    constructGsmSendSmsRilRequest(p, smscPDU, pdu[index]);
+                    p.setDataPosition(pos);
+                    pRI->pCI->dispatchFunction(p, pRI_backup);
+                }
             }
             for(index = 0; index < msg_num; index++){
                 free(pdu[index]);
             }
-
-            free(pdu);
         }
+
+        free(pdu);
     }
 
     if(pRI != NULL)
@@ -149,6 +153,7 @@
         pdu = (char **)malloc(sizeof(char *) * msg_num);
         if(pdu == NULL){
             RLOGD("%s, %s, %d, allocate memory for pdu failed", __FILE__, __FUNCTION__, __LINE__);
+            return 0;
         } else {
             for(index = 0; index < msg_num; index++){
                 pdu[index] = (char *)malloc(sizeof(char)*MAX_PDU_SIZE);
@@ -183,22 +188,23 @@
                 android::Parcel p;
                 size_t pos = p.dataPosition();
                 RequestInfo *pRI_backup = (RequestInfo *)calloc(1, sizeof(RequestInfo));
-                pRI_backup->token = pRI->token;
-                pRI_backup->pCI = pRI->pCI;
-                pRI_backup->socket_id = pRI->socket_id;
-                pRI_backup->p_next = pRI->p_next;
-                constructGsmSendSmsRilRequest(p, smscPDU, pdu[index]);
-                p.setDataPosition(pos);
-                pRI->pCI->dispatchFunction(p, pRI_backup);
+                if(pRI_backup != NULL) {
+                    pRI_backup->token = pRI->token;
+                    pRI_backup->pCI = pRI->pCI;
+                    pRI_backup->socket_id = pRI->socket_id;
+                    pRI_backup->p_next = pRI->p_next;
+                    constructGsmSendSmsRilRequest(p, smscPDU, pdu[index]);
+                    p.setDataPosition(pos);
+                    pRI->pCI->dispatchFunction(p, pRI_backup);
+                }
             }
 
             for(index = 0; index < msg_num; index++){
                 free(pdu[index]);
             }
-
-            free(pdu);
-            pdu = NULL;
         }
+
+        free(pdu);
     }
 
     if(pRI != NULL)
@@ -230,6 +236,7 @@
         pdu = (char **)malloc(sizeof(char *) * msg_num);
         if(pdu == NULL){
             RLOGD("%s, %s, %d, allocate memory for pdu failed", __FILE__, __FUNCTION__, __LINE__);
+            return 0;
         } else {
             for(index = 0; index < msg_num; index++){
                 pdu[index] = (char *)malloc(sizeof(char)*MAX_PDU_SIZE);
@@ -264,25 +271,26 @@
                 android::Parcel p;
                 size_t pos = p.dataPosition();
                 RequestInfo *pRI_backup = (RequestInfo *)calloc(1, sizeof(RequestInfo));
-                pRI_backup->token = pRI->token;
-                pRI_backup->pCI = pRI->pCI;
-                pRI_backup->socket_id = pRI->socket_id;
-                pRI_backup->p_next = pRI->p_next;
-                p.writeInt32(RADIO_TECH_3GPP);
-                p.write(&retry, sizeof(retry));
-                p.write(&messageRef, sizeof(messageRef));
-                constructGsmSendSmsRilRequest(p, smscPDU, pdu[index]);
-                p.setDataPosition(pos);
-                pRI->pCI->dispatchFunction(p, pRI_backup);
+                if(pRI_backup != NULL) {
+                    pRI_backup->token = pRI->token;
+                    pRI_backup->pCI = pRI->pCI;
+                    pRI_backup->socket_id = pRI->socket_id;
+                    pRI_backup->p_next = pRI->p_next;
+                    p.writeInt32(RADIO_TECH_3GPP);
+                    p.write(&retry, sizeof(retry));
+                    p.write(&messageRef, sizeof(messageRef));
+                    constructGsmSendSmsRilRequest(p, smscPDU, pdu[index]);
+                    p.setDataPosition(pos);
+                    pRI->pCI->dispatchFunction(p, pRI_backup);
+                }
             }
 
             for(index = 0; index < msg_num; index++){
                 free(pdu[index]);
             }
-
-            free(pdu);
-            pdu = NULL;
         }
+
+        free(pdu);
     }
 
     if(pRI != NULL)
@@ -323,6 +331,7 @@
         pdu = (char **)malloc(sizeof(char *) * msg_num);
         if(pdu == NULL){
             RLOGD("%s, %s, %d, allocate memory for pdu failed", __FILE__, __FUNCTION__, __LINE__);
+            return 0;
         } else {
             for(index = 0; index < msg_num; index++){
                 pdu[index] = (char *)malloc(sizeof(char)*MAX_PDU_SIZE);
@@ -356,24 +365,25 @@
                 android::Parcel p;
                 size_t pos = p.dataPosition();
                 RequestInfo *pRI_backup = (RequestInfo *)calloc(1, sizeof(RequestInfo));
-                pRI_backup->token = pRI->token;
-                pRI_backup->pCI = pRI->pCI;
-                pRI_backup->socket_id = pRI->socket_id;
-                pRI_backup->p_next = pRI->p_next;
-                p.writeInt32(atoi(argv[1]));
-                writeStringToParcel(p, (const char *)pdu[index]);
-                writeStringToParcel(p, (const char *)smscPDU);
-                p.setDataPosition(pos);
-                pRI->pCI->dispatchFunction(p, pRI_backup);
+                if(pRI_backup != NULL) {
+                    pRI_backup->token = pRI->token;
+                    pRI_backup->pCI = pRI->pCI;
+                    pRI_backup->socket_id = pRI->socket_id;
+                    pRI_backup->p_next = pRI->p_next;
+                    p.writeInt32(atoi(argv[1]));
+                    writeStringToParcel(p, (const char *)pdu[index]);
+                    writeStringToParcel(p, (const char *)smscPDU);
+                    p.setDataPosition(pos);
+                    pRI->pCI->dispatchFunction(p, pRI_backup);
+                }
             }
 
             for(index = 0; index < msg_num; index++){
                 free(pdu[index]);
             }
-
-            free(pdu);
-            pdu = NULL;
         }
+
+        free(pdu);
     }
     if(pRI != NULL)
     {
diff --git a/src/telephony/tel-demo/src/Ril_responsedispatch.cpp b/src/telephony/tel-demo/src/Ril_responsedispatch.cpp
old mode 100644
new mode 100755
index 1f54405..ad253c9
--- a/src/telephony/tel-demo/src/Ril_responsedispatch.cpp
+++ b/src/telephony/tel-demo/src/Ril_responsedispatch.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/tel-demo/src/atci/ATCI.cpp b/src/telephony/tel-demo/src/atci/ATCI.cpp
old mode 100644
new mode 100755
index af29d33..16f38df
--- a/src/telephony/tel-demo/src/atci/ATCI.cpp
+++ b/src/telephony/tel-demo/src/atci/ATCI.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/tel-demo/src/cc.cpp b/src/telephony/tel-demo/src/cc.cpp
old mode 100644
new mode 100755
index 471afd9..8b9b31d
--- a/src/telephony/tel-demo/src/cc.cpp
+++ b/src/telephony/tel-demo/src/cc.cpp
@@ -241,7 +241,7 @@
     } else {
         vol_value = get_mixer_ctrl_volume_value(g_mixer_name_volume_bt);
     }
-    RLOGD("The ctrl \"%s\" is set to %d", g_mixer_name_volume, vol_value);
+    RLOGD("The ctrl \"%s\" is set to %ld", g_mixer_name_volume, vol_value);
     return vol_value;
 }
 
@@ -1147,10 +1147,10 @@
     /* DL:0 UL:1 */
     if (path == 0) {
         is_mute = get_mixer_ctrl_value_int(g_DL_mute_name);
-        RLOGD("The ctrl \"%s\" is set to %d", g_DL_mute_name, is_mute);
+        RLOGD("The ctrl \"%s\" is set to %ld", g_DL_mute_name, is_mute);
     } else {
         is_mute = get_mixer_ctrl_value_int(g_UL_mute_name);
-        RLOGD("The ctrl \"%s\" is set to %d", g_UL_mute_name, is_mute);
+        RLOGD("The ctrl \"%s\" is set to %ld", g_UL_mute_name, is_mute);
     }
 
     return is_mute;
@@ -1163,7 +1163,7 @@
 
 int getCallMute() {
     long int cc_mute = mixer_get_mute(1);
-    RLOGD("getCallMute: %d", cc_mute);
+    RLOGD("getCallMute: %ld", cc_mute);
     return cc_mute;
 }
 
@@ -1314,7 +1314,7 @@
 
     if ((std::stoi(dir) == 1) && (std::stoi(sip_msg_type) == 0)
             && (std::stoi(method) == 4) && (std::stoi(resp_code) == 0)) {
-        std::string msg("SIP CANCEL:");
+        std::string msg("SIP CANCEL:");
         msg.append(reason_text);
         printf("%s", msg.c_str());
     }
@@ -1343,7 +1343,7 @@
         numStrings = responselen / sizeof(char *);
         RLOGD("[slot%d]handleUnsolCallInfoInd: numStrings: %d",socket_id, numStrings);
         if(numStrings < 9) {
-            RLOGE("[slot%d]handleUnsolCallInfoInd, invalid numStrings(%d) < 9, no pau value : numStrings", socket_id);
+            RLOGE("[slot%d]handleUnsolCallInfoInd, invalid numStrings < 9, no pau value : numStrings", socket_id);
             return -1;
         } else {
             RLOGD("[slot%d]handleUnsolCallInfoInd(): pau: %s", socket_id, p_cur[8]);
@@ -1381,7 +1381,7 @@
     numInts = responselen / sizeof(int);
     RLOGD("[slot%d]handleRingbackTone: numInts: %d",socket_id, numInts);
     if(numInts < 1) {
-        RLOGE("[slot%d]handleRingbackTone, invalid numStrings(%d) < 1", socket_id);
+        RLOGE("[slot%d]handleRingbackTone, invalid numStrings < 1", socket_id);
         return -1;
     } else {
         int start = p_int[0];
diff --git a/src/telephony/tel-demo/src/common.cpp b/src/telephony/tel-demo/src/common.cpp
old mode 100644
new mode 100755
index 469eee5..c359cf8
--- a/src/telephony/tel-demo/src/common.cpp
+++ b/src/telephony/tel-demo/src/common.cpp
@@ -1,4 +1,5 @@
- /*
+// SPDX-License-Identifier: MediaTekProprietary
+/*
  * Copyright (C) 2006 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -784,20 +785,28 @@
                 writeStringToParcel(p, items[1].c_str());
             } else if(items[0] == std::string("REQ")) {
                 int request = std::stoi(items[1]);
+
+                // For loop, free before reassign to avoid memory leak
+                if (pRI != NULL) {
+                    free(pRI);
+                }
                 pRI = creatRILInfoAndInit(request, UDP, (RIL_SOCKET_ID) ((0)));
             }
         } else {
             RLOGD("%s, too many \"=\"");
         }
     }
+
     if(pRI && pRI->pCI) {
         p.setDataPosition(pos);
         pRI->pCI->dispatchFunction(p, pRI);
-    } else {
-        if(pRI) {
-            free(pRI);
-            pRI = NULL;
-        }
     }
+
+    // Free to avoid memory leak
+    if(pRI != NULL) {
+        free(pRI);
+        pRI = NULL;
+    }
+
     return true;
 }
diff --git a/src/telephony/tel-demo/src/data/data.cpp b/src/telephony/tel-demo/src/data/data.cpp
index 7155f19..1962a2d 100755
--- a/src/telephony/tel-demo/src/data/data.cpp
+++ b/src/telephony/tel-demo/src/data/data.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/tel-demo/src/data/data_gdbus.cpp b/src/telephony/tel-demo/src/data/data_gdbus.cpp
index 7be14a1..798b5e1 100755
--- a/src/telephony/tel-demo/src/data/data_gdbus.cpp
+++ b/src/telephony/tel-demo/src/data/data_gdbus.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/tel-demo/src/demoscript/Data_API/delete_apn.sh b/src/telephony/tel-demo/src/demoscript/Data_API/delete_apn.sh
new file mode 100755
index 0000000..844200d
--- /dev/null
+++ b/src/telephony/tel-demo/src/demoscript/Data_API/delete_apn.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+#Copyright (c) 2016, MediaTek Inc. All rights reserved.
+#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.
+#Except as otherwise provided in  the applicable licensing terms with 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.
+
+
+#********************************************************************************************
+#USAGE: sh delete_apn.sh id
+#
+#typedef enum {
+#	CMD_INSERT,
+#	CMD_DELETE,
+#	CMD_QUERY,
+#	CMD_UPDATE
+#} apnSqlCmd;
+
+#define APN_PROP_ID "_id"
+#define APN_PROP_TYPE "type"
+#define APN_PROP_MCC "mcc"
+#define APN_PROP_MNC "mnc"
+#define APN_PROP_CARRIER "carrier"
+#define APN_PROP_APN "apn"
+#define APN_PROP_PORT "port"
+#define APN_PROP_PROXY "proxy"
+#define APN_PROP_MMSC "mmsc"
+#define APN_PROP_MMSPROXY "mmsproxy"
+#define APN_PROP_MMSPORT "mmsport"
+#define APN_PROP_USER "user"
+#define APN_PROP_PASSWORD "password"
+#define APN_PROP_AUTH_TYPE "authtype"
+#define APN_PROP_SERVER "server"
+#define APN_PROP_PROTOCOL "protocol"
+#define APN_PROP_ROAMING_PROTOCOL "roaming_protocol"
+#define APN_PROP_MTU "mtu"
+#define APN_PROP_CARRIER_ENABLED "carrier_enabled"
+#define APN_PROP_BEARER "bearer"
+#define APN_PROP_BEARER_BITMASK "bearer_bitmask"
+#define APN_PROP_PROFILE_ID "profile_id"
+#define APN_PROP_MODEM_COGNITIVE "modem_cognitive"
+#define APN_PROP_MAXCONNS "maxConns"
+#define APN_PROP_WAITTIME "waitTime"
+#define APN_PROP_MAXCONNSTIME "maxConnsTime"
+#define APN_PROP_MVNO_TYPE "mvno_type"
+#define APN_PROP_USER_VISIBLE "user_visible"
+#define APN_PROP_CURRENT "current"
+
+# <apn carrier="Cosmote Wireless Internet"
+#      mcc="202"
+#      mnc="01"
+#      apn="internet"
+#      type="default,supl"
+#  />
+#***********************************************************************************************
+
+upper2lower(){
+    value="$(echo $1 | tr '[:upper:]' '[:lower:]')"
+    echo $value
+}
+
+lower2upper(){
+    value="$(echo $1 | tr '[:lower:]' '[:upper:]')"
+    echo $value
+}
+
+#open a socket, communicated with Service.
+exec 9<> /dev/udp/127.0.0.1/8000
+
+if [ $# -gt 0 ]; then
+echo "the number of parameters is: $#"
+#check if the first parameter is empty
+if [ -z $1 ]
+then
+echo -n "please input id: "
+read id
+else
+id=$1
+fi
+
+echo "Delete apn for _id: $id"
+echo "RIL_REQUEST_MODIFY_APN 1 id=$id" >&9
+
+else
+echo "RIL_REQUEST_MODIFY_APN:please input apn info..."
+echo "you could use 'query_apn.sh mcc mnc' to get record id firstly."
+echo "command: delete_apn.sh id"
+fi
+
+#close socket R/W
+exec 9>&-
+exec 9<&-
+exit 0
\ No newline at end of file
diff --git a/src/telephony/tel-demo/src/demoscript/Data_API/insert_apn.sh b/src/telephony/tel-demo/src/demoscript/Data_API/insert_apn.sh
new file mode 100755
index 0000000..9ee9f82
--- /dev/null
+++ b/src/telephony/tel-demo/src/demoscript/Data_API/insert_apn.sh
@@ -0,0 +1,214 @@
+#!/bin/bash
+#Copyright (c) 2016, MediaTek Inc. All rights reserved.
+#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.
+#Except as otherwise provided in  the applicable licensing terms with 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.
+
+
+#********************************************************************************************
+#if the parameters cann't find and replace it with null.
+#USAGE: sh insert_apn.sh mcc mnc apn type user password protocol roamingprotocol carrier
+#
+#typedef enum {
+#	CMD_INSERT,
+#	CMD_DELETE,
+#	CMD_QUERY,
+#	CMD_UPDATE
+#} apnSqlCmd;
+
+#define APN_PROP_ID "_id"
+#define APN_PROP_TYPE "type"
+#define APN_PROP_MCC "mcc"
+#define APN_PROP_MNC "mnc"
+#define APN_PROP_CARRIER "carrier"
+#define APN_PROP_APN "apn"
+#define APN_PROP_PORT "port"
+#define APN_PROP_PROXY "proxy"
+#define APN_PROP_MMSC "mmsc"
+#define APN_PROP_MMSPROXY "mmsproxy"
+#define APN_PROP_MMSPORT "mmsport"
+#define APN_PROP_USER "user"
+#define APN_PROP_PASSWORD "password"
+#define APN_PROP_AUTH_TYPE "authtype"
+#define APN_PROP_SERVER "server"
+#define APN_PROP_PROTOCOL "protocol"
+#define APN_PROP_ROAMING_PROTOCOL "roaming_protocol"
+#define APN_PROP_MTU "mtu"
+#define APN_PROP_CARRIER_ENABLED "carrier_enabled"
+#define APN_PROP_BEARER "bearer"
+#define APN_PROP_BEARER_BITMASK "bearer_bitmask"
+#define APN_PROP_PROFILE_ID "profile_id"
+#define APN_PROP_MODEM_COGNITIVE "modem_cognitive"
+#define APN_PROP_MAXCONNS "maxConns"
+#define APN_PROP_WAITTIME "waitTime"
+#define APN_PROP_MAXCONNSTIME "maxConnsTime"
+#define APN_PROP_MVNO_TYPE "mvno_type"
+#define APN_PROP_USER_VISIBLE "user_visible"
+#define APN_PROP_CURRENT "current"
+#***********************************************************************************************
+
+upper2lower(){
+    value="$(echo $1 | tr '[:upper:]' '[:lower:]')"
+    echo $value
+}
+
+lower2upper(){
+    value="$(echo $1 | tr '[:lower:]' '[:upper:]')"
+    echo $value
+}
+
+#open a socket, communicated with Service.
+exec 9<> /dev/udp/127.0.0.1/8000
+
+if [ $# -gt 0 ]; then
+echo "the number of parameters is: $#"
+#check if the first parameter is empty
+
+if [ -z $1 ]
+then
+echo -n "please input mcc(if no exsit, input "null"): "
+read mcc
+else
+mcc=$1
+fi
+
+if [ -z $2 ]
+then
+echo -n "please input mnc(if no exsit, input "null"): "
+read mnc
+else
+mnc=$2
+fi
+
+if [ -z $3 ]
+then
+echo -n "please input apn(if no exsit, input "null"): "
+read apn
+else
+apn=$3
+fi
+
+if [ -z $4 ]
+then
+echo -n "please input apn type(if no exsit, input "null"): "
+read apntype
+else
+apntype=$4
+fi
+
+if [ -z $5 ]
+then
+echo -n "please input user(if no exsit, input "null"): "
+read user
+else
+user=$5
+fi
+
+if [ -z $6 ]
+then
+echo -n "please input password(if no exsit, input "null"): "
+read password
+else
+password=$6
+fi
+
+
+if [ -z $7 ]
+then
+echo -n "please input normalprotocol(if no exsit, input "null"): "
+read normalprotocol
+else
+normalprotocol=$7
+
+fi
+if [ -z $8 ]
+then
+echo -n "please input roamingprotocol(if no exsit, input "null"): "
+read roamingprotocol
+else
+roamingprotocol=$8
+fi
+
+if [ -z $9 ]
+then
+echo -n "please input carrier(if no exsit, input "null"): "
+read carrier
+else
+carrier=$9
+fi
+
+
+if [ "$mcc" != "null" ]
+then
+    mcc="mcc=$mcc;"
+else
+    mcc=""
+fi
+if [ "$mnc" != "null" ]
+then
+    mnc="mnc=$mnc;"
+else
+    mnc=""
+fi
+if [ "$apn" != "null" ]
+then
+    apn="apn=$apn;"
+else
+    apn=""
+fi
+if [ "$apntype" != "null" ]
+then
+    apntype=$(upper2lower $apntype)
+    apntype="type=$apntype;"
+else
+    apntype=""
+fi
+if [ "$user" != "null" ]
+then
+    user="user=$user;"
+else
+    user=""
+fi
+if [ "$password" != "null" ]
+then
+    password="password=$password;"
+else
+    password=""
+fi
+if [ "$normalprotocol" != "null" ]
+then
+    normalprotocol=$(lower2upper $normalprotocol)
+    normalprotocol="protocol=$normalprotocol;"
+else
+    normalprotocol=""
+fi
+if [ "$roamingprotocol" != "null" ]
+then
+    roamingprotocol=$(lower2upper $roamingprotocol)
+    roamingprotocol="roaming_protocol=$roamingprotocol;"
+else
+    roamingprotocol=""
+fi
+if [ "$carrier" != "null" ]
+then
+    carrier="carrier=$carrier;"
+else
+    carrier=""
+fi
+
+newcmd=$mcc$mnc$apn$apntype$user$password$normalprotocol$roamingprotocol$carrier
+echo $newcmd
+
+echo "carrier: $carrier, apn: $apn, apntype: $apntype, usr: $user, password: $password, normalprotocol: $normalprotocol, roamingprotocol: $roamingprotocol"
+echo "RIL_REQUEST_MODIFY_APN 0 $newcmd" >&9
+
+else
+echo "RIL_REQUEST_MODIFY_APN:please input apn info..."
+echo "command: insert_apn.sh mcc mnc apn type user password protocol roamingprotocol carrier"
+fi
+
+#close socket R/W
+exec 9>&-
+exec 9<&-
+exit 0
\ No newline at end of file
diff --git a/src/telephony/tel-demo/src/demoscript/Data_API/modify_apn.sh b/src/telephony/tel-demo/src/demoscript/Data_API/modify_apn.sh
new file mode 100755
index 0000000..0e4f8a3
--- /dev/null
+++ b/src/telephony/tel-demo/src/demoscript/Data_API/modify_apn.sh
@@ -0,0 +1,228 @@
+#!/bin/bash
+#Copyright (c) 2016, MediaTek Inc. All rights reserved.
+#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.
+#Except as otherwise provided in  the applicable licensing terms with 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.
+
+
+#********************************************************************************************
+#if the parameters cann't find and replace it with null. id is mandatory.
+#USAGE: sh modify_apn.sh id mcc mnc apn type user password protocol roamingprotocol carrier
+#
+#typedef enum {
+#	CMD_INSERT,
+#	CMD_DELETE,
+#	CMD_QUERY,
+#	CMD_UPDATE
+#} apnSqlCmd;
+
+#define APN_PROP_ID "_id"
+#define APN_PROP_TYPE "type"
+#define APN_PROP_MCC "mcc"
+#define APN_PROP_MNC "mnc"
+#define APN_PROP_CARRIER "carrier"
+#define APN_PROP_APN "apn"
+#define APN_PROP_PORT "port"
+#define APN_PROP_PROXY "proxy"
+#define APN_PROP_MMSC "mmsc"
+#define APN_PROP_MMSPROXY "mmsproxy"
+#define APN_PROP_MMSPORT "mmsport"
+#define APN_PROP_USER "user"
+#define APN_PROP_PASSWORD "password"
+#define APN_PROP_AUTH_TYPE "authtype"
+#define APN_PROP_SERVER "server"
+#define APN_PROP_PROTOCOL "protocol"
+#define APN_PROP_ROAMING_PROTOCOL "roaming_protocol"
+#define APN_PROP_MTU "mtu"
+#define APN_PROP_CARRIER_ENABLED "carrier_enabled"
+#define APN_PROP_BEARER "bearer"
+#define APN_PROP_BEARER_BITMASK "bearer_bitmask"
+#define APN_PROP_PROFILE_ID "profile_id"
+#define APN_PROP_MODEM_COGNITIVE "modem_cognitive"
+#define APN_PROP_MAXCONNS "maxConns"
+#define APN_PROP_WAITTIME "waitTime"
+#define APN_PROP_MAXCONNSTIME "maxConnsTime"
+#define APN_PROP_MVNO_TYPE "mvno_type"
+#define APN_PROP_USER_VISIBLE "user_visible"
+#define APN_PROP_CURRENT "current"
+#***********************************************************************************************
+
+upper2lower(){
+    value="$(echo $1 | tr '[:upper:]' '[:lower:]')"
+    echo $value
+}
+
+lower2upper(){
+    value="$(echo $1 | tr '[:lower:]' '[:upper:]')"
+    echo $value
+}
+
+#open a socket, communicated with Service.
+exec 9<> /dev/udp/127.0.0.1/8000
+
+if [ $# -gt 0 ]; then
+echo "the number of parameters is: $#"
+#check if the first parameter is empty
+if [ -z $1 ]
+then
+echo -n "please input id: "
+read id
+else
+id=$1
+fi
+
+if [ -z $2 ]
+then
+echo -n "please input mcc(if no exsit, input "null"): "
+read mcc
+else
+mcc=$2
+fi
+
+if [ -z $3 ]
+then
+echo -n "please input mnc(if no exsit, input "null"): "
+read mnc
+else
+mnc=$3
+fi
+
+if [ -z $4 ]
+then
+echo -n "please input apn(if no exsit, input "null"): "
+read apn
+else
+apn=$4
+fi
+
+if [ -z $5 ]
+then
+echo -n "please input apn type(if no exsit, input "null"): "
+read apntype
+else
+apntype=$5
+fi
+
+if [ -z $6 ]
+then
+echo -n "please input user(if no exsit, input "null"): "
+read user
+else
+user=$6
+fi
+
+if [ -z $7 ]
+then
+echo -n "please input password(if no exsit, input "null"): "
+read password
+else
+password=$7
+fi
+
+
+if [ -z $8 ]
+then
+echo -n "please input normalprotocol(if no exsit, input "null"): "
+read normalprotocol
+else
+normalprotocol=$8
+fi
+
+if [ -z $9 ]
+then
+echo -n "please input roamingprotocol(if no exsit, input "null"): "
+read roamingprotocol
+else
+roamingprotocol=$9
+fi
+
+if [ -z ${10} ]
+then
+echo -n "please input carrier(if no exsit, input "null"): "
+read carrier
+else
+carrier=${10}
+fi
+
+
+if [ "$id" != "null" ]
+then
+    id="_id=$id;"
+else
+    echo "id can not be null"
+    eixt 0
+fi
+if [ "$mcc" != "null" ]
+then
+    mcc="mcc=$mcc;"
+else
+    mcc=""
+fi
+if [ "$mnc" != "null" ]
+then
+    mnc="mnc=$mnc;"
+else
+    mnc=""
+fi
+if [ "$apn" != "null" ]
+then
+    apn="apn=$apn;"
+else
+    apn=""
+fi
+if [ "$apntype" != "null" ]
+then
+    apntype=$(upper2lower $apntype)
+    apntype="type=$apntype;"
+else
+    apntype=""
+fi
+if [ "$user" != "null" ]
+then
+    user="user=$user;"
+else
+    user=""
+fi
+if [ "$password" != "null" ]
+then
+    password="password=$password;"
+else
+    password=""
+fi
+if [ "$normalprotocol" != "null" ]
+then
+    normalprotocol=$(lower2upper $normalprotocol)
+    normalprotocol="protocol=$normalprotocol;"
+else
+    normalprotocol=""
+fi
+if [ "$roamingprotocol" != "null" ]
+then
+    roamingprotocol=$(lower2upper $roamingprotocol)
+    roamingprotocol="roaming_protocol=$roamingprotocol;"
+else
+    roamingprotocol=""
+fi
+if [ "$carrier" != "null" ]
+then
+    carrier="carrier=$carrier;"
+else
+    carrier=""
+fi
+
+newcmd=$id$mcc$mnc$apn$apntype$user$password$normalprotocol$roamingprotocol$carrier
+echo $newcmd
+
+echo "id: $id, apn: $apn, apntype: $apntype, usr: $user, password: $password, normalprotocol: $normalprotocol, roamingprotocol: $roamingprotocol, carrier:$carrier"
+echo "RIL_REQUEST_MODIFY_APN 3 $newcmd" >&9
+
+else
+echo "RIL_REQUEST_MODIFY_APN:please input apn info..."
+echo "command: modify_apn.sh id mcc mnc apn type user password protocol roamingprotocol carrier"
+fi
+
+#close socket R/W
+exec 9>&-
+exec 9<&-
+exit 0
\ No newline at end of file
diff --git a/src/telephony/tel-demo/src/demoscript/Data_API/query_apn.sh b/src/telephony/tel-demo/src/demoscript/Data_API/query_apn.sh
new file mode 100755
index 0000000..7b2fd7c
--- /dev/null
+++ b/src/telephony/tel-demo/src/demoscript/Data_API/query_apn.sh
@@ -0,0 +1,101 @@
+#!/bin/bash
+#Copyright (c) 2016, MediaTek Inc. All rights reserved.
+#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.
+#Except as otherwise provided in  the applicable licensing terms with 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.
+
+
+#********************************************************************************************
+#if the parameters cann't find and replace it with null.
+#USAGE: sh query_apn.sh mcc mnc
+#
+#typedef enum {
+#	CMD_INSERT,
+#	CMD_DELETE,
+#	CMD_QUERY,
+#	CMD_UPDATE
+#} apnSqlCmd;
+
+#define APN_PROP_ID "_id"
+#define APN_PROP_TYPE "type"
+#define APN_PROP_MCC "mcc"
+#define APN_PROP_MNC "mnc"
+#define APN_PROP_CARRIER "carrier"
+#define APN_PROP_APN "apn"
+#define APN_PROP_PORT "port"
+#define APN_PROP_PROXY "proxy"
+#define APN_PROP_MMSC "mmsc"
+#define APN_PROP_MMSPROXY "mmsproxy"
+#define APN_PROP_MMSPORT "mmsport"
+#define APN_PROP_USER "user"
+#define APN_PROP_PASSWORD "password"
+#define APN_PROP_AUTH_TYPE "authtype"
+#define APN_PROP_SERVER "server"
+#define APN_PROP_PROTOCOL "protocol"
+#define APN_PROP_ROAMING_PROTOCOL "roaming_protocol"
+#define APN_PROP_MTU "mtu"
+#define APN_PROP_CARRIER_ENABLED "carrier_enabled"
+#define APN_PROP_BEARER "bearer"
+#define APN_PROP_BEARER_BITMASK "bearer_bitmask"
+#define APN_PROP_PROFILE_ID "profile_id"
+#define APN_PROP_MODEM_COGNITIVE "modem_cognitive"
+#define APN_PROP_MAXCONNS "maxConns"
+#define APN_PROP_WAITTIME "waitTime"
+#define APN_PROP_MAXCONNSTIME "maxConnsTime"
+#define APN_PROP_MVNO_TYPE "mvno_type"
+#define APN_PROP_USER_VISIBLE "user_visible"
+#define APN_PROP_CURRENT "current"
+
+# <apn carrier="Cosmote Wireless Internet"
+#      mcc="202"
+#      mnc="01"
+#      apn="internet"
+#      type="default,supl"
+#  />
+#***********************************************************************************************
+
+upper2lower(){
+    value="$(echo $1 | tr '[:upper:]' '[:lower:]')"
+    echo $value
+}
+
+lower2upper(){
+    value="$(echo $1 | tr '[:lower:]' '[:upper:]')"
+    echo $value
+}
+
+#open a socket, communicated with Service.
+exec 9<> /dev/udp/127.0.0.1/8000
+
+if [ $# -gt 0 ]; then
+echo "the number of parameters is: $#"
+#check if the first parameter is empty
+if [ -z $1 ]
+then
+echo -n "please input mcc: "
+read mcc
+else
+mcc=$1
+fi
+
+if [ -z $2 ]
+then
+echo -n "please input mnc: "
+read mnc
+else
+mnc=$2
+fi
+
+echo "Query apn for mcc: $mcc, mnc: $mnc"
+echo "RIL_REQUEST_MODIFY_APN 2 mcc=$mcc;mnc=$mnc" >&9
+
+else
+echo "RIL_REQUEST_MODIFY_APN:please input apn info..."
+echo "command: query_apn.sh mcc mnc"
+fi
+
+#close socket R/W
+exec 9>&-
+exec 9<&-
+exit 0
\ No newline at end of file
diff --git a/src/telephony/tel-demo/src/ecall/eCall.cpp b/src/telephony/tel-demo/src/ecall/eCall.cpp
old mode 100644
new mode 100755
index 2e628be..da55466
--- a/src/telephony/tel-demo/src/ecall/eCall.cpp
+++ b/src/telephony/tel-demo/src/ecall/eCall.cpp
@@ -132,6 +132,7 @@
 static timer_t sT7;
 static timer_t sRedialTimer;
 static timer_t sAutoAnsTimer;
+static timer_t sAutoAnsTimer_ims;
 static timer_t gostResendMsdTimer;
 static timer_t gostDeregistrationTimer;
 
@@ -148,6 +149,7 @@
 static int sT7_sig_value = 7;
 static int redial_sig_value = 8;
 static int autoAns_sig_value = 9;
+static int autoAns_sig_value_ims = 10;
 static int gost_resend_msd_value = 11;
 static int gost_deregistration_value = 12;
 
@@ -167,6 +169,15 @@
         RLOGD("%s(), timer_id(%ld) had stopped", __FUNCTION__, (long)sAutoAnsTimer);
         return true;
     }
+    if(timer_gettime(sAutoAnsTimer_ims, &timespec) == -1) {
+        RLOGD("%s(), get ims_time fail(%s)", __FUNCTION__, strerror(errno));
+        return true;
+    }
+    RLOGD("%s(), ims tv_sec=%ld, tv_nsec=%ld", __FUNCTION__,timespec.it_value.tv_sec, timespec.it_value.tv_nsec);
+    if((timespec.it_value.tv_sec == 0)  && (timespec.it_value.tv_nsec == 0) ) {
+        RLOGD("%s(),ims timer_id(%ld) had stopped", __FUNCTION__, (long)sAutoAnsTimer_ims);
+        return true;
+    }
     return false;
 }
 
@@ -251,6 +262,8 @@
         autoAnswerEcall(true);
     } else if(sig.sival_int == autoAns_sig_value) {
         autoAnswerEcall(false);
+    } else if(sig.sival_int == autoAns_sig_value_ims) {
+        autoAnswerEcall(false);
     } else if(sig.sival_int == gost_resend_msd_value) {
         //send msd
         char** argv = new char*[gost_sms_argv.size()];
@@ -309,6 +322,7 @@
     init_ecall_timer(&sT7,sT7_sig_value);
     init_ecall_timer(&sRedialTimer,redial_sig_value);
     init_ecall_timer(&sAutoAnsTimer,autoAns_sig_value);
+    init_ecall_timer(&sAutoAnsTimer_ims,autoAns_sig_value_ims);
     init_ecall_timer(&gostResendMsdTimer,gost_resend_msd_value);
     init_ecall_timer(&gostDeregistrationTimer, gost_deregistration_value);
 }
@@ -461,19 +475,22 @@
         hangupConnection(2, argv, soc_id, pRI);
         break;
     }
-    case RIL_UNSOL_ECALL_ACTIVE: // =11,
+    case RIL_UNSOL_ECALL_ACTIVE: // = 11,
     {
         if(redial_tag == REDIAL_DOING) {
             redial_tag = REDIAL_SUCCESS;
             stop_ecall_timer(sRedialTimer, redial_sig_value);
         }
         stop_ecall_timer(sAutoAnsTimer, autoAns_sig_value);
+        stop_ecall_timer(sAutoAnsTimer_ims, autoAns_sig_value_ims);
         autoAnswerEcall(false);
         start_ecll_timer(sT2, sT2_sig_value,T2_TIMEOUT);
-        start_ecll_timer(sT5,sT5_sig_value, T5_TIMEOUT);
+        // Start T5 only when need send inband MSD.
+        if (fast_argc)
+            start_ecll_timer(sT5,sT5_sig_value, T5_TIMEOUT);
         break;
     }
-    case RIL_UNSOL_ECALL_DISCONNECTED: //=12,
+    case RIL_UNSOL_ECALL_DISCONNECTED: // = 12
     {
         start_ecll_timer(sAutoAnsTimer,autoAns_sig_value, AUTOANS_TIMEOUT);
         autoAnswerEcall(true);
@@ -506,11 +523,104 @@
         }
         break;
     }
-    //case RIL_UNSOL_ECALL_IMS_MSD_ACK: // = 20,
-    //case RIL_UNSOL_ECALL_IMS_UPDATE_MSD: // = 21,
-    //case RIL_UNSOL_ECALL_UNSPECIFIED: // = 0xffff,
+#if defined(TARGET_PLATFORM_MT2735)
+    case RIL_UNSOL_ECALL_IMS_ACTIVE: // 13 ,
+    {
+        act_fecall_socid = soc_id;
+        act_feCall_Id = p_cur->call_id;
+        stop_ecall_timer(sAutoAnsTimer, autoAns_sig_value);
+        stop_ecall_timer(sAutoAnsTimer_ims, autoAns_sig_value_ims);
+        autoAnswerEcall(false);
+        start_ecll_timer(sT2, sT2_sig_value,T2_TIMEOUT);
+        break;
+    }
+    case RIL_UNSOL_ECALL_IMS_DISCONNECTED: // 14
+    {
+        fast_argc = 0;
+        fast_argv.clear();
+        stop_ecall_timer(sT2, sT2_sig_value);
+        autoAnswerEcall(true);
+        start_ecll_timer(sAutoAnsTimer_ims, autoAns_sig_value_ims, 12*AUTOANS_TIMEOUT);
+        break;
+    }
+    case RIL_UNSOL_ECALL_IMS_MSD_ACK: // 20
+    {
+        saveEcallRecord(p_cur->ind);
+        break;
+    }
+    case RIL_UNSOL_ECALL_IMS_UPDATE_MSD: // 21,
+    {
+        RLOGD("update ims ecall msd_data: %s", msd_data==NULL ? "":msd_data);
+        if(msd_data != NULL) {
+            RequestInfo* pRI = creatRILInfoAndInit(RIL_REQUEST_ECALL_SET_MSD, RSPD, soc_id);
+            char* argv[3] = {"RIL_REQUEST_ECALL_SET_MSD", "", "" };
+            argv[1] = const_cast<char*>(std::to_string(p_cur->call_id).c_str());
+            argv[2] = msd_data;
+            setMSD(3, argv, soc_id, pRI);
+        }
+        break;
+    }
+    case RIL_UNSOL_ECALL_IMS_IN_BAND_TRANSFER: // 22
+    {
+        start_ecll_timer(sT5,sT5_sig_value, T5_TIMEOUT);
+        break;
+    }
+    case RIL_UNSOL_ECALL_IMS_MSD_NACK: // 23
+    {
+        saveEcallRecord(p_cur->ind);
+        break;
+    }
+    case RIL_UNSOL_ECALL_IMS_SRVCC: // 24
+    {
+        start_ecll_timer(sT5,sT5_sig_value, T5_TIMEOUT);
+        break;
+    }
+    case RIL_UNSOL_ECALL_PSAP_CALLBACK_START: // 40
+    {
+        // Similar to receive 11 + 1
+        if(redial_tag == REDIAL_DOING) {
+            redial_tag = REDIAL_SUCCESS;
+            stop_ecall_timer(sRedialTimer, redial_sig_value);
+        }
+        stop_ecall_timer(sAutoAnsTimer, autoAns_sig_value);
+        stop_ecall_timer(sAutoAnsTimer_ims, autoAns_sig_value_ims);
+        autoAnswerEcall(false);
+        start_ecll_timer(sT2, sT2_sig_value,T2_TIMEOUT);
+
+        RLOGD("msd_data: %s", msd_data==NULL ? "":msd_data);
+        if(msd_data != NULL) {
+            RequestInfo* pRI = creatRILInfoAndInit(RIL_REQUEST_ECALL_SET_MSD, RSPD, soc_id);
+            char* argv[3] = {"RIL_REQUEST_ECALL_SET_MSD", "", "" };
+            argv[1] = const_cast<char*>(std::to_string(p_cur->call_id).c_str());
+            argv[2] = msd_data;
+            setMSD(3, argv, soc_id, pRI);
+        }
+        break;
+    }
+    case RIL_UNSOL_ECALL_PSAP_CALLBACK_IMS_UPDATE_MSD: // 41
+    {
+        // Similar to receive 13 + 21
+        act_fecall_socid = soc_id;
+        act_feCall_Id = p_cur->call_id;
+        stop_ecall_timer(sAutoAnsTimer, autoAns_sig_value);
+        stop_ecall_timer(sAutoAnsTimer_ims, autoAns_sig_value_ims);
+        autoAnswerEcall(false);
+        start_ecll_timer(sT2, sT2_sig_value,T2_TIMEOUT);
+
+        RLOGD("update ims ecall msd_data: %s", msd_data==NULL ? "":msd_data);
+        if(msd_data != NULL) {
+            RequestInfo* pRI = creatRILInfoAndInit(RIL_REQUEST_ECALL_SET_MSD, RSPD, soc_id);
+            char* argv[3] = {"RIL_REQUEST_ECALL_SET_MSD", "", "" };
+            argv[1] = const_cast<char*>(std::to_string(p_cur->call_id).c_str());
+            argv[2] = msd_data;
+            setMSD(3, argv, soc_id, pRI);
+        }
+        break;
+    }
+#endif
     default:
-        RLOGD("handleEcallIndication don't handlt the value(%d)", p_cur->ind);
+        RLOGD("handleEcallIndication don't handle the value(%d)", p_cur->ind);
+        break;
     }
 }
 
diff --git a/src/telephony/tel-demo/src/ecall/gost/utils/GostEcallUtils.cpp b/src/telephony/tel-demo/src/ecall/gost/utils/GostEcallUtils.cpp
old mode 100644
new mode 100755
index 301e622..24936fe
--- a/src/telephony/tel-demo/src/ecall/gost/utils/GostEcallUtils.cpp
+++ b/src/telephony/tel-demo/src/ecall/gost/utils/GostEcallUtils.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/tel-demo/src/em/em.cpp b/src/telephony/tel-demo/src/em/em.cpp
old mode 100644
new mode 100755
index fcb25d2..67fc7e7
--- a/src/telephony/tel-demo/src/em/em.cpp
+++ b/src/telephony/tel-demo/src/em/em.cpp
@@ -62,7 +62,12 @@
     //{"ESM",0,NULL,1,1},
     //{"EMM",0,NULL,1,1},
     //{"MMDC",0,NULL,1,1},
+#ifdef C2K_SUPPORT
     {"EL1",0,NULL,1,1},
+#endif
+#ifdef TARGET_PLATFORM_MT2735
+    {"NR L1 Info",0,NULL,1,1},
+#endif
     //{"Timer Information",0,NULL,1,1},
     //{"TDD TAS",0,NULL,1,1},
     //{"GSM TAS",0,NULL,1,1},
@@ -185,6 +190,9 @@
 };
 em_arry_t hspa[] = {
     {"QUERY",0,NULL,1,1},
+#ifdef TARGET_PLATFORM_MT2735
+    {"QUERY_CAINFO",0,NULL,1,1},
+#endif
 };
 em_arry_t cfu[] = {
     {"Default",0,NULL,1,1},
@@ -193,7 +201,11 @@
 };
 em_arry_t bandmode[] = {
     {"getcurrentband",0,NULL,1,1},
-    {"setBand(eg: 1.1=1 add band, 1.1=0 remove band) or getSupportBand",0,NULL,1,1},
+    {"setBand(eg: 1.1=1 add band, 1.1=0 remove band) or getGSMSupportBand",0,NULL,1,1},
+#ifdef TARGET_PLATFORM_MT2735
+    {"getcurrentNRband",0,NULL,1,1},
+#endif
+//    {"[NR]setBand(eg: 1.1=1 add band, 1.1=0 remove band) or getGSMSupportBand",0,NULL,1,1},
 };
 em_arry_t networkinfo[] = {
     {"RR Cell Sel",0,NULL,1,1},
@@ -263,7 +275,11 @@
 
 em_arry_t antenna_4Gmode[] = {
     {"getmode",0,NULL,1,1},
+#ifdef TARGET_PLATFORM_MT2735
+    {"setmode",0,NULL,1,1},
+#else
     {"setmode",NUM_ITEMS(antenna_setmodes_4g),antenna_setmodes_4g,1,1},
+#endif
 };
 
 em_arry_t antenna_3Gmode[] = {
@@ -276,12 +292,20 @@
     {"setmode",NUM_ITEMS(antenna_setmodes_c2k),antenna_setmodes_c2k,1,1},
 };
 
+em_arry_t antenna_NRmode[] = {
+    {"getmode",0,NULL,1,1},
+    {"setmode",0,NULL,1,1},
+};
+
 em_arry_t antennatest[] = {
     {"4G",NUM_ITEMS(antenna_4Gmode),antenna_4Gmode,1,1},
-    {"3G",NUM_ITEMS(antenna_3Gmode),antenna_3Gmode,1,1},
 #ifdef C2K_SUPPORT
+    {"3G",NUM_ITEMS(antenna_3Gmode),antenna_3Gmode,1,1},
     {"CDMA",NUM_ITEMS(antenna_c2kmode),antenna_c2kmode,1,1},
 #endif
+#ifdef TARGET_PLATFORM_MT2735
+    {"NR",NUM_ITEMS(antenna_NRmode),antenna_NRmode,1,1},
+#endif
 };
 
 em_arry_t time_reg[] = {
@@ -555,12 +579,98 @@
         {"show default",0,NULL,0,0},
 };
 
+em_arry_t rfdesense_nr_tx_mode[] = {
+        {"Tone",0,NULL,0,0},
+        {"PUSCH",0,NULL,0,0},
+};
+
+em_arry_t rfdesense_nr_band[] = {
+        {"1",0,NULL,0,0},
+        {"3",0,NULL,0,0},
+        {"7",0,NULL,0,0},
+        {"8",0,NULL,0,0},
+        {"20",0,NULL,0,0},
+        {"28",0,NULL,0,0},
+        {"38",0,NULL,0,0},
+        {"41",0,NULL,0,0},
+        {"77",0,NULL,0,0},
+        {"78",0,NULL,0,0},
+        {"79",0,NULL,0,0},
+};
+
+em_arry_t rfdesense_nr_bandwidth[] = {
+        {"5M",0,NULL,0,0},
+        {"10M",0,NULL,0,0},
+        {"15M",0,NULL,0,0},
+        {"20M",0,NULL,0,0},
+        {"25M",0,NULL,0,0},
+        {"30M",0,NULL,0,0},
+        {"35M",0,NULL,0,0},
+        {"40M",0,NULL,0,0},
+        {"45M",0,NULL,0,0},
+        {"50M",0,NULL,0,0},
+        {"55M",0,NULL,0,0},
+        {"60M",0,NULL,0,0},
+        {"65M",0,NULL,0,0},
+        {"70M",0,NULL,0,0},
+        {"75M",0,NULL,0,0},
+        {"82M",0,NULL,0,0},
+        {"85M",0,NULL,0,0},
+        {"90M",0,NULL,0,0},
+        {"95M",0,NULL,0,0},
+        {"100M",0,NULL,0,0},
+};
+
+em_arry_t  rfdesense_nr_mcs[] = {
+        {"DFT-S BPSK",0,NULL,0,0},
+        {"CP QPSK",0,NULL,0,0},
+        {"DFT-S QPSK",0,NULL,0,0},
+        {"CP 16QAM",0,NULL,0,0},
+        {"DFT-S 16QAM",0,NULL,0,0},
+        {"CP 64QAM",0,NULL,0,0},
+        {"DFT-S 64QAM",0,NULL,0,0},
+        {"CP 256QAM",0,NULL,0,0},
+        {"DFT-S 256QAM",0,NULL,0,0},
+};
+
+em_arry_t  rfdesense_nr_scs[] = {
+        {"15KHZ(0)",0,NULL,0,0},
+        {"30KHZ(1)",0,NULL,0,0},
+        {"60KHZ(2)",0,NULL,0,0},
+        {"120KHZ(3)",0,NULL,0,0},
+        {"240KHZ(4)",0,NULL,0,0},
+};
+
+em_arry_t rfdesense_nr_sub[] = {
+        {"Tx mode",NUM_ITEMS(rfdesense_nr_tx_mode),rfdesense_nr_tx_mode,0,0},
+        {"Band",NUM_ITEMS(rfdesense_nr_band),rfdesense_nr_band,0,0},
+        {"UL bandwidth",NUM_ITEMS(rfdesense_nr_bandwidth),rfdesense_nr_bandwidth,0,0},
+        {"UL freq(1kHz)",NUM_ITEMS(set_get),set_get,0,0},
+        {"VRB start(0-272)",NUM_ITEMS(set_get),set_get,0,0},
+        {"VRB length(1-273)",NUM_ITEMS(set_get),set_get,0,0},
+        {"MCS",NUM_ITEMS(rfdesense_nr_mcs),rfdesense_nr_mcs,0,0},
+        {"SCS",NUM_ITEMS(rfdesense_nr_scs),rfdesense_nr_scs,0,0},
+        {"Power level(dbm)(-50-23)",NUM_ITEMS(set_get),set_get,0,0},
+        {"Tdd slot config(1-44)",NUM_ITEMS(set_get),set_get,0,0},
+};
+
+em_arry_t rfdesense_nr[] = {
+        {"start",0,NULL,0,0},
+        {"Parameters_set",NUM_ITEMS(rfdesense_nr_sub),rfdesense_nr_sub,0,0},
+        {"show default",0,NULL,0,0},
+};
+
 em_arry_t sub_tx_test[] = {
     { "GSM", NUM_ITEMS(rfdesense_gsm),rfdesense_gsm, 1, 1 },
+#ifndef TARGET_PLATFORM_MT2735
     { "TDSCDMA", NUM_ITEMS(rfdesense_tdscdma), rfdesense_tdscdma, 1, 1 },
+#endif
     { "WCDMA", NUM_ITEMS(rfdesense_wcdma), rfdesense_wcdma, 1, 1 },
     { "LTE(FDD)", NUM_ITEMS(rfdesense_lte_fdd), rfdesense_lte_fdd, 1, 1 },
     { "LTE(TDD)", NUM_ITEMS(rfdesense_lte_tdd), rfdesense_lte_tdd, 1, 1 },
+#ifdef TARGET_PLATFORM_MT2735
+    { "NR", NUM_ITEMS(rfdesense_nr), rfdesense_nr, 1, 1 },
+#endif
 #ifdef C2K_SUPPORT
     { "CDMA(EVDO)", NUM_ITEMS(rfdesense_cdma), rfdesense_cdma, 1, 1 },
     { "CDMA(1x)", NUM_ITEMS(rfdesense_cdma), rfdesense_cdma, 1, 1 },
@@ -579,12 +689,12 @@
 #ifdef C2K_SUPPORT
     {"CDMA modem setting",NUM_ITEMS(c2k_modem_setting),c2k_modem_setting,0,0},
 #endif
-#ifndef TARGET_PLATFORM_MT2735
     {"RF Desense Test ",NUM_ITEMS(desense_test),desense_test,0,0},
-#endif
     {"Modem Test",NUM_ITEMS(modemtest),modemtest,0,0},
     {"HSPA",NUM_ITEMS(hspa),hspa,0,0},
+#ifndef TARGET_PLATFORM_MT2735
     {"CFU",NUM_ITEMS(cfu),cfu,0,0},
+#endif
     {"Antenna Test",NUM_ITEMS(antennatest),antennatest,0,0},
     {"Band Mode",NUM_ITEMS(bandmode),bandmode,0,0},
     {"IMS",NUM_ITEMS(ims),ims,0,0},
@@ -594,15 +704,17 @@
     {"LTE",NUM_ITEMS(lte_info),lte_info,0,0},
 };
 typedef enum {
-#ifdef TARGET_PLATFORM_MT2735
-    MODEM_TEST_ITEM = 0,
-#else
+#ifdef C2K_SUPPORT
     C2K_MODEM_SETTING = 0,
     RF_DESENSE_TEST,
-    MODEM_TEST_ITEM,
+#else
+    RF_DESENSE_TEST = 0,
 #endif
+    MODEM_TEST_ITEM,
     HSPA_ITEM,
+#ifndef TARGET_PLATFORM_MT2735
     CFU_ITEM,
+#endif
     ANTENNATEST_ITEM,
     BANDMODE_ITEM,
     IMS_ITEM,
@@ -620,21 +732,21 @@
     case C2K_MODEM_SETTING:
         emC2kModemSettingStart(len - 1, multilen, &item[1]);
         break;
+    case CFU_ITEM:
+        emCfuStart(len - 1, &item[1]);
+        break;
+#endif
     case RF_DESENSE_TEST:
         emRfDesenseStart(len - 1, &item[1], multilen, value);
         break;
-#endif
     case MODEM_TEST_ITEM:
         emModemtestStart(len - 1, multilen, &item[1]);
         break;
     case HSPA_ITEM:
         emHspaStart(len - 1, &item[1]);
         break;
-    case CFU_ITEM:
-        emCfuStart(len - 1, &item[1]);
-        break;
     case ANTENNATEST_ITEM:
-        emAntennaTestStart(len - 1, &item[1],(value != NULL ? value[0] : NULL));
+        emAntennaTestStart(len - 1, &item[1], multilen, value);
         break;
     case BANDMODE_ITEM:
         emBandmodeStart(len - 1, &item[1], multilen, value);
diff --git a/src/telephony/tel-demo/src/em/em.h b/src/telephony/tel-demo/src/em/em.h
old mode 100644
new mode 100755
index 44e3e13..debdb4a
--- a/src/telephony/tel-demo/src/em/em.h
+++ b/src/telephony/tel-demo/src/em/em.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -95,6 +96,13 @@
 extern em_arry_t rfdesense_cdma_modulation[];
 extern em_arry_t rfdesense_cdma_sub[];
 extern em_arry_t rfdesense_cdma[];
+extern em_arry_t rfdesense_nr_tx_mode[];
+extern em_arry_t rfdesense_nr_band[];
+extern em_arry_t rfdesense_nr_bandwidth[];
+extern em_arry_t rfdesense_nr_mcs[];
+extern em_arry_t rfdesense_nr_scs[];
+extern em_arry_t rfdesense_nr_sub[];
+extern em_arry_t rfdesense_nr[];
 extern em_arry_t sub_tx_test[];
 extern em_arry_t desense_test[];
 extern em_arry_t emmain[];
@@ -132,7 +140,7 @@
 int emCfuStart(int argc, int *item);
 int emBandmodeStart(int len,int *item,int multilen,char *value[]);
 int emNwInfoStart(int argc, int multicnt,int *item);
-int emAntennaTestStart(int argc, int *item,char *value);
+int emAntennaTestStart(int argc, int *item,int multilen,char *value[]);
 int emC2kModemSettingStart(int argc, int multicnt,int *item);
 int emRfDesenseStart(int len,int *item,int multilen,char *value[]);
 
diff --git a/src/telephony/tel-demo/src/em/em_EL1.cpp b/src/telephony/tel-demo/src/em/em_EL1.cpp
old mode 100644
new mode 100755
index 73e8a1a..9551698
--- a/src/telephony/tel-demo/src/em/em_EL1.cpp
+++ b/src/telephony/tel-demo/src/em/em_EL1.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -44,12 +45,15 @@
 #include  "common.h"
 #include "em/em.h"
 #include "Radio_capability_switch_util.h"
+#include "../util/utils.h"
 
 #if EM_MODE_SUPPORT
 
 #undef LOG_TAG
 #define LOG_TAG "EM_EL1"
 
+#define MAX_RAN_CELL_SIZE 32
+
 static int mItemCount = 0;
 static int mFlag = 0;// at cmd flag
 static int mCurrentFlag = 0; // at cmd handle flag
@@ -57,6 +61,37 @@
 static const int MSG_NW_INFO = 1;
 static const int MSG_NW_INFO_OPEN = 4;
 static const int MSG_NW_INFO_CLOSE = 5;
+static const int MSG_NW_CA_INFO_LTE_NR = 6;
+
+
+static const int IDX_EL1 = -1;
+static const int IDX_CA_INFO_LTE_NR = 0;
+int intput_idx = 0;
+
+static const std::string CMD_SAME_EDMFAPP = "+EDMFAPP: 6,3,";
+
+struct cell_band_bandwidth_struct {
+    /** @brief Cell Identity. */
+    int cid;
+    int c_state;        /*1: SCELL_STATUS_NOTACTIVE 2: SCELL_STATUS_ACTIVE */
+    int cell_band;      /* cell band: 1~1024 */
+    int cell_bandwidth; /* cell bandwidth index */
+    int cc_cw0_cqi;     /*0~15*/
+    int cc_cw1_cqi;     /*0~15*/
+    int cc_pci;         /*0~1024*/
+    int cc_arfcn;       /*22bit*/
+};
+
+struct all_cell_band_bandwidth_struct{
+    int num_serving_lte_cell_dl;
+    int num_serving_lte_cell_ul;
+    int num_serving_nr_cell_dl;
+    int num_serving_nr_cell_ul;
+    cell_band_bandwidth_struct lte_band_bandwidth_dl[MAX_RAN_CELL_SIZE];
+    cell_band_bandwidth_struct lte_band_bandwidth_ul[MAX_RAN_CELL_SIZE];
+    cell_band_bandwidth_struct nr_band_bandwidth_dl[MAX_RAN_CELL_SIZE];
+    cell_band_bandwidth_struct nr_band_bandwidth_ul[MAX_RAN_CELL_SIZE];
+};
 
 static void sendATCommand(const char *cmd,int msg)
 {
@@ -92,6 +127,314 @@
 
 }
 
+static void parseCAInfo(char* data) {
+    RLOGD("parseCAInfo, rsp=%s", data);
+    std::vector<std::string> out;
+    utils::tokenize(string(data), "\n", out);
+    int cell_idx = 0, at_idx = 0;
+    std::string str;
+    str.clear();
+    char tmp[1024] = {0};
+
+    for(auto i: out) {
+        if(i.find(CMD_SAME_EDMFAPP) != std::string::npos) {
+            std::string splitString = i.substr(std::string(CMD_SAME_EDMFAPP).size());
+            std::vector<std::string> getDigitalVal;
+            utils::tokenize(string(splitString), ",\n", getDigitalVal);
+            RLOGD("parseCurrentMode splitString: %s, getDigitalVal.size()=%d",
+                    splitString.c_str(), getDigitalVal.size());
+
+            try {
+                all_cell_band_bandwidth_struct cells_info;
+                memset(&cells_info, 0, sizeof(all_cell_band_bandwidth_struct));
+                str.append("[Cell Info]\n");
+
+                // LTE DL
+                cells_info.num_serving_lte_cell_dl = std::stoi(getDigitalVal[at_idx]);
+                RLOGW("cells_info.num_serving_lte_cell_dl=%d", cells_info.num_serving_lte_cell_dl);
+                sprintf(tmp, "num_serving_lte_cell_dl:%d\n", cells_info.num_serving_lte_cell_dl);
+                str.append(tmp);
+                memset(tmp, 0, sizeof(char)*1024);
+                at_idx++;
+
+                if (cells_info.num_serving_lte_cell_dl != 0) {
+                    for (cell_idx = 0; cell_idx < cells_info.num_serving_lte_cell_dl; cell_idx++) {
+
+                        if (cell_idx >= MAX_RAN_CELL_SIZE) {
+                            RLOGW("cell_idx=%d > MAX_RAN_CELL_SIZE=%d, ignore", cell_idx, MAX_RAN_CELL_SIZE);
+                            continue;
+                        }
+
+                        cells_info.lte_band_bandwidth_dl[cell_idx].cid = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_dl[%d].cid=%d", cell_idx, cells_info.lte_band_bandwidth_dl[cell_idx].cid);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_dl[cell_idx].c_state = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_dl[%d].c_state=%d", cell_idx, cells_info.lte_band_bandwidth_dl[cell_idx].c_state);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_dl[cell_idx].cell_band = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_dl[%d].cell_band=%d", cell_idx, cells_info.lte_band_bandwidth_dl[cell_idx].cell_band);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_dl[cell_idx].cell_bandwidth = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_dl[%d].cell_bandwidth=%d", cell_idx, cells_info.lte_band_bandwidth_dl[cell_idx].cell_bandwidth);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_dl[cell_idx].cc_cw0_cqi = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_dl[%d].cc_cw0_cqi=%d", cell_idx, cells_info.lte_band_bandwidth_dl[cell_idx].cc_cw0_cqi);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_dl[cell_idx].cc_cw1_cqi = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_dl[%d].cc_cw1_cqi=%d", cell_idx, cells_info.lte_band_bandwidth_dl[cell_idx].cc_cw1_cqi);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_dl[cell_idx].cc_pci = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_dl[%d].cc_pci=%d", cell_idx, cells_info.lte_band_bandwidth_dl[cell_idx].cc_pci);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_dl[cell_idx].cc_arfcn = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_dl[%d].cc_arfcn=%d", cell_idx, cells_info.lte_band_bandwidth_dl[cell_idx].cc_arfcn);
+                        at_idx++;
+
+                        sprintf(tmp,
+                                "lte_dl[%d]:\n"
+                                " - cid: %d\n"
+                                " - c_state: %d\n"
+                                " - cell_band: %d\n"
+                                " - cell_bandwidth: %d\n"
+                                " - cc_cw0_cqi: %d\n"
+                                " - cc_cw1_cqi: %d\n"
+                                " - cc_pci: %d\n"
+                                " - cc_arfcn: %d\n",
+                                cell_idx,
+                                cells_info.lte_band_bandwidth_dl[cell_idx].cid,
+                                cells_info.lte_band_bandwidth_dl[cell_idx].c_state,
+                                cells_info.lte_band_bandwidth_dl[cell_idx].cell_band,
+                                cells_info.lte_band_bandwidth_dl[cell_idx].cell_bandwidth,
+                                cells_info.lte_band_bandwidth_dl[cell_idx].cc_cw0_cqi,
+                                cells_info.lte_band_bandwidth_dl[cell_idx].cc_cw1_cqi,
+                                cells_info.lte_band_bandwidth_dl[cell_idx].cc_pci,
+                                cells_info.lte_band_bandwidth_dl[cell_idx].cc_arfcn);
+                        str.append(tmp);
+                        RLOGD("result1 str=%s", str.c_str());
+                        memset(tmp, 0, sizeof(char)*1024);
+                    }
+                }
+
+                // LTE UL
+                cells_info.num_serving_lte_cell_ul = std::stoi(getDigitalVal[at_idx]);
+                RLOGW("cells_info.num_serving_lte_cell_ul=%d", cells_info.num_serving_lte_cell_ul);
+                sprintf(tmp, "num_serving_lte_cell_ul:%d\n", cells_info.num_serving_lte_cell_ul);
+                str.append(tmp);
+                memset(tmp, 0, 1024);
+                at_idx++;
+
+                if (cells_info.num_serving_lte_cell_ul != 0) {
+                    for (cell_idx = 0; cell_idx < cells_info.num_serving_lte_cell_ul; cell_idx++) {
+
+                        if (cell_idx >= MAX_RAN_CELL_SIZE) {
+                            RLOGW("cell_idx=%d >= MAX_RAN_CELL_SIZE=%d, ignore", cell_idx, MAX_RAN_CELL_SIZE);
+                            continue;
+                        }
+
+                        cells_info.lte_band_bandwidth_ul[cell_idx].cid = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_ul[%d].cid=%d", cell_idx, cells_info.lte_band_bandwidth_ul[cell_idx].cid);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_ul[cell_idx].c_state = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_ul[%d].c_state=%d", cell_idx, cells_info.lte_band_bandwidth_ul[cell_idx].c_state);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_ul[cell_idx].cell_band = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_ul[%d].cell_band=%d", cell_idx, cells_info.lte_band_bandwidth_ul[cell_idx].cell_band);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_ul[cell_idx].cell_bandwidth = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_ul[%d].cell_bandwidth=%d", cell_idx, cells_info.lte_band_bandwidth_ul[cell_idx].cell_bandwidth);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_ul[cell_idx].cc_pci = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_ul[%d].cc_pci=%d", cell_idx, cells_info.lte_band_bandwidth_ul[cell_idx].cc_pci);
+                        at_idx++;
+
+                        cells_info.lte_band_bandwidth_ul[cell_idx].cc_arfcn = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.lte_ul[%d].cc_arfcn=%d", cell_idx, cells_info.lte_band_bandwidth_ul[cell_idx].cc_arfcn);
+                        at_idx++;
+
+                        sprintf(tmp,
+                                "lte_ul[%d]:\n"
+                                " - cid: %d\n"
+                                " - c_state: %d\n"
+                                " - cell_band: %d\n"
+                                " - cell_bandwidth: %d\n"
+                                " - cc_pci: %d\n"
+                                " - cc_arfcn: %d\n",
+                                cell_idx,
+                                cells_info.lte_band_bandwidth_ul[cell_idx].cid,
+                                cells_info.lte_band_bandwidth_ul[cell_idx].c_state,
+                                cells_info.lte_band_bandwidth_ul[cell_idx].cell_band,
+                                cells_info.lte_band_bandwidth_ul[cell_idx].cell_bandwidth,
+                                cells_info.lte_band_bandwidth_ul[cell_idx].cc_pci,
+                                cells_info.lte_band_bandwidth_ul[cell_idx].cc_arfcn);
+                        str.append(tmp);
+                        RLOGD("result2 str=%s", str.c_str());
+                        memset(tmp, 0, sizeof(char)*1024);
+                    }
+                }
+
+                // NR DL
+                cells_info.num_serving_nr_cell_dl = std::stoi(getDigitalVal[at_idx]);
+                RLOGW("cells_info.num_serving_nr_cell_dl=%d", cells_info.num_serving_nr_cell_dl);
+                sprintf(tmp, "num_serving_nr_cell_dl:%d\n", cells_info.num_serving_nr_cell_dl);
+                str.append(tmp);
+                memset(tmp, 0, 1024);
+                at_idx++;
+
+                if (cells_info.num_serving_nr_cell_dl != 0) {
+                    for (cell_idx = 0; cell_idx < cells_info.num_serving_nr_cell_dl; cell_idx++) {
+
+                        if (cell_idx >= MAX_RAN_CELL_SIZE) {
+                            RLOGW("cell_idx=%d > MAX_RAN_CELL_SIZE=%d, ignore", cell_idx, MAX_RAN_CELL_SIZE);
+                            continue;
+                        }
+
+                        cells_info.nr_band_bandwidth_dl[cell_idx].cid = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_dl[%d].cid=%d", cell_idx, cells_info.nr_band_bandwidth_dl[cell_idx].cid);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_dl[cell_idx].c_state = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_dl[%d].c_state=%d", cell_idx, cells_info.nr_band_bandwidth_dl[cell_idx].c_state);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_dl[cell_idx].cell_band = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_dl[%d].cell_band=%d", cell_idx, cells_info.nr_band_bandwidth_dl[cell_idx].cell_band);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_dl[cell_idx].cell_bandwidth = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_dl[%d].cell_bandwidth=%d", cell_idx, cells_info.nr_band_bandwidth_dl[cell_idx].cell_bandwidth);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_dl[cell_idx].cc_cw0_cqi = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_dl[%d].cc_cw0_cqi=%d", cell_idx, cells_info.nr_band_bandwidth_dl[cell_idx].cc_cw0_cqi);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_dl[cell_idx].cc_cw1_cqi = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_dl[%d].cc_cw1_cqi=%d", cell_idx, cells_info.nr_band_bandwidth_dl[cell_idx].cc_cw1_cqi);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_dl[cell_idx].cc_pci = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_dl[%d].cc_pci=%d", cell_idx, cells_info.nr_band_bandwidth_dl[cell_idx].cc_pci);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_dl[cell_idx].cc_arfcn = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_dl[%d].cc_arfcn=%d", cell_idx, cells_info.nr_band_bandwidth_dl[cell_idx].cc_arfcn);
+                        at_idx++;
+
+                        sprintf(tmp,
+                                "nr_dl[%d]:\n"
+                                " - cid: %d\n"
+                                " - c_state: %d\n"
+                                " - cell_band: %d\n"
+                                " - cell_bandwidth: %d\n"
+                                " - cc_cw0_cqi: %d\n"
+                                " - cc_cw1_cqi: %d\n"
+                                " - cc_pci: %d\n"
+                                " - cc_arfcn: %d\n",
+                                cell_idx,
+                                cells_info.nr_band_bandwidth_dl[cell_idx].cid,
+                                cells_info.nr_band_bandwidth_dl[cell_idx].c_state,
+                                cells_info.nr_band_bandwidth_dl[cell_idx].cell_band,
+                                cells_info.nr_band_bandwidth_dl[cell_idx].cell_bandwidth,
+                                cells_info.nr_band_bandwidth_dl[cell_idx].cc_cw0_cqi,
+                                cells_info.nr_band_bandwidth_dl[cell_idx].cc_cw1_cqi,
+                                cells_info.nr_band_bandwidth_dl[cell_idx].cc_pci,
+                                cells_info.nr_band_bandwidth_dl[cell_idx].cc_arfcn);
+                        str.append(tmp);
+                        RLOGD("result3 str=%s", str.c_str());
+                        memset(tmp, 0, 1024);
+                    }
+                }
+
+                // NR UL
+                cells_info.num_serving_nr_cell_ul = std::stoi(getDigitalVal[at_idx]);
+                RLOGW("cells_info.num_serving_nr_cell_ul=%d", cells_info.num_serving_nr_cell_ul);
+                sprintf(tmp, "num_serving_nr_cell_ul:%d\n", cells_info.num_serving_nr_cell_ul);
+                str.append(tmp);
+                memset(tmp, 0, 1024);
+
+                at_idx++;
+
+                if (cells_info.num_serving_nr_cell_ul != 0) {
+                    for (cell_idx = 0; cell_idx < cells_info.num_serving_nr_cell_ul; cell_idx++) {
+
+                        if (cell_idx >= MAX_RAN_CELL_SIZE) {
+                            RLOGW("cell_idx=%d > MAX_RAN_CELL_SIZE=%d, ignore", cell_idx, MAX_RAN_CELL_SIZE);
+                            continue;
+                        }
+
+                        cells_info.nr_band_bandwidth_ul[cell_idx].cid = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_ul[%d].cid=%d", cell_idx, cells_info.nr_band_bandwidth_ul[cell_idx].cid);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_ul[cell_idx].c_state = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_ul[%d].c_state=%d", cell_idx, cells_info.nr_band_bandwidth_ul[cell_idx].c_state);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_ul[cell_idx].cell_band = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_ul[%d].cell_band=%d", cell_idx, cells_info.nr_band_bandwidth_ul[cell_idx].cell_band);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_ul[cell_idx].cell_bandwidth = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_ul[%d].cell_bandwidth=%d", cell_idx, cells_info.nr_band_bandwidth_ul[cell_idx].cell_bandwidth);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_ul[cell_idx].cc_pci = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_ul[%d].cc_pci=%d", cell_idx, cells_info.nr_band_bandwidth_ul[cell_idx].cc_pci);
+                        at_idx++;
+
+                        cells_info.nr_band_bandwidth_ul[cell_idx].cc_arfcn = std::stoi(getDigitalVal[at_idx]);
+                        RLOGD("cells_info.nr_ul[%d].cc_arfcn=%d", cell_idx, cells_info.nr_band_bandwidth_ul[cell_idx].cc_arfcn);
+                        at_idx++;
+
+                        sprintf(tmp,
+                                "nr_ul[%d]:\n"
+                                " - cid: %d\n"
+                                " - c_state: %d\n"
+                                " - cell_band: %d\n"
+                                " - cell_bandwidth: %d\n"
+                                " - cc_pci: %d\n"
+                                " - cc_arfcn: %d\n",
+                                cell_idx,
+                                cells_info.nr_band_bandwidth_ul[cell_idx].cid,
+                                cells_info.nr_band_bandwidth_ul[cell_idx].c_state,
+                                cells_info.nr_band_bandwidth_ul[cell_idx].cell_band,
+                                cells_info.nr_band_bandwidth_ul[cell_idx].cell_bandwidth,
+                                cells_info.nr_band_bandwidth_ul[cell_idx].cc_pci,
+                                cells_info.nr_band_bandwidth_ul[cell_idx].cc_arfcn);
+                        str.append(tmp);
+                        RLOGD("result4 str=%s", str.c_str());
+                        memset(tmp, 0, 1024);
+                    }
+                }
+
+                str.append("\ndone\n");
+                RLOGD("final result str=%s", str.c_str());
+                android::emResultNotify(str.c_str());
+
+            } catch (const out_of_range &e) {
+                android::emResultNotify(RET_STRING_LTE_FAIL);
+                RLOGD("out of range: %s", e.what());
+                return;
+            } catch (const invalid_argument &e) {
+                android::emResultNotify(RET_STRING_LTE_FAIL);
+                RLOGD("invalid argument: %s", e.what());
+                return;
+            }
+        }
+    }
+}
+
 static void el1_at_cmd_handle(char*response, int responselen) {
     switch (mCurrentFlag) {
         case MSG_NW_INFO:
@@ -106,6 +449,15 @@
         case MSG_NW_INFO_OPEN:
         case MSG_NW_INFO_CLOSE:
             break;
+        case MSG_NW_CA_INFO_LTE_NR:
+            if ((responselen > 0) && (response != NULL)) {
+                RLOGD("Get response %s", response);
+                parseCAInfo(response);
+            } else {
+                RLOGE("Query CA info fail failed.");
+                android::emResultNotify(RET_STRING_LTE_FAIL);
+            }
+            break;
         default:
             break;
     }
@@ -174,24 +526,52 @@
     }
 }
 
+//create thread to send command
+void * emEl1Thread(void* arg)
+{
+    // EL1
+    if (lte_info[intput_idx].name == "EL1") {
+        RLOGD("emEl1Thread, MSG_NW_INFO");
+
+        //sendATCommand("AT+EINFO?",MSG_NW_INFO);
+        mFlag = 8;
+        char atcommand[32] = {0};
+        sprintf(atcommand,"AT+EINFO=%d,%d,0",mFlag,EM_EL1_INFO);
+        sendATCommand(atcommand, MSG_NW_INFO_OPEN);
+
+    // Send AT+ECAINFO
+    } else if (lte_info[intput_idx].name == "NR L1 Info") {
+        RLOGD("emEl1Thread, query the latest CA information of LTE/NR");
+
+        char atcommand[32] = {0};
+        sprintf(atcommand,"AT+EDMFAPP=6,3");
+        sendATCommand(atcommand, MSG_NW_CA_INFO_LTE_NR);
+    }
+
+    pthread_exit(0);
+}
+
 int em_el1_start(int argc, int multicnt,int *item)
 {
-    RLOGD("em_el1_start called");
+    RLOGD("em_el1_start called, item[0]=%d", item[0]);
+
+    intput_idx = item[0];
     if(argc < 1)
     {
         RLOGD("em_el1_start: please select page to show info");
         android::emResultNotify(RET_STRING_LTE_FAIL);
         return -1;
     }
-    mItemCount = multicnt + 1;
-    RLOGD("mItemCount: %d, item[%d]: %d", mItemCount, multicnt, item[multicnt]);
-    android::registerForNetworkInfo(el1_urc_handle);
+
+    if (lte_info[intput_idx].name == "EL1") {
+        mItemCount = multicnt + 1;
+        RLOGD("mItemCount: %d, item[%d]: %d", mItemCount, multicnt, item[multicnt]);
+        android::registerForNetworkInfo(el1_urc_handle);
+    }
+
     android::registerForATcmdResponse(el1_at_cmd_handle);
-    //sendATCommand("AT+EINFO?",MSG_NW_INFO);
-    mFlag = 8;
-    char atcommand[32] = {0};
-    sprintf(atcommand,"AT+EINFO=%d,%d,0",mFlag,EM_EL1_INFO);
-    sendATCommand(atcommand, MSG_NW_INFO_OPEN);
+    pthread_t emEl1_thread;
+    pthread_create(&emEl1_thread,NULL, emEl1Thread, NULL);
     return (0);
 }
 #endif
diff --git a/src/telephony/tel-demo/src/em/em_antennatest.cpp b/src/telephony/tel-demo/src/em/em_antennatest.cpp
old mode 100644
new mode 100755
index 28d76fa..d804a96
--- a/src/telephony/tel-demo/src/em/em_antennatest.cpp
+++ b/src/telephony/tel-demo/src/em/em_antennatest.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -59,18 +60,63 @@
 static const int MSG_QUERY_ANTENNA_EGMC_4G = 5;
 static const int MSG_SET_ANTENNA_EGMC_4G = 6;
 static const int MSG_INIT_ANTENNA_EGMC_4G = 7;
+static const int MSG_QUERY_ANTENNA_EGMC_NR = 8;
+static const int MSG_SET_ANTENNA_EGMC_NR = 9;
+
 static const int MODE_INDEX_BASE_3G = 10;
 static const int MODE_INDEX_BASE_2G = 20;
 static const int MODE_EPCM_VALID = 0xFF;
 static const int CELL_2RX_LENGTH = 2;
 static const int CELL_4RX_LENGTH = 4;
 
+static int RAT_4G  = 0;
+#ifdef C2K_SUPPORT
+static int RAT_3G  = 1;
+static int RAT_C2K = 2;
+static int RAT_NR  = 3;
+#else
+static int RAT_3G  = -1;
+static int RAT_C2K = -1;
+static int RAT_NR  = 1;
+#endif
+
+static const std::string CMD_INIT_EGMC_4G = "AT+EGMC=1,\"rx_path\",1,0,3,15,3,15";
+static const std::string CMD_SET_EGMC_4G = "AT+EGMC=1,\"rx_path\"";
+static const std::string CMD_SET_EGMC_NR = "AT+EGMC=1,\"nr_rx_path\"";
+static const std::string CMD_SAME_EGMC = "+EGMC:";
+
 int mCurrentEmantennaFlag = 0;
 bool fgAntennaRead = true;
-static int fgget = -1;
-static int fgset = -1;
 int mAntennaMode = 0;
 char antennaretstring[128] = {0};
+int inputRat = -1;
+std::vector<int> gEgmcParam;
+
+static const std::vector<std::string> antenna_modes_egmc_4rx {
+    "None",             // 0
+    "RX1",              // 1
+    "RX2",              // 2
+    "RX1&RX2",          // 3
+    "RX3",              // 4
+    "RX1&RX3",          // 5
+    "RX2&RX3",          // 6
+    "RX1&RX2&RX3",      // 7
+    "RX4",              // 8
+    "RX1&RX4",          // 9
+    "RX2&RX4",          // 10
+    "RX1&RX2&RX4",      // 11
+    "RX3&RX4",          // 12
+    "RX1&RX3&RX4",      // 13
+    "RX2&RX3&RX4",      // 14
+    "RX1&RX2&RX3&RX4",  // 15
+};
+
+static const std::vector<std::string> antenna_modes_egmc_2rx {
+    "None",
+    "RX1",
+    "RX2",
+    "RX1&RX2",
+};
 
 static const std::vector<std::string> antenna_modes_4g {
     "RX1&RX2",
@@ -99,6 +145,19 @@
     emSendATCommand(cmd, Radio_capability_switch_util::get_main_capability_phone_id());
     return ;
 }
+
+static void queryEgmcAntNR() {
+    char cmd_str[32] = {0};
+    sprintf(cmd_str,"%s","AT+EGMC=0,\"nr_rx_path\"");
+    sendATCommand(cmd_str, MSG_QUERY_ANTENNA_EGMC_NR);
+}
+
+static void queryEgmcAnt4G() {
+    char cmd_str[32] = {0};
+    sprintf(cmd_str,"%s","AT+EGMC=0,\"rx_path\"");
+    sendATCommand(cmd_str, MSG_QUERY_ANTENNA_EGMC_4G);
+}
+
 static void queryCurrentMode() {
     char cmd_str[32] = {0};
     sprintf(cmd_str,"%s","AT+ERXPATH?");
@@ -114,6 +173,26 @@
     }
 }
 
+static void initEgmcAnt4G() {
+    sendATCommand(CMD_INIT_EGMC_4G.c_str(), MSG_INIT_ANTENNA_EGMC_4G);
+}
+
+static void setEgmcAnt4G(int force_mode, int scc_follow_pcc, int pcell_2rx, int pcell_4rx, int scell_2rx, int scell_4rx) {
+    char cmd_str[64] = {0};
+    sprintf(cmd_str,"%s,%d,%d,%d,%d,%d,%d",
+        CMD_SET_EGMC_4G.c_str(), force_mode, scc_follow_pcc, pcell_2rx, pcell_4rx, scell_2rx, scell_4rx);
+    RLOGD("setEgmcAnt4G, cmd:%s", cmd_str);
+    sendATCommand(cmd_str, MSG_SET_ANTENNA_EGMC_4G);
+}
+
+static void setEgmcAntNR(int force_mode, int scc_follow_pcc, int pcell_2rx, int pcell_4rx, int scell_2rx, int scell_4rx) {
+    char cmd_str[64] = {0};
+    sprintf(cmd_str,"%s,%d,%d,%d,%d,%d,%d",
+        CMD_SET_EGMC_NR.c_str(), force_mode, scc_follow_pcc, pcell_2rx, pcell_4rx, scell_2rx, scell_4rx);
+    RLOGD("setEgmcAntNR, cmd:%s", cmd_str);
+    sendATCommand(cmd_str, MSG_SET_ANTENNA_EGMC_NR);
+}
+
 static void setMode(int mode) {
     char cmd_str[32] = {0};
     sprintf(cmd_str,"%s%d","AT+ERXPATH=",mode);
@@ -131,13 +210,100 @@
     }
 }
 
-static void parseCurrentMode(char* data) {
-    RLOGD("parseCurrentMode(%d):%s",fgget, data);
+static void parseEgmcData(char* data) {
+    RLOGD("parseEGMCData(rat=%d), data=%s", inputRat, data);
     std::vector<std::string> out;
     utils::tokenize(string(data), "\n", out);
     std::string str;
     str.clear();
-    if(fgget == 0 || fgget == 1) {
+
+    // 4G response: +EGMC: "rx_path",1,0,3,15,3,12
+    // NR response: +EGMC: "nr_rx_path",3,15,3,12
+    for(auto i: out) {
+        if(i.find(CMD_SAME_EGMC) != std::string::npos) {
+            std::string splitString = i.substr(std::string(CMD_SAME_EGMC).size());
+            std::vector<std::string> getDigitalVal;
+            utils::tokenize(string(splitString), ",\n", getDigitalVal);
+            RLOGD("parseCurrentMode splitString: %s, getDigitalVal.size()=%d",
+                    splitString.c_str(), getDigitalVal.size());
+
+            if (getDigitalVal.size() < 5 &&
+                !((inputRat == RAT_NR) && getDigitalVal.size() == 1)) {
+                android::emResultNotify(RET_STRING_ANTENNATEST_FAIL);
+                RLOGD("Modem returned invalid getDigitalVal(%d): %s", getDigitalVal.size(), data);
+                return ;
+            }
+
+            try {
+                int idx_pcell_2rx = 3;
+                // Show result
+                if (inputRat == RAT_4G) {
+                    str.append("4G:");
+
+                } else if (inputRat == RAT_NR){
+                    str.append("NR:");
+                    idx_pcell_2rx = 1;
+                }
+
+                int pcell_2rx = 0, pcell_4rx = 0, scell_2rx = 0, scell_4rx = 0;
+                if ((inputRat == RAT_NR) && (getDigitalVal.size() == 1)) {
+                    pcell_2rx = 0;
+                    pcell_4rx = 0;
+                    scell_2rx = 0;
+                    scell_4rx = 0;
+
+                } else {
+                    pcell_2rx = std::stoi(getDigitalVal[idx_pcell_2rx]);
+                    pcell_4rx = std::stoi(getDigitalVal[++idx_pcell_2rx]);
+                    scell_2rx = std::stoi(getDigitalVal[++idx_pcell_2rx]);
+                    scell_4rx = std::stoi(getDigitalVal[++idx_pcell_2rx]);
+                }
+
+                RLOGD("pcell_2rx=%d, pcell_4rx=%d, scell_2rx=%d, scell_4rx=%d",
+                        pcell_2rx, pcell_4rx, scell_2rx, scell_4rx);
+
+                if (pcell_2rx >= 0 && pcell_2rx < antenna_modes_egmc_2rx.size()) {
+                    str.append("\npcell_2rx: ");
+                    str.append(antenna_modes_egmc_2rx[pcell_2rx]);
+                }
+                if (pcell_4rx >= 0 && pcell_4rx < antenna_modes_egmc_4rx.size()) {
+                    str.append("\npcell_4rx: ");
+                    str.append(antenna_modes_egmc_4rx[pcell_4rx]);
+                }
+                if (scell_2rx >= 0 && scell_2rx < antenna_modes_egmc_2rx.size()) {
+                    str.append("\nscell_2rx: ");
+                    str.append(antenna_modes_egmc_2rx[scell_2rx]);
+                }
+                if (scell_4rx >= 0 && scell_4rx < antenna_modes_egmc_4rx.size()) {
+                    str.append("\nscell_4rx: ");
+                    str.append(antenna_modes_egmc_4rx[scell_4rx]);
+                }
+
+            } catch (const out_of_range &e) {
+                android::emResultNotify(RET_STRING_ANTENNATEST_FAIL);
+                RLOGD("out of range: %s", e.what());
+                return;
+            } catch (const invalid_argument &e) {
+                android::emResultNotify(RET_STRING_ANTENNATEST_FAIL);
+                RLOGD("invalid argument: %s", e.what());
+                return;
+            }
+        }
+    }
+
+    str.append("\ndone\n");
+    RLOGD("result str=%s", str.c_str());
+    android::emResultNotify(str.c_str());
+}
+
+static void parseCurrentMode(char* data) {
+    RLOGD("parseCurrentMode(rat=%d), rsp=%s", inputRat, data);
+    std::vector<std::string> out;
+    utils::tokenize(string(data), "\n", out);
+    std::string str;
+    str.clear();
+
+    if((inputRat == RAT_4G && !utils::is97Modem())|| inputRat == RAT_3G) {
         for(auto i: out) {
             if(i.find("+ERXPATH:") != std::string::npos) {
                 try {
@@ -179,7 +345,8 @@
             }
         }
         android::emResultNotify(str.c_str());
-    } else if (fgget == 2) {
+
+    } else if (inputRat == RAT_C2K) {
         for(auto i: out) {
             if(i.find("+ERXTESTMODE:") != std::string::npos) {
                 try {
@@ -207,6 +374,13 @@
             }
         }
         android::emResultNotify(str.c_str());
+
+    } else if (inputRat == RAT_4G && utils::is97Modem()) {
+        parseEgmcData(data);
+
+    } else if(inputRat == RAT_NR) {
+        parseEgmcData(data);
+
     } else {
         RLOGE("error choose!!!");
         android::emResultNotify(RET_STRING_ANTENNATEST_FAIL);
@@ -219,19 +393,35 @@
     switch (mCurrentEmantennaFlag) {
     case MSG_QUERY_ANTENNA_MODE:
     case MSG_QUERY_ANTENNA_MODE_C2K:
+    case MSG_QUERY_ANTENNA_EGMC_4G:
+    case MSG_QUERY_ANTENNA_EGMC_NR:
         //parse antenna mode.
         if ((responselen > 0) && (response != NULL)) {
-            RLOGD("Get mode %s", response);
+            RLOGD("Get response %s", response);
             parseCurrentMode(response);
         } else {
-            RLOGD("Query antenna mode failed.");
-            sprintf(antennaretstring, "%s%s", ("Query antenna mode failed."),
-            RET_STRING_ANTENNATEST_FAIL);
+            RLOGD("Query antenna mode (rat=%d) failed.", inputRat);
+            sprintf(antennaretstring, "%s%s (rat=%d)", ("Query antenna mode failed."),
+            RET_STRING_ANTENNATEST_FAIL, inputRat);
             android::emResultNotify(antennaretstring);
         }
         android::unregisterNetwork();
         break;
+    case MSG_INIT_ANTENNA_EGMC_4G:
+        if ((responselen > 0) && (response != NULL)) {
+            setEgmcAnt4G(gEgmcParam[0], gEgmcParam[1], gEgmcParam[2], gEgmcParam[3], gEgmcParam[4], gEgmcParam[5]);
+
+        } else {
+            RLOGD("Init EGMC antenna mode (rat=%d) failed.", inputRat);
+            sprintf(antennaretstring, "%s%s (rat=%d)", ("Init antenna mode failed."),
+            RET_STRING_ANTENNATEST_FAIL, inputRat);
+            android::emResultNotify(antennaretstring);
+        }
+
+        break;
     case MSG_SET_ANTENNA_MODE:
+    case MSG_SET_ANTENNA_EGMC_4G:
+    case MSG_SET_ANTENNA_EGMC_NR:
         memset(antennaretstring, 0, sizeof(antennaretstring));
         if ((responselen > 0) && (response != NULL)) {
             RLOGD("Set successful.");
@@ -242,7 +432,6 @@
             sprintf(antennaretstring, "%s\n%s", ("Set failed."),
                     RET_STRING_ANTENNATEST_FAIL);
         }
-        android::unregisterNetwork();
         android::emResultNotify(antennaretstring);
         break;
     default:
@@ -256,47 +445,75 @@
 static void * emAntennaTestThread(void* arg)
 {
     if(fgAntennaRead){
-        if(fgget == 0) { //4G
+        if(inputRat == RAT_4G) {
             if (ModemCategory::isLteSupport()) {
-                queryCurrentMode();
+                if(utils::is97Modem()) {
+                    queryEgmcAnt4G();
+
+                } else {
+                    queryCurrentMode();
+                }
+
             } else {
                 android::emResultNotify("Antenna test don't support for 4G \ndone\n");
             }
-        } else if (fgget == 1){ //3G
+
+        } else if (inputRat == RAT_3G){
             if (ModemCategory::getModemType() == ModemCategory::MODEM_TD) {
                 android::emResultNotify("Antenna test don't support for 3G \ndone\n");
             } else {
                 queryCurrentMode();
             }
-        } else if (fgget == 2) { //C2K
+
+        } else if (inputRat == RAT_C2K) {
             if(ModemCategory::isCdma()) {
                 queryCurrentCdmaMode();
             } else {
                 android::emResultNotify("Antenna test don't support for C2K \ndone\n");
             }
+
+        } else if(inputRat == RAT_NR) {
+            if (ModemCategory::isNrSupport()) {
+                queryEgmcAntNR();
+            } else {
+                android::emResultNotify("Antenna test don't support for NR \ndone\n");
+            }
+
         } else {
             android::emResultNotify("Antenna test index error \ndone\n");
         }
 
     }else{
-        if(fgset == 0) { //4G
+        if(inputRat == RAT_4G) {
             if (ModemCategory::isLteSupport()) {
-                setMode(mAntennaMode);
+                if(utils::is97Modem()) {
+                    initEgmcAnt4G();
+                } else {
+                    setMode(mAntennaMode);
+                }
             } else {
                 android::emResultNotify("Antenna test don't support for 4G \ndone\n");
             }
-        } else if (fgset == 1){ //3G
+        } else if (inputRat == RAT_3G){
             if (ModemCategory::getModemType() == ModemCategory::MODEM_TD) {
                 android::emResultNotify("Antenna test don't support for 3G \ndone\n");
             } else {
                 setMode(mAntennaMode);
             }
-        } else if (fgset == 2) { //C2K
+        } else if (inputRat == RAT_C2K) {
             if(ModemCategory::isCdma()) {
                 setCdmaMode(mAntennaMode);
             } else {
                 android::emResultNotify("Antenna test don't support for C2K \ndone\n");
             }
+        } else if(inputRat == RAT_NR) {
+            if (ModemCategory::isNrSupport() && gEgmcParam.size() == 6) {
+                setEgmcAntNR(gEgmcParam[0], gEgmcParam[1], gEgmcParam[2], gEgmcParam[3], gEgmcParam[4], gEgmcParam[5]);
+            } else {
+                RLOGE("Antenna test don't support for NR or gEgmcParam size=%d", gEgmcParam.size());
+                android::emResultNotify("Antenna test don't support for NR \ndone\n");
+            }
+
         } else {
             android::emResultNotify("Antenna test index error \ndone\n");
         }
@@ -304,41 +521,83 @@
     pthread_exit(0);
 }
 
-int emAntennaTestStart(int argc, int *item,char *value)
+bool handleInputValue(int multilen, char *value[])
+{
+    if (multilen != 6) {
+        RLOGE("error input parameter");
+        android::emResultNotify("Antenna test parameter error, must count=6 \ndone\n");
+        printf("Please reference AT+EGMC = 1,\"rx_path\"[,<force mode>,<scc follow pcc>,<pcell_2rx>,<pcell_4rx>,<scell_2rx>,<scell_4rx>]\n");
+        printf("Example: 2 1 0 3 15 3 12\n");
+        return false;
+    }
+
+    for(int i=0; i< multilen; i++) {
+        printf("value[%d]=%d\n", i, atoi(value[i]));
+        gEgmcParam.push_back(atoi(value[i]));
+    }
+    return true;
+}
+
+int emAntennaTestStart(int argc, int *item, int multilen,char *value[])
 {
     RLOGD("emAntennaTestStart called");
     if(argc < 2){
         RLOGD("please select AntennaTest get or set :");
         return -1;
     }
+
     mCurrentEmantennaFlag = 0;
-    int classid = item[0];
+    gEgmcParam.clear();
+    inputRat = item[0];
     int operatorid = item[1];
-    if((item[0] != 0 ) && (item[0] != 1) && (item[0] != 2)){ // 0 4G 1 3G
-        RLOGD("emAntennaTestStart: invalid parameter %d, operatorid: %d",item[0], operatorid);
+    bool ret = false;
+
+    RLOGD("argc: %d, inputRat: %d, operatorid: %d\n", argc, inputRat, operatorid);
+
+    if((inputRat != RAT_NR) && (inputRat != RAT_4G) && (inputRat != RAT_3G)
+#ifdef C2K_SUPPORT
+        && (inputRat != RAT_C2K)
+#endif
+        ){
+        RLOGD("emAntennaTestStart: invalid inputRat %d, operatorid: %d", inputRat, operatorid);
         android::emResultNotify(RET_STRING_ANTENNATEST_FAIL);
         return -1;
     }
+
     switch(operatorid){
         case 0://get
         {
             fgAntennaRead = true;
-            fgget = classid;
             break;
         }
         case 1://set
         {
-            printf("argc: %d, fgset: %d\n", argc, classid);
-            printf("itme[2]: %d\n", item[2]);
-            fgset = classid;
-            if(classid == 0){ // 4G
-               mAntennaMode = item[2];
-            } else if(classid == 1) { //3G
+            printf("argc: %d, inputRat: %d, multilen: %d\n", argc, inputRat, multilen);
+
+            if(inputRat == RAT_4G){
+                if(utils::is97Modem()) {
+                    if(!handleInputValue(multilen, value)) {
+                        return (0);
+                    }
+
+                } else {
+                    printf("itme[2]: %d\n", item[2]);
+                    mAntennaMode = item[2];
+                }
+
+            } else if(inputRat == RAT_3G) {
                 mAntennaMode = item[2]+ MODE_INDEX_BASE_3G;
-            } else if (classid == 2) { //C2K
+
+            } else if (inputRat == RAT_C2K) {
                 mAntennaMode = item[2];
-            } else { // other
-                RLOGW("error classid");
+
+            } else if(inputRat == RAT_NR){
+                if(!handleInputValue(multilen, value)) {
+                    return (0);
+                }
+
+            } else {
+                RLOGE("error input rat");
                 android::emResultNotify(RET_STRING_ANTENNATEST_FAIL);
             }
             fgAntennaRead = false;
diff --git a/src/telephony/tel-demo/src/em/em_bandmode.cpp b/src/telephony/tel-demo/src/em/em_bandmode.cpp
old mode 100644
new mode 100755
index 8b33c18..9fecc19
--- a/src/telephony/tel-demo/src/em/em_bandmode.cpp
+++ b/src/telephony/tel-demo/src/em/em_bandmode.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -36,6 +37,7 @@
 #include <vendor-ril/telephony/ril.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <algorithm>
 #include <cutils/jstring.h>
 #include <log/log.h>
 #include <unistd.h>
@@ -70,9 +72,12 @@
 static const int INDEX_LTE_BAND_256 = 9;
 static const int INDEX_CDMA_BAND = 10;
 static const int INDEX_BAND_MAX = 11;
+static const int INDEX_NR_BAND = 12;
 static const int BAND_SET_INVALID = 1000;
 static int mSimType = -1;
 
+static const int NR_VALUES = 3;
+
 /** GSM mode bit. */
 static const int GSM_EGSM900_BIT = 1;
 static const int GSM_DCS1800_BIT = 3;
@@ -81,9 +86,15 @@
 static const std::vector<int> GSM_BAND_BIT{GSM_EGSM900_BIT,GSM_DCS1800_BIT,GSM_PCS1900_BIT,GSM_GSM850_BIT};
 
 /** Event or message id. */
-static const int EVENT_QUERY_SUPPORTED = 100;
-static const int EVENT_QUERY_CURRENT = 101;
+static const int EVENT_QUERY_SUPPORTED_GSM = 100;
+static const int EVENT_QUERY_CURRENT_GSM = 101;
+static const int EVENT_QUERY_CURRENT_CDMA = 102;
+static const int EVENT_QUERY_SUPPORTED_NR = 103;
+static const int EVENT_QUERY_CURRENT_NR = 104;
+
 static const int EVENT_SET_GSM = 110;
+static const int EVENT_SET_CDMA = 111;
+static const int EVENT_SET_NR = 112;
 
 static const int EVENT_SET_FAIL = 1;
 static const int EVENT_RESET = 2;
@@ -98,14 +109,15 @@
 static const std::string SET_COMMAND = "AT+EPBSE=";
 static const std::string SAME_COMMAND = "+EPBSE:";
 
-
-static const int EVENT_QUERY_CURRENT_CDMA = 103;
-static const int EVENT_SET_CDMA = 111;
-
 static const std::string QUERY_CURRENT_COMMAND_CDMA = "AT+ECBANDCFG?";
 static const std::string SET_COMMAND_CDMA = "AT+ECBANDCFG=";
 static const std::string SAME_COMMAND_CDMA = "+ECBANDCFG:";
 
+static const std::string QUERY_SUPPORT_COMMAND_NR = "AT+EPBSEH=?";
+static const std::string QUERY_CURRENT_COMMAND_NR = "AT+EPBSEH?";
+static const std::string SET_COMMAND_NR = "AT+EPBSEH=";
+static const std::string SAME_COMMAND_NR = "+EPBSEH:";
+
 static pthread_mutex_t s_band_Mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t s_band_Cond = PTHREAD_COND_INITIALIZER;
 #define BLOCK_LOCK() pthread_mutex_lock(&s_band_Mutex)
@@ -116,6 +128,8 @@
 bool mIsLteExtend = false;
 int mCurrentEmbandmodeFlag = 0;
 std::vector<long> gsmValues(INDEX_BAND_MAX);
+std::vector<long> nrValues(NR_VALUES);
+
 long cdmaValues = 0;
 
 struct BandModeMap{
@@ -138,8 +152,10 @@
     BandModeMap& operator=(const BandModeMap& other) = default;
 };
 
-static std::vector<BandModeMap> mModeArray;
+static std::vector<BandModeMap> mGsmModeArray;
 static std::vector<BandModeMap> mCdmaModeArray;
+static std::vector<BandModeMap> mNRModeArray;
+
 static const std::vector<std::string> band_mode_gsm { "EGSM900", "DCS1800",
         "PCS1900", "GSM850" };
 
@@ -161,7 +177,9 @@
 
 static const std::vector<std::string> band_mode_lte_tdd { "Band 33", "Band 34",
         "Band 35", "Band 36", "Band 37", "Band 38", "Band 39", "Band 40",
-        "Band 41", "Band 42", "Band 43", "Band 44" };
+        "Band 41", "Band 42", "Band 43", "Band 44", "Band 45",
+        "Band 46", "Band 47", "Band 48", "Band 49", "Band 50",
+        "Band 51", "Band 52", "Band 53"};
 
 static const std::vector<std::string> band_mode_lte_96 { "Band 65", "Band 66",
         "Band 67", "Band 68", "Band 69", "Band 70", "Band 71", "Band 72",
@@ -220,8 +238,32 @@
         "Band 13(2.5 GHz IMT-2000 Extension Band)",
         "Band 14(US PCS 1.9GHz Band)", "Band 15(AWS Band)" };
 
-int fgset = false;
-int count = -1;
+static const std::vector<std::string> band_mode_nr {
+        "Band 1",  "Band 2",  "Band 3",  "Band 4",  "Band 5",
+        "Band 6",  "Band 7",  "Band 8",  "Band 9",  "Band 10",
+        "Band 11", "Band 12", "Band 13", "Band 14", "Band 15",
+        "Band 16", "Band 17", "Band 18", "Band 19", "Band 20",
+        "Band 21", "Band 22", "Band 23", "Band 24", "Band 25",
+        "Band 26", "Band 27", "Band 28", "Band 29", "Band 30",
+        "Band 31", "Band 32", "Band 33", "Band 34", "Band 35",
+        "Band 36", "Band 37", "Band 38", "Band 39", "Band 40",
+        "Band 41", "Band 42", "Band 43", "Band 44", "Band 45",
+        "Band 46", "Band 47", "Band 48", "Band 49", "Band 50",
+        "Band 51", "Band 52", "Band 53", "Band 54", "Band 55",
+        "Band 56", "Band 57", "Band 58", "Band 59", "Band 60",
+        "Band 61", "Band 62", "Band 63", "Band 64", "Band 65",
+        "Band 66", "Band 67", "Band 68", "Band 69", "Band 70",
+        "Band 71", "Band 72", "Band 73", "Band 74", "Band 75",
+        "Band 76", "Band 77", "Band 78", "Band 79", "Band 80",
+        "Band 81", "Band 82", "Band 83", "Band 84", "Band 85",
+        "Band 86", "Band 87", "Band 88", "Band 89", "Band 90",
+        "Band 91", "Band 92", "Band 93", "Band 94", "Band 95",
+        "Band 96"};
+
+bool fgset = false;
+bool isNR = false;
+
+int len_count = -1;
 std::vector<std::string> choose_vals;
 
 static void sendATCommand(const char *cmd,int msg)
@@ -236,8 +278,8 @@
     return ;
 }
 
-static void setCurrentMode(std::vector<long> values) {
-    for (auto& m : mModeArray) {
+static void setCurrentModeGsm(std::vector<long> values) {
+    for (auto& m : mGsmModeArray) {
         if ((values[m.mIndex] & (1L << m.mBit)) == 0) {
             m.mCheck = false;
         } else {
@@ -249,8 +291,8 @@
     }
 }
 
-static void setSupportedMode(std::vector<long> values) {
-    for (auto& m : mModeArray) {
+static void setSupportedModeGsm(std::vector<long> values) {
+    for (auto& m : mGsmModeArray) {
         if ((values[m.mIndex] & (1L << m.mBit)) == 0) {
             m.mEnable = false;
         } else {
@@ -287,6 +329,68 @@
     }
 }
 
+static void setCurrentModeNR(std::vector<long> values) {
+    int temp = 0;
+    for (auto& m : mNRModeArray) {
+        if (m.mBit < 32) {
+            if ((values[0] & (1L << m.mBit)) == 0) {
+                m.mCheck = false;
+            } else {
+                if (m.mEnable) {
+                    m.mCheck = true;
+                }
+            }
+        } else if (m.mBit < 64) {
+            temp = m.mBit - 32;
+            if ((values[1] & (1L << temp)) == 0) {
+                m.mCheck = false;
+            } else {
+                if (m.mEnable) {
+                    m.mCheck = true;
+                }
+            }
+        } else {
+            temp = m.mBit - 64;
+            if ((values[2] & (1L << temp)) == 0) {
+                m.mCheck = false;
+            } else {
+                if (m.mEnable) {
+                    m.mCheck = true;
+                }
+            }
+        }
+        //RLOGD("setCurrentModeNR labels: %s, enable: %d, check: %d", m.mName.c_str(), m.mEnable, m.mCheck);
+    }
+}
+
+static void setSupportedModeNR(std::vector<long> values) {
+    int temp = 0;
+    for (auto& m : mNRModeArray) {
+        if (m.mBit < 32) {
+            if ((values[0] & (1L << m.mBit)) == 0) {
+                m.mEnable = false;
+            } else {
+                m.mEnable = true;
+            }
+        } else if (m.mBit < 64) {
+            temp = m.mBit - 32;
+            if ((values[1] & (1L << temp)) == 0) {
+                m.mEnable = false;
+            } else {
+                m.mEnable = true;
+            }
+        } else {
+            temp = m.mBit - 64;
+            if ((values[2] & (1L << temp)) == 0) {
+                m.mEnable = false;
+            } else {
+                m.mEnable = true;
+            }
+        }
+        //RLOGD("setSupportedModeNR labels: %s, enable: %d", m.mName.c_str(), m.mEnable);
+    }
+}
+
 static void showBandModeCdma(char* response, int msg) {
     std::vector<std::string> out;
     utils::tokenize(string(response), "\n", out);
@@ -324,6 +428,7 @@
 }
 
 static void showBandModeGsm(char* response, int msg) {
+    // Support/Current: +EPBSE: 154,262331,2316241119,482,0,0,0,0,0,0
     std::vector<std::string> out;
     utils::tokenize(string(response), "\n", out);
     for(auto i: out) {
@@ -349,8 +454,8 @@
                         RLOGD("invalid argument: %s", e.what());
                     }
                 }
-                if (msg == EVENT_QUERY_SUPPORTED) {
-                    setSupportedMode(values);
+                if (msg == EVENT_QUERY_SUPPORTED_GSM) {
+                    setSupportedModeGsm(values);
                     if (getDigitalVal.size() > 5) {
                         RLOGD("The Modem support Lte extend band");
                         mIsLteExtend = true;
@@ -359,7 +464,7 @@
                         mIsLteExtend = false;
                     }
                 } else {
-                    setCurrentMode(values);
+                    setCurrentModeGsm(values);
                 }
             } else {
                 android::emResultNotify(RET_STRING_BANDMODE_FAIL);
@@ -369,15 +474,70 @@
     }
 }
 
+static void showBandModeNR(char* response, int msg) {
+   // Support: +EPBSEH: "0000009a","000400bb","8A0F08DF000001E200000000","080800D50000012000007000"
+   // Current: +EPBSEH: "0000009a","000400bb","8A0F08DF000001E200000000","080800D50000012000007000"^M OK^M
+   std::vector<std::string> out;
+   utils::tokenize(string(response), "\n", out);
+   for(auto i: out) {
+       if(i.find(SAME_COMMAND_NR) != std::string::npos) {
+           std::string splitString = i.substr(std::string(SAME_COMMAND_NR).size());
+           RLOGD("showBandModeNR splitString: %s", splitString.c_str());
+           std::vector<std::string> getDigitalVal;
+           utils::tokenize(string(splitString), ",\n", getDigitalVal);
+           if (getDigitalVal.size() > 0) {
+               getDigitalVal[3].erase(remove(getDigitalVal[3].begin(), getDigitalVal[3].end(),'\"'));
+               std::string info = utils::addZeroForNum(string(getDigitalVal[3]), 24);
+               RLOGD("showBandModeNR tmpInfo=%s, info=%s", getDigitalVal[3].c_str(), info.c_str());
+
+               std::string string1 = info.substr(0, 8);
+               std::string string2 = info.substr(8, 8);
+               std::string string3 = info.substr(16, 8);
+
+               RLOGD("showBandModeNR string1=%s, string2=%s, string3=%s,",
+                       string1.c_str(), string2.c_str(), string3.c_str());
+
+               std::vector<long> values;
+               try {
+                   values.push_back(std::stol(string1, 0 ,16));
+                   values.push_back(std::stol(string2, 0 ,16));
+                   values.push_back(std::stol(string3, 0 ,16));
+
+                   RLOGD("showBandModeNR values[0]=%ld, values[1]=%ld, values[2]=%ld,",
+                           values[0], values[1], values[2]);
+
+               } catch (const out_of_range &e) {
+                   values.push_back(0);
+                   RLOGD("out of range: %s", e.what());
+               } catch (const invalid_argument &e) {
+                   values.push_back(0);
+                   RLOGD("invalid argument: %s", e.what());
+               }
+
+               if (msg == EVENT_QUERY_SUPPORTED_NR) {
+                   setSupportedModeNR(values);
+               } else {
+                   setCurrentModeNR(values);
+               }
+
+           } else {
+               android::emResultNotify(RET_STRING_BANDMODE_FAIL);
+               RLOGD("getDigitalVal is null");
+           }
+       }
+   }
+}
+
 static void printGetBand(int flag) {
     RLOGD("printGetBand(%d), fgset(%d)", flag, fgset);
+
     if(fgset) {
         return;
     }
-    if(flag == EVENT_QUERY_CURRENT) {
-        RLOGD("printGetBand start");
+    if(flag == EVENT_QUERY_CURRENT_GSM) {
+        RLOGD("printGetBand GSM start");
         std::string msg;
-        for (auto& i : mModeArray) {
+        for (auto& i : mGsmModeArray) {
             if (i.mEnable && i.mCheck) {
                 if ((i.mIndex == INDEX_GSM_BAND) && (msg.find("GSM Mode:") == std::string::npos)) {
                     msg.append("GSM Mode:\n");
@@ -392,16 +552,37 @@
                 msg.append("\n");
             }
         }
-        for (auto& i : mCdmaModeArray) {
+
+        if (ModemCategory::isCdma()) {
+            for (auto& i : mCdmaModeArray) {
+                if (i.mEnable && i.mCheck) {
+                    if ((i.mIndex == INDEX_CDMA_BAND) && (msg.find("CDMA Mode:") == std::string::npos)) {
+                        msg.append("\nCDMA Mode: \n");
+                    }
+                    msg.append("....");
+                    msg.append(i.mName);
+                    msg.append("\n");
+                }
+            }
+        }
+
+        msg.append("done\n");
+        android::emResultNotify(msg.c_str());
+
+    } else if (flag == EVENT_QUERY_CURRENT_NR) {
+        RLOGD("printGetBand NR start");
+        std::string msg;
+        for (auto& i : mNRModeArray) {
             if (i.mEnable && i.mCheck) {
-                if ((i.mIndex == INDEX_CDMA_BAND) && (msg.find("CDMA Mode:") == std::string::npos)) {
-                    msg.append("\nCDMA Mode: \n");
+                if ((i.mIndex == INDEX_NR_BAND) && (msg.find("NR Mode:") == std::string::npos)) {
+                    msg.append("\nNR Mode:\n");
                 }
                 msg.append("....");
                 msg.append(i.mName);
                 msg.append("\n");
             }
         }
+
         msg.append("done\n");
         android::emResultNotify(msg.c_str());
     }
@@ -413,6 +594,23 @@
     sendATCommand(msg.c_str(), EVENT_SET_CDMA);
 }
 
+static void setBandModeNR(std::vector<long> values_gsm, std::vector<long> values_nr) {
+    RLOGD("setBandModeNR gsmValues: %ld,%ld,%ld,%ld,%ld",
+            values_gsm[0],values_gsm[1],values_gsm[2],values_gsm[3],values_gsm[4]);
+    RLOGD("setBandModeNR nrValues: %ld,%ld,%ld",
+            values_nr[0],values_nr[1],values_nr[2]);
+
+    char cmd_str[1280] = {0};
+    sprintf(cmd_str,"%s\"%08x\",\"%08x\",\"%08x%08x%08x\",\"%08x%08x%08x\"",
+            SET_COMMAND_NR,
+            values_gsm[0], values_gsm[1],
+            values_gsm[2], values_gsm[3], values_gsm[4],
+            values_nr[0],  values_nr[1],  values_nr[2]);
+
+    RLOGD("setBandModeNR AT String:%s", cmd_str);
+    sendATCommand(cmd_str, EVENT_SET_NR);
+}
+
 /**
  * Set the selected modes.
  *
@@ -458,10 +656,10 @@
  *
  * @return values from the selected boxes
  */
-static std::vector<long> getValFromBox(bool judge) {
+static std::vector<long> getValFromBoxGsm(bool judge) {
     std::vector<long> values(INDEX_BAND_MAX,0);
     std::vector<long> values_temp(INDEX_BAND_MAX,0);
-    for (auto& m : mModeArray) {
+    for (auto& m : mGsmModeArray) {
         if (m.mCheck) {
             values[m.mIndex] |= 1L << m.mBit;
             values_temp[m.mIndex] |= 1L << m.mBit;
@@ -493,12 +691,44 @@
     return values;
 }
 
+/**
+ * Get the selected mode values.
+ *
+ * @return values from the selected boxes
+ */
+static std::vector<long> getValFromBoxNR() {
+    std::vector<long> values(NR_VALUES,0);
+
+    int temp = 0;
+    for (auto& m : mNRModeArray) {
+        if (m.mBit < 32) {
+            if (m.mCheck) {
+                values[0] |= 1L << m.mBit;
+            }
+        } else if (m.mBit < 64) {
+            temp = m.mBit - 32;
+            if (m.mCheck) {
+                values[1] |= 1L << temp;
+            }
+        } else {
+            temp = m.mBit - 64;
+            if (m.mCheck) {
+                values[2] |= 1L << temp;
+            }
+        }
+    }
+
+    RLOGD("getValFromBoxNR values[0]=%ld, values[1]=%ld, values[2]=%ld,",
+            values[0], values[1], values[2]);
+    return values;
+}
+
 static void printSupportBand(int flag) {
-    RLOGD("printSupportBand, fgset(%d), count(%d), flag(%d)",fgset, count, flag);
-    if(fgset && (count == 0) && (flag == EVENT_QUERY_CURRENT)) {
-        RLOGD("printSupportBand start");
+    RLOGD("printSupportBand, fgset(%d), len_count(%d), flag(%d)",fgset, len_count, flag);
+    if(fgset && (len_count == 0) && (flag == EVENT_QUERY_CURRENT_GSM)) {
+        RLOGD("printSupportBand GSM start");
         std::string msg;
-        for (auto& i : mModeArray) {
+        for (auto& i : mGsmModeArray) {
             if (i.mEnable) {
                 if ((i.mIndex == INDEX_GSM_BAND) && (msg.find("GSM Mode:") == std::string::npos)) {
                     msg.append("GSM Mode:\n");
@@ -520,11 +750,39 @@
                 msg.append("\n");
             }
         }
-        for (auto& i : mCdmaModeArray) {
-            if (i.mEnable) {
-                if ((i.mIndex == INDEX_CDMA_BAND) && (msg.find("CDMA Mode:") == std::string::npos)) {
-                    msg.append("\nCDMA Mode: \n");
+
+        if (ModemCategory::isCdma()) {
+            for (auto& i : mCdmaModeArray) {
+                if (i.mEnable) {
+                    if ((i.mIndex == INDEX_CDMA_BAND) && (msg.find("CDMA Mode:") == std::string::npos)) {
+                        msg.append("\nCDMA Mode: \n");
+                    }
+                    msg.append("....");
+                    msg.append("(");
+                    msg.append(std::to_string(i.mIndex));
+                    msg.append(".");
+                    msg.append(std::to_string(i.mBit));
+                    msg.append("): ");
+                    msg.append(i.mName);
+                    msg.append("....");
+                    msg.append(i.mIndex ? "true":"false");
+                    msg.append("\n");
                 }
+            }
+        }
+
+        msg.append("done\n");
+        android::emResultNotify(msg.c_str());
+
+    } else if(fgset && (len_count == 0) && (flag == EVENT_QUERY_CURRENT_NR)) {
+        RLOGD("printSupportBand NR start");
+        std::string msg;
+        for (auto& i : mNRModeArray) {
+            if (i.mEnable) {
+                if ((i.mIndex == INDEX_NR_BAND) && (msg.find("NR Mode:") == std::string::npos)) {
+                    msg.append("\nNR Mode:\n");
+                }
+
                 msg.append("....");
                 msg.append("(");
                 msg.append(std::to_string(i.mIndex));
@@ -533,10 +791,11 @@
                 msg.append("): ");
                 msg.append(i.mName);
                 msg.append("....");
-                msg.append(i.mIndex ? "true":"false");
+                msg.append(i.mCheck ? "true":"false");
                 msg.append("\n");
             }
         }
+
         msg.append("done\n");
         android::emResultNotify(msg.c_str());
     }
@@ -552,42 +811,52 @@
     return NULL;
 }
 
+static void* setNRBandMode(void* arg) {
+    setBandModeNR(gsmValues, nrValues);
+    return NULL;
+}
+
 static void emBandmodeAtCmdHandle(char* response, int responselen) {
-    RLOGD("emBandmodeAtCmdHandle, flag=%d, data=%s", mCurrentEmbandmodeFlag, response);
+    RLOGD("emBandmodeAtCmdHandle, mCurrentEmbandmodeFlag=%d, rsp=%s", mCurrentEmbandmodeFlag, response);
     switch (mCurrentEmbandmodeFlag) {
-    case EVENT_QUERY_CURRENT_CDMA: {
+    case EVENT_QUERY_SUPPORTED_GSM:
+    {
         if ((responselen > 0) && (response != NULL)) {
-            showBandModeCdma(response, EVENT_QUERY_CURRENT_CDMA);
+            showBandModeGsm(response, EVENT_QUERY_SUPPORTED_GSM);
         } else {
             android::emResultNotify(RET_STRING_BANDMODE_FAIL);
-            RLOGD("don't support(%d)", EVENT_QUERY_CURRENT_CDMA);
+            RLOGD("don't support(%d)", EVENT_QUERY_SUPPORTED_GSM);
         }
         BLOCK_WAKEUP();
         break;
     }
-    case EVENT_QUERY_SUPPORTED:
+    case EVENT_QUERY_SUPPORTED_NR:
     {
         if ((responselen > 0) && (response != NULL)) {
-            showBandModeGsm(response, EVENT_QUERY_SUPPORTED);
+            showBandModeNR(response, EVENT_QUERY_SUPPORTED_NR);
         } else {
             android::emResultNotify(RET_STRING_BANDMODE_FAIL);
-            RLOGD("don't support(%d)", EVENT_QUERY_SUPPORTED);
+            RLOGD("don't support(%d)", EVENT_QUERY_SUPPORTED_NR);
         }
         BLOCK_WAKEUP();
         break;
     }
-    case EVENT_QUERY_CURRENT:
+    case EVENT_QUERY_CURRENT_GSM:
     {
         if ((responselen > 0) && (response != NULL)) {
-            showBandModeGsm(response, EVENT_QUERY_CURRENT);
+            showBandModeGsm(response, EVENT_QUERY_CURRENT_GSM);
         } else {
             android::emResultNotify(RET_STRING_BANDMODE_FAIL);
-            RLOGD("don't support(%d)", EVENT_QUERY_CURRENT);
+            RLOGD("don't support(%d)", EVENT_QUERY_CURRENT_GSM);
         }
-        printGetBand(EVENT_QUERY_CURRENT);
-        printSupportBand(EVENT_QUERY_CURRENT);
+
+        if (!isNR) {
+            printGetBand(EVENT_QUERY_CURRENT_GSM);
+            printSupportBand(EVENT_QUERY_CURRENT_GSM);
+        }
         BLOCK_WAKEUP();
-        if(fgset && (count > 0)) {
+
+        if(fgset && !isNR && (len_count > 0)) {
             for(auto& val : choose_vals) {
                 RLOGD("handle values: %s", val.c_str());
                 std::vector<std::string> out;
@@ -600,19 +869,21 @@
                             int index = std::stoi(indexs[0]);
                             int bit = std::stoi(indexs[1]);
                             bool check = std::stoi(out[1]) > 0 ? true : false;
-                            for (auto& i : mModeArray) {
+                            for (auto& i : mGsmModeArray) {
                                 if((i.mIndex == index) && (i.mBit == bit)) {
                                     i.mCheck = check;
                                     RLOGD("set gsm band: lales=%s, index=%d, bit=%d, enable=%d, check=%d",
                                             i.mName.c_str(),i.mIndex, i.mBit, i.mEnable, i.mCheck);
                                 }
                             }
-                            for (auto& i : mCdmaModeArray) {
-                                if((i.mIndex == index) && (i.mBit == bit)) {
+                            if (ModemCategory::isCdma()) {
+                                for (auto& i : mCdmaModeArray) {
                                     if((i.mIndex == index) && (i.mBit == bit)) {
-                                        i.mCheck = check;
-                                        RLOGD("set gsm band: lales=%s, index=%d, bit=%d, enable=%d, check=%d",
-                                                i.mName.c_str(),i.mIndex, i.mBit, i.mEnable, i.mCheck);
+                                        if((i.mIndex == index) && (i.mBit == bit)) {
+                                            i.mCheck = check;
+                                            RLOGD("set gsm band: lales=%s, index=%d, bit=%d, enable=%d, check=%d",
+                                                    i.mName.c_str(),i.mIndex, i.mBit, i.mEnable, i.mCheck);
+                                        }
                                     }
                                 }
                             }
@@ -633,8 +904,11 @@
                     return;
                 }
             }
-            cdmaValues = getValFromBoxCdma();
-            gsmValues = getValFromBox(true);
+
+            if (ModemCategory::isCdma()) {
+                cdmaValues = getValFromBoxCdma();
+            }
+            gsmValues = getValFromBoxGsm(true);
             pthread_t setBandMode_thread;
             pthread_create(&setBandMode_thread,NULL, setGsmBandMode, NULL);
         }
@@ -658,6 +932,88 @@
         }
         break;
     }
+    case EVENT_QUERY_CURRENT_NR:
+    {
+        if ((responselen > 0) && (response != NULL)) {
+            showBandModeNR(response, EVENT_QUERY_CURRENT_NR);
+        } else {
+            android::emResultNotify(RET_STRING_BANDMODE_FAIL);
+            RLOGD("don't support(%d)", EVENT_QUERY_CURRENT_NR);
+        }
+
+        if (isNR) {
+            printGetBand(EVENT_QUERY_CURRENT_NR);
+            printSupportBand(EVENT_QUERY_CURRENT_NR);
+        }
+        BLOCK_WAKEUP();
+
+        if(fgset && isNR && (len_count > 0)) {
+            for(auto& val : choose_vals) {
+                RLOGD("handle values: %s", val.c_str());
+                std::vector<std::string> out;
+                utils::tokenize(val, "=", out);
+                if(out.size() == 2) {
+                    std::vector<std::string> indexs;
+                    utils::tokenize(out[0], ".", indexs);
+                    if(indexs.size() == 2) {
+                        try {
+                            int index = std::stoi(indexs[0]);
+                            int bit = std::stoi(indexs[1]);
+                            bool check = std::stoi(out[1]) > 0 ? true : false;
+                            for (auto& i : mNRModeArray) {
+                                if((i.mIndex == index) && (i.mBit == bit)) {
+                                    i.mCheck = check;
+                                    RLOGD("set NR band: lales=%s, index=%d, bit=%d, enable=%d, check=%d",
+                                            i.mName.c_str(),i.mIndex, i.mBit, i.mEnable, i.mCheck);
+                                }
+                            }
+                        } catch (const out_of_range &e) {
+                            RLOGD("out of range: %s", e.what());
+                        } catch (const invalid_argument &e) {
+                            RLOGD("invalid argument: %s", e.what());
+                        }
+                    }else {
+                        RLOGD("invalid parameters: %s", out[0].c_str());
+                        android::emResultNotify(RET_STRING_BANDMODE_FAIL);
+                        return;
+                    }
+
+                } else {
+                    RLOGD("invalid parameters: %s", val.c_str());
+                    android::emResultNotify(RET_STRING_BANDMODE_FAIL);
+                    return;
+                }
+            }
+            nrValues = getValFromBoxNR();
+            gsmValues = getValFromBoxGsm(true);
+            pthread_t setBandMode_thread;
+            pthread_create(&setBandMode_thread,NULL, setNRBandMode, NULL);
+        }
+
+        break;
+    }
+    case EVENT_SET_NR:
+    {
+        BLOCK_WAKEUP();
+        if ((responselen > 0) && (response != NULL)) {
+            RLOGD("Set NR bandmode success: %s", response);
+            android::emResultNotify(RET_STRING_BANDMODE_SUCCESS);
+        } else {
+            RLOGD("Set NR bandmode fail ");
+            android::emResultNotify(RET_STRING_BANDMODE_FAIL);
+        }
+        break;
+    }
+    case EVENT_QUERY_CURRENT_CDMA: {
+        if ((responselen > 0) && (response != NULL)) {
+            showBandModeCdma(response, EVENT_QUERY_CURRENT_CDMA);
+        } else {
+            android::emResultNotify(RET_STRING_BANDMODE_FAIL);
+            RLOGD("don't support(%d)", EVENT_QUERY_CURRENT_CDMA);
+        }
+        BLOCK_WAKEUP();
+        break;
+    }
     case EVENT_SET_CDMA:
     {
         BLOCK_WAKEUP();
@@ -689,63 +1045,81 @@
 /**
  * Query Modem supported band modes.
  */
-static void querySupportMode() {
+static void querySupportModeGSM() {
     //SAME_COMMAND
-    RLOGD("querySupportMode AT String: %s", QUERY_SUPPORT_COMMAND.c_str());
-    sendATCommand(QUERY_SUPPORT_COMMAND.c_str(), EVENT_QUERY_SUPPORTED);
+    RLOGD("querySupportModeGSM AT String: %s", QUERY_SUPPORT_COMMAND.c_str());
+    sendATCommand(QUERY_SUPPORT_COMMAND.c_str(), EVENT_QUERY_SUPPORTED_GSM);
 }
 
 /**
  * Query Modem is being used band modes.
  */
-static void queryCurrentMode() {
+static void queryCurrentModeGSM() {
     //SAME_COMMAND
-    RLOGD("queryCurrentMode AT String: %s", QUERY_CURRENT_COMMAND.c_str());
-    sendATCommand(QUERY_CURRENT_COMMAND.c_str(), EVENT_QUERY_CURRENT);
+    RLOGD("queryCurrentModeGSM AT String: %s", QUERY_CURRENT_COMMAND.c_str());
+    sendATCommand(QUERY_CURRENT_COMMAND.c_str(), EVENT_QUERY_CURRENT_GSM);
+}
+
+/**
+ * Query NR Modem supported band modes.
+ */
+static void querySupportModeNR() {
+    //SAME_COMMAND
+    RLOGD("querySupportModeNR AT String: %s", QUERY_SUPPORT_COMMAND_NR.c_str());
+    sendATCommand(QUERY_SUPPORT_COMMAND_NR.c_str(), EVENT_QUERY_SUPPORTED_NR);
+}
+
+/**
+ * Query NR Modem is being used band modes.
+ */
+static void queryCurrentModeNR() {
+    //SAME_COMMAND
+    RLOGD("queryCurrentModeNR AT String: %s", QUERY_CURRENT_COMMAND_NR.c_str());
+    sendATCommand(QUERY_CURRENT_COMMAND_NR.c_str(), EVENT_QUERY_CURRENT_NR);
 }
 
 static void initGsmArray() {
     for (int i = 0; i < band_mode_gsm.size(); i++) {
-        mModeArray.emplace_back(band_mode_gsm[i], INDEX_GSM_BAND, GSM_BAND_BIT[i], false, false);
+        mGsmModeArray.emplace_back(band_mode_gsm[i], INDEX_GSM_BAND, GSM_BAND_BIT[i], false, false);
     }
 }
 
 static void initLteArray() {
     for (int i = 0; i < band_mode_lte_fdd.size(); i++) {
-        mModeArray.emplace_back(band_mode_lte_fdd[i], INDEX_LTE_FDD_BAND, i, false, false);
+        mGsmModeArray.emplace_back(band_mode_lte_fdd[i], INDEX_LTE_FDD_BAND, i, false, false);
     }
     for (int i = 0; i < band_mode_lte_tdd.size(); i++) {
-        mModeArray.emplace_back(band_mode_lte_tdd[i], INDEX_LTE_TDD_BAND, i, false, false);
+        mGsmModeArray.emplace_back(band_mode_lte_tdd[i], INDEX_LTE_TDD_BAND, i, false, false);
     }
     for (int i = 0; i < band_mode_lte_96.size(); i++) {
-        mModeArray.emplace_back(band_mode_lte_96[i], INDEX_LTE_BAND_96, i, false, false);
+        mGsmModeArray.emplace_back(band_mode_lte_96[i], INDEX_LTE_BAND_96, i, false, false);
     }
     for (int i = 0; i < band_mode_lte_128.size(); i++) {
-        mModeArray.emplace_back(band_mode_lte_128[i], INDEX_LTE_BAND_128, i, false, false);
+        mGsmModeArray.emplace_back(band_mode_lte_128[i], INDEX_LTE_BAND_128, i, false, false);
     }
     for (int i = 0; i < band_mode_lte_160.size(); i++) {
-        mModeArray.emplace_back(band_mode_lte_160[i], INDEX_LTE_BAND_160, i, false, false);
+        mGsmModeArray.emplace_back(band_mode_lte_160[i], INDEX_LTE_BAND_160, i, false, false);
     }
     for (int i = 0; i < band_mode_lte_192.size(); i++) {
-        mModeArray.emplace_back(band_mode_lte_192[i], INDEX_LTE_BAND_192, i, false, false);
+        mGsmModeArray.emplace_back(band_mode_lte_192[i], INDEX_LTE_BAND_192, i, false, false);
     }
     for (int i = 0; i < band_mode_lte_224.size(); i++) {
-        mModeArray.emplace_back(band_mode_lte_224[i], INDEX_LTE_BAND_224, i, false, false);
+        mGsmModeArray.emplace_back(band_mode_lte_224[i], INDEX_LTE_BAND_224, i, false, false);
     }
     for (int i = 0; i < band_mode_lte_256.size(); i++) {
-        mModeArray.emplace_back(band_mode_lte_256[i], INDEX_LTE_BAND_256, i, false, false);
+        mGsmModeArray.emplace_back(band_mode_lte_256[i], INDEX_LTE_BAND_256, i, false, false);
     }
 }
 
 static void initTdscdmaArray() {
     for (int i = 0; i < band_mode_tdscdma.size(); i++) {
-        mModeArray.emplace_back(band_mode_tdscdma[i], INDEX_UMTS_BAND, i, false, false);
+        mGsmModeArray.emplace_back(band_mode_tdscdma[i], INDEX_UMTS_BAND, i, false, false);
     }
 }
 
 static void initWcdmaArray() {
     for (int i = 0; i < band_mode_wcdma.size(); i++) {
-        mModeArray.emplace_back(band_mode_wcdma[i], INDEX_UMTS_BAND, i, false, false);
+        mGsmModeArray.emplace_back(band_mode_wcdma[i], INDEX_UMTS_BAND, i, false, false);
     }
 }
 
@@ -755,12 +1129,21 @@
     }
 }
 
+static void initNRArray() {
+    for (int i = 0; i < band_mode_nr.size(); i++) {
+        mNRModeArray.emplace_back(band_mode_nr[i], INDEX_NR_BAND, i, false, false);
+    }
+}
+
 static void * emBandmodeThread(void* arg)
 {
-    mModeArray.clear();
+    mGsmModeArray.clear();
     mCdmaModeArray.clear();
+    mNRModeArray.clear();
+
     initGsmArray();
     int modemType = ModemCategory::getModemType();
+
     if (modemType == TDSCDMA && ModemCategory::isCapabilitySim(mSimType)) {
         initTdscdmaArray();
         if (ModemCategory::isLteSupport()) {
@@ -782,14 +1165,24 @@
         }
     }
 
+#ifdef C2K_SUPPORT
     if (mSimType == 0 && ModemCategory::isCdma() && !utils::is90Modem()) {
         initCdmaArray();
     }
     if (ModemCategory::isCdma() && !utils::is90Modem() && (mSimType == 0)) {
         queryCurrentCdmaMode();
     }
-    querySupportMode();
-    queryCurrentMode();
+#endif
+
+    querySupportModeGSM();
+    queryCurrentModeGSM();
+
+    if (utils::isMt2735()/* && ModemCategory.CheckViceSimNRCapability(mSimType)*/) {
+        initNRArray();
+        querySupportModeNR();
+        queryCurrentModeNR();
+    }
+
     pthread_exit(0);
 }
 
@@ -797,7 +1190,9 @@
 int emBandmodeStart(int len,int *item,int multilen,char *value[])
 {
     mSimType = get_default_sim_all_except_data();
-    RLOGD("emBandmodeStart called : simType:%d", mSimType);
+    RLOGD("emBandmodeStart called : simType:%d, len=%d, item[0]=%d, multilen=%d",
+            mSimType, len, item[0], multilen);
+
     //1. reset to default: select all supported bands: AT+EPBSE=255,63355
     if(len < 1)
     {
@@ -805,24 +1200,53 @@
         android::emResultNotify(RET_STRING_BANDMODE_FAIL);
         return -1;
     }
-    if((item[0] > 1 ) || (item[0] < 0)){
+    if((item[0] > 2 ) || (item[0] < 0)){
         RLOGD("emBandmodeStart: invalid parameter %d",item[0]);
         android::emResultNotify(RET_STRING_BANDMODE_FAIL);
         return -1;
     }
-    if(item[0] == 0){
+
+    int INDEX_GSM_GET=0, INDEX_GSM_SET=1, INDEX_NR_GET=2, INDEX_NR_SET=3;
+
+    // 1. Get current GSM band
+    if(item[0] == INDEX_GSM_GET){
         fgset = false;
-    }else{
+        isNR = false;
+
+    // 2. Set GSM band
+    } else if(item[0] == INDEX_GSM_SET){
         fgset = true;
-        count = multilen;
-        RLOGD("emBandmodeStart count = %d", count);
+        isNR = false;
+
+        len_count = multilen;
+        RLOGD("emBandmodeStart count = %d", len_count);
         choose_vals.clear();
-        if(count > 0){
-            for(int i=0; i< count; i++) {
+        if(len_count > 0){
+            for(int i=0; i< len_count; i++) {
+                choose_vals.push_back(value[i]);
+            }
+        }
+
+    // 3. Get current NR band
+    } else if(item[0] == INDEX_NR_GET){
+        fgset = false;
+        isNR = true;
+
+    // 4. Set NR band
+    } else if(item[0] == INDEX_NR_SET){
+        fgset = true;
+        isNR = true;
+
+        len_count = multilen;
+        RLOGD("emBandmodeStart count = %d", len_count);
+        choose_vals.clear();
+        if(len_count > 0){
+            for(int i=0; i< len_count; i++) {
                 choose_vals.push_back(value[i]);
             }
         }
     }
+
     mCurrentEmbandmodeFlag = 0;
     android::registerForATcmdResponse(emBandmodeAtCmdHandle);
     pthread_t embandmode_thread;
diff --git a/src/telephony/tel-demo/src/em/em_hspa.cpp b/src/telephony/tel-demo/src/em/em_hspa.cpp
old mode 100644
new mode 100755
index 1447b26..0782990
--- a/src/telephony/tel-demo/src/em/em_hspa.cpp
+++ b/src/telephony/tel-demo/src/em/em_hspa.cpp
@@ -64,38 +64,55 @@
     "HSDPA on\nHSUPA on\nHSPA+ on\n",
 };
 
+char *ca_info_state_array[] = {
+    "0 CA_CONFIGURED: NW configure CA\n",
+    "1 CA_NOT_CONFIGURED: NW remove CA configuration or CA configured is invalid\n",
+    "2 CA_ACTIVATED: Lower layer use CA to transfer data\n",
+    "3 CA_DEACTIVATED: Lower layer does not use CA to transfer data\n",
+};
+
 const int EVENT_HSPA_INFO = 1;
 //const int EVENT_DC_HSPA_INFO = 2;
 const int EVENT_SET_HSPA = 3;
-#define QUERY_CMD "AT+EHSM?"
-#define SET_CMD "AT+EHSM="
-#define RESPONSE_CMD "+EHSM:"
-int mCurrentEmhspaFlag = 0;
+const int EVENT_CA_INFO = 4;
+
+#define HSPA_QUERY_CMD "AT+EHSM?"
+#define HSPA_SET_CMD "AT+EHSM="
+#define HSPA_RESPONSE_CMD "+EHSM:"
+int mCurrentFlag = 0;
 int hspamode = 0;
+int intput_index = 0;
+
+#define ECAINFO_QUERY_CMD "AT+ECAINFO?"
+#define ECAINFO_RESPONSE_CMD "+ECAINFO:"
 
 void  sendATCommand_ehspa(const char *cmd,int msg)
 {
-    mCurrentEmhspaFlag = msg;
+    mCurrentFlag = msg;
     emSendATCommand(cmd, Radio_capability_switch_util::get_main_capability_phone_id());
     return ;
 }
 
 void showHspa(int mode) {
+    std::string str;
     RLOGD("showHspa, mode=%d", mode);
+
     if (mode < 0 || mode >= 4) {
         RLOGD("Modem return invalid mode: %d", mode);
         android::emResultNotify(RET_STRING_HSPA_FAIL);
         return;
     }
     if (WorldPhoneUtil::getModemType() == WorldPhoneUtil::MODEM_TD) {
-        android::emResultNotify(hspa_info_mode_array_td[mode]);
+        str = hspa_info_mode_array_td[mode];
     } else {
-        android::emResultNotify(hspa_info_mode_array_fd[mode]);
+        str = hspa_info_mode_array_fd[mode];
     }
+    str += "\ndone\n";
+    android::emResultNotify(str.c_str());
 }
 
 void parseHspaAtCmd(const char* line) {
-    if (strstr(line, RESPONSE_CMD) != NULL) {
+    if (strstr(line, HSPA_RESPONSE_CMD) != NULL) {
         AtLine* atLine = new AtLine(line, NULL);
         int err;
         atLine->atTokStart(&err);
@@ -115,8 +132,67 @@
     }
 }
 
-void emHspaAtCmdHandle(char*response, int responselen) {
-    switch (mCurrentEmhspaFlag) {
+void parseCAInfoAtCmd(const char* line) {
+    AtLine* atLine = new AtLine(line, NULL);
+    int err, ca_info, pcell_bw, scell_bw1, scell_bw2, scell_bw3, scell_bw4;
+    char cainfo_str[1024] = {0};
+
+    atLine->atTokStart(&err);
+    if (err < 0) {
+        RLOGW("this is not a valid response string");
+        goto invalid;
+    }
+
+    //+ECAINFO: <ca_info>,<pcell_bw>,<scell_bw1>, <scell_bw2>,<scell_bw3>,<scell_bw4>
+    ca_info = atLine->atTokNextint(&err);
+    if (err < 0) {
+        RLOGW("parse ca_info fail");
+        goto invalid;
+    }
+    if (ca_info < 0 || ca_info >= 4) {
+        RLOGW("ca_info return invalid state: %d", ca_info);
+        goto invalid;
+    }
+    pcell_bw = atLine->atTokNextint(&err);
+    if (err < 0) {
+        RLOGW("parse pcell_bw fail");
+        goto invalid;
+    }
+    scell_bw1 = atLine->atTokNextint(&err);
+    if (err < 0) {
+        RLOGW("parse scell_bw1 fail");
+        goto invalid;
+    }
+    scell_bw2 = atLine->atTokNextint(&err);
+    if (err < 0) {
+        RLOGW("parse scell_bw2 fail");
+        goto invalid;
+    }
+    scell_bw3 = atLine->atTokNextint(&err);
+    if (err < 0) {
+        RLOGW("parse scell_bw3 fail");
+        goto invalid;
+    }
+    scell_bw4= atLine->atTokNextint(&err);
+    if (err < 0) {
+        RLOGW("parse scell_bw4 fail");
+        goto invalid;
+    }
+
+    sprintf(cainfo_str, "\n%s\npcell_bw=%d\nscell_bw1=%d\nscell_bw2=%d\nscell_bw3=%d\nscell_bw4=%d\ndone\n",
+            ca_info_state_array[ca_info], pcell_bw, scell_bw1, scell_bw2, scell_bw3, scell_bw4);
+    android::emResultNotify(cainfo_str);
+    delete atLine;
+    return;
+
+invalid:
+    android::emResultNotify(RET_STRING_HSPA_FAIL);
+    delete atLine;
+}
+
+
+void emAtCmdHandle(char*response, int responselen) {
+    switch (mCurrentFlag) {
         case EVENT_HSPA_INFO:
         {
             //parse hspa mode.
@@ -140,6 +216,17 @@
             }
             break;
         }
+        case EVENT_CA_INFO:
+        {
+            if ((responselen > 0) && (response != NULL)) {
+                RLOGD("+ECAINFO response: %s\n",response);
+                parseCAInfoAtCmd(response);
+            }
+            else {
+                android::emResultNotify(RET_STRING_HSPA_FAIL);
+                RLOGD("send fail ");
+            }
+        }
         default:
             break;
     }
@@ -149,12 +236,23 @@
 //create thread to send command
 void * emHspaThread(void* arg)
 {
-    char cmd_str[32] = {0};
-    //sprintf(cmd_str,"%s%d,0", SET_CMD,hspamode);
-    //sendATCommand_ehspa(cmd_str,EVENT_SET_HSPA);
-    sendATCommand_ehspa(QUERY_CMD,EVENT_HSPA_INFO);
-    android::unregisterNetwork();
-    //android::emResultNotify(RET_STRING_HSPA_SUCCESS);
+    // HSPA
+    if (intput_index == 0) {
+        RLOGD("emHspaThread, query HSPA");
+
+        //char cmd_str[32] = {0};
+        //sprintf(cmd_str,"%s%d,0", HSPA_SET_CMD,hspamode);
+        //sendATCommand_ehspa(cmd_str,EVENT_SET_HSPA);
+        sendATCommand_ehspa(HSPA_QUERY_CMD,EVENT_HSPA_INFO);
+        //android::unregisterNetwork();
+        //android::emResultNotify(RET_STRING_HSPA_SUCCESS);
+
+    // Send AT+ECAINFO
+    } else if (intput_index == 1) {
+        RLOGD("emHspaThread, query CA information");
+        sendATCommand_ehspa(ECAINFO_QUERY_CMD, EVENT_CA_INFO);
+    }
+
     pthread_exit(0);
 }
 
@@ -168,15 +266,19 @@
         android::emResultNotify(RET_STRING_HSPA_FAIL);
         return -1;
     }
-    if((item[0] > 1 ) || (item[0] < 0)){
-        RLOGD("emHspaStart: invalid parameter %d",item[0]);
+
+    intput_index = item[0];
+    RLOGD("emHspaStart, intput_index=%d", intput_index);
+    if((intput_index > 1 ) || (intput_index < 0)){
+        RLOGD("emHspaStart: invalid parameter %d", intput_index);
         android::emResultNotify(RET_STRING_HSPA_FAIL);
         return -1;
     }
+
     //int modemapping[2] = {0,2};
-    mCurrentEmhspaFlag = 0;
+    mCurrentFlag = 0;
     //hspamode = modemapping[item[0]];
-    android::registerForATcmdResponse(emHspaAtCmdHandle);
+    android::registerForATcmdResponse(emAtCmdHandle);
     pthread_t emhspa_thread;
     pthread_create(&emhspa_thread,NULL, emHspaThread, NULL);
     return (0);
diff --git a/src/telephony/tel-demo/src/em/em_modemtest.cpp b/src/telephony/tel-demo/src/em/em_modemtest.cpp
old mode 100644
new mode 100755
index 30c2d7f..ba4b5eb
--- a/src/telephony/tel-demo/src/em/em_modemtest.cpp
+++ b/src/telephony/tel-demo/src/em/em_modemtest.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -136,7 +137,7 @@
     sendATCommand_modemtest(cmd.c_str(), message);
     sendATCommand_modemtest("AT+RFSSYNC", -1);
 }
-
+#ifdef C2K_SUPPORT
 void setCdmaOption() {
     if (modem_option[0] == INDEX_SPIRENT) {
         sendATCommandCdma("\"SPIRENT\"", MODEM_CDMA);
@@ -144,6 +145,7 @@
         sendATCommandCdma("\"NONE\"", MODEM_CDMA);
     }
 }
+#endif
 void  sendATCommand_modemtest(const char *str,int flag,int msg)
 {
     char cmd[32] = {0};
@@ -324,12 +326,14 @@
             }
             break;
         }
+#ifdef C2K_SUPPORT
         case MODEM_CDMA:
         {
             RLOGD("modemTestProcess MODEM_CDMA");
             setCdmaOption();
             break;
         }
+#endif
         case MODEM_FACTORY:
         {
             RLOGD("modemTestProcess MODEM_FACTORY");
@@ -456,7 +460,7 @@
         android::emResultNotify(RET_STRING_MODEMTEST_FAIL);
         return -1;
     }
-    int idmapping[7] = {MODEM_NONE,MODEM_CTA,MODEM_FTA,MODEM_IOT,MODEM_FACTORY,MODEM_FACTORY, MODEM_CDMA};
+    int idmapping[7] = {MODEM_NONE,MODEM_CTA,MODEM_FTA,MODEM_IOT,MODEM_OPERATOR,MODEM_FACTORY, MODEM_CDMA};
     RLOGD("emModemtestStart called item[0]: %d", item[0]);
     modem_id = idmapping[item[0]];
     modem_option_cnt = multicnt;
diff --git a/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTest.cpp b/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTest.cpp
old mode 100644
new mode 100755
index b9c6cdc..1b08166
--- a/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTest.cpp
+++ b/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTest.cpp
@@ -52,6 +52,7 @@
 #include "rfdesense/RfDesenseTxTestGsm.h"
 #include "rfdesense/RfDesenseTxTestLte.h"
 #include "rfdesense/RfDesenseTxTestTd.h"
+#include "rfdesense/RfDesenseTxTestNr.h"
 #include "util/log_extra.h"
 #include "util/utils.h"
 
@@ -66,12 +67,23 @@
 const int RfDesenseTxTest::STATE_STOPPED = 2;
 
 const int RfDesenseTxTest::MSG_START_TX = 1;
+const int RfDesenseTxTest::MSG_CONTINUE_TX = 2;
 const int RfDesenseTxTest::MSG_NEXT_RAT = 4;
 const int RfDesenseTxTest::MSG_READ_POWER = 10;
 const int RfDesenseTxTest::MSG_EWMPOLICY_TDSCDMA = 12;
 const int RfDesenseTxTest::MSG_EWMPOLICY_WCDMA = 13;
 const int RfDesenseTxTest::MSG_ECSRA = 14;
 const int RfDesenseTxTest::MSG_SWITCH_RAT_DONE = 15;
+const int RfDesenseTxTest::MSG_NR_READ_POWER = 20;
+
+int RfDesenseTxTest::INDEX_GSM = -1;
+int RfDesenseTxTest::INDEX_TDSCDMA = -1;
+int RfDesenseTxTest::INDEX_WCDMA = -1;
+int RfDesenseTxTest::INDEX_LTE_FDD = -1;
+int RfDesenseTxTest::INDEX_LTE_TDD = -1;
+int RfDesenseTxTest::INDEX_NR = -1;
+int RfDesenseTxTest::INDEX_CDMA_EVDO = -1;
+int RfDesenseTxTest::INDEX_CDMA_1X = -1;
 
 int RfDesenseTxTest::mState = STATE_NONE;
 
@@ -82,6 +94,8 @@
 long RfDesenseTxTest::mCheckLimit = 2;
 long RfDesenseTxTest::mReadbackInterval = 5;
 
+const static std::string CMD_SAME_EGMC = "+EGMC:";
+
 const std::string RfDesenseTxTest::KEY_GSM_ATCMD = "gsm_at_cmd";
 const std::string RfDesenseTxTest::KEY_TDSCDMA_ATCMD = "tdscdma_at_cmd";
 const std::string RfDesenseTxTest::KEY_WCDMA_ATCMD = "wcdma_at_cmd";
@@ -94,42 +108,124 @@
 const std::string RfDesenseTxTest::KEY_CHECK_LIMIT = "check_limit";
 const std::string RfDesenseTxTest::KEY_READBACK_INTREVAL = "readback_interval";
 
-const std::string RfDesenseTxTest::DEFAULT_GSM_ATCMD =
-            "AT+ERFTX=2,1,190,4100,128,0,5,0";
+const std::string RfDesenseTxTest::DEFAULT_GSM_ATCMD = "AT+ERFTX=2,1,190,4100,128,0,5,0";
 const std::string RfDesenseTxTest::DEFAULT_TDSCDMA_ATCMD = "AT+ERFTX=0,0,1,10087,24";
 const std::string RfDesenseTxTest::DEFAULT_WCDMA_ATCMD = "AT+ERFTX=0,0,1,9750,23";
-const std::string RfDesenseTxTest::DEFAULT_LTE_FDD_ATCMD =
-            "AT+ERFTX=6,0,1,3,3,17475,1,0,0,0,1,0,23";
-const std::string RfDesenseTxTest::DEFAULT_LTE_TDD_ATCMD =
-            "AT+ERFTX=6,0,1,38,3,25950,0,0,0,0,1,0,23";
+const std::string RfDesenseTxTest::DEFAULT_LTE_FDD_ATCMD = "AT+ERFTX=6,0,1,3,3,17475,1,0,0,0,1,0,23";
+const std::string RfDesenseTxTest::DEFAULT_LTE_TDD_ATCMD = "AT+ERFTX=6,0,1,38,3,25950,0,0,0,0,1,0,23";
+const std::string RfDesenseTxTest::DEFAULT_NR_ATCMD = "AT+EGMC=1,\"NrForcedTx\",2,1,1950000,23";
 const std::string RfDesenseTxTest::DEFAULT_CDMA_EVDO_ATCMD = "AT+ERFTX=13,4,384,0,83";
 const std::string RfDesenseTxTest::DEFAULT_CDMA_1X_ATCMD = "AT+ECRFTX=1,384,0,83,0";
 
 const std::string RfDesenseTxTest::DEFAULT_CDMA_EVDO_ATCMD_93before =
             "AT+ERFTX=1,384,0,83,1";
 
-const std::vector<std::string> RfDesenseTxTest::mRatName = { "GSM", "TDSCDMA", "WCDMA",
-            "LTE(FDD)", "LTE(TDD)", "CDMA(EVDO)", "CDMA(1X)" };
-std::vector<std::string> RfDesenseTxTest::mRatCmdStart = { DEFAULT_GSM_ATCMD,
-            DEFAULT_TDSCDMA_ATCMD, DEFAULT_WCDMA_ATCMD, DEFAULT_LTE_FDD_ATCMD,
-            DEFAULT_LTE_TDD_ATCMD, DEFAULT_CDMA_EVDO_ATCMD,
-            DEFAULT_CDMA_1X_ATCMD };
+const std::vector<std::string> RfDesenseTxTest::mRatName = {
+            "GSM"
+#ifndef TARGET_PLATFORM_MT2735
+            , "TDSCDMA"
+#endif
+            , "WCDMA"
+            , "LTE(FDD)", "LTE(TDD)"
+#ifdef TARGET_PLATFORM_MT2735
+            , "NR"
+#endif
+#ifdef C2K_SUPPORT
+            ,"CDMA(EVDO)", "CDMA(1X)"
+#endif
+            };
+std::vector<std::string> RfDesenseTxTest::mRatCmdStart = {
+            DEFAULT_GSM_ATCMD
+#ifndef TARGET_PLATFORM_MT2735
+            , DEFAULT_TDSCDMA_ATCMD
+#endif
+            , DEFAULT_WCDMA_ATCMD
+            , DEFAULT_LTE_FDD_ATCMD, DEFAULT_LTE_TDD_ATCMD
+#ifdef TARGET_PLATFORM_MT2735
+            , DEFAULT_NR_ATCMD
+#endif
+#ifdef C2K_SUPPORT
+            , DEFAULT_CDMA_EVDO_ATCMD, DEFAULT_CDMA_1X_ATCMD
+#endif
+            };
 
-std::vector<std::string> RfDesenseTxTest::mRatCmdStop = { "AT+ERFTX=2,0",
-            "AT+ERFTX=0,1", "AT+ERFTX=0,1", "AT+ERFTX=6,0,0", "AT+ERFTX=6,0,0",
-            "AT+ERFTX=13,5", "AT+ECRFTX=0" };
+std::vector<std::string> RfDesenseTxTest::mRatCmdStop = {
+            "AT+ERFTX=2,0"
+#ifndef TARGET_PLATFORM_MT2735
+            , "AT+ERFTX=0,1"
+#endif
+            , "AT+ERFTX=0,1"
+            , "AT+ERFTX=6,0,0", "AT+ERFTX=6,0,0"
+#ifdef TARGET_PLATFORM_MT2735
+            , "AT+EGMC=1,\"NrForcedTx\",0"
+#endif
+#ifdef C2K_SUPPORT
+            ,"AT+ERFTX=13,5", "AT+ECRFTX=0"
+#endif
+            };
 
- std::vector<std::string> RfDesenseTxTest::mRatCmdSwitch = { "AT+ERAT=0", "AT+ERAT=1",
-            "AT+ERAT=1", "AT+ERAT=6,4", "AT+ERAT=6,4", "AT+ERAT=7,64",
-            "AT+ERAT=7,32" };
+ std::vector<std::string> RfDesenseTxTest::mRatCmdSwitch = {
+            "AT+ERAT=0"
+#ifndef TARGET_PLATFORM_MT2735
+            , "AT+ERAT=1"
+#endif
+            , "AT+ERAT=1"
+            , "AT+ERAT=6,4", "AT+ERAT=6,4"
+#ifdef TARGET_PLATFORM_MT2735
+            , "AT+ERAT=22,128"
+#endif
+#ifdef C2K_SUPPORT
+            , "AT+ERAT=7,64", "AT+ERAT=7,32"
+#endif
+            };
 
-std::vector<std::string> RfDesenseTxTest::mRatCmdPowerRead = { "", "AT+ERFTX=0,3",
-            "AT+ERFTX=0,3", "AT+ERFTX=6,1", "AT+ERFTX=6,1", "AT+ERFTX=13,3",
-            "AT+ERFTX=13,3" };
-std::vector<std::string> RfDesenseTxTest::mRatBand = { "19", "1", "1", "3", "38", "0", "0" };
-std::vector<std::string> RfDesenseTxTest::mRatPowerSet = { "19", "10", "24", "23", "23", "23", "23" };
-std::vector<bool> RfDesenseTxTest::mRatCheck = {false, false,false,false,false,false,false};
-std::vector<bool> RfDesenseTxTest::mSendState = {false, false,false,false,false,false,false};
+std::vector<std::string> RfDesenseTxTest::mRatCmdPowerRead = {
+            ""
+#ifndef TARGET_PLATFORM_MT2735
+            , "AT+ERFTX=0,3"
+#endif
+            , "AT+ERFTX=0,3"
+            , "AT+ERFTX=6,1", "AT+ERFTX=6,1"
+#ifdef TARGET_PLATFORM_MT2735
+            , "AT+EGMC=0,\"NrFetchTxPwr\""
+#endif
+#ifdef C2K_SUPPORT
+            , "AT+ERFTX=13,3", "AT+ERFTX=13,3"
+#endif
+            };
+
+std::vector<std::string> RfDesenseTxTest::mRatBand = {
+            "19"
+#ifndef TARGET_PLATFORM_MT2735
+            , "1"
+#endif
+            , "1"
+            , "3", "38"
+#ifdef TARGET_PLATFORM_MT2735
+            , "1"
+#endif
+#ifdef C2K_SUPPORT
+            , "0", "0"
+#endif
+            };
+
+std::vector<std::string> RfDesenseTxTest::mRatPowerSet = {
+            "19"
+#ifndef TARGET_PLATFORM_MT2735
+            , "10"
+#endif
+            , "24"
+            , "23", "23"
+#ifdef TARGET_PLATFORM_MT2735
+            , "23"
+#endif
+#ifdef C2K_SUPPORT
+            , "23", "23"
+#endif
+            };
+
+std::vector<bool> RfDesenseTxTest::mRatCheck = {false, false, false, false, false, false, false, false};
+std::vector<bool> RfDesenseTxTest::mSendState = {false, false, false, false, false, false, false, false};
 std::string RfDesenseTxTest::str_msg = "";
 bool RfDesenseTxTest::trm_flag = false;
 int RfDesenseTxTest::phone_id = 0;
@@ -159,6 +255,7 @@
                 while(!isRadioOn((RIL_SOCKET_ID)phone_id)) {
                     LOG_D(LOG_TAG, "radio isn't on");
                     std::this_thread::sleep_for(std::chrono::milliseconds(200));
+                    turnOnRf();
                 }
                 //turnOnRf();
                 LOG_D(LOG_TAG, "radio on again");
@@ -201,7 +298,7 @@
     if (mCurrectRatInfo) {
         mCurrectRatInfo->setRatSendState(true);
         rf_send_at_cmd(mCurrectRatInfo->getRatCmdStart(), MSG_START_TX);
-        LOG_D(LOG_TAG, "send: %s  %s",mCurrectRatInfo->getRatName().c_str() ,mCurrectRatInfo->getRatCmdStart().c_str());
+        LOG_D(LOG_TAG, "send:Ratname=%s, RatCmd=%s",mCurrectRatInfo->getRatName().c_str() ,mCurrectRatInfo->getRatCmdStart().c_str());
     } else {
         LOG_D(LOG_TAG, "mCurrectRatInfo == null");
     }
@@ -389,24 +486,53 @@
     return handler;
 }
 
+char* RfDesenseTxTest::msg_type_to_str(int msgType) {
+    switch (msgType) {
+        case MSG_START_TX:
+            return "MSG_START_TX";
+        case MSG_CONTINUE_TX:
+            return "MSG_CONTINUE_TX";
+        case MSG_NEXT_RAT:
+            return "MSG_NEXT_RAT";
+        case MSG_READ_POWER:
+            return "MSG_READ_POWER";
+        case MSG_EWMPOLICY_TDSCDMA:
+            return "MSG_EWMPOLICY_TDSCDMA";
+        case MSG_EWMPOLICY_WCDMA:
+            return "MSG_EWMPOLICY_WCDMA";
+        case MSG_ECSRA:
+            return "MSG_ECSRA";
+        case MSG_SWITCH_RAT_DONE:
+            return "MSG_SWITCH_RAT_DONE";
+        case MSG_NR_READ_POWER:
+            return "MSG_NR_READ_POWER";
+        default:
+            return "unknown type";
+    }
+}
+
 void RfDesenseTxTest::emRfDesenseAtCmdHandle(sp<RfRequestMessage> msg){
-    LOG_D(LOG_TAG, "emRfDesenseAtCmdHandle, type: %d", msg->mMsgType);
+    LOG_D(LOG_TAG, "emRfDesenseAtCmdHandle(), %s", msg_type_to_str(msg->mMsgType));
     int responselen = msg->responselen;
     std::string response = msg->response;
     switch (msg->mMsgType) {
     case MSG_SWITCH_RAT_DONE: {
         if (msg->e == RIL_E_SUCCESS) {
-            LOG_D(LOG_TAG, "switch rat succeed");
-            if (mCurrectRatInfo->getRatName() == mRatName[1]) { // tdscdma
+            LOG_D(LOG_TAG, "switch rat=%s succeed", mCurrectRatInfo->getRatName().c_str());
+#ifndef TARGET_PLATFORM_MT2735
+            if (mCurrectRatInfo->getRatName() == mRatName[INDEX_TDSCDMA]) { // tdscdma
                 LOG_D(LOG_TAG, "end AT+EWMPOLICY=0");
                 rf_send_at_cmd("AT+EWMPOLICY=0", MSG_EWMPOLICY_TDSCDMA);
-            } else if (mCurrectRatInfo->getRatName() == mRatName[2]) { // wcdma
+            } else
+#endif
+            if (mCurrectRatInfo->getRatName() == mRatName[INDEX_WCDMA]) { // wcdma
                 LOG_D(LOG_TAG,  "send AT+EWMPOLICY=0");
                 rf_send_at_cmd("AT+EWMPOLICY=0", MSG_EWMPOLICY_WCDMA);
             } else { // other rat
                 registerRadioOffOrNotAvailable(m_instance);
                 turnOffRf();
             }
+
         } else {
             LOG_D(LOG_TAG, "switch rat failed");
             emResultNotifyWithDone(mCurrectRatInfo->getRatName() + " switch rat failed\n");
@@ -433,9 +559,27 @@
     case MSG_START_TX:{
         if (msg->e == RIL_E_SUCCESS) {
             LOG_D(LOG_TAG, "start cmd ok");
-            if (utils::is93Modem() && mCurrectRatInfo && !mCurrectRatInfo->getRatCmdPowerRead().empty()) {
-                LOG_D(LOG_TAG,"start read cmd: %s", mCurrectRatInfo->getRatCmdPowerRead().c_str());
-                rf_send_at_cmd(mCurrectRatInfo->getRatCmdPowerRead(), MSG_READ_POWER);
+
+            if (utils::is93ModemAndAbove() && mCurrectRatInfo && !mCurrectRatInfo->getRatCmdPowerRead().empty()) {
+#ifdef TARGET_PLATFORM_MT2735
+                // For NR, need send get power after 5s, 10s (2 times)
+                if (mCurrectRatInfo->getRatName() == sub_tx_test[INDEX_NR].name) {
+                    LOG_D(LOG_TAG, "For NR, wait and start read cmd");
+                    sp<RfRequestMessage> nr_msg = new RfRequestMessage(this);
+                    nr_msg->mMsgType = MSG_CONTINUE_TX;
+                    nr_msg->response = msg->response;
+                    nr_msg->responselen = msg->responselen;
+                    nr_msg->slot = msg->slot;
+                    nr_msg->e = RIL_E_SUCCESS;
+                    sendMessage(nr_msg, 1000);
+
+                } else {
+#endif
+                    LOG_D(LOG_TAG,"start read cmd: %s", mCurrectRatInfo->getRatCmdPowerRead().c_str());
+                    rf_send_at_cmd(mCurrectRatInfo->getRatCmdPowerRead(), MSG_READ_POWER);
+#ifdef TARGET_PLATFORM_MT2735
+                }
+#endif
             } else {
                 LOG_D(LOG_TAG, "don't read");
                 txTestStop(MSG_NEXT_RAT);
@@ -446,6 +590,47 @@
         }
         break;
     }
+
+    case MSG_CONTINUE_TX:{
+        mTestDurationSended += mReadbackInterval;
+        if (mTestDurationSended >= mTestDuration) {
+            LOG_D(LOG_TAG, "read tx power succeed");
+            txTestStop(MSG_NEXT_RAT);
+            mTestDurationSended = 0;
+
+        } else {
+            LOG_D(LOG_TAG, "Wait again for mTestDurationSended=%d < %d", mTestDurationSended, mTestDuration);
+            sp<RfRequestMessage> nr_msg = new RfRequestMessage(this);
+            nr_msg->mMsgType = MSG_CONTINUE_TX;
+            nr_msg->response = msg->response;
+            nr_msg->responselen = msg->responselen;
+            nr_msg->slot = msg->slot;
+            nr_msg->e = msg->e;
+            sendMessage(msg, mReadbackInterval*1000);
+
+            if (utils::is93ModemAndAbove() && mCurrectRatInfo && !mCurrectRatInfo->getRatCmdPowerRead().empty()) {
+                LOG_D(LOG_TAG,"start read cmd: %s", mCurrectRatInfo->getRatCmdPowerRead().c_str());
+                rf_send_at_cmd(mCurrectRatInfo->getRatCmdPowerRead(), MSG_NR_READ_POWER);
+            } else {
+                LOG_D(LOG_TAG,"start read cmd fail");
+            }
+        }
+        break;
+    }
+
+    case MSG_NR_READ_POWER:{
+        if ((msg->e == RIL_E_SUCCESS) && (responselen > 0)) {
+            RLOGD("Get response %s", msg->response.c_str());
+            parse_read_power(response);
+
+        } else {
+            LOG_D(LOG_TAG, "read tx power failed");
+            emResultNotifyWithDone(mCurrectRatInfo->getRatName() + " read tx power failed\n");
+        }
+
+        break;
+    }
+
     case MSG_READ_POWER:{
         mTestDurationSended += mReadbackInterval;
         if (mTestDurationSended >= mTestDuration) {
@@ -464,9 +649,9 @@
             }
             mTestDurationSended = 0;
         } else {
-            if (utils::is93Modem() && mCurrectRatInfo && !mCurrectRatInfo->getRatCmdPowerRead().empty()) {
+            if (utils::is93ModemAndAbove() && mCurrectRatInfo && !mCurrectRatInfo->getRatCmdPowerRead().empty()) {
                 LOG_D(LOG_TAG,"(sencond)start read cmd: %s", mCurrectRatInfo->getRatCmdPowerRead().c_str());
-                rf_send_at_cmd(mCurrectRatInfo->getRatCmdPowerRead(),  MSG_READ_POWER);
+                rf_send_at_cmd(mCurrectRatInfo->getRatCmdPowerRead(), MSG_READ_POWER);
             } else {
                 LOG_D(LOG_TAG,"(sencond)start read cmd fail");
             }
@@ -489,7 +674,7 @@
                 mRatList[i]->setRatCheckState(false);
             }
 //            if(rat == mRatName[1] || rat == mRatName[2]) {
-//                if(utils::is93Modem()){
+//                if(utils::is93ModemAndAbove()){
 //                    utils::mtk_property_set("vendor.ril.mux.report.case", "2");
 //                    utils::mtk_property_set("vendor.ril.muxreport", "1");
 //                }else {
@@ -523,6 +708,72 @@
     }
 }
 
+void RfDesenseTxTest::parse_read_power(std::string response) {
+    std::vector<std::string> out;
+    utils::tokenize(response, "\n", out);
+    std::string str;
+    str.clear();
+
+    for(auto i: out) {
+        if(i.find(CMD_SAME_EGMC) != std::string::npos) {
+            std::string splitString = i.substr(std::string(CMD_SAME_EGMC).size());
+            std::vector<std::string> getDigitalVal;
+            utils::tokenize(string(splitString), ",\n", getDigitalVal);
+            RLOGD("parseCurrentMode splitString: %s, getDigitalVal.size()=%d",
+                    splitString.c_str(), getDigitalVal.size());
+
+            if (getDigitalVal.size() <= 0 || getDigitalVal.size() > 2) {
+                LOG_D(LOG_TAG, "read tx power size failed");
+                emResultNotifyWithDone(mCurrectRatInfo->getRatName() + " read tx power failed\n");
+                return ;
+            }
+
+            try {
+                float getPower = std::stof(getDigitalVal[1]);
+                LOG_D(LOG_TAG, "Readback tx power = %f", getPower);
+
+                std::string result = "";
+                std::string rat = "";
+
+                if (std::abs(std::stoi(mCurrectRatInfo->getRatPowerSet()) - getPower) > mCheckLimit) {
+                    result = "failed\n";
+                } else {
+                    result = "succeed\n";
+                }
+
+                std::string s = std::string("Start TX:\n")
+                        + std::string("Rat(band)          ") + std::string("Power_Set   ")
+                        + std::string("Power_Get    ") + std::string("Result\n");
+                rat = utils::format("%-20s   %-15s   %-10s",
+                        (mCurrectRatInfo->getRatName()+ "(b" + mCurrectRatInfo->getRatband() + ")").c_str(),
+                        mCurrectRatInfo->getRatPowerSet().c_str(),
+                        std::to_string(getPower).c_str()
+                );
+
+                std::string ret;
+                if (!result.compare("failed\n")) {
+                    ret = utils::format("%10s", result.c_str());
+                } else {
+                    ret = utils::format("%10s", result.c_str());
+                }
+                str_msg += s + rat + ret;
+
+                RLOGD("%s", str_msg.c_str());
+
+            } catch (const out_of_range &e) {
+                emResultNotifyWithDone(mCurrectRatInfo->getRatName() + " read tx power failed\n");
+                RLOGD("out of range: %s", e.what());
+                return;
+            } catch (const invalid_argument &e) {
+                emResultNotifyWithDone(mCurrectRatInfo->getRatName() + " read tx power failed\n");
+                RLOGD("invalid argument: %s", e.what());
+                return;
+            }
+
+        }
+    }
+}
+
 void RfDesenseTxTest::handle_gsm_para(const std::string& name, int last_pos,
         const std::string& sub_name) {
     bool flag = false;
@@ -878,6 +1129,125 @@
     }
 }
 
+void RfDesenseTxTest::handle_nr_para(const std::string& name, int last_pos,
+        const std::string& sub_name) {
+    //NR
+    bool flag = false;
+    std::shared_ptr<RfDesenseTxTestNr> nr =
+            RfDesenseTxTestNr::get_instance();
+
+    if (name == rfdesense_nr_sub[INDEX_NR_SUB_MODE].name) {
+        flag = nr->set_tx_mode(last_pos);
+
+    } else if (name == rfdesense_nr_sub[INDEX_NR_SUB_BAND].name) {
+        flag = nr->set_band_idx(last_pos);
+
+    } else if (name == rfdesense_nr_sub[INDEX_NR_SUB_BANDWIDTH].name) {
+        flag = nr->set_bandwith_idx(last_pos);
+
+    } else if (name == rfdesense_nr_sub[INDEX_NR_SUB_FREQ].name) {
+        if (sub_name == set_get[0].name) {
+            //get
+            nr->show_freq();
+        } else if (sub_name == set_get[1].name) {
+            // set
+            if (mCurrentSettingsValues.size() > 0) {
+                flag = nr->set_freq(mCurrentSettingsValues[0]);
+            } else {
+                LOG_D(LOG_TAG, "mCurrentSettingsValues size is 0");
+                em_result_notify_error("please input set values, now, only select the set item. value is empty");
+            }
+        } else {
+            LOG_D(LOG_TAG, "error");
+            em_result_notify_error("get/set input error");
+        }
+
+    } else if (name == rfdesense_nr_sub[INDEX_NR_SUB_START].name) {
+        if (sub_name == set_get[0].name) {
+            //get
+            nr->show_start();
+        } else if (sub_name == set_get[1].name) {
+            // set
+            if (mCurrentSettingsValues.size() > 0) {
+                flag = nr->set_vrb_start(mCurrentSettingsValues[0]);
+            } else {
+                LOG_D(LOG_TAG, "mCurrentSettingsValues size is 0");
+                em_result_notify_error("please input set values, now, only select the set item. value is empty");
+            }
+        } else {
+            LOG_D(LOG_TAG, "error");
+            em_result_notify_error("get/set input error");
+        }
+
+    } else if (name == rfdesense_nr_sub[INDEX_NR_SUB_LENGTH].name) {
+        if (sub_name == set_get[0].name) {
+            //get
+            nr->show_length();
+        } else if (sub_name == set_get[1].name) {
+            // set
+            if (mCurrentSettingsValues.size() > 0) {
+                flag = nr->set_vrb_length(mCurrentSettingsValues[0]);
+            } else {
+                LOG_D(LOG_TAG, "mCurrentSettingsValues size is 0");
+                em_result_notify_error("please input set values, now, only select the set item. value is empty");
+            }
+        } else {
+            LOG_D(LOG_TAG, "error");
+            em_result_notify_error("get/set input error");
+        }
+
+    } else if (name == rfdesense_nr_sub[INDEX_NR_SUB_MCS].name) {
+        flag = nr->set_mcs(last_pos);
+
+    } else if (name == rfdesense_nr_sub[INDEX_NR_SUB_SCS].name) {
+        flag = nr->set_scs(last_pos);
+
+    } else if (name == rfdesense_nr_sub[INDEX_NR_SUB_POWER].name) {
+        if (sub_name == set_get[0].name) {
+            //get
+            nr->show_power();
+        } else if (sub_name == set_get[1].name) {
+            // set
+            if (mCurrentSettingsValues.size() > 0) {
+                flag = nr->set_power(mCurrentSettingsValues[0]);
+            } else {
+                LOG_D(LOG_TAG, "mCurrentSettingsValues size is 0");
+                em_result_notify_error("please input set values, now, only select the set item. value is empty");
+            }
+        } else {
+            LOG_D(LOG_TAG, "error");
+            em_result_notify_error("get/set input error");
+        }
+
+    } else if (name == rfdesense_nr_sub[INDEX_NR_SUB_CONFIG].name) {
+        if (sub_name == set_get[0].name) {
+            //get
+            nr->show_config();
+        } else if (sub_name == set_get[1].name) {
+            // set
+            if (mCurrentSettingsValues.size() > 0) {
+                flag = nr->set_tdd_slot_config(mCurrentSettingsValues[0]);
+            } else {
+                LOG_D(LOG_TAG, "mCurrentSettingsValues size is 0");
+                em_result_notify_error("please input set values, now, only select the set item. value is empty");
+            }
+        } else {
+            LOG_D(LOG_TAG, "error");
+            em_result_notify_error("get/set input error");
+        }
+    } else {
+        LOG_D(LOG_TAG, "No name=%s", name.c_str());
+        em_result_notify_error("get/set input error");
+    }
+
+    if (flag) {
+        mRatList[INDEX_NR]->setRatCmdStart(nr->get_command());
+        mRatList[INDEX_NR]->setRatband(nr->get_band());
+        mRatList[INDEX_NR]->setRatPowerSet(nr->get_power());
+        save(INDEX_NR);
+    }
+}
+
 void RfDesenseTxTest::handle_cdma_evdo_para(const std::string& name,
         int last_pos, const std::string& sub_name) {
     //CDMA(EVDO)
@@ -985,11 +1355,13 @@
         std::shared_ptr<RfDesenseTxTestGsm> gsm =
                 RfDesenseTxTestGsm::get_instance();
         gsm->show_default();
+#ifndef TARGET_PLATFORM_MT2735
     } else if (standard == sub_tx_test[INDEX_TDSCDMA].name) {
         //"TDSCDMA"
         std::shared_ptr<RfDesenseTxTestTd> tdscdma = std::make_shared<
                 RfDesenseTxTestTd>(utils::MODEM_TDSCDMA);
         tdscdma->show_default();
+#endif
     } else if (standard == sub_tx_test[INDEX_WCDMA].name) {
         //"WCDMA"
         std::shared_ptr<RfDesenseTxTestTd> wcdma = std::make_shared<
@@ -1005,6 +1377,13 @@
         std::shared_ptr<RfDesenseTxTestLte> tdd = std::make_shared<
                 RfDesenseTxTestLte>(utils::MODEM_LTE_TDD);
         tdd->show_default();
+#ifdef TARGET_PLATFORM_MT2735
+    } else if (standard == sub_tx_test[INDEX_NR].name) {
+        //NR
+        std::shared_ptr<RfDesenseTxTestNr> nr =
+                RfDesenseTxTestNr::get_instance();
+        nr->show_default();
+#endif
 #ifdef C2K_SUPPORT
     } else if ((standard == sub_tx_test[INDEX_CDMA_EVDO].name)
             && utils::isC2KSupport()) {
@@ -1042,9 +1421,11 @@
     if (standard == sub_tx_test[INDEX_GSM].name) {
         //"GSM"
         handle_gsm_para(name, last_pos, sub_name);
+#ifndef TARGET_PLATFORM_MT2735
     } else if (standard == sub_tx_test[INDEX_TDSCDMA].name) {
         //"TDSCDMA"
         handle_tdscdma_para(name, last_pos, sub_name);
+#endif
     } else if (standard == sub_tx_test[INDEX_WCDMA].name) {
         //"WCDMA"
         handle_wcdma_para(name, last_pos, sub_name);
@@ -1054,6 +1435,11 @@
     } else if (standard == sub_tx_test[INDEX_LTE_TDD].name) {
         //LTE(TDD)
         handle_lte_tdd_para(name, last_pos, sub_name);
+#ifdef TARGET_PLATFORM_MT2735
+    } else if (standard == sub_tx_test[INDEX_NR].name) {
+        //NR
+        handle_nr_para(name, last_pos, sub_name);
+#endif
 #ifdef C2K_SUPPORT
     } else if ((standard == sub_tx_test[INDEX_CDMA_EVDO].name)
             && utils::isC2KSupport()) {
@@ -1077,9 +1463,11 @@
     if (standard == sub_tx_test[INDEX_GSM].name) {
         //"GSM"
         mRatList[INDEX_GSM]->setRatCheckState(true);
+#ifndef TARGET_PLATFORM_MT2735
     } else if (standard == sub_tx_test[INDEX_TDSCDMA].name) {
         //"TDSCDMA"
         mRatList[INDEX_TDSCDMA]->setRatCheckState(true);
+#endif
     } else if (standard == sub_tx_test[INDEX_WCDMA].name) {
         //"WCDMA"
         mRatList[INDEX_WCDMA]->setRatCheckState(true);
@@ -1089,6 +1477,11 @@
     } else if (standard == sub_tx_test[INDEX_LTE_TDD].name) {
         //LTE(TDD)
         mRatList[INDEX_LTE_TDD]->setRatCheckState(true);
+#ifdef TARGET_PLATFORM_MT2735
+    } else if (standard == sub_tx_test[INDEX_NR].name) {
+        //NR
+        mRatList[INDEX_NR]->setRatCheckState(true);
+#endif
 #ifdef C2K_SUPPORT
     } else if ((standard == sub_tx_test[INDEX_CDMA_EVDO].name)
             && utils::isC2KSupport()) {
@@ -1108,6 +1501,26 @@
 
 int RfDesenseTxTest::emRfDesenseStart(int len,int *item,int multilen,char *value[]) {
     LOG_D(LOG_TAG,"emRfDesenseStart called");
+
+    // Update manu index
+    int idx_count = 0;
+    INDEX_GSM = idx_count;
+#ifndef TARGET_PLATFORM_MT2735
+    INDEX_TDSCDMA = ++idx_count;
+#endif
+    INDEX_WCDMA = ++idx_count;
+    INDEX_LTE_FDD = ++idx_count;
+    INDEX_LTE_TDD = ++idx_count;
+#ifdef TARGET_PLATFORM_MT2735
+    INDEX_NR = ++idx_count;
+#endif
+#ifdef C2K_SUPPORT
+    INDEX_CDMA_EVDO = ++idx_count;
+    INDEX_CDMA_1X = ++idx_count;
+#endif
+    LOG_D(LOG_TAG, "Manu index: GSM=%d, TDSCDMA=%d, WCDMA=%d, LTE_FDD=%d, LTE_TDD=%d, NR=%d, CDMA_EVDO=%d, CDMA_1X=%d",
+            INDEX_GSM, INDEX_TDSCDMA, INDEX_WCDMA, INDEX_LTE_FDD, INDEX_LTE_TDD, INDEX_NR, INDEX_CDMA_EVDO, INDEX_CDMA_1X);
+
     update_rat();
     if (len < 3) {
         LOG_D(LOG_TAG, "please select redesense get or set");
@@ -1116,12 +1529,15 @@
     int classid = item[0];
     int propertyid = item[1];
     int operatorid = item[2];
+    LOG_D(LOG_TAG, "classid=%d, propertyid=%d, operatorid=%d", classid, propertyid, operatorid);
+
     mCurrentSettingsValues.clear();
     for(int i = 0; i < multilen; i++ ) {
         mCurrentSettingsValues.push_back(value[i]);
         LOG_D(LOG_TAG, "value[%d]: %s", i, value[i]);
     }
-    LOG_D(LOG_TAG, "mCurrentSettingsValues size: " + mCurrentSettingsValues.size());
+    LOG_D(LOG_TAG, "mCurrentSettingsValues size: %d" + mCurrentSettingsValues.size());
+
     em_arry_t *subarry = &(desense_test[classid].subarray[propertyid]);
     std::string standard = subarry->name;
     LOG_D(LOG_TAG,"rfdesense property name: %s, operatorid: %d",subarry->name, operatorid);
@@ -1186,7 +1602,8 @@
 void RfDesenseTxTest::initRatList() {
     phone_id = Radio_capability_switch_util::get_main_capability_phone_id();
     mState = STATE_NONE;
-    if(!utils::is93Modem()){
+
+    if(!utils::is93ModemAndAbove()){
         mRatCmdStart[5] = DEFAULT_CDMA_EVDO_ATCMD_93before;
         mRatCmdStop[5] = "AT+ECRFTX=0";
     }
@@ -1195,6 +1612,7 @@
         mRatCmdSwitch[5] = "AT^PREFMODE=4";
         mRatCmdSwitch[6] = "AT^EIRATMODE=2";
     }
+
     for (int i = 0; i < mRatName.size(); i++) {
         std::shared_ptr<RfDesenseRatInfo> Info = std::make_shared<RfDesenseRatInfo>();
         Info->setRatName(mRatName[i]);
@@ -1207,11 +1625,6 @@
         Info->setRatCheckState(false);
         Info->setRatSendState(false);
         mRatList.push_back(Info);
-        if(!(utils::isC2KSupport())){
-            if (i == 4) {
-                break;
-            }
-        }
     }
 }
 
@@ -1226,11 +1639,6 @@
         mRatList[i]->setRatPowerSet(mRatPowerSet[i]);
         mRatList[i]->setRatCheckState(false);
         mRatList[i]->setRatSendState(false);
-        if(!(utils::isC2KSupport())){
-            if (i == 4) {
-                break;
-            }
-        }
     }
 }
 void RfDesenseTxTest::save(int index) {
diff --git a/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTest.h b/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTest.h
old mode 100644
new mode 100755
index 5f9d0b2..8250064
--- a/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTest.h
+++ b/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTest.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -73,12 +74,14 @@
     static const int STATE_STOPPED;
 
     static const int MSG_START_TX;
+    static const int MSG_CONTINUE_TX;
     static const int MSG_NEXT_RAT;
     static const int MSG_READ_POWER;
     static const int MSG_EWMPOLICY_TDSCDMA;
     static const int MSG_EWMPOLICY_WCDMA;
     static const int MSG_ECSRA;
     static const int MSG_SWITCH_RAT_DONE;
+    static const int MSG_NR_READ_POWER;
 
     static const std::string KEY_GSM_ATCMD;
     static const std::string KEY_TDSCDMA_ATCMD;
@@ -97,6 +100,7 @@
     static const std::string DEFAULT_WCDMA_ATCMD;
     static const std::string DEFAULT_LTE_FDD_ATCMD;
     static const std::string DEFAULT_LTE_TDD_ATCMD;
+    static const std::string DEFAULT_NR_ATCMD;
     static const std::string DEFAULT_CDMA_EVDO_ATCMD;
     static const std::string DEFAULT_CDMA_1X_ATCMD;
     static const std::string DEFAULT_CDMA_EVDO_ATCMD_93before;
@@ -122,13 +126,15 @@
     const int MSG_SET = 1;
     int mCurrentFlag = 0;
     std::vector<std::string> mCurrentSettingsValues;
-    static const int INDEX_GSM = 0;
-    static const int INDEX_TDSCDMA = 1;
-    static const int INDEX_WCDMA = 2;
-    static const int INDEX_LTE_FDD = 3;
-    static const int INDEX_LTE_TDD = 4;
-    static const int INDEX_CDMA_EVDO = 5;
-    static const int INDEX_CDMA_1X = 6;
+
+    static int INDEX_GSM;
+    static int INDEX_TDSCDMA;
+    static int INDEX_WCDMA;
+    static int INDEX_LTE_FDD;
+    static int INDEX_LTE_TDD;
+    static int INDEX_NR;
+    static int INDEX_CDMA_EVDO;
+    static int INDEX_CDMA_1X;
 
     static constexpr int INDEX_GSM_SUB_BAND = 0;
     static constexpr int INDEX_GSM_SUB_CHANNEL = 1;
@@ -166,6 +172,17 @@
     static constexpr int INDEX_TDD_SUB_MCS = 8;
     static constexpr int INDEX_TDD_SUB_POWER = 9;
 
+    static constexpr int INDEX_NR_SUB_MODE = 0;
+    static constexpr int INDEX_NR_SUB_BAND = 1;
+    static constexpr int INDEX_NR_SUB_BANDWIDTH = 2;
+    static constexpr int INDEX_NR_SUB_FREQ = 3;
+    static constexpr int INDEX_NR_SUB_START = 4;
+    static constexpr int INDEX_NR_SUB_LENGTH = 5;
+    static constexpr int INDEX_NR_SUB_MCS = 6;
+    static constexpr int INDEX_NR_SUB_SCS = 7;
+    static constexpr int INDEX_NR_SUB_POWER = 8;
+    static constexpr int INDEX_NR_SUB_CONFIG = 9;
+
     class RequestHandleThread: public Thread {
     public:
         RequestHandleThread(RfDesenseTxTest* tx);
@@ -238,11 +255,14 @@
     void handle_wcdma_para(const std::string& name, int last_pos,const std::string& sub_name);
     void handle_lte_fdd_para(const std::string& name, int last_pos,const std::string& sub_name);
     void handle_lte_tdd_para(const std::string& name, int last_pos,const std::string& sub_name);
+    void handle_nr_para(const std::string& name, int last_pos,const std::string& sub_name);
     void handle_cdma_evdo_para(const std::string& name, int last_pos,const std::string& sub_name);
     void handle_cdma_1X_para(const std::string& name, int last_pos,const std::string& sub_name);
     bool handle_show_default(const std::string& standard);
     bool handle_para(int len, int classid, int propertyid, int operatorid,const std::string& standard, int* item);
     bool handle_start(const std::string& standard);
+    void parse_read_power(std::string response);
+    char* msg_type_to_str(int msgType);
 
     static int mState;
     static std::string str_msg;
diff --git a/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTestGsm.cpp b/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTestGsm.cpp
old mode 100644
new mode 100755
index e792f7b..8bbe469
--- a/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTestGsm.cpp
+++ b/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTestGsm.cpp
@@ -285,8 +285,13 @@
 
 void RfDesenseTxTestGsm::show_default() {
     int band_index = utils::find_index(band_values, band);
+    if (band_index > 5 || band_index < 0) {
+        LOG_W(LOG_TAG, "show_default, band_index=%d, out of range\n" , band_index);
+        band_index = 0;
+    }
+
     int pattern_index = std::stoi(pattern);
-    std::string temp = "GSM parameter: Band: " + std::string(rfdesense_gsm_band[band_index > 5 ? 0 : band_index].name) +
+    std::string temp = "GSM parameter: Band: " + std::string(rfdesense_gsm_band[band_index].name) +
             ", Channel(ARFCN): " + channel + ", Power Level: " + power + ", AFC: " + afc + ", TSC: " + tsc +
             ", PATTERN: " + std::string(rfdesense_gsm_pattern[pattern_index > 6 ? 0 : pattern_index].name);
     emResultNotifyWithDone(temp);
diff --git a/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTestNr.cpp b/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTestNr.cpp
new file mode 100755
index 0000000..1d49366
--- /dev/null
+++ b/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTestNr.cpp
@@ -0,0 +1,412 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* 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) 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 "rfdesense/RfDesenseTxTestNr.h"
+
+#include <algorithm>
+#include <iterator>
+#include <stdexcept>
+
+#include "rfdesense/RfDesenseTxTestBase.h"
+#include "util/log_extra.h"
+#include "em.h"
+
+#undef LOG_TAG
+#define LOG_TAG "EM_RfDesenseTxTestNr"
+
+const int RfDesenseTxTestNr::INDEX_TX_MODE = 0;
+const int RfDesenseTxTestNr::INDEX_BAND = 1;
+const int RfDesenseTxTestNr::INDEX_BAND_WIDTH = 2;
+const int RfDesenseTxTestNr::INDEX_FREQ = 3;
+const int RfDesenseTxTestNr::INDEX_VRB_START = 4;
+const int RfDesenseTxTestNr::INDEX_VRB_LENGTH = 5;
+const int RfDesenseTxTestNr::INDEX_MCS = 6;
+const int RfDesenseTxTestNr::INDEX_SCS = 7;
+const int RfDesenseTxTestNr::INDEX_POWER = 8;
+const int RfDesenseTxTestNr::INDEX_TDD_SLOT_CONFIG = 9;
+const int RfDesenseTxTestNr::INDEX_ANT_MODE = 10;
+
+std::string RfDesenseTxTestNr::mTxMode="";
+int RfDesenseTxTestNr::mBandIdx=0;
+std::string RfDesenseTxTestNr::mBand="";
+int RfDesenseTxTestNr::mBandWidthIdx=0;
+std::string RfDesenseTxTestNr::mBandWidth="";
+std::string RfDesenseTxTestNr::mFreq="";
+std::string RfDesenseTxTestNr::mVrbStart="";
+std::string RfDesenseTxTestNr::mVrbLength="";
+std::string RfDesenseTxTestNr::mMcs="";
+std::string RfDesenseTxTestNr::mScs="";
+std::string RfDesenseTxTestNr::mPower="";
+std::string RfDesenseTxTestNr::mTddSlotConfig="";
+int RfDesenseTxTestNr::mAntMode=0;
+
+std::shared_ptr<RfDesenseTxTestNr> RfDesenseTxTestNr::m_instance;
+std::mutex RfDesenseTxTestNr::mutex;
+
+std::string RfDesenseTxTestNr::DEFAULT_TX_MODE = "0";//TONE
+int RfDesenseTxTestNr::DEFAULT_BAND_IDX = 0;//BAND1
+int RfDesenseTxTestNr::DEFAULT_BAND_WIDTH_IDX = 1;//10MHZ
+std::string RfDesenseTxTestNr::DEFAULT_NR_FREQ = "1950000";
+std::string RfDesenseTxTestNr::DEFAULT_VRB_START = "0";
+std::string RfDesenseTxTestNr::DEFAULT_VRB_LENGTH = "1";
+std::string RfDesenseTxTestNr::DEFAULT_MCS = "0";//DFT-S BPSK
+std::string RfDesenseTxTestNr::DEFAULT_SCS_CONFIG = "0";//15KHZ
+std::string RfDesenseTxTestNr::DEFAULT_POWER = "23";
+std::string RfDesenseTxTestNr::DEFAULT_TDD_SLOT_CONFIG = "1";
+int RfDesenseTxTestNr::DEFAULT_ANT_MODE= 0;
+
+int VRB_START_MIN = 0;
+int VRB_START_MAX = 272;
+int VRB_LENGTH_MIN = 0;
+int VRB_LENGTH_MAX = 273;
+int POWER_MIN = -50;
+int POWER_MAX_PUSCH = 23;
+int POWER_MAX_TONE = 26;
+int TDD_SLOT_CONFIG_MIN = 1;
+int TDD_SLOT_CONFIG_MAX = 44;
+
+const std::vector<std::string> RfDesenseTxTestNr::mBandMapping = {"1", "3", "7", "8", "20", "28", "38", "41", "77", "78", "79"};
+const std::vector<std::string> RfDesenseTxTestNr::mBandWidthMapping = {"5000", "10000", "15000", "20000", "25000", "30000",
+        "35000", "40000", "45000", "50000", "55000", "60000", "65000", "70000", "75000", "80000", "85000", "90000",
+        "95000", "100000"};
+
+RfDesenseTxTestNr::RfDesenseTxTestNr() {
+    LOG_D(LOG_TAG, "RfDesenseTxTestNr()");
+
+    mTxMode = DEFAULT_TX_MODE;
+    mBandIdx = DEFAULT_BAND_IDX;
+    mBand = mBandMapping[mBandIdx];
+    mBandWidthIdx = DEFAULT_BAND_WIDTH_IDX;
+    mBandWidth = mBandWidthMapping[mBandWidthIdx];
+    mFreq = DEFAULT_NR_FREQ;
+    mVrbStart = DEFAULT_VRB_START;
+    mVrbLength = DEFAULT_VRB_LENGTH;
+    mMcs = DEFAULT_MCS;
+    mScs = DEFAULT_SCS_CONFIG;
+    mPower = DEFAULT_POWER;
+    mTddSlotConfig = DEFAULT_TDD_SLOT_CONFIG;
+    mAntMode = DEFAULT_ANT_MODE;
+}
+
+void RfDesenseTxTestNr::show_default() {
+    std::string str;
+    std::string tx_mode_str(rfdesense_nr_tx_mode[std::stoi(mTxMode)].name);
+    std::string band_str(rfdesense_nr_band[mBandIdx].name);
+    std::string band_width_str(rfdesense_nr_bandwidth[mBandWidthIdx].name);
+    std::string mcs_str(rfdesense_nr_mcs[std::stoi(mMcs)].name);
+    std::string scs_str(rfdesense_nr_scs[std::stoi(mScs)].name);
+
+    str = "\nTx mode: " + tx_mode_str
+            + "\nBand: " + band_str
+            + "\nUL Bandwidth: " + band_width_str
+            + "\nUL Freq(1kHz): " + mFreq
+            + "\nVRB Start(0~272): " + mVrbStart
+            + "\nVRB Length(0~273): " + mVrbLength
+            + "\nMCS: " + mcs_str
+            + "\nSCS: " + scs_str
+            + "\nPower Level(dBm)(-50-23): " + mPower
+            + "\nTDD Slot Config: " + mTddSlotConfig;
+
+    LOG_D(LOG_TAG, "show_default, str=%s", str.c_str());
+    emResultNotifyWithDone(str);
+}
+
+RfDesenseTxTestNr::~RfDesenseTxTestNr() {
+    // TODO Auto-generated destructor stub
+}
+
+std::shared_ptr<RfDesenseTxTestNr> RfDesenseTxTestNr::get_instance() {
+    if(!m_instance) {
+        mutex.lock();
+        if(!m_instance) {
+            m_instance = std::make_shared<RfDesenseTxTestNr>();
+        }
+        mutex.unlock();
+    }
+    return m_instance;
+}
+
+std::string RfDesenseTxTestNr::get_command() {
+    std::string command;
+
+    //Tone mode
+    if (mTxMode == "0") {
+        command = "AT+EGMC=1,\"NrForcedTx\",2,";
+        command += mBand + "," + mFreq + "," + mPower;
+
+    //PUSCH mode
+    } else {
+        command = "AT+EGMC=1,\"NrForcedTx\",1,";
+        command += mBand + "," + mBandWidth + "," + mFreq + "," +
+                mVrbStart + "," + mVrbLength + "," + mMcs + ","
+                + mScs + "," + mPower + "," + mTddSlotConfig;
+    }
+
+    LOG_D(LOG_TAG, "NR command: %s\n", command.c_str());
+    return command;
+}
+
+std::string RfDesenseTxTestNr::get_band() {
+    return mBand;
+}
+std::string RfDesenseTxTestNr::get_power() {
+    return mPower;
+}
+
+std::string RfDesenseTxTestNr::get_ant_mode() {
+    std::string ant_str;
+    int antStatustx = DEFAULT_ANT_MODE, antStatusrx = DEFAULT_ANT_MODE;
+
+    if (mAntMode == 1)
+        ant_str = utils::format("AT+EGMC=1,\"NrForceTxRx\",1,%d,%d,0", antStatustx, antStatusrx);
+    else {
+        ant_str = utils::format("AT+EGMC=1,\"NrForceTxRx\",0,,,0");
+    }
+
+    LOG_D(LOG_TAG, "ant_str: %s\n", ant_str.c_str());
+    return ant_str;
+}
+
+bool RfDesenseTxTestNr::set_tx_mode(int mode){
+    std::string s;
+    if(mode !=0 && mode != 1) {
+        s = utils::format("set_mode: mode(%d) is out of range", mode);
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    mTxMode = std::to_string(mode);
+    // For PUSCH mode, we adjust parameter to pass tx
+    if (mTxMode == "1") {
+        mBandIdx = 7;
+        mBand = mBandMapping[mBandIdx]; //Band 41
+        mFreq = "2593010";
+        LOG_D(LOG_TAG, "For PUSCH mode, adjust parameter band=%s, freq=%s", mBand.c_str(), mFreq.c_str());
+    }
+
+    std::string tx_mode_str(rfdesense_nr_tx_mode[std::stoi(mTxMode)].name);
+    em_result_notify_ok("Tx mode=" + tx_mode_str);
+
+    return true;
+}
+
+bool RfDesenseTxTestNr::set_band_idx(int bandidx){
+    std::string s;
+
+    if(bandidx < 0 || bandidx >= mBandMapping.size()){
+        s = utils::format("set_band_idx: bandidx(%d) is out of range", bandidx);
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    mBandIdx = bandidx;
+    mBand = mBandMapping[bandidx];
+
+    em_result_notify_ok("mBand=" + mBand);
+    return true;
+}
+
+bool RfDesenseTxTestNr::set_bandwith_idx(int bandwidthidx){
+    std::string s;
+    if (bandwidthidx < 0 || bandwidthidx >= mBandWidthMapping.size()) {
+        s = utils::format("set_bandwith_idx value range is [%d, %d], input value is %d", 0, mBandWidthMapping.size(), bandwidthidx);
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    mBandWidthIdx = bandwidthidx;
+    mBandWidth = mBandWidthMapping[mBandWidthIdx];
+
+    em_result_notify_ok("mBandWidth=" + mBandWidth);
+    return true;
+}
+
+bool RfDesenseTxTestNr::set_freq(std::string str){
+    mFreq = str;
+    em_result_notify_ok("freq=" + mFreq);
+    return true;
+}
+
+bool RfDesenseTxTestNr::set_vrb_start(std::string start){
+    std::string s;
+    int value = -1;
+    try {
+        value = std::stoi(start);
+    } catch (std::invalid_argument &err) {
+        s = utils::format("set_vrb_start, vrb_start=%s is invalid, reason: %s", start.c_str(), err.what());
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    if (value < VRB_START_MIN || value > VRB_START_MAX) {
+        s = utils::format("set_vrb_start value range is [%d, %d], input value is %d", VRB_START_MIN, VRB_START_MAX, value);
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    mVrbStart = start;
+    em_result_notify_ok("vrb_start=" + mVrbStart);
+    return true;
+}
+
+bool RfDesenseTxTestNr::set_vrb_length(std::string length){
+    std::string s;
+    int value = -1;
+    try {
+        value = std::stoi(length);
+    } catch (std::invalid_argument &err) {
+        s = utils::format("set_vrb_length, vrb_length=%s is invalid, reason: %s", length.c_str(), err.what());
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    if (value < VRB_LENGTH_MIN || value > VRB_LENGTH_MAX) {
+        s = utils::format("set_vrb_length value range is [%d, %d], input value is %d", VRB_LENGTH_MIN, VRB_LENGTH_MAX, value);
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    mVrbLength = length;
+    em_result_notify_ok("vrb_length=" + mVrbLength);
+    return true;
+}
+
+bool RfDesenseTxTestNr::set_mcs(int mcs) {
+    if (mcs < 0 || mcs > 8) {
+        std::string s;
+        s = utils::format("check_mcs value range is [%d, %d], input value is %d", 0, 8, mcs);
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    mMcs = std::to_string(mcs);
+    em_result_notify_ok(std::string("mcs=") + rfdesense_nr_mcs[mcs].name);
+    return true;
+}
+
+bool RfDesenseTxTestNr::set_scs(int scs) {
+    if (scs < 0 || scs > 4) {
+        std::string s;
+        s = utils::format("check_mcs value range is [%d, %d], input value is %d", 0, 4, scs);
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    mScs = std::to_string(scs);
+    em_result_notify_ok(std::string("scs=") + rfdesense_nr_scs[scs].name);
+    return true;
+}
+
+bool RfDesenseTxTestNr::set_power(std::string power){
+    std::string s;
+    int value = -1, powerMax = POWER_MAX_TONE;
+
+    powerMax = (mTxMode == "0")? POWER_MAX_TONE: POWER_MAX_PUSCH;
+
+    try {
+        value = std::stoi(power);
+    } catch (std::invalid_argument &err) {
+        s = utils::format("set_power,check_power(%s) is invalid, reason: %s", power.c_str(), err.what());
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    if (value < POWER_MIN || value > powerMax) {
+        s = utils::format("check_power value range is [%d, %d], input value is %d", POWER_MIN, powerMax, value);
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    mPower = power;
+    em_result_notify_ok("power=" + power);
+    return true;
+}
+
+bool RfDesenseTxTestNr::set_tdd_slot_config(std::string config){
+    std::string s;
+    int value = -1;
+
+    try {
+        value = std::stoi(config);
+    } catch (std::invalid_argument &err) {
+        s = utils::format("set_tdd_slot_config, config(%s) is invalid, reason: %s", config.c_str(), err.what());
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    if(value < TDD_SLOT_CONFIG_MIN || value > TDD_SLOT_CONFIG_MAX){
+        s = utils::format("check_tdd_config value range is [%d, %d], input value is %d", TDD_SLOT_CONFIG_MIN, TDD_SLOT_CONFIG_MAX, value);
+        LOG_E(LOG_TAG, "%s", s.c_str());
+        em_result_notify_fail(s);
+        return false;
+    }
+
+    mTddSlotConfig = config;
+    em_result_notify_ok("tdd_config=" + mTddSlotConfig);
+    return true;
+}
+
+void RfDesenseTxTestNr::show_freq(){
+    emResultNotifyWithDone("UL Freq(1kHZ): " + mFreq);
+}
+
+void RfDesenseTxTestNr::show_start(){
+    emResultNotifyWithDone("VRB Start(0~272): " + mVrbStart);
+}
+
+void RfDesenseTxTestNr::show_length(){
+    emResultNotifyWithDone("VRB Length(0~273): " + mVrbLength);
+}
+
+void RfDesenseTxTestNr::show_power(){
+    emResultNotifyWithDone("Power Level(dBm)(-50~23): " + mPower);
+}
+
+void RfDesenseTxTestNr::show_config(){
+    emResultNotifyWithDone("TDD slot config(1~44): " + mTddSlotConfig);
+}
+
diff --git a/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTestNr.h b/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTestNr.h
new file mode 100755
index 0000000..9026bf9
--- /dev/null
+++ b/src/telephony/tel-demo/src/em/rfdesense/RfDesenseTxTestNr.h
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: MediaTekProprietary
+/* 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) 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.
+ */
+
+#ifndef RFDESENSETXTESTNR_H_
+#define RFDESENSETXTESTNR_H_
+
+#include <string>
+#include <vector>
+#include <map>
+#include <memory>
+#include <mutex>
+
+#include "util/utils.h"
+
+class RfDesenseTxTestNr {
+public:
+    RfDesenseTxTestNr();
+    virtual ~RfDesenseTxTestNr();
+
+    static std::shared_ptr<RfDesenseTxTestNr> get_instance();
+
+    void show_default();
+    std::string get_command();
+    std::string get_band();
+    std::string get_power();
+    std::string get_ant_mode();
+
+    bool set_tx_mode(int mode);
+    bool set_band_idx(int bandidx);
+    bool set_bandwith_idx(int bandwidthidx);
+    bool set_freq(std::string freq);
+    bool set_vrb_start(std::string start);
+    bool set_vrb_length(std::string length);
+    bool set_mcs(int mcs);
+    bool set_scs(int scs);
+    bool set_power(std::string power);
+    bool set_tdd_slot_config(std::string config);
+
+    void show_freq();
+    void show_start();
+    void show_length();
+    void show_power();
+    void show_config();
+
+private:
+    static std::shared_ptr<RfDesenseTxTestNr> m_instance;
+    static std::mutex mutex;
+    std::string command;
+
+    static const int INDEX_TX_MODE;
+    static const int INDEX_BAND;
+    static const int INDEX_BAND_WIDTH;
+    static const int INDEX_FREQ;
+    static const int INDEX_VRB_START;
+    static const int INDEX_VRB_LENGTH;
+    static const int INDEX_MCS;
+    static const int INDEX_SCS;
+    static const int INDEX_POWER;
+    static const int INDEX_TDD_SLOT_CONFIG;
+    static const int INDEX_ANT_MODE;
+
+    static std::string DEFAULT_TX_MODE;
+    static int DEFAULT_BAND_IDX;
+    static std::string DEFAULT_BAND;
+    static int DEFAULT_BAND_WIDTH_IDX;
+    static std::string DEFAULT_BAND_WIDTH;//40MHZ
+    static std::string DEFAULT_NR_FREQ;
+    static std::string DEFAULT_VRB_START;
+    static std::string DEFAULT_VRB_LENGTH;
+    static std::string DEFAULT_MCS;
+    static std::string DEFAULT_SCS_CONFIG;
+    static std::string DEFAULT_POWER;
+    static std::string DEFAULT_TDD_SLOT_CONFIG;
+    static int DEFAULT_ANT_MODE;
+
+    static std::string mTxMode;
+    static int mBandIdx;
+    static std::string mBand;
+    static int mBandWidthIdx;
+    static std::string mBandWidth;
+    static std::string mFreq;
+    static std::string mVrbStart;
+    static std::string mVrbLength;
+    static std::string mMcs;
+    static std::string mScs;
+    static std::string mPower;
+    static std::string mTddSlotConfig;
+    static int mAntMode;
+
+    static const std::vector<std::string> mBandMapping;
+    static const std::vector<std::string> mBandWidthMapping;
+};
+
+#endif /* RFDESENSETXTESTNR_H_ */
diff --git a/src/telephony/tel-demo/src/makefile b/src/telephony/tel-demo/src/makefile
old mode 100644
new mode 100755
index 2ce4a68..fe20046
--- a/src/telephony/tel-demo/src/makefile
+++ b/src/telephony/tel-demo/src/makefile
@@ -38,6 +38,7 @@
 
 ifeq ($(strip $(TARGET_PLATFORM)), mt2735)
 LOCAL_CFLAGS += -DTARGET_PLATFORM_MT2735
+LOCAL_CFLAGS += -DMD_97_SUPPORT
 LOCAL_CFLAGS += -DBASELIB_DIR_LIB64 -DTELEMATIC_5G_SUPPORT
 endif
 
diff --git a/src/telephony/tel-demo/src/network.cpp b/src/telephony/tel-demo/src/network.cpp
old mode 100644
new mode 100755
index 418e0d2..17ba150
--- a/src/telephony/tel-demo/src/network.cpp
+++ b/src/telephony/tel-demo/src/network.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -399,19 +400,19 @@
 
 //RIL_REQUEST_QUERY_AVAILABLE_NETWORKS_WITH_ACT
 /**
-* ”data” is NULL
-*”response” is const char ** that should be an arry of n*6, where n is the number of available networks
+* "data" is NULL
+*"response" is const char ** that should be an arry of n*6, where n is the number of available networks
 *
 *((const char **)response)[n+0] is long alpha ONS or EONS
 *((const char **)response)[n+1] is short alpha ONS or EONS
 *((const char **)response)[n+2] is 5 or 6 digit numeric code
 *((const char **)response)[n+3] is a string value of :
-*  “unkonwn”
-*  “available”
-*  “current”
-*  “forbidden”
+*  "unkonwn"
+*  "available"
+*  "current"
+*  "forbidden"
 *((const char **)response)[n+4] is lac
-*((const char **)response)[n+5] is a string value of the Act: “2G”, “3G”, “4G”
+*((const char **)response)[n+5] is a string value of the Act: "2G", "3G", "4G"
 **/
 int getAvailableNetworksWithAct(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI) {
     android::Parcel p;
diff --git a/src/telephony/tel-demo/src/powerManager.cpp b/src/telephony/tel-demo/src/powerManager.cpp
old mode 100644
new mode 100755
index b3a33fd..9a2551e
--- a/src/telephony/tel-demo/src/powerManager.cpp
+++ b/src/telephony/tel-demo/src/powerManager.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /*
 * Copyright Statement:
 *
diff --git a/src/telephony/tel-demo/src/ril.cpp b/src/telephony/tel-demo/src/ril.cpp
old mode 100644
new mode 100755
index 53b4766..b8ddac1
--- a/src/telephony/tel-demo/src/ril.cpp
+++ b/src/telephony/tel-demo/src/ril.cpp
@@ -6035,7 +6035,7 @@
 
 #ifdef MEMSET_FREED
     memsetString(eCallReqMsg.address);
-    memset(eCallReqMsg.msd_data, 0, eCallReqMsg.length);
+    memset(eCallReqMsg.msd_data, 0, digitLimit);
 #endif
 
     free(eCallReqMsg.address);
diff --git a/src/telephony/tel-demo/src/sms/gsm/sms_pdu.cpp b/src/telephony/tel-demo/src/sms/gsm/sms_pdu.cpp
old mode 100644
new mode 100755
index 81d07e3..8d9c5fa
--- a/src/telephony/tel-demo/src/sms/gsm/sms_pdu.cpp
+++ b/src/telephony/tel-demo/src/sms/gsm/sms_pdu.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephony/tel-demo/src/ss.cpp b/src/telephony/tel-demo/src/ss.cpp
old mode 100644
new mode 100755
index 2d3f50f..3b726ad
--- a/src/telephony/tel-demo/src/ss.cpp
+++ b/src/telephony/tel-demo/src/ss.cpp
@@ -1,4 +1,5 @@
- /*
+//SPDX-License-Identifier: MediaTekProprietary
+/*
  * Copyright (C) 2006 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/src/telephony/tel-demo/src/util/ModemCategory.cpp b/src/telephony/tel-demo/src/util/ModemCategory.cpp
old mode 100644
new mode 100755
index b9a79ec..31ef0b6
--- a/src/telephony/tel-demo/src/util/ModemCategory.cpp
+++ b/src/telephony/tel-demo/src/util/ModemCategory.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -106,6 +107,10 @@
     return (RatConfiguration::isTdscdmaSupported());
 }
 
+bool ModemCategory::isNrSupport() {
+    return (RatConfiguration::isNrSupported());
+}
+
 bool ModemCategory::isCapabilitySim(int type) {
     int mainCard = Radio_capability_switch_util::get_main_capability_phone_id();
     bool isCapability = (type == mainCard) ? true : false;
diff --git a/src/telephony/tel-demo/src/util/ModemCategory.h b/src/telephony/tel-demo/src/util/ModemCategory.h
old mode 100644
new mode 100755
index 847a9d8..4ce826d
--- a/src/telephony/tel-demo/src/util/ModemCategory.h
+++ b/src/telephony/tel-demo/src/util/ModemCategory.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -58,6 +59,7 @@
     static bool isGsmSupport();
     static bool isWcdmaSupport();
     static bool isTdscdmaSupport();
+    static bool isNrSupport();
     static bool isCapabilitySim(int type);
     static bool checkViceSimCapability(int simType, int capability);
 };
diff --git a/src/telephony/tel-demo/src/util/RatConfiguration.cpp b/src/telephony/tel-demo/src/util/RatConfiguration.cpp
old mode 100644
new mode 100755
index 60fb5af..8337193
--- a/src/telephony/tel-demo/src/util/RatConfiguration.cpp
+++ b/src/telephony/tel-demo/src/util/RatConfiguration.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -49,6 +50,7 @@
         "ro.boot.opt_using_default";
 /* the valid characters of the human-readable rat config */
 /* the defination must be sync with ratconfig.c */
+const std::string RatConfiguration::NR = "N";
 const std::string RatConfiguration::CDMA = "C";
 const std::string RatConfiguration::LteFdd = "Lf";
 const std::string RatConfiguration::LteTdd = "Lt";
@@ -59,6 +61,7 @@
 
 /* bitmask */
 /* the defination must be sync with ratconfig.c */
+const int RatConfiguration::MASK_NR = (1 << 6);
 const int RatConfiguration::MASK_CDMA = (1 << 5);
 const int RatConfiguration::MASK_LteFdd = (1 << 4);
 const int RatConfiguration::MASK_LteTdd = (1 << 3);
@@ -117,6 +120,9 @@
     if (rat.find(GSM) != std::string::npos) {
         iRat = iRat | MASK_GSM;
     }
+    if (rat.find(NR) != std::string::npos) {
+        iRat = iRat | MASK_NR;
+    }
     return iRat;
 }
 
@@ -192,6 +198,9 @@
  */
 std::string RatConfiguration::ratToString(int iRat) {
     std::string rat = "";
+    if ((iRat & MASK_NR) == MASK_NR) {
+        rat += (DELIMITER + NR);
+    }
     if ((iRat & MASK_CDMA) == MASK_CDMA) {
         rat += (DELIMITER + CDMA);
     }
@@ -283,6 +292,16 @@
 }
 
 /*
+ * check NR suppport
+ * @return boolean, cases as following
+ *       true, rat is active and project config supports it.
+ *       false, rat is inactive no matter project config supports.
+ */
+bool RatConfiguration::isNrSupported() {
+    return (getMaxRat() & getRatConfig() & MASK_NR) == MASK_NR ? true : false;
+}
+
+/*
  * get the active rat
  * @return String, the rat in format like C/Lf/Lt/T/W/G
  */
diff --git a/src/telephony/tel-demo/src/util/RatConfiguration.h b/src/telephony/tel-demo/src/util/RatConfiguration.h
old mode 100644
new mode 100755
index 1a941fe..fd87693
--- a/src/telephony/tel-demo/src/util/RatConfiguration.h
+++ b/src/telephony/tel-demo/src/util/RatConfiguration.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -47,6 +48,7 @@
     static const std::string PROPERTY_IS_USING_DEFAULT_CONFIG;
     /* the valid characters of the human-readable rat config */
     /* the defination must be sync with ratconfig.c */
+    static const std::string NR;
     static const std::string CDMA;
     static const std::string LteFdd;
     static const std::string LteTdd;
@@ -57,6 +59,7 @@
 
     /* bitmask */
     /* the defination must be sync with ratconfig.c */
+    static const int MASK_NR;
     static const int MASK_CDMA;
     static const int MASK_LteFdd;
     static const int MASK_LteTdd;
@@ -92,6 +95,7 @@
     static bool isWcdmaSupported();
     static bool isTdscdmaSupported();
     static bool isGsmSupported();
+    static bool isNrSupported();
     static std::string getActiveRatConfig();
 
 };
diff --git a/src/telephony/tel-demo/src/util/utils.cpp b/src/telephony/tel-demo/src/util/utils.cpp
old mode 100644
new mode 100755
index a430d10..2a301b9
--- a/src/telephony/tel-demo/src/util/utils.cpp
+++ b/src/telephony/tel-demo/src/util/utils.cpp
@@ -1,3 +1,4 @@
+ // SPDX-License-Identifier: MediaTekProprietary
  /*
  * Copyright (C) 2006 The Android Open Source Project
  *
@@ -46,6 +47,22 @@
     // TODO Auto-generated destructor stub
 }
 
+bool utils::is93ModemAndAbove() {
+#if defined(MD_93_SUPPORT) || defined(MD_97_SUPPORT)
+    return true;
+#else
+    return false;
+#endif
+}
+
+bool utils::is97Modem() {
+#ifdef MD_97_SUPPORT
+    return true;
+#else
+    return false;
+#endif
+}
+
 bool utils::is93Modem() {
 #ifdef MD_93_SUPPORT
     return true;
@@ -87,6 +104,14 @@
 #endif
 }
 
+bool utils::isMt2735(){
+#ifdef TARGET_PLATFORM_MT2735
+    return true;
+#else
+    return false;
+#endif
+}
+
 bool utils::is_support_dsds(){
 #ifdef MODE_DSDS
     return true;
@@ -234,6 +259,19 @@
     }
 }
 
+std::string utils::addZeroForNum(std::string const &str, int strLength) {
+    std::string result_str;
+    result_str.append(str);
+
+    while (result_str.length() < strLength) {
+        result_str.append("0");
+    }
+
+    LOG_D(LOG_TAG,"addZeroForNum- result_str=%s", result_str.c_str());
+
+    return result_str;
+}
+
 void utils::setMSimProperty(int phoneId, char *pPropertyName, char *pUpdateValue) {
     #define MAX_PHONE_NUM 10
     #define MIN(a,b) ((a)<(b) ? (a) : (b))
diff --git a/src/telephony/tel-demo/src/util/utils.h b/src/telephony/tel-demo/src/util/utils.h
old mode 100644
new mode 100755
index 83a46a1..593a626
--- a/src/telephony/tel-demo/src/util/utils.h
+++ b/src/telephony/tel-demo/src/util/utils.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -45,17 +46,21 @@
 public:
     utils();
     virtual ~utils();
+    static bool is97Modem();
+    static bool is93ModemAndAbove();
     static bool is93Modem();
     static bool is90Modem();
     static bool isC2KSupport();
     static bool isMt2635();
     static bool isMt2731();
+    static bool isMt2735();
     static bool is_support_dsds();
     static bool is_suppport_dsss();
     static int find_index(std::vector<std::string> v, std::string& str);
     static std::string format(const std::string& format, ...);
     static void tokenize(std::string const &str, const char delim, std::vector<std::string> &out);
     static void tokenize(std::string const &str, const char* delim, std::vector<std::string> &out);
+    static std::string addZeroForNum(std::string const &str, int strLength);
     static int mtk_property_set(const char *key, const char *value);
     static int mtk_property_get(const char *key, char *value, const char *default_value);
     static bool mtk_property_get_bool(const char *key, bool default_value);
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/CMakeLists.txt b/src/telephonyware/3.0/hardware/ril/fusion/libril/CMakeLists.txt
old mode 100644
new mode 100755
index 09c4886..01e30d6
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/CMakeLists.txt
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/CMakeLists.txt
@@ -20,6 +20,7 @@
 include_directories("${CMAKE_CURRENT_SOURCE_DIR}/rilmipc/telephony/radio/")
 include_directories("${CMAKE_CURRENT_SOURCE_DIR}/rilmipc/telephony/sim/")
 include_directories("${CMAKE_CURRENT_SOURCE_DIR}/rilmipc/telephony/call/")
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}/rilmipc/telephony/ecall/")
 include_directories("${CMAKE_CURRENT_SOURCE_DIR}/rilmipc/telephony/ss/")
 include_directories("${CMAKE_CURRENT_SOURCE_DIR}/rilmipc/telephony/sms/")
 include_directories("${CMAKE_CURRENT_SOURCE_DIR}/rilmipc/telephony/stk/")
@@ -76,6 +77,7 @@
 	rilmipc/telephony/sim/RpSimController.cpp
 	rilmipc/telephony/call/GsmUtil.cpp
 	rilmipc/telephony/call/RpCallController.cpp
+	rilmipc/telephony/ecall/RpEcallController.cpp
 	rilmipc/telephony/ss/RpSsController.cpp
 	rilmipc/telephony/ss/RpSsUtils.cpp
 	rilmipc/telephony/sms/RpSmsController.cpp
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/ril.cpp b/src/telephonyware/3.0/hardware/ril/fusion/libril/ril.cpp
old mode 100644
new mode 100755
index d439436..17802d4
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/ril.cpp
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/ril.cpp
@@ -728,11 +728,6 @@
     return rild;
 }
 
-extern "C"
-void RIL_setRilSocketName(const char * s) {
-    strncpy(rild, s, MAX_SOCKET_NAME_LENGTH);
-}
-
 static char *
 strdupReadString(Parcel &p) {
     size_t stringlen;
@@ -8593,9 +8588,6 @@
     status = p.readInt32(&t);
     eCallReqMsg.ecall_variant = (RIL_ECall_Variant)t;
 
-    status = p.readInt32(&t);
-    eCallReqMsg.ivs_mode = (RIL_ECall_Ivs_Config_Mode)t;
-
     eCallReqMsg.address = strdupReadString(p);
 
     //debug
@@ -8620,8 +8612,8 @@
     }
 
     startRequest;
-    appendPrintBuf("%secall_cat=%d,ecall_variant=%d,ivs_mode=%d,address=%s,length=%d", printBuf,
-        eCallReqMsg.ecall_cat, eCallReqMsg.ecall_variant, eCallReqMsg.ivs_mode, (char*)eCallReqMsg.address,\
+    appendPrintBuf("%secall_cat=%d,ecall_variant=%d,address=%s,length=%d", printBuf,
+        eCallReqMsg.ecall_cat, eCallReqMsg.ecall_variant, (char*)eCallReqMsg.address,\
         eCallReqMsg.length
         );
     closeRequest;
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/framework/core/RfxControllerFactory.cpp b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/framework/core/RfxControllerFactory.cpp
old mode 100644
new mode 100755
index 9355c16..22b783d
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/framework/core/RfxControllerFactory.cpp
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/framework/core/RfxControllerFactory.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -56,6 +57,7 @@
 #include "RpStkController.h"
 #include "RpNwController.h"
 #include "RpImsController.h"
+#include "RpEcallController.h"
 
 /*****************************************************************************
  * Define
@@ -80,6 +82,7 @@
     RFX_CONTROLLER_CREATION_ENTRY(RpStkController),
     RFX_CONTROLLER_CREATION_ENTRY(RpNwController),
     RFX_CONTROLLER_CREATION_ENTRY(RpImsController),
+    RFX_CONTROLLER_CREATION_ENTRY(RpEcallController),
 };
 
 const RfxCreateControllerFuncptr RfxControllerFactory::s_non_slot_controllers[] = {
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RmcDataDefs.h b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RmcDataDefs.h
old mode 100644
new mode 100755
index a0e3e6f..c0477b7
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RmcDataDefs.h
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RmcDataDefs.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -141,6 +142,8 @@
 #define ESM_CAUSE_END ESM_CAUSE_BASE + 0xFF
 #define PAM_CAUSE_BASE 0x1200 // PAM cause
 #define PAM_CAUSE_END PAM_CAUSE_BASE + 0xC9
+#define FIVESMGSM_CAUSE_BASE 0x1A00 // 5GSM cause
+#define FIVESMGSM_CAUSE_END FIVESMGSM_CAUSE_BASE + 0xFF
 #define CME_CAUSE_BASE_V14 0x64 // Defined in 3GPP TS 27.007 V14
 #define CME_CAUSE_END_V14 CME_CAUSE_BASE_V14 + 0x64
 
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RpDataController.cpp b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RpDataController.cpp
old mode 100644
new mode 100755
index 0fe027c..edc24af
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RpDataController.cpp
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RpDataController.cpp
@@ -214,12 +214,75 @@
     }
 }
 
+void mipc_data_get_retry_timer_cb(mipc_sim_ps_id_enum sim_ps_id,
+    mipc_data_get_retry_timer_struct_v *result_ptr, void *cb_priv_ptr) {
+    Get_Retry_timer_call_back_priv* cb_priv = (Get_Retry_timer_call_back_priv*)cb_priv_ptr;
+    Parcel * parcel = NULL;
+    int ret = 0;
+
+    RpDataController * dataController = RpDataController::getInstance(sim_ps_id - 1);
+
+    if (dataController == NULL){
+        RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] NULL dataController", __FUNCTION__, __LINE__ ,sim_ps_id);
+        goto error;
+    }
+    if (cb_priv == NULL || cb_priv->response == NULL) {
+        RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] NULL cb_priv && response", __FUNCTION__, __LINE__ ,sim_ps_id);
+        goto error;
+    }
+
+    parcel = new Parcel();
+    if (parcel == NULL){
+        RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] NULL dataController", __FUNCTION__, __LINE__ ,sim_ps_id);
+        goto error;
+    }
+    if (result_ptr != NULL) {
+        cb_priv->response->suggestedRetryTime = result_ptr->retry_timer;
+    } else {
+        cb_priv->response->suggestedRetryTime = -1;
+    }
+
+    ret = responseDataCallListV11(*parcel, cb_priv->response, sizeof(MTK_RIL_Data_Call_Response_v11));
+    if (ret != 0){
+        RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] NULL dataController", __FUNCTION__, __LINE__ ,sim_ps_id);
+        goto error;
+    }
+
+    goto finish;
+
+error:
+    if (parcel != NULL){
+        delete(parcel);
+        parcel = NULL;
+    }
+    RFX_LOG_E(RFX_LOG_TAG, "%s:%d notify failure", __FUNCTION__ ,  __LINE__);
+finish:
+    RFX_LOG_D(RFX_LOG_TAG, "%s:%d notify response", __FUNCTION__ ,  __LINE__);
+    if (parcel == NULL)
+        rfx_enqueue_response_message(NULL, cb_priv->token, mipc_sim_id_to_slot_id(sim_ps_id), RIL_E_GENERIC_FAILURE);
+    else
+        rfx_enqueue_response_message(parcel, cb_priv->token, mipc_sim_id_to_slot_id(sim_ps_id), RIL_E_SUCCESS);
+
+    if (cb_priv->response != NULL) {
+        dataController->freeDataResponse(cb_priv->response);
+        FREEIF(cb_priv->response);
+        FREEIF(cb_priv);
+    }
+    RFX_LOG_D(RFX_LOG_TAG, "[%s] finish", __FUNCTION__);
+
+}
+
 void mipc_data_call_act_cb(mipc_sim_ps_id_enum sim_ps_id,
     mipc_data_call_act_struct *result_ptr, void *cb_priv_ptr) {
 
     MTK_RIL_Data_Call_Response_v11* response = NULL;
     Parcel * parcel = NULL;
     int ret = 0;
+    mipc_api_result_enum result = MIPC_API_RESULT_SUCCESS;
+    char *apn = NULL;
+    Act_Data_call_back_priv* data_cb_priv = (Act_Data_call_back_priv*)cb_priv_ptr;
+    Get_Retry_timer_call_back_priv* retry_timer_cb_priv = NULL;
+    RIL_DataCallFailCause dataCallFailCause = PDP_FAIL_NONE;
 
     RFX_LOG_D(RFX_LOG_TAG,"%s %d sim_ps_id[%d] result_ptr[%p] cb_priv_ptr[%p]",__FUNCTION__, __LINE__, sim_ps_id, \
         result_ptr, cb_priv_ptr);
@@ -250,15 +313,51 @@
 
    if (result_ptr->result_code != MIPC_API_RESULT_SUCCESS) {
         RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] MIPC_API_RESULT_FAIL", __FUNCTION__, __LINE__ ,sim_ps_id);
-        response->status = result_ptr->result_code;
-        dataController->setGprsFailureCause((int)result_ptr->result_code);
-            goto error;
+        if (result_ptr->apn == NULL || strlen((char*)result_ptr->apn) <= 0) {
+            if (data_cb_priv != NULL) {
+                RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] cb apn %s", __FUNCTION__, __LINE__ , sim_ps_id, data_cb_priv->apn);
+                asprintf(&apn, "%s", data_cb_priv->apn);
+            }
+        } else {
+            apn = (char*)result_ptr->apn;
+        }
+        pPdnManager->clearPdnInfo(result_ptr->id);
+    } else {
+        pPdnManager->fillPdnInfoByMipcDataCallAct(result_ptr);
     }
 
-    pPdnManager->fillPdnInfoByMipcDataCallAct(result_ptr);
     dataController->createDataResponse(dataController->calculateTransIntfId(result_ptr->id, result_ptr->interface_id), IPV4V6, response);
-    RFX_LOG_D(RFX_LOG_TAG, "[%d][%s] %s", sim_ps_id, __FUNCTION__, dataController->responsesToString(response, 1).string());
 
+
+    if (result_ptr->result_code != MIPC_API_RESULT_SUCCESS) {
+        dataCallFailCause = dataController->convertFailCauseToRilStandard((int)result_ptr->result_code);
+        if (dataCallFailCause == PDP_FAIL_NONE) {
+            RFX_LOG_E(RFX_LOG_TAG, "[%d][%s] NO CAUSE(0) but mipc_data_call_act_req failed",
+                    sim_ps_id, __FUNCTION__);
+            dataCallFailCause = PDP_FAIL_ERROR_UNSPECIFIED;
+        } else {
+            RFX_LOG_E(RFX_LOG_TAG, "[%d][%s] FAIL CAUSE: %X",
+                    sim_ps_id, __FUNCTION__, dataCallFailCause);
+        }
+        response->status = dataCallFailCause;
+        dataController->setGprsFailureCause((int)dataCallFailCause);
+        retry_timer_cb_priv = (Get_Retry_timer_call_back_priv*)calloc(1, sizeof(Get_Retry_timer_call_back_priv));
+        if (retry_timer_cb_priv != NULL) {
+            retry_timer_cb_priv->token = data_cb_priv->token;
+            retry_timer_cb_priv->response = response;
+            RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] MIPC_API_RESULT_FAIL [%s]", __FUNCTION__, __LINE__ ,sim_ps_id,(char*)result_ptr->apn);
+            result = mipc_data_get_retry_timer_async(sim_ps_id, mipc_data_get_retry_timer_cb, (void*)retry_timer_cb_priv, apn);
+            if (result != MIPC_API_RESULT_SUCCESS) {
+                RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] mipc_data_get_retry_timer_sync fail", __FUNCTION__, __LINE__ ,sim_ps_id);
+            }
+            FREEIF(apn);
+            FREEIF(data_cb_priv);
+            return;
+        } else {
+            RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] null calloc",__FUNCTION__,__LINE__, sim_ps_id);
+        }
+        FREEIF(apn);
+    }
     parcel = new Parcel();
     if (parcel == NULL){
         RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] NULL dataController", __FUNCTION__, __LINE__ ,sim_ps_id);
@@ -281,14 +380,15 @@
 finish:
     RFX_LOG_D(RFX_LOG_TAG, "%s:%d notify response", __FUNCTION__ ,  __LINE__);
     if (parcel == NULL)
-        rfx_enqueue_response_message(NULL, cb_priv_ptr, mipc_sim_id_to_slot_id(sim_ps_id), RIL_E_GENERIC_FAILURE);
+        rfx_enqueue_response_message(NULL, data_cb_priv->token, mipc_sim_id_to_slot_id(sim_ps_id), RIL_E_GENERIC_FAILURE);
     else
-        rfx_enqueue_response_message(parcel, cb_priv_ptr, mipc_sim_id_to_slot_id(sim_ps_id), RIL_E_SUCCESS);
+        rfx_enqueue_response_message(parcel, data_cb_priv->token, mipc_sim_id_to_slot_id(sim_ps_id), RIL_E_SUCCESS);
 
     if (response != NULL) {
         dataController->freeDataResponse(response);
         FREEIF(response);
     }
+    FREEIF(data_cb_priv);
     RFX_LOG_D(RFX_LOG_TAG, "[%s] finish", __FUNCTION__);
 }
 
@@ -383,6 +483,7 @@
 
 void mipc_data_call_deact_ind_cb(mipc_sim_ps_id_enum sim_ps_id,
     mipc_data_call_deact_struct *result_ptr, void *cb_priv_ptr) {
+    PdnInfo pdn_info;
 
     RFX_LOG_D(RFX_LOG_TAG,"%s %d  sim_ps_id[%d] result_ptr[%p]",__FUNCTION__, __LINE__, sim_ps_id, result_ptr);
 
@@ -397,8 +498,18 @@
         return;
     }
 
-    RFX_LOG_D(RFX_LOG_TAG,"%s %d:sim_ps_id %d result_code %d",__FUNCTION__, __LINE__,
-        sim_ps_id,result_ptr->result_code);
+    RmcDcPdnManager* pPdnManager = dataController->m_pPdnManager;
+
+    if (pPdnManager == NULL){
+        RFX_LOG_E(RFX_LOG_TAG, "[%s][%d] sim_ps_id[%d] NULL m_pPdnManager", __FUNCTION__, __LINE__ ,sim_ps_id);
+        return;
+    }
+
+    pdn_info = pPdnManager->getPdnInfo(result_ptr->id);
+    pdn_info.deactReason = dataController->convertFailCauseToRilStandard(result_ptr->network_error);
+    pPdnManager->setPdnInfo(result_ptr->id, &pdn_info);
+    RFX_LOG_D(RFX_LOG_TAG,"%s %d:sim_ps_id %d result_code %d, deactReason %d",__FUNCTION__, __LINE__,
+        sim_ps_id,result_ptr->result_code, pdn_info.deactReason);
 
     dataController->sendDataCallListResponse(result_ptr->id);
 }
@@ -830,28 +941,39 @@
             s_dataSetting[m_slot_id][DOMESTIC_ROAMING_DATA] == SKIP_DATA_SETTINGS &&
             s_dataSetting[m_slot_id][INTERNATIONAL_ROAMING_DATA] == SKIP_DATA_SETTINGS) {
             result = mipc_data_set_config_sync(mipc_sim_ps_id_enum(request->getSlotId()), &dataConfigResult, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][MOBILE_DATA], \
-                (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][DOMESTIC_ROAMING_DATA], MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
-                MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][INTERNATIONAL_ROAMING_DATA]);
+                MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                (mipc_data_config_type_const_enum)imsTestMode, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE);
         } else if (s_dataSetting[m_slot_id][MOBILE_DATA] == SKIP_DATA_SETTINGS &&
             s_dataSetting[m_slot_id][DOMESTIC_ROAMING_DATA] != SKIP_DATA_SETTINGS &&
             s_dataSetting[m_slot_id][INTERNATIONAL_ROAMING_DATA] == SKIP_DATA_SETTINGS) {
-            result = mipc_data_set_config_sync(mipc_sim_ps_id_enum(request->getSlotId()), &dataConfigResult, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][MOBILE_DATA], \
-                (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][DOMESTIC_ROAMING_DATA], MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
-                MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][INTERNATIONAL_ROAMING_DATA]);
+            result = mipc_data_set_config_sync(mipc_sim_ps_id_enum(request->getSlotId()), &dataConfigResult, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                MIPC_DATA_CONFIG_TYPE_NO_CHANGE, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][DOMESTIC_ROAMING_DATA], MIPC_DATA_CONFIG_TYPE_NO_CHANGE);
         } else if (s_dataSetting[m_slot_id][MOBILE_DATA] == SKIP_DATA_SETTINGS &&
             s_dataSetting[m_slot_id][DOMESTIC_ROAMING_DATA] == SKIP_DATA_SETTINGS &&
             s_dataSetting[m_slot_id][INTERNATIONAL_ROAMING_DATA] != SKIP_DATA_SETTINGS) {
+            result = mipc_data_set_config_sync(mipc_sim_ps_id_enum(request->getSlotId()), &dataConfigResult, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                (mipc_data_config_type_const_enum)imsTestMode, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][INTERNATIONAL_ROAMING_DATA]);
         //    RFX_LOG_I(RFX_LOG_TAG, "Enter ECNCFG, only international on/off");
             //p_response = atSendCommand(String8::format("AT+ECNCFG=,,,%d,,%d",
             //    imsTestMode, s_dataSetting[m_slot_id][INTERNATIONAL_ROAMING_DATA]));
         } else if (s_dataSetting[m_slot_id][MOBILE_DATA] == SKIP_DATA_SETTINGS &&
             s_dataSetting_resend[m_slot_id][DOMESTIC_ROAMING_DATA] != SKIP_DATA_SETTINGS &&
             s_dataSetting_resend[m_slot_id][INTERNATIONAL_ROAMING_DATA] != SKIP_DATA_SETTINGS) {
+            result = mipc_data_set_config_sync(mipc_sim_ps_id_enum(request->getSlotId()), &dataConfigResult, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                (mipc_data_config_type_const_enum)imsTestMode, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][DOMESTIC_ROAMING_DATA], \
+                (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][INTERNATIONAL_ROAMING_DATA]);
         //    RFX_LOG_I(RFX_LOG_TAG, "Enter ECNCFG, domestic and international on/off");
             //p_response = atSendCommand(String8::format("AT+ECNCFG=,,,%d,%d,%d",
             //    imsTestMode, s_dataSetting_resend[m_slot_id][DOMESTIC_ROAMING_DATA],
             //    s_dataSetting_resend[m_slot_id][INTERNATIONAL_ROAMING_DATA]));
         } else {
+            result = mipc_data_set_config_sync(mipc_sim_ps_id_enum(request->getSlotId()), &dataConfigResult, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][MOBILE_DATA], \
+                MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                (mipc_data_config_type_const_enum)imsTestMode, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][DOMESTIC_ROAMING_DATA], \
+                (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][INTERNATIONAL_ROAMING_DATA]);
         //    RFX_LOG_I(RFX_LOG_TAG, "Enter ECNCFG,else ");
             //p_response = atSendCommand(String8::format("AT+ECNCFG=%d,,,%d,%d,%d",
             //    s_dataSetting[m_slot_id][MOBILE_DATA],imsTestMode,
@@ -864,27 +986,39 @@
     // AT+ECNCFG=<mobile_data>,<data_roaming>,[<volte>,<ims_test_mode>]
         if (s_dataSetting[m_slot_id][MOBILE_DATA] != SKIP_DATA_SETTINGS &&
             s_dataSetting[m_slot_id][ROAMING_DATA] == SKIP_DATA_SETTINGS) {
+            result = mipc_data_set_config_sync(mipc_sim_ps_id_enum(request->getSlotId()), &dataConfigResult, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][MOBILE_DATA], \
+                MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                (mipc_data_config_type_const_enum)imsTestMode, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE);
             //p_response = atSendCommand(String8::format("AT+ECNCFG=%d,,,%d,,",
              //   s_dataSetting[m_slot_id][MOBILE_DATA],imsTestMode));
         } else if (s_dataSetting[m_slot_id][MOBILE_DATA] == SKIP_DATA_SETTINGS &&
             s_dataSetting[m_slot_id][ROAMING_DATA] != SKIP_DATA_SETTINGS) {
+            result = mipc_data_set_config_sync(mipc_sim_ps_id_enum(request->getSlotId()), &dataConfigResult, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][ROAMING_DATA], MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                (mipc_data_config_type_const_enum)imsTestMode, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE);
             //p_response = atSendCommand(String8::format("AT+ECNCFG=,%d,,%d,,",
              //       s_dataSetting[m_slot_id][ROAMING_DATA], imsTestMode));
         } else {
+            result = mipc_data_set_config_sync(mipc_sim_ps_id_enum(request->getSlotId()), &dataConfigResult, (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][MOBILE_DATA], \
+                (mipc_data_config_type_const_enum)s_dataSetting[m_slot_id][ROAMING_DATA], MIPC_DATA_CONFIG_TYPE_NO_CHANGE, \
+                (mipc_data_config_type_const_enum)imsTestMode, MIPC_DATA_CONFIG_TYPE_NO_CHANGE, MIPC_DATA_CONFIG_TYPE_NO_CHANGE);
            // p_response = atSendCommand(String8::format("AT+ECNCFG=%d,%d,,%d,,",
             //    s_dataSetting[m_slot_id][MOBILE_DATA], s_dataSetting[m_slot_id][ROAMING_DATA],
            //     imsTestMode));
         }
     }
 
-   RFX_LOG_D(RFX_LOG_TAG, "[%d][%s] End", rid, __FUNCTION__);
+   RFX_LOG_D(RFX_LOG_TAG, "[%d][%s] End result: %d", rid, __FUNCTION__, result);
 
-error:
-    RFX_LOG_E(RFX_LOG_TAG, "%s:%d notify failure", __FUNCTION__ ,  __LINE__);
 finish:
     RFX_LOG_D(RFX_LOG_TAG, "%s:%d notify response", __FUNCTION__ ,  __LINE__);
+    rfx_enqueue_response_message(NULL, request->getRilToken(),(RIL_SOCKET_ID)request->getSlotId(), RIL_E_SUCCESS);
     FREEIF(pReqData);
     return;
+error:
+    RFX_LOG_E(RFX_LOG_TAG, "%s:%d notify failure", __FUNCTION__ ,  __LINE__);
+    rfx_enqueue_response_message(NULL, request->getRilToken(),(RIL_SOCKET_ID)request->getSlotId(), RIL_E_GENERIC_FAILURE);
+    return;
 }
 
 
@@ -1086,7 +1220,7 @@
                 goto error;
             }
             result = mipc_apn_profile_update_sync(slot_id_to_mipc_sim_id(request->getSlotId()), &apnProfiles, i+1, mccmnc, \
-                dataProfiles[i].apn, (uint32_t)dataProfiles[i].profileId, apnPdpType, MIPC_APN_ENUM_PDP_TYPE_IPV4V6, (mipc_apn_auth_type_enum)dataProfiles[i].authType, \
+                dataProfiles[i].apn, (uint32_t)dataProfiles[i].supportedTypesBitmask, apnPdpType, MIPC_APN_ENUM_PDP_TYPE_IPV4V6, (mipc_apn_auth_type_enum)dataProfiles[i].authType, \
                 dataProfiles[i].user, dataProfiles[i].password, 0xffffffff, MIPC_APN_ENUM_COMPRESSION_ENABLE);
             RFX_LOG_D(RFX_LOG_TAG,"%s %d2 apn[%s] result[%d] apnProfiles.result_code[%d], apnProfiles.apn_list_count[%d]", __FUNCTION__, __LINE__, dataProfiles[i].apn, result, apnProfiles.result_code, apnProfiles.apn_list_count);
             if (result != MIPC_API_RESULT_SUCCESS) {
@@ -1449,10 +1583,120 @@
     rfx_enqueue_response_message(NULL, request->getRilToken(),(RIL_SOCKET_ID)request->getSlotId(), RIL_E_GENERIC_FAILURE);
 }
 
+RIL_DataCallFailCause RpDataController::convertFailCauseToRilStandard(int cause) {
+    int rid = m_slot_id;
+
+    if (cause > MIPC_RESULT_PDN_EXT_NETWORK_ERROR_BEGIN /*0x140000*/ &&
+            cause < MIPC_RESULT_PDN_EXT_NETWORK_ERROR_END) {
+        cause -= MIPC_RESULT_PDN_EXT_NETWORK_ERROR_BEGIN;
+        if (cause > SM_CAUSE_BASE && cause < SM_CAUSE_END) {
+            cause -= SM_CAUSE_BASE;
+        } else if (cause > ESM_CAUSE_BASE && cause < ESM_CAUSE_END) {
+            RFX_LOG_E(RFX_LOG_TAG, "[%d][%s] ESM CAUSE: %X",
+                    rid, __FUNCTION__, cause);
+            cause -= ESM_CAUSE_BASE;
+        } else if (cause > PAM_CAUSE_BASE && cause < PAM_CAUSE_END) {
+            RFX_LOG_E(RFX_LOG_TAG, "[%d][%s] PAM CAUSE: %X",
+                    rid, __FUNCTION__, cause);
+            cause -= PAM_CAUSE_BASE;
+        } else if (cause > FIVESMGSM_CAUSE_BASE && cause < FIVESMGSM_CAUSE_END) {
+            RFX_LOG_E(RFX_LOG_TAG, "[%d][%s] 5GSM CAUSE: %X",
+                    rid, __FUNCTION__, cause);
+            cause -= FIVESMGSM_CAUSE_BASE;
+        } else if (cause > CME_CAUSE_BASE_V14 && cause < CME_CAUSE_END_V14) {
+            RFX_LOG_E(RFX_LOG_TAG, "[%d][%s] CME CAUSE: %X",
+                    rid, __FUNCTION__, cause);
+            if (cause == 149) {//CME_PDP_AUTHENTICATION_FAILED = 149
+                return PDP_FAIL_USER_AUTHENTICATION;
+            } else {
+                cause -= CME_CAUSE_BASE_V14;
+            }
+        }
+
+        switch (cause) {
+            case 0: return PDP_FAIL_NONE;
+            case 0x08: return PDP_FAIL_OPERATOR_BARRED;
+            case 0x0E: return PDP_FAIL_NAS_SIGNALLING;
+            case 0x18: return PDP_FAIL_MBMS_CAPABILITIES_INSUFFICIENT;
+            case 0x19: return PDP_FAIL_LLC_SNDCP;
+            case 0x1A: return PDP_FAIL_INSUFFICIENT_RESOURCES;
+            case 0x1B: return PDP_FAIL_MISSING_UKNOWN_APN;
+            case 0x1C: return PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE;
+            case 0x1D: return PDP_FAIL_USER_AUTHENTICATION;
+            case 0x1E: return PDP_FAIL_ACTIVATION_REJECT_GGSN;
+            case 0x1F: return PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED;
+            case 0x20: return PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED;
+            case 0x21: return PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED;
+            case 0x22: return PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER;
+            case 0x23: return PDP_FAIL_NSAPI_IN_USE;
+            case 0x24: return PDP_FAIL_REGULAR_DEACTIVATION;
+            case 0x25: return PDP_FAIL_QOS_NOT_ACCEPTED;
+            case 0x26: return PDP_FAIL_NETWORK_FAILURE;
+            case 0x27: return PDP_FAIL_UMTS_REACTIVATION_REQ;
+            case 0x28: return PDP_FAIL_FEATURE_NOT_SUPP;
+            case 0x29: return PDP_FAIL_TFT_SEMANTIC_ERROR;
+            case 0x2A: return PDP_FAIL_TFT_SYTAX_ERROR;
+            case 0x2B: return PDP_FAIL_UNKNOWN_PDP_CONTEXT;
+            case 0x2C: return PDP_FAIL_FILTER_SEMANTIC_ERROR;
+            case 0x2D: return PDP_FAIL_FILTER_SYTAX_ERROR;
+            case 0x2E: return PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT;
+            case 0x2F: return PDP_FAIL_MULTICAST_GROUP_MEMBERSHIP_TIMEOUT;
+            case 0x30: return PDP_FAIL_BCM_VIOLATION;
+            case 0x31: return PDP_FAIL_LAST_PDN_DISC_NOT_ALLOWED;
+            case 0x32: return PDP_FAIL_ONLY_IPV4_ALLOWED;
+            case 0x33: return PDP_FAIL_ONLY_IPV6_ALLOWED;
+            case 0x34: return PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED;
+            case 0x35: return PDP_FAIL_ESM_INFO_NOT_RECEIVED;
+            case 0x36: return PDP_FAIL_PDN_CONN_DOES_NOT_EXIST;
+            case 0x37: return PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED;
+            case 0x38: return PDP_FAIL_COLLISION_WITH_NW_INITIATED_REQUEST;
+            case 0x3B: return PDP_FAIL_ESM_UNSUPPORTED_QCI_VALUE;
+            case 0x3C: return PDP_FAIL_BEARER_HANDLING_NOT_SUPPORT;
+            case 0x41: return PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED;
+            case 0x42: return PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN;
+            case 0x51: return PDP_FAIL_INVALID_TRANSACTION_ID;
+            case 0x5F: return PDP_FAIL_MESSAGE_INCORRECT_SEMANTIC;
+            case 0x60: return PDP_FAIL_INVALID_MANDATORY_INFO;
+            case 0x61: return PDP_FAIL_MESSAGE_TYPE_UNSUPPORTED;
+            case 0x62: return PDP_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE;
+            case 0x63: return PDP_FAIL_UNKNOWN_INFO_ELEMENT;
+            case 0x64: return PDP_FAIL_CONDITIONAL_IE_ERROR;
+            case 0x65: return PDP_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE;
+            case 0x6F: return PDP_FAIL_PROTOCOL_ERRORS;
+            case 0x70: return PDP_FAIL_APN_TYPE_CONFLICT;
+            case 0x71: return PDP_FAIL_INVALID_PCSCF_ADDR;
+            case 0x72: return PDP_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN;
+            case 0x73: return PDP_FAIL_EMM_ACCESS_BARRED;
+            case 0x74: return PDP_FAIL_EMERGENCY_IFACE_ONLY;
+            case 0x75: return PDP_FAIL_IFACE_MISMATCH;
+            case 0x76: return PDP_FAIL_COMPANION_IFACE_IN_USE;
+            case 0x77: return PDP_FAIL_IP_ADDRESS_MISMATCH;
+            case 0x78: return PDP_FAIL_IFACE_AND_POL_FAMILY_MISMATCH;
+            case 0x79: return PDP_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY;
+            case 0x7A: return PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL;
+            case 0x0E0F: return PDP_FAIL_LOCAL_REJECT_ACT_REQ_DUE_TO_REACH_RETRY_COUNTER;
+            case 0x0F47: return PDP_FAIL_TCM_ESM_TIMER_TIMEOUT;
+            case 0x1402: return PDP_FAIL_PAM_ATT_PDN_ACCESS_REJECT_IMS_PDN_BLOCK_TEMP;
+            case 0x1671: return PDP_FAIL_DATA_NOT_ALLOW;
+            case -1: return PDP_FAIL_VOICE_REGISTRATION_FAIL;
+            case -2: return PDP_FAIL_DATA_REGISTRATION_FAIL;
+            case -3: return PDP_FAIL_SIGNAL_LOST;
+            case -4: return PDP_FAIL_PREF_RADIO_TECH_CHANGED;
+            case -5: return PDP_FAIL_RADIO_POWER_OFF;
+            case -6: return PDP_FAIL_TETHERED_CALL_ACTIVE;
+            default: return PDP_FAIL_ERROR_UNSPECIFIED;
+        }
+    } else {
+        return PDP_FAIL_ERROR_UNSPECIFIED;
+    }
+}
+
 void RpDataController::handleGetLastFailCauseRequest(const sp<RfxMessage>& request) {
 
     Parcel * parcel = NULL;
+    int lastFailCause = 0;
     RFX_LOG_D(RFX_LOG_TAG, "[%d][%s][%d] m_nGprsFailureCause[%d]", m_slot_id, __FUNCTION__, __LINE__, m_nGprsFailureCause);
+
     parcel = new Parcel();
 
     if (parcel == NULL){
@@ -1460,19 +1704,19 @@
                 request->getSlotId(), request->getClientId(), request->getToken());
         goto error;
     }
-
+    lastFailCause = getGprsFailureCause();
+    parcel->writeInt32(1);
+    parcel->writeInt32(lastFailCause);
+    RFX_LOG_D(RFX_LOG_TAG, "[%d][%s][%d] lastFailCause[%d]", m_slot_id, __FUNCTION__, __LINE__, lastFailCause);
+    rfx_enqueue_response_message(parcel, request->getRilToken(),(RIL_SOCKET_ID)request->getSlotId(), RIL_E_SUCCESS);
+    return;
 error:
     if (parcel != NULL){
         delete(parcel);
         parcel = NULL;
     }
     RFX_LOG_E(RFX_LOG_TAG, "%s:%d notify failure", __FUNCTION__ ,  __LINE__);
-
-    if (parcel == NULL)
-        rfx_enqueue_response_message(NULL, request->getRilToken(),(RIL_SOCKET_ID)request->getSlotId(), RIL_E_GENERIC_FAILURE);
-    else
-        rfx_enqueue_response_message(parcel, request->getRilToken(),(RIL_SOCKET_ID)request->getSlotId(), RIL_E_SUCCESS);
-    return;
+    rfx_enqueue_response_message(NULL, request->getRilToken(),(RIL_SOCKET_ID)request->getSlotId(), RIL_E_GENERIC_FAILURE);
 }
 
 
@@ -1737,6 +1981,7 @@
     mipc_api_result_enum result = MIPC_API_RESULT_SUCCESS;
     Parcel * parcel = NULL;
     Parcel *p = NULL;
+    Act_Data_call_back_priv* data_call_cb = NULL;
 
 
     memset(&dataCallAct, 0, sizeof(dataCallAct));
@@ -1834,7 +2079,17 @@
 
     mapPdpTypeFromStringToEnum(pStrings[6], &pdpType);
 
-    result = mipc_data_call_act_async(slot_id_to_mipc_sim_id(request->getSlotId()), mipc_data_call_act_cb, (void *)request->getRilToken(), pStrings[2], \
+    data_call_cb = (Act_Data_call_back_priv*)calloc(1, sizeof(Act_Data_call_back_priv));
+    if (data_call_cb == NULL) {
+        RFX_LOG_E(RFX_LOG_TAG, "%s:%d  slotid[%d] clientid[%d] token[%d] NULL calloc", __FUNCTION__ ,  __LINE__, \
+                request->getSlotId(), request->getClientId(), request->getToken());
+        goto error;
+    }
+    data_call_cb->token = request->getRilToken();
+    memset(data_call_cb->apn, 0, MAX_APN_NAME_LENGTH);
+    strncpy(data_call_cb->apn, pStrings[2], strlen(pStrings[2]));
+
+    result = mipc_data_call_act_async(slot_id_to_mipc_sim_id(request->getSlotId()), mipc_data_call_act_cb, (void *)data_call_cb, pStrings[2], \
         apnType, pdpType, pdpType, authType, pStrings[3], pStrings[4], \
         MIPC_DATA_ENUM_FALLBACK_TYPE_IPV4_FIRST, 0xffffffff);
 error:
@@ -1922,3 +2177,7 @@
     m_nGprsFailureCause = gprsFailureCause;
 }
 
+int RpDataController::getGprsFailureCause(){
+    return m_nGprsFailureCause;
+}
+
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RpDataController.h b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RpDataController.h
old mode 100644
new mode 100755
index 4f530c0..790cf9e
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RpDataController.h
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/data/RpDataController.h
@@ -61,6 +61,15 @@
 
 #define SKIP_DATA_SETTINGS    -2
 
+typedef struct Act_Data_call_back_priv {
+    RIL_Token token;
+    char apn[MAX_APN_NAME_LENGTH];
+} Act_Data_call_back_priv;
+
+typedef struct Get_Retry_timer_call_back_priv {
+    RIL_Token token;
+    MTK_RIL_Data_Call_Response_v11* response;
+} Get_Retry_timer_call_back_priv;
 
 /*****************************************************************************
  * Class RpDataController
@@ -117,6 +126,9 @@
     bool validateAid(int aid);
     String8 responsesToString(MTK_RIL_Data_Call_Response_v11* responses, int num);
     void setGprsFailureCause(int gprsFailureCause);
+    int getGprsFailureCause();
+    RIL_DataCallFailCause convertFailCauseToRilStandard(int cause);
+
 
 protected:
     int m_nGprsFailureCause;
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/ecall/RpEcallController.cpp b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/ecall/RpEcallController.cpp
new file mode 100755
index 0000000..1bbdc29
--- /dev/null
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/ecall/RpEcallController.cpp
Binary files differ
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/ecall/RpEcallController.h b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/ecall/RpEcallController.h
new file mode 100755
index 0000000..dfd52af
--- /dev/null
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/ecall/RpEcallController.h
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: MediaTekProprietary

+/*****************************************************************************

+*  Copyright Statement:

+*  --------------------

+*  Copyright (c) [2020], MediaTek Inc. All rights reserved.

+*  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. Except as otherwise provided in the

+*  applicable licensing terms with 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.

+*****************************************************************************/

+

+#ifndef __RP_ECALL_CONTROLLER_H__

+#define __RP_ECALL_CONTROLLER_H__

+

+#include <string>

+

+#include "RfxController.h"

+#include "RpUtils.h"

+#include "RilParcelUtils.h"

+#include <telephony/mtk_ril_request_info.h>

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+#include "mipc_ecall_api.h"

+#include "mipc_msg_tlv_const.h"

+#ifdef __cplusplus

+}

+#endif

+

+/*****************************************************************************

+ * Class RpEcallController

+ *****************************************************************************/

+class RpEcallController : public RfxController {

+    RFX_DECLARE_CLASS(RpEcallController);  // Required: declare this class

+

+public:

+    RpEcallController();

+

+    virtual ~RpEcallController();

+

+// Override

+protected:

+

+    virtual void onInit();

+    virtual void onDeinit();

+    virtual bool onHandleRequest(const sp<RfxMessage>& message);

+

+private:

+    std::string mLog_tag;

+    String8 mEccListWithCard;

+    String8 mEccListNoCard;

+    bool mIsSimInsert;

+    String8 mGsmEcc;

+

+private:

+    void registerInd(mipc_sim_ps_id_enum sim_ps_id,void *cb_priv_ptr);

+

+    void handleEcallFastMakeEcall(const sp<RfxMessage> &request);

+    void handleEcallUpdateMsd(const sp<RfxMessage>& request);

+    void handleEcallResetIvs(const sp<RfxMessage>& request);

+    void handleEcallSetRegState(const sp<RfxMessage>& request);

+    int handleEcallGetSimInfo();

+    void handleEcallSetTestAddr(const sp<RfxMessage>& request);

+    void handleEcallSetReconfAddr(const sp<RfxMessage> &request);

+    void handleEcallSetAddrPri(const sp<RfxMessage> &request);

+

+    void checkEccNumberAndServiceCategory(char* number, const sp<RfxMessage> &request);

+    bool isEmergencyNumber(String8 number);

+    int getServiceCategory(String8 number);

+    bool isEccMatchInList(String8 number, String8 eccList);

+

+    std::string IdToString(int request);

+};

+

+#endif /* __RP_ECALL_CONTROLLER_H__ */

diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/network/RpNwController.cpp b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/network/RpNwController.cpp
old mode 100644
new mode 100755
index cea50da..c643c1c
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/network/RpNwController.cpp
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/network/RpNwController.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -118,6 +119,7 @@
 int prefNwType[RIL_SOCKET_NUM];
 int mCurPreferedNetWorkType[RIL_SOCKET_NUM];
 int mPhoneMode[RIL_SOCKET_NUM];
+bool mHasSetRat[RIL_SOCKET_NUM];
 /*****************************************************************************
  * Class RfxNwController
  * The class is created if the slot is single mode, LWG or C,
@@ -649,7 +651,7 @@
             writeStringToParcel(p,responseStr[i]);
             free(responseStr[i]);
         }
-        rfx_enqueue_urc_message(RIL_UNSOL_RESPONSE_CS_NETWORK_STATE_CHANGED,p,mipc_sim_id_to_slot_id(sim_ps_id),RIL_E_SUCCESS);
+        rfx_enqueue_urc_message(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,p,mipc_sim_id_to_slot_id(sim_ps_id),RIL_E_SUCCESS);
         isNeedNotifyStateChanged(mipc_sim_id_to_slot_id(sim_ps_id));
     }
 }
@@ -861,6 +863,28 @@
     updatePhoneMode(mipc_sim_id_to_slot_id(sim_ps_id));
 }
 
+void mipc_unsol_nw_etxpwr_ind_cb(mipc_msg_t *msg_ptr, void *cb_priv_ptr) {
+    mipc_sim_ps_id_enum sim_ps_id;
+    uint32_t act = 0;
+    int32_t tx_power = 0;
+
+    sim_ps_id = (mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id;
+    act = mipc_nw_etxpwr_ind_get_act(msg_ptr,0);
+    tx_power = mipc_nw_etxpwr_ind_get_tx_power(msg_ptr,0);
+    RFX_LOG_D(RFX_LOG_TAG,"mipc_unsol_nw_etxpwr_ind_cb act=%d, tx_power=%d\n", act, tx_power);
+
+    Parcel *p = new Parcel();
+    if(p != NULL) {
+        p->writeInt32(2);
+        p->writeUint32(act);
+        p->writeInt32(tx_power);
+        rfx_enqueue_urc_message(RIL_UNSOL_TX_POWER, p, mipc_sim_id_to_slot_id(sim_ps_id), RIL_E_SUCCESS);
+
+    } else {
+        RFX_LOG_E(RFX_LOG_TAG,"mipc_unsol_nw_cs_ind_cb new parcel error!");
+    }
+}
+
 }
 
 void RpNwController::onInit() {
@@ -872,6 +896,7 @@
     mCurPreferedNetWorkType[getSlotId()] = -1;
     prefNwType[getSlotId()] = -1;
     mPhoneMode[getSlotId()] = RADIO_TECH_UNKNOWN;
+    mHasSetRat[getSlotId()] = false;
 
     const int request_id_list[] = {
             RIL_REQUEST_SIGNAL_STRENGTH,  // 19
@@ -906,6 +931,7 @@
     mipc_nw_ciev_ind_register(slot_id_to_mipc_sim_id(getSlotId()),mipc_unsol_nw_ciev_ind_cb,NULL);
     mipc_nw_egmss_ind_register(slot_id_to_mipc_sim_id(getSlotId()),mipc_unsol_nw_egmss_ind_cb,NULL);
     mipc_nw_psbearer_ind_register(slot_id_to_mipc_sim_id(getSlotId()),mipc_unsol_nw_psbearer_ind_cb,NULL);
+    mipc_nw_etxpwr_ind_register(slot_id_to_mipc_sim_id(getSlotId()),mipc_unsol_nw_etxpwr_ind_cb,NULL);
 
     // register request id list
     registerToHandleRequest(request_id_list,
@@ -1450,6 +1476,9 @@
         } else if (nt_type == 6 && prefer_type == 0) {
             //4G/3G/2G(Auto) item
             return_type = PREF_NET_TYPE_LTE_GSM_WCDMA;
+        } else if (nt_type == 6 && prefer_type == 128) {
+            //4G/3G/2G(Auto) item
+            return_type = PREF_NET_TYPE_LTE_GSM_WCDMA;
         } else if (nt_type == 14) {
             // LTE CDMA EVDO GSM/WCDMA mode
             return_type = PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA;
@@ -1699,6 +1728,11 @@
             mCurPreferedNetWorkType[slotid] = prefNwType[slotid];
             updatePhoneMode(mipc_sim_id_to_slot_id(sim_ps_id));
         }
+
+        mHasSetRat[mipc_sim_id_to_slot_id(sim_ps_id)] = true;
+        RFX_LOG_D(RFX_LOG_TAG,"mipc_set_prefer_network_cb set mHasSetRat[%d]=%d\n",
+                mipc_sim_id_to_slot_id(sim_ps_id),
+                mHasSetRat[mipc_sim_id_to_slot_id(sim_ps_id)]);
     }
 
     if (cb_priv_ptr == NULL) {
@@ -2042,6 +2076,23 @@
     int ret = 0;
     rfx_property_get(mccMncKey.c_str(), value, "");
     RFX_LOG_D(RFX_LOG_TAG, "handleGetOperator plmnid[%s]",value);
+
+    // Handle for test SIM, always return 00101
+    if (strcmp(value, "00101") == 0) {
+        Parcel * p = new Parcel();
+        if(p == NULL) {
+            rfx_enqueue_response_message(NULL,request->getRilToken(),(RIL_SOCKET_ID)request->getSlotId(),RIL_E_GENERIC_FAILURE);
+            return;
+        }
+        p->writeInt32(3); //number of strings
+        writeStringToParcel(p,value);
+        writeStringToParcel(p,value);
+        writeStringToParcel(p,value);
+        RFX_LOG_D(RFX_LOG_TAG,"%s plmn_id[%s],shortname[%s]", __FUNCTION__, value, value);
+        rfx_enqueue_response_message(p,request->getRilToken(),(RIL_SOCKET_ID)request->getSlotId(),RIL_E_SUCCESS);
+        return;
+    }
+
     //get operator name with plmnid
     mipc_nw_provider_name_get_async(slot_id_to_mipc_sim_id(request->getSlotId()), mipc_get_Operator_cb,
         (void *)request->getRilToken(), value);
@@ -2238,8 +2289,8 @@
         p->readInt32(&pInt[1]);
         p->readInt32(&pInt[2]);
     }
-    int req, err, gsm_band, umts_band;
-    unsigned int lte_band_1_32=0,lte_band_33_64=0;
+    int req, err;
+    unsigned int gsm_band=0, umts_band=0, lte_band_1_32=0, lte_band_33_64=0;
     req = pInt[0];
     switch (req) {
         case BM_AUTO_MODE: //"unspecified" (selected by baseband automatically)
@@ -2312,12 +2363,13 @@
         }
     }
     mipc_nw_band_mode_struct BandMode;
+    memset(&BandMode, 0, sizeof(BandMode));
     BandMode.GSM_band_mode=gsm_band;
-    BandMode.GSM_band_mode=umts_band;
+    BandMode.UMTS_band_mode=umts_band;
     BandMode.LTE_band[0]=lte_band_1_32;
     BandMode.LTE_band[1]=lte_band_33_64;
-    RFX_LOG_D(RFX_LOG_TAG, "gsm_band:%d, umts_band : %d, lte_band_1_32 : %d, lte_band_33_64: %d, req: %d ",
-        gsm_band, umts_band, lte_band_1_32, lte_band_33_64, req);
+    RFX_LOG_D(RFX_LOG_TAG, "GSM_band_mode:%d, UMTS_band_mode: %d, LTE_band[0]: %d, LTE_band[1]: %d, req: %d",
+        BandMode.GSM_band_mode, BandMode.UMTS_band_mode, BandMode.LTE_band[0], BandMode.LTE_band[1], req);
     mipc_nw_band_mode_set_async(slot_id_to_mipc_sim_id(request->getSlotId()), mipc_band_set_network_cb, (void *)request->getRilToken(),&BandMode);
 }
 
@@ -2383,21 +2435,29 @@
     RFX_UNUSED(key);
     RFX_UNUSED(old_value);
 
-    int rat = 6, rat1 = 4; //6: GSM + UMTS + LTE, 4: LTE prefer
-
     if (value.asBool() == true) {
         int newCardType = getStatusManager(slotId)->getIntValue(RFX_STATUS_KEY_CARD_TYPE, CARD_TYPE_NONE);
-        RFX_LOG_D(RFX_LOG_TAG, "[%d]%s get slotId[%d] RFX_STATUS_KEY_CARD_TYPE = %d",
-                getSlotId(), __FUNCTION__, slotId, newCardType);
+        //RFX_LOG_D(RFX_LOG_TAG, "[%d]%s get slotId[%d] RFX_STATUS_KEY_CARD_TYPE = %d",
+        //        getSlotId(), __FUNCTION__, slotId, newCardType);
 
-        /// M: there is no sim card, that mean: card has been plugout.
-        /// M: Send global rat mode
-        if (newCardType == CARD_TYPE_NONE) {
-            RFX_LOG_D(RFX_LOG_TAG, "[%d]%s send RAT mode for slotid=%d: no sim card state = %d, rat=%d, rat1=%d",
-                    getSlotId(), __FUNCTION__, slotId, newCardType, rat, rat1);
+        /// M: Must set rat mode when first time boot (Never set RAT before)
+        if ((newCardType == CARD_TYPE_NONE) && (mHasSetRat[getSlotId()] == false)) {
+            mipc_nw_get_rat_struct cur_rat;
+            mipc_nw_get_rat_sync(slot_id_to_mipc_sim_id(getSlotId()), &cur_rat);
+
+            RFX_LOG_D(RFX_LOG_TAG, "[%d]%s send RAT mode for slotid=%d: no sim card state = %d, rat=%d, prefer_rat=%d",
+                    getSlotId(), __FUNCTION__, slotId, newCardType, cur_rat.rat, cur_rat.prefer_rat);
+
+            if (0 > cur_rat.rat || 30 < cur_rat.rat) {
+                //6: GSM + UMTS + LTE, 4: LTE prefer
+                cur_rat.rat = 6;
+                cur_rat.prefer_rat = 4;
+                RFX_LOG_D(RFX_LOG_TAG, "[%d]%s Update as rat=%d, prefer_rat=%d",
+                        getSlotId(), __FUNCTION__, cur_rat.rat, cur_rat.prefer_rat);
+            }
 
             mipc_nw_set_rat_async(slot_id_to_mipc_sim_id(getSlotId()), mipc_set_prefer_network_cb, NULL,
-                (uint8_t)rat,(uint8_t)rat1);
+                (uint8_t)cur_rat.rat,(uint8_t)cur_rat.prefer_rat);
         }
     }
 }
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/radio/RpRadioController.cpp b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/radio/RpRadioController.cpp
old mode 100644
new mode 100755
index b83f8bc..6e70ad6
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/radio/RpRadioController.cpp
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/radio/RpRadioController.cpp
@@ -94,10 +94,11 @@
     RFX_OBJ_GET_INSTANCE(RfxRootController)->getStatusManager(mipc_sim_id_to_slot_id(sim_ps_id))->setIntValue(RFX_STATUS_KEY_RADIO_LOCK, RADIO_LOCK_IDLE);
 
     //retry set radio status
-    if(result_ptr->result_code != MIPC_RESULT_SUCCESS) {
+    if(result_ptr->result_code != MIPC_RESULT_SUCCESS ||
+        result_ptr->sw_radio_state != mPendingRequest[mipc_sim_id_to_slot_id(sim_ps_id)]) {
         RFX_OBJ_GET_INSTANCE(RfxRootController)->getStatusManager(mipc_sim_id_to_slot_id(sim_ps_id))->setIntValue(RFX_STATUS_KEY_RADIO_LOCK, RADIO_LOCK_BY_RADIO);
         int radio_state = mPendingRequest[mipc_sim_id_to_slot_id(sim_ps_id)];
-        RFX_LOG_D(getTag(sim_ps_id).c_str(), "%s, set radio fail, start retry, radio_state", __FUNCTION__, radio_state);
+        RFX_LOG_D(getTag(sim_ps_id).c_str(), "%s, set radio fail or not equal pending, start retry, radio_state", __FUNCTION__, radio_state);
         int ret = mipc_nw_radio_state_set_async(
                 sim_ps_id,
                 mipc_nw_radio_state_booup_set_cb,
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/sim/RpSimController.cpp b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/sim/RpSimController.cpp
old mode 100644
new mode 100755
index 0fa766a..6615766
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/sim/RpSimController.cpp
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/sim/RpSimController.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /*****************************************************************************
  *  Copyright Statement:
  *  --------------------
@@ -281,12 +282,32 @@
     }
 }
 
+int transferMipcSimResultCode(mipc_result_enum result_code) {
+    switch(result_code) {
+        case MIPC_RESULT_SIM_NOT_INSERTED:
+            return RIL_E_SIM_ABSENT;
+        case MIPC_RESULT_PIN_REQUIRED:
+        case MIPC_RESULT_PIN_DISABLED:
+            return RIL_E_PASSWORD_INCORRECT;
+        case MIPC_RESULT_BUSY:
+            return RIL_E_SIM_BUSY;
+        case MIPC_RESULT_BAD_SIM:
+            return RIL_E_SIM_ERR;
+        case MIPC_RESULT_FAILURE:
+            return RIL_E_GENERIC_FAILURE;
+        default:
+            return result_code;
+    }
+}
 
 static void mipc_sim_status_get_cb(mipc_sim_ps_id_enum sim_ps_id, mipc_sim_status_struct *result_ptr, void *cb_priv_ptr) {
     RFX_LOG_D(getTag(sim_ps_id).c_str(),"%s, %s", __FUNCTION__, dump_mipc_sim_status(result_ptr,cb_priv_ptr).c_str());
-    if(cb_priv_ptr && (result_ptr->result_code != MIPC_RESULT_SUCCESS)) {
-        //result code to ril error transfer
-        rfx_enqueue_response_message(NULL,cb_priv_ptr,mipc_sim_id_to_slot_id(sim_ps_id),result_ptr->result_code);
+    if(cb_priv_ptr &&
+            !(result_ptr->result_code == MIPC_RESULT_SUCCESS ||
+            result_ptr->result_code == MIPC_RESULT_SIM_NOT_INSERTED ||
+            result_ptr->result_code == MIPC_RESULT_PIN_REQUIRED ||
+            result_ptr->result_code == MIPC_RESULT_PIN_DISABLED)) {
+        rfx_enqueue_response_message(NULL,cb_priv_ptr,mipc_sim_id_to_slot_id(sim_ps_id),transferMipcSimResultCode(result_ptr->result_code));
     } else {
         if(result_ptr->gsm_app_idx >= 0 && result_ptr->gsm_app_idx < result_ptr->app_count){
             handleCardType(result_ptr->app_list[result_ptr->gsm_app_idx].app_type,sim_ps_id);
@@ -478,6 +499,24 @@
     return str;
 }
 
+const char HEX_DIGITS[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+unsigned char* byteArrayToHexString(unsigned char* array,int length)
+{
+    unsigned char* buf = (unsigned char*)calloc(1, length*2+1);
+    assert(buf != NULL);
+    int bufIndex = 0;
+    int i = 0;
+    for (i = 0 ; i < length; i++)
+    {
+        unsigned char b = array[i];
+        buf[bufIndex++] = HEX_DIGITS[(b >> 4) & 0x0F];
+        buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
+    }
+    buf[bufIndex] = '\0';
+    return buf;
+}
+
 static void mipc_sim_channel_restricted_access_cb(mipc_sim_ps_id_enum sim_ps_id, mipc_sim_apdu_access_struct *result_ptr, void *cb_priv_ptr) {
     RFX_LOG_D(getTag(sim_ps_id).c_str(),"%s, %s", __FUNCTION__, dump_sim_channel_restricted_access(result_ptr,cb_priv_ptr).c_str());
     if(result_ptr->result_code != MIPC_RESULT_SUCCESS) {
@@ -493,7 +532,14 @@
         sscanf(out.c_str(), "%02x%02x", &(sw1), &(sw2));
         p->writeInt32(sw1);
         p->writeInt32(sw2);
-        writeStringToParcel(p, string(strlen(result_ptr->resp_apdu) == 0 ? "" : result_ptr->resp_apdu).c_str());
+
+        char* temp = (char*)byteArrayToHexString((unsigned char*)result_ptr->resp_apdu, result_ptr->resp_len);
+        RFX_LOG_D(getTag(sim_ps_id).c_str(),"%s, temp %s", __FUNCTION__, temp);
+        writeStringToParcel(p, string(strlen(temp) == 0 ? "" : temp).c_str());
+        if (temp != NULL) {
+            free(temp);
+        }
+
         rfx_enqueue_response_message(p,cb_priv_ptr,mipc_sim_id_to_slot_id(sim_ps_id),RIL_E_SUCCESS);
     }
 }
@@ -527,7 +573,13 @@
         sscanf(out.c_str(), "%02x%02x", &(sw1), &(sw2));
         p->writeInt32(sw1);
         p->writeInt32(sw2);
-        writeStringToParcel(p, string(strlen(result_ptr->resp_apdu) == 0 ? "" : result_ptr->resp_apdu).c_str());
+
+        char* temp = (char*)byteArrayToHexString((unsigned char*)result_ptr->resp_apdu, result_ptr->resp_len);
+        RFX_LOG_D(getTag(sim_ps_id).c_str(),"%s, temp %s", __FUNCTION__, temp);
+        writeStringToParcel(p, string(strlen(temp) == 0 ? "" : temp).c_str());
+        if (temp != NULL) {
+            free(temp);
+        }
         rfx_enqueue_response_message(p,cb_priv_ptr,mipc_sim_id_to_slot_id(sim_ps_id),RIL_E_SUCCESS);
     }
 }
@@ -583,8 +635,15 @@
             sscanf(out.c_str(), "%02x%02x", &(sw1), &(sw2));
             p->writeInt32(sw1);
             p->writeInt32(sw2);
+            writeStringToParcel(p, string(strlen(result_ptr->resp) == 0 ? "" : result_ptr->resp).c_str());
+        } else { //RIL_REQUEST_ISIM_AUTHENTICATION
+            char* temp = (char*)byteArrayToHexString((unsigned char*)result_ptr->resp, result_ptr->resp_len);
+            RFX_LOG_D(getTag(sim_ps_id).c_str(),"%s, temp %s", __FUNCTION__, temp);
+            writeStringToParcel(p, string(strlen(temp) == 0 ? "" : temp).c_str());
+            if (temp != NULL) {
+                free(temp);
+            }
         }
-        writeStringToParcel(p, string(strlen(result_ptr->resp) == 0 ? "" : result_ptr->resp).c_str());
         rfx_enqueue_response_message(p,cb_priv_ptr,mipc_sim_id_to_slot_id(sim_ps_id),RIL_E_SUCCESS);
     }
 }
@@ -776,7 +835,7 @@
     Parcel *parcel = new Parcel();
     parcel->writeInt32(result_ptr->sim_refresh_result);
     parcel->writeInt32((result_ptr->ef_id == UINT32_MAX) ? -1:result_ptr->ef_id);
-    writeStringToParcel(parcel, ((strlen(result_ptr->aid) == 0) ? "": result_ptr->aid));
+    writeStringToParcel(parcel, ((result_ptr->aid == NULL || (result_ptr->aid != NULL && strlen(result_ptr->aid) == 0)) ? "": result_ptr->aid));
     rfx_enqueue_urc_message(RIL_UNSOL_SIM_REFRESH,parcel,mipc_sim_id_to_slot_id(sim_ps_id),err);
 }
 
@@ -1279,28 +1338,43 @@
         p3 = (int)t;
 
         data_ptr = strdupReadString(p);
-        if(string(data_ptr).empty()) {
-            RFX_LOG_D(mLog_tag.c_str(), "%s data_ptr = NULL", __FUNCTION__);
-            if(data_ptr) {
-                free(data_ptr);
+        if (data_ptr != NULL) {
+            RFX_LOG_E(mLog_tag.c_str(), "data_ptr %d", __FUNCTION__,data_ptr);
+            if(string(data_ptr).empty()) {
+                RFX_LOG_D(mLog_tag.c_str(), "%s data_ptr = NULL", __FUNCTION__);
+                if(data_ptr) {
+                    free(data_ptr);
+                }
+                data_ptr = NULL;
             }
-            data_ptr = NULL;
+        } else {
+            RFX_LOG_E(mLog_tag.c_str(), "data_ptr NULL", __FUNCTION__);
         }
         pin2 = strdupReadString(p);
-        if(string(pin2).empty()) {
-            RFX_LOG_D(mLog_tag.c_str(), "%s pin2 = NULL", __FUNCTION__);
-            if(pin2) {
-                free(pin2);
+        if (pin2 != NULL) {
+            RFX_LOG_E(mLog_tag.c_str(), "pin2 %d", __FUNCTION__,pin2);
+            if(string(pin2).empty()) {
+                RFX_LOG_D(mLog_tag.c_str(), "%s pin2 = NULL", __FUNCTION__);
+                if(pin2) {
+                    free(pin2);
+                }
+                pin2 = NULL;
             }
-            pin2 = NULL;
+        } else {
+            RFX_LOG_E(mLog_tag.c_str(), "pin2 NULL", __FUNCTION__);
         }
         aidPtr = strdupReadString(p);
-        if(string(aidPtr).empty()) {
-            RFX_LOG_D(mLog_tag.c_str(), "%s aidPtr = NULL", __FUNCTION__);
-            if(aidPtr) {
-                free(aidPtr);
+        if (aidPtr != NULL) {
+            RFX_LOG_E(mLog_tag.c_str(), "aidPtr %d", __FUNCTION__,aidPtr);
+            if(string(aidPtr).empty()) {
+                RFX_LOG_D(mLog_tag.c_str(), "%s aidPtr = NULL", __FUNCTION__);
+                if(aidPtr) {
+                    free(aidPtr);
+                }
+                aidPtr = NULL;
             }
-            aidPtr = NULL;
+        } else {
+            RFX_LOG_E(mLog_tag.c_str(), "aidPtr NULL", __FUNCTION__);
         }
         app_id = queryAppTypeId(aidPtr==NULL? "": aidPtr);
         RFX_LOG_D(mLog_tag.c_str(), "cmd:%d, file_id:%d,path:%s,p1=%d,p2=%d,p3=%u,data=%s,pin2=%s,aid=%s, app_id=%d", cmd, file_id,
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/stk/RpStkController.cpp b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/stk/RpStkController.cpp
old mode 100644
new mode 100755
index 5216fd3..322860b
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/stk/RpStkController.cpp
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/stk/RpStkController.cpp
@@ -877,7 +877,7 @@
             //Todo: Add the data structure for RIL_SimRefreshResponse_v7
             parcel->writeInt32(simRefreshRspV7.result);
             parcel->writeInt32((simRefreshRspV7.ef_id == UINT32_MAX) ? -1:simRefreshRspV7.ef_id);
-            writeStringToParcel(parcel, ((strlen(simRefreshRspV7.aid) == 0) ? "": simRefreshRspV7.aid));
+            writeStringToParcel(parcel, ((simRefreshRspV7.aid != NULL && strlen(simRefreshRspV7.aid) == 0) ? "": simRefreshRspV7.aid));
             rfx_enqueue_urc_message(RIL_UNSOL_SIM_REFRESH,parcel,mipc_sim_id_to_slot_id(sim_ps_id),err);
             readIdx += 4;  // go to next EFID
         }
@@ -885,7 +885,7 @@
             //Todo: Add the data structure for RIL_SimRefreshResponse_v7
             parcel->writeInt32(simRefreshRspV7.result);
             parcel->writeInt32((simRefreshRspV7.ef_id == UINT32_MAX) ? -1:simRefreshRspV7.ef_id);
-            writeStringToParcel(parcel, ((strlen(simRefreshRspV7.aid) == 0) ? "": simRefreshRspV7.aid));
+            writeStringToParcel(parcel, ((simRefreshRspV7.aid != NULL && strlen(simRefreshRspV7.aid) == 0) ? "": simRefreshRspV7.aid));
             rfx_enqueue_urc_message(RIL_UNSOL_SIM_REFRESH,parcel,mipc_sim_id_to_slot_id(sim_ps_id),err);
     }
 
@@ -914,6 +914,24 @@
     }
 }
 
+static void mipc_stk_pac_set_cb(
+    mipc_sim_ps_id_enum sim_ps_id,
+    mipc_stk_pac_set_struct *result_ptr,
+    void *cb_priv_ptr)
+{
+    int i = 0;
+    if (result_ptr != NULL) {
+        RFX_LOG_D(RFX_LOG_TAG,"mipc_stk_pac_set_cb result_code %d\n", result_ptr->result_code);
+        for (i = 0; i < 32; i++) {
+            RFX_LOG_D(RFX_LOG_TAG,"pac[%d][%d][%d][%d][%d][%d][%d][%d]\n",
+                result_ptr->pac_profile[(8*i)],result_ptr->pac_profile[(8*i)+1],result_ptr->pac_profile[(8*i)+2],result_ptr->pac_profile[(8*i)+3],
+                result_ptr->pac_profile[(8*i)+4],result_ptr->pac_profile[(8*i)+5],result_ptr->pac_profile[(8*i)+6],result_ptr->pac_profile[(8*i)+7]);
+        }
+    } else {
+        RFX_LOG_E(RFX_LOG_TAG,"mipc_stk_pac_set_cb result_code NULL\n");
+    }
+}
+
 static void mipc_stk_send_envelope_cb(
     mipc_sim_ps_id_enum sim_ps_id,
     mipc_stk_envelope_struct *result_ptr,
@@ -1077,7 +1095,7 @@
 
         stkController->handleStkCommand(cmd, CMD_TYPE_NOTIFY, sim_ps_id);
         break;
-        case CMD_YPE_SESSIONEND:
+        case CMD_TYPE_SESSIONEND:
             rfx_enqueue_urc_message(RIL_UNSOL_STK_SESSION_END,NULL,mipc_sim_id_to_slot_id(sim_ps_id),err);
             break;
     }
@@ -1098,6 +1116,9 @@
         RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING,//103
         RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS //107
     };
+    uint8_t value[32];
+    uint8_t len = 32;
+    memset(value, 0xFF, len);
 
     sInstance[getSlotId()] = this;
     // register request id list
@@ -1105,7 +1126,7 @@
             sizeof(request_id_list) / sizeof(int));
     slotid = getSlotId();
     mipc_stk_pac_ind_register(slot_id_to_mipc_sim_id(slotid), mipc_stk_proactive_notification_command_cb, NULL);
-
+    mipc_stk_pac_set_async(slot_id_to_mipc_sim_id(slotid), mipc_stk_pac_set_cb, NULL, value);
     RFX_LOG_D(RFX_LOG_TAG, "RpStkController onInit done");
 }
 
@@ -1360,7 +1381,7 @@
         switch(cmdType) {
             case CMD_REFRESH:
                 //handle sim refresh
-                handleSimRefresh(&(cmd[type_pos - 6]), sim_ps_id);
+                //L5 has handled it and we use mipc_stk_sim_refresh_ind_cb to report the sim refresh command.
                 break;
             case CMD_SETUP_CALL:
                 //handle setup call
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/stk/RpStkController.h b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/stk/RpStkController.h
old mode 100644
new mode 100755
index f1335a0..5441330
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/stk/RpStkController.h
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/stk/RpStkController.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -92,7 +93,7 @@
 typedef enum {
     CMD_TYPE_PROACTIVE = 0x00,
     CMD_TYPE_NOTIFY = 0x01,
-    CMD_YPE_SESSIONEND = 0x02
+    CMD_TYPE_SESSIONEND = 0x02
 } sat_cmd_type_num;
 
 typedef struct {
diff --git a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/sys/RpSysController.cpp b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/sys/RpSysController.cpp
old mode 100644
new mode 100755
index 2d07983..00d321e
--- a/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/sys/RpSysController.cpp
+++ b/src/telephonyware/3.0/hardware/ril/fusion/libril/rilmipc/telephony/sys/RpSysController.cpp
@@ -875,7 +875,7 @@
 
     mipc_sys_mapping_struct sys_mapping;
     uint8_t mapping_list_count = getSimCount();
-    mipc_sys_mapping_struct4 ps_list[4];
+    mipc_sys_mapping_struct4 ps_list[4] = {0};
 
     if (m_new_main_slot == 0) {
         // PS1 on SIM1
diff --git a/src/telephonyware/3.0/hardware/ril/include/telephony/mtk_ril_ivt.h b/src/telephonyware/3.0/hardware/ril/include/telephony/mtk_ril_ivt.h
old mode 100644
new mode 100755
index 7d787f6..a13482f
--- a/src/telephonyware/3.0/hardware/ril/include/telephony/mtk_ril_ivt.h
+++ b/src/telephonyware/3.0/hardware/ril/include/telephony/mtk_ril_ivt.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -54,15 +55,9 @@
     ECALL_RECONFIG = 3,     /*  Reconfiguration eCall */
 }RIL_ECall_Variant;
 
-typedef enum{
-    ECALL_PSAP_PULL_MODE = 1,   /*  PSAP will PULL the data */
-    ECALL_IVS_PUSH_MODE = 2,    /*  IVS should request PSAP to PULL the data */
-}RIL_ECall_Ivs_Config_Mode;
-
 typedef struct{
     RIL_ECall_Category   ecall_cat;
     RIL_ECall_Variant   ecall_variant;
-    RIL_ECall_Ivs_Config_Mode    ivs_mode;
     char* address;
     unsigned int length;
     unsigned char* msd_data;
@@ -89,6 +84,8 @@
     RIL_UNSOL_ECALL_IMS_IN_BAND_TRANSFER = 22,
     RIL_UNSOL_ECALL_IMS_MSD_NACK = 23,
     RIL_UNSOL_ECALL_IMS_SRVCC = 24,
+    RIL_UNSOL_ECALL_ONLY_DEREGISTRATION = 31,
+    RIL_UNSOL_ECALL_MAY_DEREGISTER = 32,
     RIL_UNSOL_ECALL_UNSPECIFIED = 0xffff,
 }RIL_ECall_Indication;
 
diff --git a/src/telephonyware/3.0/hardware/ril/include/telephony/ril.h b/src/telephonyware/3.0/hardware/ril/include/telephony/ril.h
old mode 100644
new mode 100755
index 88bf56f..c769602
--- a/src/telephonyware/3.0/hardware/ril/include/telephony/ril.h
+++ b/src/telephonyware/3.0/hardware/ril/include/telephony/ril.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /*
  * Copyright (C) 2006 The Android Open Source Project
  *
@@ -1127,6 +1128,7 @@
     PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
 
     PDP_FAIL_LOCAL_REJECT_ACT_REQ_DUE_TO_REACH_RETRY_COUNTER = 0x0E0F,  /* M */
+    PDP_FAIL_TCM_ESM_DETACH = 0x0F45,  /* M */
     PDP_FAIL_TCM_ESM_TIMER_TIMEOUT = 0x0F46,  /* M */
     PDP_FAIL_TCM_ESM_DEACT_DUE_TO_DRB_RELEASE = 0x0F8E,  /* M */
     PDP_FAIL_PAM_ATT_PDN_ACCESS_REJECT_IMS_PDN_BLOCK_TEMP = 0x1402,  /* M */
diff --git a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/CMakeLists.txt b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/CMakeLists.txt
old mode 100644
new mode 100755
index 63e5d21..662945a
--- a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/CMakeLists.txt
+++ b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/CMakeLists.txt
@@ -27,6 +27,7 @@
 	lib/src/api/mipc_stk_api.c
 	lib/src/api/mipc_sys_api.c
 	lib/src/api/mipc_call_api.c
+	lib/src/api/mipc_ecall_api.c
 	lib/src/api/mipc_radio_api.c)
 
 add_library(mipc_api SHARED ${api_src_files})
diff --git a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_data_api.h b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_data_api.h
old mode 100644
new mode 100755
index c05afc4..6c3ec31
--- a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_data_api.h
+++ b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_data_api.h
@@ -136,7 +136,7 @@
     /** @brief id */
     uint8_t id;
 
-    mipc_data_error_enum network_error;
+    uint32_t network_error;
 } mipc_data_call_deact_struct;
 
 /** @brief pco info. */
@@ -176,6 +176,11 @@
     mipc_result_enum result_code;
 } mipc_data_set_data_config_struct_v;
 
+typedef struct {
+    /** @brief result code*/
+    mipc_result_enum result_code;
+    uint32_t retry_timer;
+} mipc_data_get_retry_timer_struct_v;
 
 
 /** @brief packet filter*/
@@ -695,7 +700,37 @@
     mipc_data_config_type_const_enum data_international_roaming
 );
 
+typedef void (*MIPC_DATA_RETRY_TIMER_CB)(
+    mipc_sim_ps_id_enum sim_ps_id,
+    mipc_data_get_retry_timer_struct_v *result_ptr,
+    void *cb_priv_ptr
+);
 
+/**
+  *@brief function for async. packet filter get operation
+  *@param[in] sim_ps_id indicate which sim or ps received the event (the value is decided by what is used when doing register operation)
+  *@param[in] result_ptr point to the execution result
+  *@param[in] apnName apn name
+*/
+mipc_api_result_enum mipc_data_get_retry_timer_sync(
+    mipc_sim_ps_id_enum sim_ps_id,
+    mipc_data_get_retry_timer_struct_v *result_ptr,
+    char* apnName
+);
+
+/**
+  *@brief function for async. packet filter get operation
+  *@param[in] sim_ps_id indicate which sim or ps received the event (the value is decided by what is used when doing register operation)
+  *@param[in] cb which callback function will be invoked after the operation completion
+  *@param[in] cb_priv_ptr point to the callback private data
+  *@param[in] apnName apn name
+*/
+mipc_api_result_enum mipc_data_get_retry_timer_async(
+    mipc_sim_ps_id_enum sim_ps_id,
+    MIPC_DATA_RETRY_TIMER_CB cb,
+    void *cb_priv_ptr,
+    char* apnName
+);
 
 /*!
     @}
diff --git a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_ecall_api.h b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_ecall_api.h
new file mode 100755
index 0000000..226c9d2
--- /dev/null
+++ b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_ecall_api.h
@@ -0,0 +1,477 @@
+// SPDX-License-Identifier: MediaTekProprietary

+/*****************************************************************************

+*  Copyright Statement:

+*  --------------------

+*  Copyright (c) [2020], MediaTek Inc. All rights reserved.

+*  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. Except as otherwise provided in the

+*  applicable licensing terms with 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.

+*****************************************************************************/

+

+#ifndef MIPC_ECALL_INTERFACE_H_

+#define MIPC_ECALL_INTERFACE_H_

+

+#include "mipc_api.h"

+#include "mipc_msg_host.h"

+#include "mipc_msg_tlv_const.h"

+

+/** @brief mipc ecall make an ecall */

+typedef struct {

+    /** @brief result code*/

+    mipc_result_enum result_code;

+} mipc_call_ivs_onekey_ecall_struct;

+

+/**

+  *@brief callback function prototype for async. SIM status get operation

+  *@param[in] sim_ps_id indicate which sim or ps completed the operation (the value is decided by what is used when doing aysnc. operation)

+  *@param[in] result_ptr point to the execution result

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+*/

+typedef void (*MIPC_CALL_IVS_ONEKEY_ECALL_CB)(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_call_ivs_onekey_ecall_struct *result_ptr,

+    void *cb_priv_ptr

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] result_ptr point to the execution result

+  *@param[in] ecall_type

+  *@param[in] ecall_format

+  *@param[in] msd_length

+  *@param[in] msd_data

+*/

+mipc_api_result_enum mipc_call_ivs_onekey_ecall_sync(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_call_ivs_onekey_ecall_struct *result_ptr,

+    mipc_ecall_type_const_enum ecall_type,

+    mipc_ecall_msd_format_const_enum ecall_format,

+    unsigned int msd_length,

+    unsigned char* msd_data

+);

+

+/**

+  *@brief function for async.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] cb

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+  *@param[in] ecall_type

+  *@param[in] ecall_format

+  *@param[in] msd_length

+  *@param[in] msd_data

+*/

+mipc_api_result_enum mipc_call_ivs_onekey_ecall_async(

+    mipc_sim_ps_id_enum sim_ps_id,

+    MIPC_CALL_IVS_ONEKEY_ECALL_CB cb,

+    void *cb_priv_ptr,

+    mipc_ecall_type_const_enum ecall_type,

+    mipc_ecall_msd_format_const_enum ecall_format,

+    unsigned int msd_length,

+    unsigned char* msd_data

+);

+

+/** @brief mipc ecall update msd struct */

+typedef struct {

+    /** @brief result code*/

+    mipc_result_enum result_code;

+} mipc_ecall_ivs_update_msd_struct;

+

+/**

+  *@brief callback function prototype for async. SIM status get operation

+  *@param[in] sim_ps_id indicate which sim or ps completed the operation (the value is decided by what is used when doing aysnc. operation)

+  *@param[in] result_ptr point to the execution result

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+*/

+typedef void (*MIPC_ECALL_IVS_UPDATE_MSD_CB)(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_update_msd_struct *result_ptr,

+    void *cb_priv_ptr

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] result_ptr point to the execution result

+  *@param[in] ecall_type

+  *@param[in] ecall_format

+  *@param[in] msd_length

+  *@param[in] msd_data

+*/

+mipc_api_result_enum mipc_ecall_ivs_update_msd_sync(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_update_msd_struct *result_ptr,

+    mipc_ecall_msd_format_const_enum msd_format,

+    unsigned int msd_length,

+    unsigned char* msd_data

+);

+

+/**

+  *@brief function for async.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] cb

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+  *@param[in] ecall_type

+  *@param[in] ecall_format

+  *@param[in] msd_length

+  *@param[in] msd_data

+*/

+mipc_api_result_enum mipc_ecall_ivs_update_msd_async(

+    mipc_sim_ps_id_enum sim_ps_id,

+    MIPC_ECALL_IVS_UPDATE_MSD_CB cb,

+    void *cb_priv_ptr,

+    mipc_ecall_msd_format_const_enum msd_format,

+    unsigned int msd_length,

+    unsigned char* msd_data

+);

+

+/** @brief mipc ecall reset ivs struct */

+typedef struct {

+    /** @brief result code*/

+    mipc_result_enum result_code;

+} mipc_ecall_ivs_reset_struct;

+

+/**

+  *@brief callback function prototype for async. SIM status get operation

+  *@param[in] sim_ps_id indicate which sim or ps completed the operation (the value is decided by what is used when doing aysnc. operation)

+  *@param[in] result_ptr point to the execution result

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+*/

+typedef void (*MIPC_ECALL_IVS_RESET_CB)(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_reset_struct *result_ptr,

+    void *cb_priv_ptr

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] result_ptr point to the execution result

+*/

+mipc_api_result_enum mipc_ecall_ivs_reset_sync(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_reset_struct *result_ptr

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] result_ptr point to the execution result

+  *@param[in] dail_address dail address

+  *@param[in] dial_addr_type

+  *@param[in] type, isn't mandatory, default voice

+  *@param[in] domain isn't mandatory,default auto

+  *@param[in] ecc_retry_domain isn't mandatory,default auto

+  *@param[in] ecc_category isn't mandatory,default 0

+  *@param[in] clir isn't mandatory,default false

+*/

+mipc_api_result_enum mipc_ecall_ivs_reset_async(

+    mipc_sim_ps_id_enum sim_ps_id,

+    MIPC_ECALL_IVS_RESET_CB cb,

+    void *cb_priv_ptr

+);

+

+

+/** @brief mipc ecall get sim info resp struct*/

+typedef struct {

+    /** @brief result code*/

+    mipc_result_enum result_code;

+    mipc_ecall_sim_type_const_enum sim_type;

+    char* usim_test_ecall_uri;

+    char* usim_test_ecall_num;

+    char* usim_reconf_ecall_uri;

+    char* usim_reconf_ecall_num;

+} mipc_ecall_ivs_get_sim_info_struct;

+

+/**

+  *@brief callback function prototype for async. SIM status get operation

+  *@param[in] sim_ps_id indicate which sim or ps completed the operation (the value is decided by what is used when doing aysnc. operation)

+  *@param[in] result_ptr point to the execution result

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+*/

+typedef void (*MIPC_ECALL_IVS_GET_SIM_INFO_CB)(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_get_sim_info_struct *result_ptr,

+    void *cb_priv_ptr

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] result_ptr point to the execution result

+  *@param[in] test_address test address

+  *@param[in] num

+  *@param[in] type

+*/

+mipc_api_result_enum mipc_ecall_ivs_get_sim_info_sync(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_get_sim_info_struct *result_ptr

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] cb

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+  *@param[in] test_address test address

+  *@param[in] num

+  *@param[in] type

+*/

+mipc_api_result_enum mipc_ecall_ivs_get_sim_info_async(

+    mipc_sim_ps_id_enum sim_ps_id,

+    MIPC_ECALL_IVS_GET_SIM_INFO_CB cb,

+    void *cb_priv_ptr

+);

+

+

+/** @brief mipc ecall set reg state resp struct*/

+typedef struct {

+    /** @brief result code*/

+    mipc_result_enum result_code;

+} mipc_ecall_ivs_set_reg_state_struct;

+

+

+/**

+  *@brief callback function prototype for async. SIM status get operation

+  *@param[in] sim_ps_id indicate which sim or ps completed the operation (the value is decided by what is used when doing aysnc. operation)

+  *@param[in] result_ptr point to the execution result

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+*/

+typedef void (*MIPC_ECALL_IVS_SET_REG_STATE_CB)(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_set_reg_state_struct *result_ptr,

+    void *cb_priv_ptr

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] result_ptr point to the execution result

+  *@param[in] test_address test address

+  *@param[in] num

+  *@param[in] type

+*/

+mipc_api_result_enum mipc_ecall_ivs_set_reg_state_sync(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_set_reg_state_struct *result_ptr,

+    mipc_nw_register_mode_const_enum reg_state

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] cb

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+  *@param[in] test_address test address

+  *@param[in] num

+  *@param[in] type

+*/

+mipc_api_result_enum mipc_ecall_ivs_set_reg_state_async(

+    mipc_sim_ps_id_enum sim_ps_id,

+    MIPC_ECALL_IVS_SET_REG_STATE_CB cb,

+    void *cb_priv_ptr,

+    mipc_nw_register_mode_const_enum reg_state

+);

+

+

+/** @brief mipc ecall set test addr resp struct*/

+typedef struct {

+    /** @brief result code*/

+    mipc_result_enum result_code;

+} mipc_ecall_ivs_set_test_addr_struct;

+

+

+/**

+  *@brief callback function prototype for async. SIM status get operation

+  *@param[in] sim_ps_id indicate which sim or ps completed the operation (the value is decided by what is used when doing aysnc. operation)

+  *@param[in] result_ptr point to the execution result

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+*/

+typedef void (*MIPC_ECALL_IVS_SET_TEST_ADDR_CB)(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_set_test_addr_struct *result_ptr,

+    void *cb_priv_ptr

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] result_ptr point to the execution result

+  *@param[in] test_address test address

+  *@param[in] num

+  *@param[in] type

+*/

+mipc_api_result_enum mipc_ecall_ivs_set_test_addr_sync(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_set_test_addr_struct *result_ptr,

+    char *test_address,

+	mipc_call_dial_address_type_const_enum address_type

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] cb

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+  *@param[in] test_address test address

+  *@param[in] num

+  *@param[in] type

+*/

+mipc_api_result_enum mipc_ecall_ivs_set_test_addr_async(

+    mipc_sim_ps_id_enum sim_ps_id,

+    MIPC_ECALL_IVS_SET_TEST_ADDR_CB cb,

+    void *cb_priv_ptr,

+    char *test_address,

+	mipc_call_dial_address_type_const_enum address_type

+);

+

+/** @brief mipc ecall set reconf addr resp struct*/

+typedef struct {

+    /** @brief result code*/

+    mipc_result_enum result_code;

+} mipc_ecall_ivs_set_reconf_addr_struct;

+

+

+/**

+  *@brief callback function prototype for async. SIM status get operation

+  *@param[in] sim_ps_id indicate which sim or ps completed the operation (the value is decided by what is used when doing aysnc. operation)

+  *@param[in] result_ptr point to the execution result

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+*/

+typedef void (*MIPC_ECALL_IVS_SET_RECONF_ADDR_CB)(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_set_reconf_addr_struct *result_ptr,

+    void *cb_priv_ptr

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] result_ptr point to the execution result

+  *@param[in] test_address test address

+  *@param[in] num

+  *@param[in] type

+*/

+mipc_api_result_enum mipc_ecall_ivs_set_reconf_addr_sync(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_set_reconf_addr_struct *result_ptr,

+    char *reconf_address,

+	mipc_call_dial_address_type_const_enum address_type

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] cb

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+  *@param[in] test_address test address

+  *@param[in] num

+  *@param[in] type

+*/

+mipc_api_result_enum mipc_ecall_ivs_set_reconf_addr_async(

+    mipc_sim_ps_id_enum sim_ps_id,

+    MIPC_ECALL_IVS_SET_RECONF_ADDR_CB cb,

+    void *cb_priv_ptr,

+    char *reconf_address,

+	mipc_call_dial_address_type_const_enum address_type

+);

+

+/** @brief mipc ecall addr pri resp struct*/

+typedef struct {

+    /** @brief result code*/

+    mipc_result_enum result_code;

+} mipc_ecall_ivs_set_addr_pri_struct;

+

+

+/**

+  *@brief callback function prototype for async. SIM status get operation

+  *@param[in] sim_ps_id indicate which sim or ps completed the operation (the value is decided by what is used when doing aysnc. operation)

+  *@param[in] result_ptr point to the execution result

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+*/

+typedef void (*MIPC_ECALL_IVS_SET_ADDR_PRI_CB)(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_set_addr_pri_struct *result_ptr,

+    void *cb_priv_ptr

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] result_ptr point to the execution result

+  *@param[in] test_address test address

+  *@param[in] num

+  *@param[in] type

+*/

+mipc_api_result_enum mipc_ecall_ivs_set_addr_pri_sync(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_ivs_set_addr_pri_struct *result_ptr,

+    mipc_ecall_address_priority_class_const_enum first_pri,

+    mipc_ecall_address_priority_class_const_enum second_pri,

+    mipc_ecall_address_priority_class_const_enum third_pri,

+    mipc_ecall_address_priority_class_const_enum fourth_pri

+);

+

+/**

+  *@brief function for sync.

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in, out] cb

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+  *@param[in] test_address test address

+  *@param[in] num

+  *@param[in] type

+*/

+mipc_api_result_enum mipc_ecall_ivs_set_addr_pri_async(

+    mipc_sim_ps_id_enum sim_ps_id,

+    MIPC_ECALL_IVS_SET_ADDR_PRI_CB cb,

+    void *cb_priv_ptr,

+    mipc_ecall_address_priority_class_const_enum first_pri,

+    mipc_ecall_address_priority_class_const_enum second_pri,

+    mipc_ecall_address_priority_class_const_enum third_pri,

+    mipc_ecall_address_priority_class_const_enum fourth_pri

+);

+

+/////////////////////////////////INDICATIONS////////////////////////////////////////////

+typedef struct {

+    /** @brief result code*/

+    mipc_result_enum result_code;

+    /** @brief ecall state list*/

+    mipc_ecall_status_const_enum state;

+    uint8_t callid;

+} mipc_ecall_status_ind_struct;

+

+

+/**

+  *@brief callback function prototype for  call status changed notification operation

+  * This function will be called when radio state changed.

+  *@param[in] sim_ps_id indicate which sim or ps received the event (the value is decided by what is used when doing register operation)

+  *@param[in] result_ptr point to the execution result

+  *@param[in] cb_priv_ptr point to the private data assigned when doing async. operation

+*/

+typedef void (*MIPC_ECALL_STATUS_IND_CB)(

+    mipc_sim_ps_id_enum sim_ps_id,

+    mipc_ecall_status_ind_struct *result_ptr,

+    void *cb_priv_ptr

+);

+

+/**

+  *@brief function to register callback function for call status changed

+  *@param[in] sim_ps_id indicate which sim or ps is assigned to do the operation

+  *@param[in] cb which callback function will be invoked after the operation completion

+  *@param[in] cb_priv_ptr point to the callback private data

+*/

+mipc_api_result_enum mipc_ecall_status_register(

+    mipc_sim_ps_id_enum sim_ps_id,

+    MIPC_ECALL_STATUS_IND_CB cb,

+    void *cb_priv_ptr

+);

+

+

+#endif /* MIPC_ECALL_INTERFACE_H_ */

+

diff --git a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_nw_api.h b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_nw_api.h
old mode 100644
new mode 100755
index ec05943..40e7099
--- a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_nw_api.h
+++ b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/include/api/mipc_nw_api.h
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /*****************************************************************************
 *  Copyright Statement:
 *  --------------------
@@ -866,6 +867,11 @@
     MIPC_MSG_CB cb,
     void *cb_priv_ptr);
 
+mipc_api_result_enum mipc_nw_etxpwr_ind_register(
+    mipc_sim_ps_id_enum sim_ps_id,
+    MIPC_MSG_CB cb,
+    void *cb_priv_ptr);
+
 /**
   *@brief callback function prototype for async. home provider set operation
   *@param[in] sim_ps_id indicate which sim or ps completed the operation (the value is decided by what is used when doing aysnc. operation)
@@ -1423,6 +1429,7 @@
 mipc_api_result_enum mipc_nw_band_mode_set_async(mipc_sim_ps_id_enum sim_ps_id, MIPC_NW_BAND_MODE_SET_CB cb, void *cb_priv_ptr,mipc_nw_band_mode_struct *band_mode);
 mipc_api_result_enum mipc_nw_set_rat_async(mipc_sim_ps_id_enum sim_ps_id, MIPC_NW_SET_RAT_CB cb, void *cb_priv_ptr, uint8_t rat,uint8_t prefer_rat);
 mipc_api_result_enum mipc_nw_get_rat_async(mipc_sim_ps_id_enum sim_ps_id, MIPC_NW_GET_RAT_CB cb, void *cb_priv_ptr);
+mipc_api_result_enum mipc_nw_get_rat_sync(mipc_sim_ps_id_enum sim_ps_id, mipc_nw_get_rat_struct *cb_priv_ptr);
 mipc_api_result_enum mipc_nw_data_get_async(mipc_sim_ps_id_enum sim_ps_id, MIPC_NW_DATA_GET_CB cb, void *cb_priv_ptr);
 mipc_api_result_enum mipc_nw_band_mode_get_async(mipc_sim_ps_id_enum sim_ps_id, MIPC_NW_BAND_MODE_GET_CB cb, void *cb_priv_ptr);
 mipc_api_result_enum mipc_nw_band_mode_get_sync(mipc_sim_ps_id_enum sim_ps_id, mipc_nw_band_mode_struct *cb_priv_ptr);
diff --git a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_data_api.c b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_data_api.c
old mode 100644
new mode 100755
index 3db527e..7d56c73
--- a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_data_api.c
+++ b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_data_api.c
@@ -17,6 +17,10 @@
 #include "mipc_msg.h"
 #include "mipc_msg_host.h"
 #include "mipc_data_api.h"
+#include "mipc_msg_tlv_api.h"
+#include "mtk_log.h"
+
+#define LOG_TAG "MIPC_DATA_API"
 
 #define mipc_msg_address_decode(addr_len, count, type, addrs)\
 do{val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, type, NULL);\
@@ -234,9 +238,9 @@
         val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_DATA_DEACT_CALL_IND_T_ID, NULL);
         if (NULL == val_ptr) break;
         result_ptr->id = *((uint8_t*)val_ptr);
-        val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_DATA_DEACT_CALL_IND_T_RES, NULL);
+        val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_DATA_DEACT_CALL_IND_T_NEW_RES, NULL);
         if (NULL == val_ptr) break;
-        result_ptr->network_error = (mipc_data_error_enum)(*((uint8_t*)val_ptr));
+        result_ptr->network_error = (*((uint32_t*)val_ptr));
         result = MIPC_API_RESULT_SUCCESS;
     } while (0);
 
@@ -1129,7 +1133,7 @@
 
 mipc_api_result_enum mipc_data_set_config_sync(mipc_sim_ps_id_enum sim_ps_id, mipc_data_set_data_config_struct_v *result_ptr, mipc_data_config_type_const_enum mobile_data, mipc_data_config_type_const_enum data_roaming, mipc_data_config_type_const_enum volte, mipc_data_config_type_const_enum ims_test_mode, mipc_data_config_type_const_enum data_domestic_roaming, mipc_data_config_type_const_enum data_international_roaming)
 {
-    return mipc_data_set_config(sim_ps_id, NULL, NULL, NULL, mobile_data, data_roaming, volte, ims_test_mode, data_domestic_roaming, data_international_roaming);
+    return mipc_data_set_config(sim_ps_id, NULL, NULL, result_ptr, mobile_data, data_roaming, volte, ims_test_mode, data_domestic_roaming, data_international_roaming);
 }
 
 
@@ -1141,3 +1145,95 @@
     return mipc_data_set_config(sim_ps_id, cb, cb_priv_ptr, NULL, mobile_data, data_roaming, volte, ims_test_mode, data_domestic_roaming, data_international_roaming);
 }
 
+static mipc_api_result_enum mipc_data_get_retry_timer_decode(mipc_msg_t *msg_cnf_ptr, mipc_data_get_retry_timer_struct_v *result_ptr)
+{
+    void* val_ptr;
+    mipc_api_result_enum result = MIPC_API_RESULT_FAIL;
+    mipc_data_retry_type_const_enum retry_type = mipc_data_retry_type_const_NONE;
+
+    if (result_ptr) {
+        MEMSET(result_ptr, 0, sizeof(mipc_data_get_retry_timer_struct_v));
+    } else {
+        return result;
+    }
+
+    if (msg_cnf_ptr == NULL) {
+        if (result_ptr) {
+            result_ptr->result_code = MIPC_RESULT_TIMEOUT;
+        }
+        return MIPC_API_RESULT_TIMEOUT;
+    }
+    mtkLogD(LOG_TAG, "[%s] result_code=%d", __FUNCTION__, result_ptr->result_code);
+    do {
+        result_ptr->result_code = (mipc_result_enum)mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_T_RESULT, 0xFFFFFFFF);
+        if (MIPC_RESULT_SUCCESS != result_ptr->result_code) {
+            break;
+        }
+        retry_type = mipc_data_retry_timer_cnf_get_retry_type(msg_cnf_ptr, 0);
+
+        if (retry_type == MIPC_DATA_RETRY_TYPE_RETRY_TYPE_NO_SUGGEST) {
+            mtkLogD(LOG_TAG, "[%s] no suggest", __FUNCTION__);
+            result_ptr->retry_timer = -1;
+        } else if (retry_type == MIPC_DATA_RETRY_TYPE_RETRY_TYPE_NO_RETRY) {
+            mtkLogD(LOG_TAG, "[%s] no retry", __FUNCTION__);
+            result_ptr->retry_timer = 0x7fffffff;
+        } else if (retry_type == MIPC_DATA_RETRY_TYPE_RETRY_TYPE_WITH_SUGGEST) {
+            result_ptr->retry_timer = mipc_data_retry_timer_cnf_get_retry_time(msg_cnf_ptr, 0);
+            mtkLogD(LOG_TAG, "[%s] suggest=%d", __FUNCTION__, result_ptr->retry_timer);
+            result_ptr->retry_timer = result_ptr->retry_timer * 1000;
+        }
+
+        result = MIPC_API_RESULT_SUCCESS;
+    } while (0);
+
+    return result;
+}
+
+static void mipc_data_get_retry_timer_cb(mipc_msg_t *msg_ptr, MIPC_API_CB cb, void *cb_priv_ptr)
+{
+    mipc_data_get_retry_timer_struct_v result;
+    mipc_sim_ps_id_enum sim_ps_id = (mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id;
+    MEMSET(&result, 0, sizeof(mipc_data_get_retry_timer_struct_v));
+    mipc_data_get_retry_timer_decode(msg_ptr, &result);
+    cb(sim_ps_id, &result, cb_priv_ptr);
+}
+
+static mipc_api_result_enum mipc_data_get_retry_timer(mipc_sim_ps_id_enum sim_ps_id, MIPC_DATA_RETRY_TIMER_CB cb, void *cb_priv_ptr, mipc_data_get_retry_timer_struct_v *result_ptr, char* apnName)
+{
+    mipc_msg_t *msg_req_ptr = mipc_msg_init(MIPC_DATA_RETRY_TIMER_REQ, (mipc_msg_sim_ps_id_enum)sim_ps_id);
+    mipc_msg_t *msg_cnf_ptr = NULL;
+    mipc_api_result_enum ret = MIPC_API_RESULT_FAIL;
+
+    if (apnName == NULL) {
+        mipc_msg_deinit(msg_req_ptr);
+        return ret;
+    }
+    mipc_data_retry_timer_req_add_mode(msg_req_ptr, MIPC_DATA_RETRY_MODE_QUERY_TIMER);
+    mipc_data_retry_timer_req_add_apn_name(msg_req_ptr, strlen(apnName) + 1, apnName);
+    mtkLogD(LOG_TAG, "[%s] mode=%d, apn=%s", __FUNCTION__, MIPC_DATA_RETRY_MODE_QUERY_TIMER, apnName);
+    if (cb) {
+        mipc_msg_async_api(msg_req_ptr, (void *)mipc_data_get_retry_timer_cb, (MIPC_API_CB)cb, cb_priv_ptr);
+        mipc_msg_deinit(msg_req_ptr);
+        return MIPC_API_RESULT_SUCCESS;
+    } else {
+        msg_cnf_ptr = mipc_msg_sync_timeout(msg_req_ptr);
+        mipc_msg_deinit(msg_req_ptr);
+        ret = mipc_data_get_retry_timer_decode(msg_cnf_ptr, result_ptr);
+        mipc_msg_deinit(msg_cnf_ptr);
+        return ret;
+    }
+}
+
+mipc_api_result_enum mipc_data_get_retry_timer_sync(mipc_sim_ps_id_enum sim_ps_id, mipc_data_get_retry_timer_struct_v *result_ptr, char* apnName)
+{
+    return mipc_data_get_retry_timer(sim_ps_id, NULL, NULL, result_ptr, apnName);
+}
+
+mipc_api_result_enum mipc_data_get_retry_timer_async(mipc_sim_ps_id_enum sim_ps_id, MIPC_DATA_RETRY_TIMER_CB cb, void *cb_priv_ptr, char* apnName)
+{
+    if (cb == NULL) {
+        return MIPC_API_RESULT_FAIL;
+    }
+    return mipc_data_get_retry_timer(sim_ps_id, cb, cb_priv_ptr, NULL, apnName);
+}
+
diff --git a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_ecall_api.c b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_ecall_api.c
new file mode 100755
index 0000000..7c34a20
--- /dev/null
+++ b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_ecall_api.c
@@ -0,0 +1,754 @@
+//SPDX-License-Identifier: MediaTekProprietary

+/*****************************************************************************

+*  Copyright Statement:

+*  --------------------

+*  Copyright (c) [2020], MediaTek Inc. All rights reserved.

+*  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. Except as otherwise provided in the

+*  applicable licensing terms with 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.

+*****************************************************************************/

+#include "mipc_ecall_api.h"

+#include <stddef.h>

+

+static mipc_api_result_enum mipc_call_ivs_onekey_ecall_cnf_decode(mipc_msg_t *msg_cnf_ptr, mipc_call_ivs_onekey_ecall_struct *result_ptr)

+{

+    mipc_api_result_enum result = MIPC_API_RESULT_FAIL;

+

+    if (msg_cnf_ptr == NULL) { //timeout

+        if (result_ptr) {

+            result_ptr->result_code = MIPC_RESULT_TIMEOUT;

+        }

+        return MIPC_API_RESULT_TIMEOUT;

+    }

+    do {

+        void* val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_T_RESULT, NULL);

+        if (NULL == val_ptr) break;

+        result_ptr->result_code = (mipc_result_enum)(*((uint32_t*)val_ptr));

+        //acording to MBIM spec, non-succ result should have no information buffer(9.4.5)

+        if (MIPC_RESULT_SUCCESS != result_ptr->result_code) {

+            result = MIPC_API_RESULT_SUCCESS;

+            break;

+        }

+

+        result = MIPC_API_RESULT_SUCCESS;

+    } while (0);

+    return result;

+}

+

+static void mipc_call_ivs_onekey_ecall_cb(mipc_msg_t *msg_ptr, MIPC_CALL_IVS_ONEKEY_ECALL_CB cb, void *cb_priv_ptr)

+{

+    mipc_call_ivs_onekey_ecall_struct *result_ptr = (mipc_call_ivs_onekey_ecall_struct *)ALLOC(sizeof(mipc_call_ivs_onekey_ecall_struct));

+

+    if (result_ptr) {

+        MEMSET(result_ptr, 0, sizeof(mipc_call_ivs_onekey_ecall_struct));

+        mipc_call_ivs_onekey_ecall_cnf_decode(msg_ptr, result_ptr);

+    }

+    cb((mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id, result_ptr, cb_priv_ptr);

+    if (result_ptr) {

+        FREE(result_ptr);

+    }

+}

+

+static mipc_api_result_enum mipc_call_ivs_onekey_ecall(MIPC_CALL_IVS_ONEKEY_ECALL_CB cb,

+        void *cb_priv_ptr, mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_type_const_enum ecall_type,

+        mipc_ecall_msd_format_const_enum ecall_format,

+        unsigned int msd_length,

+        unsigned char* msd_data,

+        mipc_call_ivs_onekey_ecall_struct *result_ptr)

+{

+    mipc_msg_t *msg_req_ptr = mipc_msg_init(MIPC_CALL_IVS_ONEKEY_ECALL_REQ, (mipc_msg_sim_ps_id_enum)sim_ps_id);

+    mipc_msg_t *msg_cnf_ptr;

+    mipc_api_result_enum ret;

+

+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_CALL_IVS_ONEKEY_ECALL_REQ_T_TYPE, ecall_type);

+    if (msd_length > 0) {

+        mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_CALL_IVS_ONEKEY_ECALL_REQ_T_MSD_FORMAT, ecall_format);

+        if (msd_data) {

+            mipc_msg_add_tlv(msg_req_ptr, MIPC_CALL_IVS_ONEKEY_ECALL_REQ_T_MSD, (msd_length < MIPC_MAX_ECALL_MSD_DATA_LEN ? msd_length :MIPC_MAX_ECALL_MSD_DATA_LEN), msd_data);

+        } else {

+            return MIPC_API_RESULT_FAIL;

+        }

+    }

+    if (cb) {

+        mipc_msg_async_api(msg_req_ptr, (void *)mipc_call_ivs_onekey_ecall_cb, (MIPC_API_CB)cb, cb_priv_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        return MIPC_API_RESULT_SUCCESS;

+    } else {

+        msg_cnf_ptr = mipc_msg_sync_timeout(msg_req_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        ret = mipc_call_ivs_onekey_ecall_cnf_decode(msg_cnf_ptr, result_ptr);

+        mipc_msg_deinit(msg_cnf_ptr);

+        return ret;

+    }

+}

+

+mipc_api_result_enum mipc_call_ivs_onekey_ecall_sync(mipc_sim_ps_id_enum sim_ps_id,

+        mipc_call_ivs_onekey_ecall_struct *result_ptr,

+        mipc_ecall_type_const_enum ecall_type,

+        mipc_ecall_msd_format_const_enum ecall_format,

+        unsigned int msd_length,

+        unsigned char* msd_data)

+{

+    if (NULL == result_ptr) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_call_ivs_onekey_ecall(NULL, NULL, sim_ps_id, ecall_type, ecall_format, msd_length, msd_data, result_ptr);

+}

+

+mipc_api_result_enum mipc_call_ivs_onekey_ecall_async(mipc_sim_ps_id_enum sim_ps_id,

+        MIPC_CALL_IVS_ONEKEY_ECALL_CB cb, void *cb_priv_ptr,

+        mipc_ecall_type_const_enum ecall_type,

+        mipc_ecall_msd_format_const_enum ecall_format,

+        unsigned int msd_length,

+        unsigned char* msd_data)

+{

+    if (NULL == cb) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_call_ivs_onekey_ecall(cb, cb_priv_ptr, sim_ps_id, ecall_type, ecall_format, msd_length, msd_data, NULL);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_update_msd_cnf_decode(mipc_msg_t *msg_cnf_ptr, mipc_ecall_ivs_update_msd_struct *result_ptr)

+{

+    mipc_api_result_enum result = MIPC_API_RESULT_FAIL;

+

+    if (msg_cnf_ptr == NULL) { //timeout

+        if (result_ptr) {

+            result_ptr->result_code = MIPC_RESULT_TIMEOUT;

+        }

+        return MIPC_API_RESULT_TIMEOUT;

+    }

+    do {

+        void* val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_T_RESULT, NULL);

+        if (NULL == val_ptr) break;

+        result_ptr->result_code = (mipc_result_enum)(*((uint32_t*)val_ptr));

+        //acording to MBIM spec, non-succ result should have no information buffer(9.4.5)

+        if (MIPC_RESULT_SUCCESS != result_ptr->result_code) {

+            result = MIPC_API_RESULT_SUCCESS;

+            break;

+        }

+

+        result = MIPC_API_RESULT_SUCCESS;

+    } while (0);

+    return result;

+}

+

+static void mipc_ecall_ivs_update_msd_cb(mipc_msg_t *msg_ptr, MIPC_ECALL_IVS_UPDATE_MSD_CB cb, void *cb_priv_ptr)

+{

+    mipc_ecall_ivs_update_msd_struct *result_ptr = (mipc_ecall_ivs_update_msd_struct *)ALLOC(sizeof(mipc_ecall_ivs_update_msd_struct));

+

+    if (result_ptr) {

+        MEMSET(result_ptr, 0, sizeof(mipc_ecall_ivs_update_msd_struct));

+        mipc_ecall_ivs_update_msd_cnf_decode(msg_ptr, result_ptr);

+    }

+    cb((mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id, result_ptr, cb_priv_ptr);

+    if (result_ptr) {

+        FREE(result_ptr);

+    }

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_update_msd(MIPC_ECALL_IVS_UPDATE_MSD_CB cb, void *cb_priv_ptr, mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_msd_format_const_enum msd_format,

+        unsigned int msd_length,

+        unsigned char* msd_data,

+        mipc_ecall_ivs_update_msd_struct *result_ptr)

+{

+    mipc_msg_t *msg_req_ptr = mipc_msg_init(MIPC_ECALL_IVS_UPDATE_MSD_REQ, (mipc_msg_sim_ps_id_enum)sim_ps_id);

+    mipc_msg_t *msg_cnf_ptr;

+    mipc_api_result_enum ret;

+

+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_ECALL_IVS_UPDATE_MSD_REQ_T_MSD_FORMAT, msd_format);

+    if (msd_data) {

+        mipc_msg_add_tlv(msg_req_ptr, MIPC_ECALL_IVS_UPDATE_MSD_REQ_T_MSD_DATA, (msd_length < MIPC_MAX_ECALL_MSD_DATA_LEN ? msd_length :MIPC_MAX_ECALL_MSD_DATA_LEN), msd_data);

+    }

+

+    if (cb) {

+        mipc_msg_async_api(msg_req_ptr, (void *)mipc_ecall_ivs_update_msd_cb, (MIPC_API_CB)cb, cb_priv_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        return MIPC_API_RESULT_SUCCESS;

+    } else {

+        msg_cnf_ptr = mipc_msg_sync_timeout(msg_req_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        ret = mipc_ecall_ivs_update_msd_cnf_decode(msg_cnf_ptr, result_ptr);

+        mipc_msg_deinit(msg_cnf_ptr);

+        return ret;

+    }

+}

+

+mipc_api_result_enum mipc_ecall_ivs_update_msd_sync(mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_ivs_update_msd_struct *result_ptr,

+        mipc_ecall_msd_format_const_enum msd_format,

+        unsigned int msd_length,

+        unsigned char* msd_data)

+{

+    if (NULL == result_ptr) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_update_msd(NULL, NULL, sim_ps_id, msd_format, msd_length, msd_data, result_ptr);

+}

+

+mipc_api_result_enum mipc_ecall_ivs_update_msd_async(mipc_sim_ps_id_enum sim_ps_id,

+        MIPC_ECALL_IVS_UPDATE_MSD_CB cb, void *cb_priv_ptr,

+        mipc_ecall_msd_format_const_enum msd_format,

+        unsigned int msd_length,

+        unsigned char* msd_data)

+{

+    if (NULL == cb) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_update_msd(cb, cb_priv_ptr, sim_ps_id, msd_format, msd_length, msd_data, NULL);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_reset_cnf_decode(mipc_msg_t *msg_cnf_ptr, mipc_ecall_ivs_reset_struct *result_ptr)

+{

+    mipc_api_result_enum result = MIPC_API_RESULT_FAIL;

+

+    if (msg_cnf_ptr == NULL) { //timeout

+        if (result_ptr) {

+            result_ptr->result_code = MIPC_RESULT_TIMEOUT;

+        }

+        return MIPC_API_RESULT_TIMEOUT;

+    }

+    do {

+        void* val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_T_RESULT, NULL);

+        if (NULL == val_ptr) break;

+        result_ptr->result_code = (mipc_result_enum)(*((uint32_t*)val_ptr));

+        //acording to MBIM spec, non-succ result should have no information buffer(9.4.5)

+        if (MIPC_RESULT_SUCCESS != result_ptr->result_code) {

+            result = MIPC_API_RESULT_SUCCESS;

+            break;

+        }

+

+        result = MIPC_API_RESULT_SUCCESS;

+    } while (0);

+    return result;

+}

+

+static void mipc_ecall_ivs_reset_cb(mipc_msg_t *msg_ptr, MIPC_ECALL_IVS_RESET_CB cb, void *cb_priv_ptr)

+{

+    mipc_ecall_ivs_reset_struct *result_ptr = (mipc_ecall_ivs_reset_struct *)ALLOC(sizeof(mipc_ecall_ivs_reset_struct));

+

+    if (result_ptr) {

+        MEMSET(result_ptr, 0, sizeof(mipc_ecall_ivs_reset_struct));

+        mipc_ecall_ivs_reset_cnf_decode(msg_ptr, result_ptr);

+    }

+    cb((mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id, result_ptr, cb_priv_ptr);

+    if (result_ptr) {

+        FREE(result_ptr);

+    }

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_reset(MIPC_ECALL_IVS_RESET_CB cb, void *cb_priv_ptr, mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_ivs_reset_struct *result_ptr)

+{

+    mipc_msg_t *msg_req_ptr = mipc_msg_init(MIPC_ECALL_IVS_RESET_REQ, (mipc_msg_sim_ps_id_enum)sim_ps_id);

+    mipc_msg_t *msg_cnf_ptr;

+    mipc_api_result_enum ret;

+

+    if (cb) {

+        mipc_msg_async_api(msg_req_ptr, (void *)mipc_ecall_ivs_reset_cb, (MIPC_API_CB)cb, cb_priv_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        return MIPC_API_RESULT_SUCCESS;

+    } else {

+        msg_cnf_ptr = mipc_msg_sync_timeout(msg_req_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        ret = mipc_ecall_ivs_reset_cnf_decode(msg_cnf_ptr, result_ptr);

+        mipc_msg_deinit(msg_cnf_ptr);

+        return ret;

+    }

+}

+

+mipc_api_result_enum mipc_ecall_ivs_reset_sync(mipc_sim_ps_id_enum sim_ps_id, mipc_ecall_ivs_reset_struct *result_ptr)

+{

+    if (NULL == result_ptr) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_reset(NULL, NULL, sim_ps_id, result_ptr);

+}

+

+mipc_api_result_enum mipc_ecall_ivs_reset_async(mipc_sim_ps_id_enum sim_ps_id, MIPC_ECALL_IVS_RESET_CB cb, void *cb_priv_ptr)

+{

+    if (NULL == cb) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_reset(cb, cb_priv_ptr, sim_ps_id, NULL);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_set_reg_state_cnf_decode(mipc_msg_t *msg_cnf_ptr, mipc_ecall_ivs_set_reg_state_struct *result_ptr)

+{

+    mipc_api_result_enum result = MIPC_API_RESULT_FAIL;

+

+    if (msg_cnf_ptr == NULL) { //timeout

+        if (result_ptr) {

+            result_ptr->result_code = MIPC_RESULT_TIMEOUT;

+        }

+        return MIPC_API_RESULT_TIMEOUT;

+    }

+    do {

+        void* val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_T_RESULT, NULL);

+        if (NULL == val_ptr) break;

+        result_ptr->result_code = (mipc_result_enum)(*((uint32_t*)val_ptr));

+        //acording to MBIM spec, non-succ result should have no information buffer(9.4.5)

+        if (MIPC_RESULT_SUCCESS != result_ptr->result_code) {

+            result = MIPC_API_RESULT_SUCCESS;

+            break;

+        }

+

+        result = MIPC_API_RESULT_SUCCESS;

+    } while (0);

+    return result;

+}

+

+static void mipc_ecall_ivs_set_reg_state_cb(mipc_msg_t *msg_ptr, MIPC_ECALL_IVS_SET_REG_STATE_CB cb, void *cb_priv_ptr)

+{

+    mipc_ecall_ivs_set_reg_state_struct result_ptr;

+

+    MEMSET(&result_ptr, 0, sizeof(mipc_ecall_ivs_set_reg_state_struct));

+    mipc_ecall_ivs_set_reg_state_cnf_decode(msg_ptr, &result_ptr);

+    cb((mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id, &result_ptr, cb_priv_ptr);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_set_reg_state(MIPC_ECALL_IVS_SET_REG_STATE_CB cb,

+        void *cb_priv_ptr,

+        mipc_sim_ps_id_enum sim_ps_id,

+        mipc_nw_register_mode_const_enum reg_state,

+        mipc_ecall_ivs_set_reg_state_struct *result_ptr)

+{

+    mipc_msg_t *msg_req_ptr = mipc_msg_init(MIPC_NW_SET_REGISTER_STATE_REQ, (mipc_msg_sim_ps_id_enum)sim_ps_id);

+    mipc_msg_t *msg_cnf_ptr;

+    mipc_api_result_enum ret;

+

+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_NW_SET_REGISTER_STATE_REQ_T_MODE, reg_state);

+

+    if (cb) {

+        mipc_msg_async_api(msg_req_ptr, (void *)mipc_ecall_ivs_set_reg_state_cb, (MIPC_API_CB)cb, cb_priv_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        return MIPC_API_RESULT_SUCCESS;

+    } else {

+        msg_cnf_ptr = mipc_msg_sync_timeout(msg_req_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        ret = mipc_ecall_ivs_set_reg_state_cnf_decode(msg_cnf_ptr, result_ptr);

+        mipc_msg_deinit(msg_cnf_ptr);

+        return ret;

+    }

+}

+

+mipc_api_result_enum mipc_ecall_ivs_set_reg_state_sync(mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_ivs_set_reg_state_struct *result_ptr,

+        mipc_nw_register_mode_const_enum reg_state)

+{

+    if (NULL == result_ptr) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_set_reg_state(NULL, NULL, sim_ps_id, reg_state, result_ptr);

+}

+

+mipc_api_result_enum mipc_ecall_ivs_set_reg_state_async(mipc_sim_ps_id_enum sim_ps_id,

+        MIPC_ECALL_IVS_SET_REG_STATE_CB cb, void *cb_priv_ptr,

+        mipc_nw_register_mode_const_enum reg_state)

+{

+    if (NULL == cb) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_set_reg_state(cb, cb_priv_ptr, sim_ps_id, reg_state, NULL);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_get_sim_info_cnf_decode(mipc_msg_t *msg_cnf_ptr, mipc_ecall_ivs_get_sim_info_struct *result_ptr)

+{

+    mipc_api_result_enum result = MIPC_API_RESULT_FAIL;

+    uint16_t val_len = 0;

+

+    if (msg_cnf_ptr == NULL) { //timeout

+        if (result_ptr) {

+            result_ptr->result_code = MIPC_RESULT_TIMEOUT;

+        }

+        return MIPC_API_RESULT_TIMEOUT;

+    }

+    do {

+        void* val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_T_RESULT, NULL);

+        if (NULL == val_ptr) break;

+        result_ptr->result_code = (mipc_result_enum)(*((uint32_t*)val_ptr));

+        //acording to MBIM spec, non-succ result should have no information buffer(9.4.5)

+        if (MIPC_RESULT_SUCCESS != result_ptr->result_code) {

+            result = MIPC_API_RESULT_SUCCESS;

+            break;

+        }

+

+        val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_ECALL_IVS_GET_SIM_INFO_CNF_T_SIM_TYPE, NULL);

+        if (NULL == val_ptr) break;

+        result_ptr->sim_type = (uint32_t)(*((uint32_t*)val_ptr));

+

+        result = MIPC_API_RESULT_SUCCESS;

+    } while (0);

+    return result;

+}

+

+static void mipc_ecall_ivs_get_sim_info_cb(mipc_msg_t *msg_ptr, MIPC_ECALL_IVS_GET_SIM_INFO_CB cb, void *cb_priv_ptr)

+{

+    mipc_ecall_ivs_get_sim_info_struct result_ptr;

+

+    MEMSET(&result_ptr, 0, sizeof(mipc_ecall_ivs_get_sim_info_struct));

+    mipc_ecall_ivs_get_sim_info_cnf_decode(msg_ptr, &result_ptr);

+    cb((mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id, &result_ptr, cb_priv_ptr);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_get_sim_info(MIPC_ECALL_IVS_GET_SIM_INFO_CB cb,

+        void *cb_priv_ptr,

+        mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_ivs_get_sim_info_struct *result_ptr)

+{

+    mipc_msg_t *msg_req_ptr = mipc_msg_init(MIPC_ECALL_IVS_GET_SIM_INFO_REQ, (mipc_msg_sim_ps_id_enum)sim_ps_id);

+    mipc_msg_t *msg_cnf_ptr;

+    mipc_api_result_enum ret;

+

+    if (cb) {

+        mipc_msg_async_api(msg_req_ptr, (void *)mipc_ecall_ivs_get_sim_info_cb, (MIPC_API_CB)cb, cb_priv_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        return MIPC_API_RESULT_SUCCESS;

+    } else {

+        msg_cnf_ptr = mipc_msg_sync_timeout(msg_req_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        ret = mipc_ecall_ivs_get_sim_info_cnf_decode(msg_cnf_ptr, result_ptr);

+        mipc_msg_deinit(msg_cnf_ptr);

+        return ret;

+    }

+}

+

+mipc_api_result_enum mipc_ecall_ivs_get_sim_info_sync(mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_ivs_get_sim_info_struct *result_ptr)

+{

+    if (NULL == result_ptr) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_get_sim_info(NULL, NULL, sim_ps_id, result_ptr);

+}

+

+mipc_api_result_enum mipc_ecall_ivs_get_sim_info_async(mipc_sim_ps_id_enum sim_ps_id,

+        MIPC_ECALL_IVS_GET_SIM_INFO_CB cb, void *cb_priv_ptr) {

+    if (NULL == cb) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_get_sim_info(cb, cb_priv_ptr, sim_ps_id, NULL);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_set_test_addr_cnf_decode(mipc_msg_t *msg_cnf_ptr, mipc_ecall_ivs_set_test_addr_struct *result_ptr)

+{

+    mipc_api_result_enum result = MIPC_API_RESULT_FAIL;

+

+    if (msg_cnf_ptr == NULL) { //timeout

+        if (result_ptr) {

+            result_ptr->result_code = MIPC_RESULT_TIMEOUT;

+        }

+        return MIPC_API_RESULT_TIMEOUT;

+    }

+    do {

+        void* val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_T_RESULT, NULL);

+        if (NULL == val_ptr) break;

+        result_ptr->result_code = (mipc_result_enum)(*((uint32_t*)val_ptr));

+        //acording to MBIM spec, non-succ result should have no information buffer(9.4.5)

+        if (MIPC_RESULT_SUCCESS != result_ptr->result_code) {

+            result = MIPC_API_RESULT_SUCCESS;

+            break;

+        }

+

+        result = MIPC_API_RESULT_SUCCESS;

+    } while (0);

+    return result;

+}

+

+static void mipc_ecall_ivs_set_test_addr_cb(mipc_msg_t *msg_ptr, MIPC_ECALL_IVS_SET_TEST_ADDR_CB cb, void *cb_priv_ptr)

+{

+    mipc_ecall_ivs_set_test_addr_struct result_ptr;

+

+    MEMSET(&result_ptr, 0, sizeof(mipc_ecall_ivs_set_test_addr_struct));

+    mipc_ecall_ivs_set_test_addr_cnf_decode(msg_ptr, &result_ptr);

+    cb((mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id, &result_ptr, cb_priv_ptr);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_set_test_addr(MIPC_ECALL_IVS_SET_TEST_ADDR_CB cb,

+        void *cb_priv_ptr,

+        mipc_sim_ps_id_enum sim_ps_id,

+        char* test_address,

+	    mipc_call_dial_address_type_const_enum address_type,

+        mipc_ecall_ivs_set_test_addr_struct *result_ptr)

+{

+    mipc_msg_t *msg_req_ptr = mipc_msg_init(MIPC_ECALL_IVS_SET_TEST_ADDR_REQ, (mipc_msg_sim_ps_id_enum)sim_ps_id);

+    mipc_msg_t *msg_cnf_ptr;

+    mipc_api_result_enum ret;

+

+    if (test_address) {

+        mipc_msg_add_tlv(msg_req_ptr, MIPC_ECALL_IVS_SET_TEST_ADDR_REQ_T_ADDRESS,

+			(strlen(test_address) < MIPC_MAX_DIAL_ADDRESS_LEN ? strlen(test_address) :MIPC_MAX_DIAL_ADDRESS_LEN), test_address);

+    }

+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_ECALL_IVS_SET_TEST_ADDR_REQ_T_ADDR_TYPE, address_type);

+

+    if (cb) {

+        mipc_msg_async_api(msg_req_ptr, (void *)mipc_ecall_ivs_set_test_addr_cb, (MIPC_API_CB)cb, cb_priv_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        return MIPC_API_RESULT_SUCCESS;

+    } else {

+        msg_cnf_ptr = mipc_msg_sync_timeout(msg_req_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        ret = mipc_ecall_ivs_set_test_addr_cnf_decode(msg_cnf_ptr, result_ptr);

+        mipc_msg_deinit(msg_cnf_ptr);

+        return ret;

+    }

+}

+

+mipc_api_result_enum mipc_ecall_ivs_set_test_addr_sync(mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_ivs_set_test_addr_struct *result_ptr,

+        char* test_address,

+        mipc_call_dial_address_type_const_enum address_type)

+{

+    if (NULL == result_ptr || NULL == test_address) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_set_test_addr(NULL, NULL, sim_ps_id, test_address, address_type, result_ptr);

+}

+

+mipc_api_result_enum mipc_ecall_ivs_set_test_addr_async(mipc_sim_ps_id_enum sim_ps_id,

+        MIPC_ECALL_IVS_SET_TEST_ADDR_CB cb, void *cb_priv_ptr,

+        char* test_address,

+        mipc_call_dial_address_type_const_enum address_type)

+{

+    if (NULL == cb) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_set_test_addr(cb, cb_priv_ptr, sim_ps_id, test_address, address_type, NULL);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_set_reconf_addr_cnf_decode(mipc_msg_t *msg_cnf_ptr, mipc_ecall_ivs_set_reconf_addr_struct *result_ptr)

+{

+    mipc_api_result_enum result = MIPC_API_RESULT_FAIL;

+

+    if (msg_cnf_ptr == NULL) { //timeout

+        if (result_ptr) {

+            result_ptr->result_code = MIPC_RESULT_TIMEOUT;

+        }

+        return MIPC_API_RESULT_TIMEOUT;

+    }

+    do {

+        void* val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_T_RESULT, NULL);

+        if (NULL == val_ptr) break;

+        result_ptr->result_code = (mipc_result_enum)(*((uint32_t*)val_ptr));

+        //acording to MBIM spec, non-succ result should have no information buffer(9.4.5)

+        if (MIPC_RESULT_SUCCESS != result_ptr->result_code) {

+            result = MIPC_API_RESULT_SUCCESS;

+            break;

+        }

+

+        result = MIPC_API_RESULT_SUCCESS;

+    } while (0);

+    return result;

+}

+

+static void mipc_ecall_ivs_set_reconf_addr_cb(mipc_msg_t *msg_ptr, MIPC_ECALL_IVS_SET_RECONF_ADDR_CB cb, void *cb_priv_ptr)

+{

+    mipc_ecall_ivs_set_reconf_addr_struct result_ptr;

+

+    MEMSET(&result_ptr, 0, sizeof(mipc_ecall_ivs_set_addr_pri_struct));

+    mipc_ecall_ivs_set_reconf_addr_cnf_decode(msg_ptr, &result_ptr);

+    cb((mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id, &result_ptr, cb_priv_ptr);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_set_reconf_addr(MIPC_ECALL_IVS_SET_RECONF_ADDR_CB cb,

+        void *cb_priv_ptr,

+        mipc_sim_ps_id_enum sim_ps_id,

+        char* reconf_address,

+        mipc_call_dial_address_type_const_enum address_type,

+        mipc_ecall_ivs_set_reconf_addr_struct *result_ptr)

+{

+    mipc_msg_t *msg_req_ptr = mipc_msg_init(MIPC_ECALL_IVS_SET_RECONF_ADDR_REQ, (mipc_msg_sim_ps_id_enum)sim_ps_id);

+    mipc_msg_t *msg_cnf_ptr;

+    mipc_api_result_enum ret;

+

+    if (reconf_address) {

+        mipc_msg_add_tlv(msg_req_ptr, MIPC_ECALL_IVS_SET_RECONF_ADDR_REQ_T_ADDRESS,

+            (strlen(reconf_address) < MIPC_MAX_DIAL_ADDRESS_LEN ? strlen(reconf_address) :MIPC_MAX_DIAL_ADDRESS_LEN), reconf_address);

+    }

+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_ECALL_IVS_SET_RECONF_ADDR_REQ_T_ADDR_TYPE, address_type);

+

+    if (cb) {

+        mipc_msg_async_api(msg_req_ptr, (void *)mipc_ecall_ivs_set_reconf_addr_cb, (MIPC_API_CB)cb, cb_priv_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        return MIPC_API_RESULT_SUCCESS;

+    } else {

+        msg_cnf_ptr = mipc_msg_sync_timeout(msg_req_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        ret = mipc_ecall_ivs_set_reconf_addr_cnf_decode(msg_cnf_ptr, result_ptr);

+        mipc_msg_deinit(msg_cnf_ptr);

+        return ret;

+    }

+}

+

+mipc_api_result_enum mipc_ecall_ivs_set_reconf_addr_sync(mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_ivs_set_reconf_addr_struct *result_ptr,

+        char* reconf_address,

+        mipc_call_dial_address_type_const_enum address_type)

+{

+    if (NULL == result_ptr) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_set_reconf_addr(NULL, NULL, sim_ps_id, reconf_address, address_type, result_ptr);

+}

+

+mipc_api_result_enum mipc_ecall_ivs_set_reconf_addr_async(mipc_sim_ps_id_enum sim_ps_id,

+        MIPC_ECALL_IVS_SET_RECONF_ADDR_CB cb, void *cb_priv_ptr,

+        char* reconf_address,

+        mipc_call_dial_address_type_const_enum address_type)

+{

+    if (NULL == cb) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_set_test_addr(cb, cb_priv_ptr, sim_ps_id, reconf_address, address_type, NULL);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_set_addr_pri_cnf_decode(mipc_msg_t *msg_cnf_ptr, mipc_ecall_ivs_set_addr_pri_struct *result_ptr)

+{

+    mipc_api_result_enum result = MIPC_API_RESULT_FAIL;

+

+    if (msg_cnf_ptr == NULL) { //timeout

+        if (result_ptr) {

+            result_ptr->result_code = MIPC_RESULT_TIMEOUT;

+        }

+        return MIPC_API_RESULT_TIMEOUT;

+    }

+    do {

+        void* val_ptr = mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_T_RESULT, NULL);

+        if (NULL == val_ptr) break;

+        result_ptr->result_code = (mipc_result_enum)(*((uint32_t*)val_ptr));

+        //acording to MBIM spec, non-succ result should have no information buffer(9.4.5)

+        if (MIPC_RESULT_SUCCESS != result_ptr->result_code) {

+            result = MIPC_API_RESULT_SUCCESS;

+            break;

+        }

+

+        result = MIPC_API_RESULT_SUCCESS;

+    } while (0);

+    return result;

+}

+

+static void mipc_ecall_ivs_set_addr_pri_cb(mipc_msg_t *msg_ptr, MIPC_ECALL_IVS_SET_ADDR_PRI_CB cb, void *cb_priv_ptr)

+{

+    mipc_ecall_ivs_set_addr_pri_struct result_ptr;

+

+    MEMSET(&result_ptr, 0, sizeof(mipc_ecall_ivs_set_addr_pri_struct));

+    mipc_ecall_ivs_set_addr_pri_cnf_decode(msg_ptr, &result_ptr);

+    cb((mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id, &result_ptr, cb_priv_ptr);

+}

+

+static mipc_api_result_enum mipc_ecall_ivs_set_addr_pri(MIPC_ECALL_IVS_SET_ADDR_PRI_CB cb,

+        void *cb_priv_ptr,

+        mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_address_priority_class_const_enum first_pri,

+        mipc_ecall_address_priority_class_const_enum second_pri,

+        mipc_ecall_address_priority_class_const_enum third_pri,

+        mipc_ecall_address_priority_class_const_enum fourth_pri,

+        mipc_ecall_ivs_set_addr_pri_struct *result_ptr)

+{

+    mipc_msg_t *msg_req_ptr = mipc_msg_init(MIPC_ECALL_IVS_SET_ADDR_PRI_REQ, (mipc_msg_sim_ps_id_enum)sim_ps_id);

+    mipc_msg_t *msg_cnf_ptr;

+    mipc_api_result_enum ret;

+

+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_ECALL_IVS_SET_ADDR_PRI_REQ_T_FIRST_PRI, first_pri);

+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_ECALL_IVS_SET_ADDR_PRI_REQ_T_SECOND_PRI, second_pri);

+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_ECALL_IVS_SET_ADDR_PRI_REQ_T_THIRD_PRI, third_pri);

+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_ECALL_IVS_SET_ADDR_PRI_REQ_T_FOURTH_PRI, fourth_pri);

+

+    if (cb) {

+        mipc_msg_async_api(msg_req_ptr, (void *)mipc_ecall_ivs_set_addr_pri_cb, (MIPC_API_CB)cb, cb_priv_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        return MIPC_API_RESULT_SUCCESS;

+    } else {

+        msg_cnf_ptr = mipc_msg_sync_timeout(msg_req_ptr);

+        mipc_msg_deinit(msg_req_ptr);

+        ret = mipc_ecall_ivs_set_addr_pri_cnf_decode(msg_cnf_ptr, result_ptr);

+        mipc_msg_deinit(msg_cnf_ptr);

+        return ret;

+    }

+}

+

+mipc_api_result_enum mipc_ecall_ivs_set_addr_pri_sync(mipc_sim_ps_id_enum sim_ps_id,

+        mipc_ecall_ivs_set_addr_pri_struct *result_ptr,

+        mipc_ecall_address_priority_class_const_enum first_pri,

+        mipc_ecall_address_priority_class_const_enum second_pri,

+        mipc_ecall_address_priority_class_const_enum third_pri,

+        mipc_ecall_address_priority_class_const_enum fourth_pri)

+{

+    if (NULL == result_ptr) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_set_addr_pri(NULL, NULL, sim_ps_id, first_pri, second_pri, third_pri, fourth_pri, result_ptr);

+}

+

+mipc_api_result_enum mipc_ecall_ivs_set_addr_pri_async(mipc_sim_ps_id_enum sim_ps_id,

+        MIPC_ECALL_IVS_SET_ADDR_PRI_CB cb, void *cb_priv_ptr,

+        mipc_ecall_address_priority_class_const_enum first_pri,

+        mipc_ecall_address_priority_class_const_enum second_pri,

+        mipc_ecall_address_priority_class_const_enum third_pri,

+        mipc_ecall_address_priority_class_const_enum fourth_pri)

+{

+    if (NULL == cb) {

+        return MIPC_API_RESULT_FAIL;

+    }

+    return mipc_ecall_ivs_set_addr_pri(cb, cb_priv_ptr, sim_ps_id, first_pri, second_pri, third_pri, fourth_pri, NULL);

+}

+

+//////////////////////////////////////////INDICATIONS////////////////////////////////////////////

+static mipc_api_result_enum mipc_ecall_status_ind(mipc_msg_t *msg_ptr, mipc_ecall_status_ind_struct *result_ptr)

+{

+    void *val_ptr;

+    uint8_t api_error = 1;

+

+    do {

+        result_ptr->result_code = MIPC_RESULT_SUCCESS;

+

+        if ((val_ptr = mipc_msg_get_val_ptr(msg_ptr, MIPC_ECALL_STATUS_IND_T_STATE, NULL)) == NULL) break;

+        result_ptr->state = (mipc_ecall_status_const_enum) * ((uint8_t *)val_ptr);

+        if ((val_ptr = mipc_msg_get_val_ptr(msg_ptr, MIPC_ECALL_STATUS_IND_T_CALL_ID, NULL)) == NULL) break;

+        result_ptr->callid = (uint8_t) * ((uint8_t *)val_ptr);

+

+        api_error = 0;

+    } while (0);

+

+    if (api_error) {

+        result_ptr->result_code = MIPC_RESULT_FAILURE;

+        return MIPC_API_RESULT_FAIL;

+    } else {

+        return MIPC_API_RESULT_SUCCESS;

+    }

+}

+

+static void mipc_ecall_status_ind_cb(mipc_msg_t *msg_ptr, MIPC_ECALL_STATUS_IND_CB cb, void *cb_priv_ptr)

+{

+    mipc_ecall_status_ind_struct result_ptr;

+

+    MEMSET(&result_ptr, 0, sizeof(mipc_ecall_status_ind_struct));

+    if (mipc_ecall_status_ind(msg_ptr, &result_ptr) == MIPC_API_RESULT_SUCCESS) {

+        cb((mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id, &result_ptr, cb_priv_ptr);

+    }

+}

+

+mipc_api_result_enum mipc_ecall_status_register(mipc_sim_ps_id_enum sim_ps_id, MIPC_ECALL_STATUS_IND_CB cb, void *cb_priv_ptr)

+{

+    void *callback;

+    if (cb) {

+        callback = (void *)mipc_ecall_status_ind_cb;

+    } else {

+        callback = NULL;

+    }

+

+    if (mipc_msg_register_ind_api((mipc_msg_sim_ps_id_enum)sim_ps_id, MIPC_ECALL_STATUS_IND, callback, (MIPC_API_CB)cb, cb_priv_ptr) == 0) {

+        return MIPC_API_RESULT_SUCCESS;

+    } else {

+        return MIPC_API_RESULT_FAIL;

+    }

+}

+

diff --git a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_nw_api.c b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_nw_api.c
old mode 100644
new mode 100755
index e14ccfc..f68e16b
--- a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_nw_api.c
+++ b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_nw_api.c
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /*****************************************************************************
 *  Copyright Statement:
 *  --------------------
@@ -1042,6 +1043,14 @@
     }
 }
 
+mipc_api_result_enum mipc_nw_etxpwr_ind_register(mipc_sim_ps_id_enum sim_ps_id, MIPC_MSG_CB cb, void *cb_priv_ptr)
+{
+    if (mipc_msg_register_ind_api((mipc_msg_sim_ps_id_enum)sim_ps_id, MIPC_NW_ETXPWR_IND, cb, NULL, cb_priv_ptr) == 0) {
+        return MIPC_API_RESULT_SUCCESS;
+    } else {
+        return MIPC_API_RESULT_FAIL;
+    }
+}
 
 /////////////////////////////////////////////////////////////////////////////////////////////////////
 //fill result_ptr according to msg_ptr
@@ -2680,11 +2689,19 @@
 
     //STEP5: fill the result
     do {
-        if ((t_result_ptr = (uint32_t *)mipc_msg_get_val_ptr(msg_ptr, MIPC_T_RESULT, NULL)) == NULL) break;
+        if ((t_result_ptr = (uint32_t *)mipc_msg_get_val_ptr(msg_ptr, MIPC_T_RESULT, NULL)) == NULL) {
+            mtkLogE(LOG_TAG, "%s result=NULL", __FUNCTION__);
+            break;
+        }
+
         if (*t_result_ptr == 0) { // SUCCESS
             result_ptr->result_code = MIPC_RESULT_SUCCESS;
 
-            if ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_CS_CNF_T_REG_INFO, &t_nwtmp_len)) == NULL) break;
+            if ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_CS_CNF_T_REG_INFO, &t_nwtmp_len)) == NULL) {
+                mtkLogE(LOG_TAG, "%s REG_INFO=NULL", __FUNCTION__);
+                break;
+            }
+
             result_ptr->cs_reg.stat = ((mipc_nw_cs_reg_info_struct4 *)t_nwtmp_ptr)->stat;
             result_ptr->cs_reg.rat = ((mipc_nw_cs_reg_info_struct4 *)t_nwtmp_ptr)->rat;
             result_ptr->cs_reg.css = ((mipc_nw_cs_reg_info_struct4 *)t_nwtmp_ptr)->css;
@@ -2692,10 +2709,19 @@
             result_ptr->cs_reg.is_in_prl = ((mipc_nw_cs_reg_info_struct4 *)t_nwtmp_ptr)->is_in_prl;
             result_ptr->cs_reg.def_roaming_ind = ((mipc_nw_cs_reg_info_struct4 *)t_nwtmp_ptr)->def_roaming_ind;
             result_ptr->cs_reg.reason_for_denial = ((mipc_nw_cs_reg_info_struct4 *)t_nwtmp_ptr)->reason_for_denial;
-            if ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_CS_CNF_T_CELL_TYPE, &t_nwtmp_len)) == NULL) break;
+            if ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_CS_CNF_T_CELL_TYPE, &t_nwtmp_len)) == NULL) {
+                mtkLogE(LOG_TAG, "%s CELL_TYPE=NULL", __FUNCTION__);
+                break;
+            }
+
             signal_type = (mipc_nw_cell_type_const_enum )(*(uint8_t *)t_nwtmp_ptr);
             result_ptr->cell_list.cell_type = signal_type;
-            if ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_CS_CNF_T_CELL_INFO, &t_nwtmp_len)) == NULL) break;
+            if ((signal_type != mipc_nw_cell_type_const_NONE) &&
+                ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_CS_CNF_T_CELL_INFO, &t_nwtmp_len)) == NULL)) {
+                mtkLogE(LOG_TAG, "%s cell_type!=NONE && CELL_INFO=NULL", __FUNCTION__);
+                break;
+            }
+
             switch(signal_type)
             {
                 case MIPC_NW_CELL_TYPE_GSM:
@@ -2816,11 +2842,19 @@
 
     //STEP5: fill the result
     do {
-        if ((t_result_ptr = (uint32_t *)mipc_msg_get_val_ptr(msg_ptr, MIPC_T_RESULT, NULL)) == NULL) break;
+        if ((t_result_ptr = (uint32_t *)mipc_msg_get_val_ptr(msg_ptr, MIPC_T_RESULT, NULL)) == NULL) {
+            mtkLogE(LOG_TAG, "%s result=NULL", __FUNCTION__);
+            break;
+        }
+
         if (*t_result_ptr == 0) { // SUCCESS
             result_ptr->result_code = MIPC_RESULT_SUCCESS;
 
-            if ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_PS_CNF_T_REG_INFO, &t_nwtmp_len)) == NULL) break;
+            if ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_PS_CNF_T_REG_INFO, &t_nwtmp_len)) == NULL) {
+                mtkLogE(LOG_TAG, "%s REG_INFO=NULL", __FUNCTION__);
+                break;
+            }
+
             result_ptr->ps_reg.stat = ((mipc_nw_ps_reg_info_struct4 *)t_nwtmp_ptr)->stat;
             result_ptr->ps_reg.rat = ((mipc_nw_ps_reg_info_struct4 *)t_nwtmp_ptr)->rat;
             result_ptr->ps_reg.reason_for_denial = ((mipc_nw_ps_reg_info_struct4 *)t_nwtmp_ptr)->reason_for_denial;
@@ -2828,10 +2862,19 @@
             result_ptr->ps_reg.is_in_prl = ((mipc_nw_ps_reg_info_struct4 *)t_nwtmp_ptr)->is_in_prl;
             result_ptr->ps_reg.def_roaming_ind = ((mipc_nw_ps_reg_info_struct4 *)t_nwtmp_ptr)->def_roaming_ind;
             result_ptr->ps_reg.reason_for_denial = ((mipc_nw_ps_reg_info_struct4 *)t_nwtmp_ptr)->reason_for_denial;
-            if ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_PS_CNF_T_CELL_TYPE, &t_nwtmp_len)) == NULL) break;
+            if ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_PS_CNF_T_CELL_TYPE, &t_nwtmp_len)) == NULL) {
+                mtkLogE(LOG_TAG, "%s CELL_TYPE=NULL", __FUNCTION__);
+                break;
+            }
+
             signal_type = (mipc_nw_cell_type_const_enum )(*(uint8_t *)t_nwtmp_ptr);
             result_ptr->cell_list.cell_type = signal_type;
-            if ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_PS_CNF_T_CELL_INFO, &t_nwtmp_len)) == NULL) break;
+            if ((signal_type != mipc_nw_cell_type_const_NONE) &&
+                ((t_nwtmp_ptr = (char *)mipc_msg_get_val_ptr(msg_ptr, MIPC_NW_GET_PS_CNF_T_CELL_INFO, &t_nwtmp_len)) == NULL)) {
+                mtkLogE(LOG_TAG, "%s cell_type!=NONE && CELL_INFO=NULL", __FUNCTION__);
+                break;
+            }
+
             switch(signal_type)
             {
                 case MIPC_NW_CELL_TYPE_GSM:
@@ -3387,3 +3430,11 @@
     return mipc_nw_get_rat_req(cb, cb_priv_ptr, sim_ps_id, NULL);
 }
 
+mipc_api_result_enum mipc_nw_get_rat_sync(mipc_sim_ps_id_enum sim_ps_id, mipc_nw_get_rat_struct *cb_priv_ptr)
+{
+    //SETP0: check input
+    if (cb_priv_ptr == NULL) {
+        return MIPC_API_RESULT_FAIL;
+    }
+    return mipc_nw_get_rat_req(NULL, cb_priv_ptr, sim_ps_id, cb_priv_ptr);
+}
diff --git a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_sim_api.c b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_sim_api.c
old mode 100644
new mode 100755
index b6cb1c5..b07312d
--- a/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_sim_api.c
+++ b/src/telephonyware/3.0/hardware/ril/platformlib/libmipc/lib/src/api/mipc_sim_api.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /*****************************************************************************
 *  Copyright Statement:
 *  --------------------
@@ -1896,6 +1897,7 @@
     mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SIM_CHANNEL_RESTRICTED_ACCESS_REQ_T_P2, p2);
     mipc_msg_add_tlv_uint16(msg_req_ptr, MIPC_SIM_CHANNEL_RESTRICTED_ACCESS_REQ_T_P3, p3);
     mipc_msg_add_tlv_uint16(msg_req_ptr, MIPC_SIM_CHANNEL_RESTRICTED_ACCESS_REQ_T_DATA_LEN, data_len);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SIM_CHANNEL_RESTRICTED_ACCESS_REQ_T_FCP_CONVERT, MIPC_SIM_FCP_CONVERT_ENABLE);
     if (data_ptr) {
         mipc_msg_add_tlv(msg_req_ptr, MIPC_SIM_CHANNEL_RESTRICTED_ACCESS_REQ_T_DATA, data_len, data_ptr);
     }
@@ -4316,9 +4318,9 @@
     do {
         result_ptr->result_code = MIPC_RESULT_SUCCESS;
         if ((val_ptr = mipc_msg_get_val_ptr(msg_ptr, MIPC_STK_SIM_REFRESH_IND_T_SIM_REFRESH_RESULT, NULL)) == NULL) break;
-        result_ptr->sim_refresh_result = (mipc_sim_refresh_result_type_const_enum) * ((uint8_t *)val_ptr);
+        result_ptr->sim_refresh_result = mipc_stk_sim_refresh_ind_get_sim_refresh_result(msg_ptr, mipc_sim_refresh_result_type_const_NONE);
         if ((val_ptr = mipc_msg_get_val_ptr(msg_ptr, MIPC_STK_SIM_REFRESH_IND_T_EF_ID, NULL)) != NULL) {
-            result_ptr->ef_id = (uint32_t) * ((uint32_t *)val_ptr);
+            result_ptr->ef_id = mipc_stk_sim_refresh_ind_get_ef_id(msg_ptr, 0);
         } else {
             result_ptr->ef_id = UINT32_MAX;
         }
@@ -4341,7 +4343,7 @@
 static void mipc_stk_sim_refresh_ind_cb(mipc_msg_t *msg_ptr, MIPC_STK_SIM_REFRESH_IND_CB cb, void *cb_priv_ptr)
 {
     mipc_stk_sim_refresh_ind_struct result_ptr;
-    MEMSET(&result_ptr, 0, sizeof(mipc_sim_physical_slots_mapping_done_ind_struct));
+    MEMSET(&result_ptr, 0, sizeof(mipc_stk_sim_refresh_ind_struct));
     if (mipc_stk_sim_refresh_ind(msg_ptr, &result_ptr) == MIPC_API_RESULT_SUCCESS) {
         cb((mipc_sim_ps_id_enum)msg_ptr->hdr.msg_sim_ps_id, &result_ptr, cb_priv_ptr);
     } else {
diff --git a/src/telephonyware/3.0/libvendor-ril/apn/inc/LogUtils.h b/src/telephonyware/3.0/libvendor-ril/apn/inc/LogUtils.h
index 5c0a402..a8d6085 100755
--- a/src/telephonyware/3.0/libvendor-ril/apn/inc/LogUtils.h
+++ b/src/telephonyware/3.0/libvendor-ril/apn/inc/LogUtils.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /*
  * LogUtils.h
  *
@@ -12,7 +13,7 @@
 #undef LOG_TAG
 #define LOG_TAG "APN"
 
-namespace logutils {
+namespace apn_logutils {
 class SLOG {
 private:
 	const static char* SEPERATE;
@@ -25,7 +26,7 @@
 };
 }
 
-#define SLOGD(...) logutils::SLOG::D(LOG_TAG, ##__VA_ARGS__)
-#define SLOGFATAL(f, a...) logutils::SLOG::FATAL(LOG_TAG, f "(%s, %d)", __FILE__, __LINE__,## a)
+#define SLOGD(...) apn_logutils::SLOG::D(LOG_TAG, ##__VA_ARGS__)
+#define SLOGFATAL(f, a...) apn_logutils::SLOG::FATAL(LOG_TAG, f "(%s, %d)", ##a,  __FILE__, __LINE__)
 
 #endif /* SRC_LogUtils_H_ */
diff --git a/src/telephonyware/3.0/libvendor-ril/apn/src/LogUtils.cpp b/src/telephonyware/3.0/libvendor-ril/apn/src/LogUtils.cpp
index 0997cfa..2dc7743 100755
--- a/src/telephonyware/3.0/libvendor-ril/apn/src/LogUtils.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/apn/src/LogUtils.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /*
  * LogUtils.cpp
  *
@@ -15,7 +16,7 @@
 #include <stdio.h>
 
 using namespace std;
-using logutils::SLOG;
+using apn_logutils::SLOG;
 
 #define LOG_BUF_SIZE 1024
 
diff --git a/src/telephonyware/3.0/libvendor-ril/apn/src/apn_manager.cpp b/src/telephonyware/3.0/libvendor-ril/apn/src/apn_manager.cpp
index f9654b2..8b2b80a 100755
--- a/src/telephonyware/3.0/libvendor-ril/apn/src/apn_manager.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/apn/src/apn_manager.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /*
  * apn_manager.cpp
  *
@@ -186,8 +187,10 @@
 	sql.append(";");
 	char* errmsg = NULL;
 	if (sqlite3_exec(mDb, sql.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
-		SLOGFATAL("update error %s", errmsg);
-		return APN_ERR;
+            if(errmsg != NULL) {
+                SLOGFATAL("update error %s", errmsg);
+            }
+            return APN_ERR;
 	}
 	return APN_OK;
 }
diff --git a/src/telephonyware/3.0/libvendor-ril/include/telephony/mtk_ril_ivt.h b/src/telephonyware/3.0/libvendor-ril/include/telephony/mtk_ril_ivt.h
old mode 100644
new mode 100755
index 693672e..dad33d5
--- a/src/telephonyware/3.0/libvendor-ril/include/telephony/mtk_ril_ivt.h
+++ b/src/telephonyware/3.0/libvendor-ril/include/telephony/mtk_ril_ivt.h
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /*
  * mtk_ril_ivt.h
  *
@@ -460,9 +461,18 @@
     RIL_UNSOL_ECALL_ALACK_CLEARDOWN_RECEIVED = 5,
     RIL_UNSOL_ECALL_ACTIVE = 11,
     RIL_UNSOL_ECALL_DISCONNECTED = 12,
+    RIL_UNSOL_ECALL_IMS_ACTIVE = 13,
+    RIL_UNSOL_ECALL_IMS_DISCONNECTED = 14,
     RIL_UNSOL_ECALL_ABNORMAL_HANGUP=15,
     RIL_UNSOL_ECALL_IMS_MSD_ACK = 20,
     RIL_UNSOL_ECALL_IMS_UPDATE_MSD = 21,
+    RIL_UNSOL_ECALL_IMS_IN_BAND_TRANSFER = 22,
+    RIL_UNSOL_ECALL_IMS_MSD_NACK = 23,
+    RIL_UNSOL_ECALL_IMS_SRVCC = 24,
+    RIL_UNSOL_ECALL_ONLY_DEREGISTRATION = 31,
+    RIL_UNSOL_ECALL_MAY_DEREGISTER = 32,
+    RIL_UNSOL_ECALL_PSAP_CALLBACK_START = 40,
+    RIL_UNSOL_ECALL_PSAP_CALLBACK_IMS_UPDATE_MSD = 41,
     RIL_UNSOL_ECALL_UNSPECIFIED = 0xffff,
 }RIL_ECall_Indication;
 
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/framework/base/RfxParcelTransferUtils.cpp b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/framework/base/RfxParcelTransferUtils.cpp
old mode 100644
new mode 100755
index f7367c4..bac1102
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/framework/base/RfxParcelTransferUtils.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/framework/base/RfxParcelTransferUtils.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -126,6 +127,8 @@
         case PREF_NET_TYPE_NR_ONLY:
         case PREF_NET_TYPE_NR_LTE:
         case PREF_NET_TYPE_NR_LTE_CDMA_EVDO:
+        case PREF_NET_TYPE_NR_LTE_GSM_WCDMA:
+        case PREF_NET_TYPE_NR_LTE_WCDMA:
         case PREF_NET_TYPE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
         case PREF_NET_TYPE_NR_LTE_TDSCDMA_GSM_WCDMA:
         case PREF_NET_TYPE_NR_LTE_TDSCDMA_WCDMA:
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/framework/base/RfxTransferUtils.cpp b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/framework/base/RfxTransferUtils.cpp
old mode 100644
new mode 100755
index 0a92f93..dd95982
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/framework/base/RfxTransferUtils.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/framework/base/RfxTransferUtils.cpp
@@ -177,7 +177,7 @@
 void RfxTransferUtils::parcelToDataResponse(RIL_Token t, RIL_Errno e, int request,
         Parcel * parcel, int slotId) {
     DataToParcelInfo *parcelInfo;
-    if (request >= 1 && request <= (int32_t)NUM_ELEMS(s_data_to_parcel_request)) {
+    if (request >= 1 && request < (int32_t)NUM_ELEMS(s_data_to_parcel_request)) {
         parcelInfo = &(s_data_to_parcel_request[request]);
     } else if (request >= RIL_REQUEST_VENDOR_BASE && (request< RIL_REQUEST_VENDOR_BASE +
             (int32_t)NUM_ELEMS(s_data_to_parcel_mtk_request))) {
@@ -3526,6 +3526,8 @@
     RequestInfo *requestInfo = (RequestInfo *)t;
     int type = getTypeAndJumpToData(p, id);
 
+    memset(&mem_status, 0, sizeof(mem_status));
+
     if (p->dataAvail() > 0) {
         p->readInt32(&mem_status.used);
         p->readInt32(&mem_status.total);
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/apn/RpApnController.cpp b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/apn/RpApnController.cpp
old mode 100644
new mode 100755
index 8b1f596..d5475d4
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/apn/RpApnController.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/apn/RpApnController.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -47,6 +48,7 @@
 #include <RfxMainThread.h>
 #include <cutils/properties.h>
 #include <unistd.h>
+#include <string.h>
 
 #define RFX_LOG_TAG "RPApnController"
 extern int rfx_get_data_allowed_slotid(void);
@@ -66,6 +68,11 @@
 #define APNDB_NOTREADY (0)
 bool gApnDoneCond_flag = APNDB_NOTREADY;
 
+using std::string;
+
+special_char_pattern_t APN_PROP_CHAR[CHAR_ID_TOTAL] = {
+    { CHAR_QUOTE, CHAR_REP_QUOTE },
+};
 
 
 /*****************************************************************************
@@ -406,11 +413,31 @@
     return false;
 }
 
+bool RpApnController::handleSpecialChar(std::string& source, const std::string& pattern, const std::string& replace)
+{
+    if(source.find(pattern) == std::string::npos) {
+        return false;
+    }
+    std::size_t result = 0;
+    std::size_t index = 0;
+    while((result = source.find(pattern, index)) != std::string::npos) {
+        source.replace(result, pattern.size(), replace);
+        index = result + replace.size();
+    }
+    logD(RFX_LOG_TAG, "[handleSpecialChar] source : %s",  source.c_str());
+    return true;
+}
+
 char * RpApnController::getPropValue(const char *string) {
     const char *start = NULL;
     const char *end = NULL;
     int length = -1;
     char *return_value = NULL;
+    std::string target;
+    std::size_t found = 0;
+    int i = 0;
+    bool result = false;
+
     logD(RFX_LOG_TAG, "[getPropValue]input string: %s", string);
     while((';' != *string) && ('\0' != *string)) {
         if ('=' == *string) {
@@ -437,6 +464,19 @@
         return NULL;
     return_value = (char *)malloc(length+1);
     snprintf(return_value, length+1, "%s", start);
+
+    target = return_value;
+
+    for (i = 0; i < CHAR_ID_TOTAL; i++) {
+        if (true == handleSpecialChar(target, APN_PROP_CHAR[i].pattern, APN_PROP_CHAR[i].replace_char)) {
+            result = true;
+        }
+    }
+    if (result == true) {
+        free(return_value);
+        return_value = (char *)calloc(1, target.length() + 1);
+        strncpy(return_value, target.c_str(), target.length());
+    }
     logD(RFX_LOG_TAG, "[getPropValue] return_value : %s",  return_value);
     return return_value;
 }
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/apn/RpApnController.h b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/apn/RpApnController.h
old mode 100644
new mode 100755
index 9ff29df..baab352
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/apn/RpApnController.h
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/apn/RpApnController.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -84,6 +85,18 @@
     string mvno_match_data;
 }ApnsettingT;
 
+typedef struct {
+    const char* pattern;
+    const char* replace_char;
+} special_char_pattern_t;
+
+typedef enum {
+    CHAR_ID_QUOTE,
+    CHAR_ID_TOTAL
+} prop_char_id_enum;
+
+#define CHAR_QUOTE "'"
+#define CHAR_REP_QUOTE "''"
 
 extern "C"
 void apncallback(int ret, void* data);
@@ -149,6 +162,8 @@
     bool checkPropEmpty(apn_record_t* record, int index);
     bool checkPropExist(apn_record_t* record, int index);
     string constructQueryResult(const apn_list_t * apn_list);
+    bool handleSpecialChar(std::string& source, const std::string& pattern, const std::string& replce);
+
 public:
     RfxSignal0 apn_ready_singal;
     apn_list_t* g_apnlist;
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/ApnContext.cpp b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/ApnContext.cpp
old mode 100644
new mode 100755
index 8b8224d..3d2f26f
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/ApnContext.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/ApnContext.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /*
  * ApnContext.cpp
  *
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcController.cpp b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcController.cpp
old mode 100644
new mode 100755
index 46577d4..a3eb1d2
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcController.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcController.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /*
  * DcController.cpp
  *
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcTracker.cpp b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcTracker.cpp
old mode 100644
new mode 100755
index 64a694a..f92fd54
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcTracker.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcTracker.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /*
  * DcTracker.cpp
  *
@@ -809,8 +810,7 @@
     if (isPsRestricted == true) {
         dataAllowFailReason.addDataAllowFailReason(PS_RESTRICTED);
     }
-    RFX_LOG_D(RFX_LOG_TAG, "%s always return true", __FUNCTION__);
-    return true;
+
     return !dataAllowFailReason.isFailed();
 }
 
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcTracker.h b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcTracker.h
old mode 100644
new mode 100755
index 0477dd0..66c1c46
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcTracker.h
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/DcTracker.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /*
  * DcTracker.h
  *
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/RpDataController.cpp b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/RpDataController.cpp
old mode 100644
new mode 100755
index ae5c6c3..4dc7432
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/RpDataController.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/data/RpDataController.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -450,7 +451,6 @@
     }
 
     logD(RFX_LOG_TAG, "RpDataController::isAllCallingStateIdle, with result: %s", RpDataUtils::b2s(result).c_str());
-    result = true;
     return result;
 }
 
@@ -459,8 +459,8 @@
     RfxNwServiceState ss = getStatusManager()->getServiceStateValue(RFX_STATUS_KEY_SERVICE_STATE);
     result = ss.isConcurrentVoiceAndDataAllowed();
 
-    result = true;
-    logD(RFX_LOG_TAG, "RpDataController::isDataSupportConcurrent, with result: %s", RpDataUtils::b2s(result).c_str());
+    logD(RFX_LOG_TAG, "RpDataController::isDataSupportConcurrent, rilVoiceRadioTech(%d) with result: %s m_slot_id %d",
+            ss.getRilVoiceRadioTech(), RpDataUtils::b2s(result).c_str(), m_slot_id);
     return result;
 }
 
@@ -468,7 +468,6 @@
     bool result = false;
     result = getStatusManager()->getBoolValue(RFX_STATUS_KEY_PS_RESTRICT_STATE, false);
 
-    result = true;
     logD(RFX_LOG_TAG, "RpDataController::isPsRestricted, with result: %s", RpDataUtils::b2s(result).c_str());
 
     return result;
@@ -488,7 +487,6 @@
     RfxNwServiceState ss = getStatusManager()->getServiceStateValue(RFX_STATUS_KEY_SERVICE_STATE);
     result = ss.isInService(ss.getRilDataRegState());
  
-    result = true;
     logD(RFX_LOG_TAG, "RpDataController::isAttached, with result: %s", RpDataUtils::b2s(result).c_str());
 
     return result;
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/power/RpRadioController.cpp b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/power/RpRadioController.cpp
old mode 100644
new mode 100755
index 888e944..4661c35
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/power/RpRadioController.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/power/RpRadioController.cpp
@@ -1,3 +1,4 @@
+//SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/suplmessageparser/SuplMsgDispatcher.cpp b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/suplmessageparser/SuplMsgDispatcher.cpp
old mode 100644
new mode 100755
index 2c6d63a..f64e668
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/suplmessageparser/SuplMsgDispatcher.cpp
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/suplmessageparser/SuplMsgDispatcher.cpp
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
diff --git a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/suplmessageparser/SuplMsgDispatcher.h b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/suplmessageparser/SuplMsgDispatcher.h
old mode 100644
new mode 100755
index 709b924..b8f9946
--- a/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/suplmessageparser/SuplMsgDispatcher.h
+++ b/src/telephonyware/3.0/libvendor-ril/mtk-rilproxy/telephony/suplmessageparser/SuplMsgDispatcher.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: MediaTekProprietary
 /* Copyright Statement:
  *
  * This software/firmware and related documentation ("MediaTek Software") are
@@ -48,8 +49,9 @@
 #define HAL_MNL_BUFF_SIZE           (16 * 1024)
 #define HAL2MNL_NI_MESSAGE          401
 #define HAL_MNL_INTERFACE_VERSION   1
+
 #ifndef MTK_HAS_HAL2MNL_EXT_SERVER
-#define MTK_HAL2MNL                 "mtk_hal2mnl"
+#define MTK_HAL2MNL      "mtk_hal2mnl"
 #else
 #define MTK_HAL2MNL      "mnldinf_ext"
 #endif
diff --git a/src/telephonyware/3.0/mcf_cmd/LICENSE b/src/telephonyware/3.0/mcf_cmd/LICENSE
new file mode 100755
index 0000000..10f9164
--- /dev/null
+++ b/src/telephonyware/3.0/mcf_cmd/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.
+
+Copyright  (C) 2021 MediaTek Inc. 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/telephonyware/3.0/mcf_cmd/Makefile b/src/telephonyware/3.0/mcf_cmd/Makefile
new file mode 100755
index 0000000..98b4167
--- /dev/null
+++ b/src/telephonyware/3.0/mcf_cmd/Makefile
@@ -0,0 +1,13 @@
+TARGET := mcf_cmd
+SRCS := ./mcf_cmd.c
+
+.PHONY: all clean
+
+all: mcf_cmd
+
+mcf_cmd:
+	$(CC) $(CFLAGS) -o $@ $(SRCS) $(LDFLAGS) $(LIBS)
+
+clean:
+	$(warning "makefile mcf_cmd clean")
+	rm -f $(TARGET)
\ No newline at end of file
diff --git a/src/telephonyware/3.0/mcf_cmd/mcf_cmd.c b/src/telephonyware/3.0/mcf_cmd/mcf_cmd.c
new file mode 100755
index 0000000..3248e0d
--- /dev/null
+++ b/src/telephonyware/3.0/mcf_cmd/mcf_cmd.c
@@ -0,0 +1,758 @@
+/******************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2020
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER 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 BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'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 BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*******************************************************************************/
+
+/******************************************************************************
+ * Filename:
+ * ---------
+ *   mcf_cmd.c
+ *
+ * Project:
+ * --------
+ *   Colgin
+ *
+ * Description:
+ * ------------
+ *   MD Configuration Framework, opreation command, send by sAP/openWrt
+ *
+*******************************************************************************/
+
+/******************************************************************************
+ *  Includes
+ ******************************************************************************/
+#include <stdbool.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include "mipc_msg_host.h"
+
+/******************************************************************************
+ *  Macro
+ ******************************************************************************/
+#define SPECIFIC_MIPC_PORT "/dev/ttyCMIPC9"
+
+/******************************************************************************
+ *  Typedefs
+ ******************************************************************************/
+typedef enum {
+    MCF_CMD_BIN_TYPE_DEFAULT_BIN         = 0,
+    MCF_CMD_BIN_TYPE_CARRIER_BIN         = 1,
+    MCF_CMD_BIN_TYPE_GENERAL_CARRIER_BIN = 2,
+    MCF_CMD_BIN_TYPE_MAX
+} mcf_cmd_bin_type_enum;
+
+typedef enum {
+    MCF_CMD_PATH_TYPE_OTA                = 0,
+    MCF_CMD_PATH_TYPE_RUNTIME            = 1,
+    MCF_CMD_PATH_TYPE_MAX
+} mcf_cmd_path_type_enum;
+
+typedef enum {
+    MCF_CMD_VARIABLE_ACT_READ_OTA        = 0,
+    MCF_CMD_VARIABLE_ACT_READ_OPOTA      = 1,
+    MCF_CMD_VARIABLE_ACT_WRITE_OTA       = 2,
+    MCF_CMD_VARIABLE_ACT_WRITE_OPOTA     = 3,
+    MCF_CMD_VARIABLE_ACT_MAX
+} mcf_cmd_variable_act_enum;
+
+typedef enum {
+    MCF_CMD_QUERY_VARIABLE_FORM_PATH     = 0,
+    MCF_CMD_QUERY_VARIABLE_FORM_GID      = 1,
+}mcf_cmd_query_variable_form_enum;
+
+typedef enum {
+    MCF_CMD_IS_TRIGGER_FALSE             = 0,
+    MCF_CMD_IS_TRIGGER_TRUE              = 1,
+
+    MCF_CMD_IS_APPEND_OTA                = 0,
+    MCF_CMD_IS_RESET_LID                 = 1,
+
+    MCF_CMD_IS_UPDATE_WITH_NO_READ_INI   = 0,
+    MCF_CMD_IS_UPDATE_WITH_READ_INI      = 1,
+
+    MCF_PARA_IS_MAX                      = 2,
+} mcf_para_is_enum;
+
+typedef struct {
+    uint8_t num;
+    char str[7];
+} mapping_table_t;
+
+typedef struct {
+    /* required parameter */
+    uint8_t opnum;
+    uint8_t bin_type;
+    uint8_t path_folder_idx;
+    uint8_t appendOTA_resetLID;
+    /* optional parameter */
+    uint8_t is_trigger;
+    uint8_t is_with;
+    uint8_t record_id;
+    uint8_t data_length;
+    /* internal use variable */
+    uint8_t write_flag;
+    uint8_t real_write_length;
+    /* required parameter */
+    uint32_t gid;
+    char* file_name;
+    char* write_value;
+    /* optional parameter */
+    char* lid_str;
+    char* array_index;
+    /* internal use variable */
+    uint16_t run_cmd_ret;
+    uint16_t sim_ps_id;
+} mcf_cmd_parameter_list_t;
+
+/******************************************************************************
+ *  Global variables
+ ******************************************************************************/
+#define PARA_INT8_ERROE_MAX 0xFF
+#define RESULT_SUCCESS 0
+#define WRITE_FLAG 90
+
+extern char *optarg;
+extern int optind, optopt, opterr;
+static mipc_msg_t* msg_req_ptr = NULL;
+static mipc_msg_t* msg_cnf_ptr = NULL;
+static mcf_cmd_parameter_list_t mc;
+
+/* NOTE: read and write are same opreation code 10 */
+static mapping_table_t cmd_map[9] = {
+    {MIPC_SYS_MCF_OP_GET_APPLIED_FILE_PATH, "get"},
+    {MIPC_SYS_MCF_OP_DUMP_LID_DATA, "dump"},
+    {MIPC_SYS_MCF_OP_SET_FILE_PATH_AND_AUTO_SELECT_BIN, "set"},
+    {MIPC_SYS_MCF_OP_UPDATE_OPOTA_FILE, "update"},
+    {MIPC_SYS_MCF_OP_QUERY_VARIABLE_VALUE, "read"},
+    {MIPC_SYS_MCF_OP_QUERY_VARIABLE_VALUE + WRITE_FLAG, "write"},
+    {MIPC_SYS_MCF_OP_ASSIGN_COMBINED_PATH, "merge"},
+    {99,"reboot"},
+};
+
+static mapping_table_t path_map[2] = {
+    {MCF_CMD_PATH_TYPE_OTA, "mdota2"},
+    {MCF_CMD_PATH_TYPE_RUNTIME, "mdota"}
+};
+
+#define CMD_MAP_LEN (sizeof(cmd_map)/sizeof(cmd_map[0]))
+#define PATH_MAP_LEN (sizeof(path_map)/sizeof(path_map[0]))
+
+//#define USE_DEBUG_LOG
+#ifdef USE_DEBUG_LOG
+#define debug_log(format, ...) printf(format, ##__VA_ARGS__)
+#else
+#define debug_log(format, ...)
+#endif
+
+/******************************************************************************
+ *  Feature: wait ind callback by linux signal
+ ******************************************************************************/
+#define USE_MCF_THREAD_WAIT_IND_CB
+
+#ifdef USE_MCF_THREAD_WAIT_IND_CB
+#define WAIT_IND_CB_TIMEOUT_SEC 5
+static pthread_cond_t g_cond;
+static pthread_mutex_t g_mutex;
+static bool g_ind_cb_done = false;
+
+static void mcf_thread_wait_ind_cb(void)
+{
+    struct timeval now_time;
+    struct timespec out_time;
+
+    if (g_ind_cb_done == false) {
+        pthread_cond_init(&g_cond, NULL);
+        pthread_mutex_init(&g_mutex, NULL);
+
+        gettimeofday(&now_time, NULL);
+        out_time.tv_sec = now_time.tv_sec + WAIT_IND_CB_TIMEOUT_SEC;
+        out_time.tv_nsec = now_time.tv_usec * 1000;
+
+        debug_log("wait mcf ind cb\n");
+        pthread_mutex_lock(&g_mutex);
+        pthread_cond_timedwait(&g_cond, &g_mutex, &out_time);
+        pthread_mutex_unlock(&g_mutex);
+        debug_log("wait done\n");
+
+        pthread_cond_destroy(&g_cond);
+        pthread_mutex_destroy(&g_mutex);
+    }
+}
+
+static void mcf_thread_send_signal(void)
+{
+    if (g_ind_cb_done == false) {
+        pthread_mutex_lock(&g_mutex);
+        pthread_cond_signal(&g_cond);
+        pthread_mutex_unlock(&g_mutex);
+        g_ind_cb_done = true;
+    }
+}
+
+#else
+#define mcf_thread_wait_ind_cb()
+#define mcf_thread_send_signal()
+#endif  /* THREAD_WAIT_MCF_IND_CB */
+
+/******************************************************************************
+ *  Functions
+ ******************************************************************************/
+static void printf_help(void)
+{
+    char help_text[] = {"Usage:\n"
+        "  mcf_cmd <-o get> <-b bin_type>\n"
+        "  mcf_cmd <-o dump> [-d lid1,lid2,...,lid32]\n"
+        "  mcf_cmd <-o set> <-b bin_type> <-p path_folder> <-f file_name> <-r appendOTA_resetLID> [-t trigger_dsbp] [-s sim_id]\n"
+        "  mcf_cmd <-o update> [-w with_ini]\n"
+        "  mcf_cmd <-o read> <-b bin_type> <-g GID> [-i record_id] [-y array_index] [-l length]\n"
+        "  mcf_cmd <-o write> <-b bin_type> <-g GID> [-i record_id] [-y array_index] [-l length] <-v write_value>\n"
+        "  mcf_cmd <-o merge> <-b bin_type> <-p path_folder> <-f file_name>\n"
+        "    <> is required parameter; [] is optional parameter, notice its default value if not set\n"
+        "    -o, operation (str): get/dump/set/update/read/write/merge\n"
+        "    -b, bin type: 0:OTA, 1:OTA by OP, 2:general OTA by OP\n"
+        "    -d, LID list (str): use \",\" to split, max num is 32; default dump all\n"
+        "    -p, path folder (str): \"mdota\"/\"mdota2\"\n"
+        "    -f, OTA file name (str)\n"
+        "    -r, appendOTA_resetLID: Valid after running merge cmd, 0:append OTA file, 1:reset LIDs\n"
+        "    -t, trigger dsbp: 0:not trigger, 1:trigger; default 0\n"
+        "    -w, update with ini file: 0:no read ini, 1:read ini; default 0\n"
+        "    -i, NVRAM item record id: default 1\n"
+        "    -g, GID number\n"
+        "    -y, array index (str): use \",\" to split; default \"\"\n"
+        "    -l, data length\n"
+        "    -v, write value (str): hex string, use \"3412\" for 0x1234\n"
+        "    -s, send cmd by sim id, support all cmd: 0 for sim1, 1 for sim2, optional, defatul 0\n"
+        "  note: if parameter is string, its \"\" can be omitted\n"
+    };
+    printf("%s", help_text);
+}
+
+static void mcf_ind_cb(mipc_msg_t *msg_ptr, void *priv_ptr)
+{
+    uint32_t ret;
+
+    printf("MCF cmd CB type=%u result=%u\n", mipc_msg_get_val_uint8(msg_ptr, MIPC_SYS_MCF_IND_T_TYPE, 0xff),
+            ret = mipc_msg_get_val_uint8(msg_ptr, MIPC_SYS_MCF_IND_T_RESULT, 0xff));
+
+    if ((mc.opnum == MIPC_SYS_MCF_OP_DUMP_LID_DATA) && (ret == RESULT_SUCCESS)) {
+        mc.run_cmd_ret = RESULT_SUCCESS;
+    }
+
+    mcf_thread_send_signal();
+}
+
+static void mcf_mipc_init(void)
+{
+#ifdef SPECIFIC_MIPC_PORT
+    SETCOM(SPECIFIC_MIPC_PORT);
+    printf("MCF cmd SETCOM %s\n", SPECIFIC_MIPC_PORT);
+#endif
+
+    mipc_init("mcf_cmd");
+    mipc_msg_register_ind(mc.sim_ps_id, MIPC_SYS_MCF_IND, mcf_ind_cb, NULL);
+}
+
+static void mcf_mipc_deinit(void)
+{
+    mipc_msg_deinit(msg_req_ptr);
+    mipc_msg_deinit(msg_cnf_ptr);
+    mipc_deinit();
+}
+
+static char* mcf_get_map_str(uint8_t num, mapping_table_t *map, uint32_t map_len)
+{
+    static char* null_str = "";
+    uint32_t i = 0;
+
+    for (i=0;i<map_len;i++) {
+        if (num == (map+i)->num) {
+            return (map+i)->str;
+        }
+    }
+
+    return null_str;
+}
+
+static uint8_t mcf_get_map_num(char* str, mapping_table_t *map, uint32_t map_len)
+{
+    uint32_t i = 0;
+
+    for (i=0;i<map_len;i++) {
+        if (strcmp(str, (map+i)->str) == 0) {
+            if (strcmp(str, "write") == 0) {
+                mc.write_flag = WRITE_FLAG;
+                return (map+i)->num - mc.write_flag;
+            } else {
+                return (map+i)->num;
+            }
+        }
+    }
+
+    return PARA_INT8_ERROE_MAX;
+}
+
+static void log_op_error_parameter(uint8_t num)
+{
+    printf("MCF op=\"%s\" error parameter, CHECK!\nRun mcf_cmd to see the format!", mcf_get_map_str(num, cmd_map, CMD_MAP_LEN));
+}
+
+static void log_mipc_result_fail(uint32_t result)
+{
+    printf("MCF cmd FAIL, mipc result=%u\n", result);
+}
+
+static void mcf_cmd_parameters_init(void)
+{
+    /* required parameter, will check them */
+    mc.opnum = PARA_INT8_ERROE_MAX;
+    mc.bin_type = PARA_INT8_ERROE_MAX;
+    mc.path_folder_idx = PARA_INT8_ERROE_MAX;
+    mc.appendOTA_resetLID = PARA_INT8_ERROE_MAX;
+    mc.gid = 0;
+    mc.file_name = NULL;
+    mc.write_value = NULL;
+    /* optional parameter, set default value */
+    mc.is_trigger = 0;
+    mc.is_with = 0;
+    mc.record_id = 1;
+    mc.data_length = 0;
+    mc.lid_str = "";
+    mc.array_index = "";
+    /* internal use variable */
+    mc.write_flag = 0;
+    mc.real_write_length = 0;
+    mc.run_cmd_ret = PARA_INT8_ERROE_MAX;   // linux shell only get 0~255
+    mc.sim_ps_id = MIPC_MSG_PS0;            // set default as MIPC_MSG_PS0
+}
+
+static void mcf_cmd_hex_string_to_bytes(char *input_string)
+{
+    uint32_t length = strlen(input_string);
+    uint8_t temp[2];
+    uint32_t i,j;
+
+    if (length%2 != 0) {
+        printf("write_value str len need be even\n");
+        return;
+    }
+
+    char* pdata = malloc(length/2);
+    if (pdata == NULL) return;
+
+    for (i=0;i<length/2;i++) {
+        temp[0] = input_string[i*2];
+        temp[1] = input_string[i*2+1];
+
+        for (j=0; j<2; j++) {
+            if (temp[j] >= '0' && temp[j] <= '9') {
+                temp[j] = temp[j] - '0';
+            } else if (temp[j] >= 'a' && temp[j] <= 'f') {
+                temp[j] = temp[j] - 'a' + 10;
+            } else if (temp[j] >= 'A' && temp[j] <= 'F') {
+                temp[j] = temp[j] - 'A' + 10;
+            } else {
+                free(pdata);
+                return;
+            }
+        }
+
+        pdata[i] = (temp[0]<<4) | temp[1];
+    }
+
+    if (mc.write_value != NULL) free(mc.write_value);
+    mc.write_value = pdata;
+    mc.real_write_length = length/2;
+}
+
+static void mcf_cmd_parameters_parser(int argc, char *argv[])
+{
+    uint32_t ch;
+    uint16_t sim_id;
+    char* opstr = "";
+
+    if (argc == 1) {
+        printf_help();
+        mc.run_cmd_ret = RESULT_SUCCESS;
+        return;
+    }
+
+    while ((ch = getopt(argc, argv, "o:b:d:p:f:t:r:w:g:i:y:l:v:s:")) != -1) {
+        switch(ch) {
+            case 'o':
+                mc.opnum = mcf_get_map_num(optarg, cmd_map, CMD_MAP_LEN);
+                opstr = optarg;
+                break;
+            case 'b':
+                mc.bin_type = atoi(optarg);
+                break;
+            case 'd':
+                mc.lid_str = optarg;
+                break;
+            case 'p':
+                mc.path_folder_idx = mcf_get_map_num(optarg, path_map, PATH_MAP_LEN);
+                break;
+            case 'f':
+                mc.file_name = optarg;
+                break;
+            case 't':
+                mc.is_trigger = atoi(optarg);
+                break;
+            case 'r':
+                mc.appendOTA_resetLID = atoi(optarg);
+                break;
+            case 'w':
+                mc.is_with = atoi(optarg);
+                break;
+            case 'g':
+                mc.gid = atoi(optarg);
+                break;
+            case 'i':
+                mc.record_id = atoi(optarg);
+                break;
+            case 'y':
+                mc.array_index = optarg;
+                break;
+            case 'l':
+                mc.data_length = atoi(optarg);
+                break;
+            case 'v':
+                mcf_cmd_hex_string_to_bytes(optarg);
+                break;
+            case 's':
+                sim_id = atoi(optarg);
+                if (sim_id == 0xFF) {
+                    mc.sim_ps_id = MIPC_MSG_ALL;
+                } else if (sim_id <= 7) {
+                    mc.sim_ps_id = (mipc_msg_sim_ps_id_enum)(1 << sim_id);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (mc.opnum == PARA_INT8_ERROE_MAX) {
+        printf("MCF unsupport: -o \"%s\"\n", opstr);
+    }
+}
+
+static void mcf_cmd_parameters_free(void)
+{
+    if(mc.write_value != NULL)
+        free(mc.write_value);
+}
+
+/*******************************************************************************
+ * origin cmd: AT+EMCFC=4,<config_type>
+ * response:   +EMCFC:4,<config_type>,<path_type>,<config1 str>
+ * ind cb:     none
+ * mcf cmd:    mcf_cmd <-o get> <-b bin_type>
+ *******************************************************************************/
+static void mcf_cmd_op_get_applied_file_path(int argc, char *argv[])
+{
+    uint32_t mipc_ret = 0;
+
+    if (mc.bin_type >= MCF_CMD_BIN_TYPE_MAX) {
+        log_op_error_parameter(MIPC_SYS_MCF_OP_GET_APPLIED_FILE_PATH);
+        return;
+    }
+
+    msg_req_ptr = mipc_msg_init(MIPC_SYS_MCF_REQ, mc.sim_ps_id);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_OP, MIPC_SYS_MCF_OP_GET_APPLIED_FILE_PATH);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_CONFIG_TYPE, mc.bin_type);
+    msg_cnf_ptr = mipc_msg_sync(msg_req_ptr);
+
+    mipc_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_T_RESULT, MIPC_RESULT_FAILURE);
+
+    if (mipc_ret == MIPC_RESULT_SUCCESS) {
+        printf("MCF cmd SUCCESS op=\"%s\" bin_type=%u path_folder=\"%s\" config_file=\"%s\"\n",
+                mcf_get_map_str(mipc_msg_get_val_uint8(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_OP, 0xff), cmd_map, CMD_MAP_LEN),
+                mipc_msg_get_val_uint8(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_CONFIG_TYPE, 0xff),
+                mcf_get_map_str(mipc_msg_get_val_uint8(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_PATH_TYPE, 0xff), path_map, PATH_MAP_LEN),
+                (char *)mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_CONFIG1, NULL));
+        mc.run_cmd_ret = RESULT_SUCCESS;
+    } else {
+        log_mipc_result_fail(mipc_ret);
+    }
+}
+
+/*******************************************************************************
+ * origin cmd: AT+EMCFC=5 [lid1,lid2,...,lid32]
+ * response:   +EMCFC:5,<MCF result>
+ * ind cb:     +EMCFRPT:<type>,<MCF result>
+ * mcf cmd:    mcf_cmd <-o dump> [-d lid1,lid2,...,lid32]
+ *******************************************************************************/
+static void mcf_cmd_op_dump_lid_data(int argc, char *argv[])
+{
+    uint32_t mipc_ret = 0, mcf_ret = 0xffffffff;
+
+    msg_req_ptr = mipc_msg_init(MIPC_SYS_MCF_REQ, mc.sim_ps_id);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_OP, MIPC_SYS_MCF_OP_DUMP_LID_DATA);
+    if (strcmp(mc.lid_str, "") != 0) {
+        mipc_msg_add_tlv(msg_req_ptr, MIPC_SYS_MCF_REQ_T_DUMP_LIDS, strlen(mc.lid_str) + 1, mc.lid_str);
+    }
+    msg_cnf_ptr = mipc_msg_sync(msg_req_ptr);
+
+    mipc_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_T_RESULT, MIPC_RESULT_FAILURE);
+    if (mipc_ret == MIPC_RESULT_SUCCESS) {
+        printf("MCF cmd SUCCESS op=\"%s\" mcf_result=%u\n",
+                mcf_get_map_str(mipc_msg_get_val_uint8(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_OP, 0xff), cmd_map, CMD_MAP_LEN),
+                mcf_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_MCF_RESULT, 0xffffffff));
+    } else {
+        log_mipc_result_fail(mipc_ret);
+    }
+
+    if(mcf_ret == RESULT_SUCCESS) {
+        mcf_thread_wait_ind_cb();
+    }
+}
+
+/*******************************************************************************
+ * origin cmd: AT+EMCFC=6,<config_type>,<path_type>,<config1 str>,<trigger_dsbp>,<is_reset>
+ * response:  +EMCFC:6,<MCF result>,<DSBP result>
+ * ind cb:    (if trigger_dsbp == 1) +EMCFRPT:<type>,<DSBP result>
+ * mcf cmd:   mcf_cmd <-o set> <-b bin_type> <-p path_folder> <-f file_name> <-r append_resetLID> [-t trigger_dsbp]
+ *******************************************************************************/
+static void mcf_cmd_op_set_file_path_and_auto_select_bin(int argc, char *argv[])
+{
+    uint32_t mipc_ret = 0, mcf_ret = 0xffffffff, dsbp_ret = 0xffffffff;
+
+    if ((mc.bin_type >= MCF_CMD_BIN_TYPE_MAX) || (mc.path_folder_idx >= MCF_CMD_PATH_TYPE_MAX) || (mc.file_name == NULL ) ||
+            (mc.is_trigger >= MCF_PARA_IS_MAX )|| (mc.appendOTA_resetLID >= MCF_PARA_IS_MAX)) {
+        log_op_error_parameter(MIPC_SYS_MCF_OP_SET_FILE_PATH_AND_AUTO_SELECT_BIN);
+        return;
+    }
+
+    msg_req_ptr = mipc_msg_init(MIPC_SYS_MCF_REQ, mc.sim_ps_id);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_OP, MIPC_SYS_MCF_OP_SET_FILE_PATH_AND_AUTO_SELECT_BIN);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_CONFIG_TYPE, mc.bin_type);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_PATH_TYPE, mc.path_folder_idx);
+    mipc_msg_add_tlv(msg_req_ptr, MIPC_SYS_MCF_REQ_T_CONFIG1, strlen(mc.file_name)+1, mc.file_name);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_TRIGGER_DSBP, mc.is_trigger);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_IS_RESET, mc.appendOTA_resetLID);
+    msg_cnf_ptr = mipc_msg_sync(msg_req_ptr);
+
+    mipc_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_T_RESULT, MIPC_RESULT_FAILURE);
+    if (mipc_ret == MIPC_RESULT_SUCCESS) {
+        printf("MCF cmd SUCCESS op=\"%s\" mcf_result=%u dsbp_result=%u\n",
+                mcf_get_map_str(mipc_msg_get_val_uint8(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_OP, 0xff), cmd_map, CMD_MAP_LEN),
+                mcf_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_MCF_RESULT, 0xffffffff),
+                dsbp_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_DSBP_RESULT, 0xffffffff));
+    } else {
+        log_mipc_result_fail(mipc_ret);
+    }
+
+    if (mcf_ret == RESULT_SUCCESS && dsbp_ret == RESULT_SUCCESS) {
+        mc.run_cmd_ret = RESULT_SUCCESS;
+        if(mc.is_trigger == MCF_CMD_IS_TRIGGER_TRUE) {
+            mcf_thread_wait_ind_cb();
+        }
+    }
+}
+
+/*******************************************************************************
+ * cmd:      AT+EMCFC=7,<action>
+ * response: +EMCFC:7,<MCF result>
+ * ind cb:   +EMCFRPT:<type>,<result>
+ * mcf cmd:  mcf_cmd <-o update> [-w with_ini]
+ *******************************************************************************/
+static void mcf_cmd_op_update_opota_file(int argc, char *argv[])
+{
+    uint32_t mipc_ret = 0, mcf_ret = 0xffffffff;
+
+    if (mc.is_with >= MCF_PARA_IS_MAX) {
+        log_op_error_parameter(MIPC_SYS_MCF_OP_UPDATE_OPOTA_FILE);
+        return;
+    }
+
+    msg_req_ptr = mipc_msg_init(MIPC_SYS_MCF_REQ, mc.sim_ps_id);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_OP, MIPC_SYS_MCF_OP_UPDATE_OPOTA_FILE);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_ACTION, mc.is_with);
+    msg_cnf_ptr = mipc_msg_sync(msg_req_ptr);
+
+    mipc_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_T_RESULT, MIPC_RESULT_FAILURE);
+    if (mipc_ret == MIPC_RESULT_SUCCESS) {
+        printf("MCF cmd SUCCESS op=\"%s\" mcf_result=%u\n",
+            mcf_get_map_str(mipc_msg_get_val_uint8(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_OP, 0xff), cmd_map, CMD_MAP_LEN),
+            mcf_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_MCF_RESULT, 0xffffffff));
+    } else {
+        log_mipc_result_fail(mipc_ret);
+    }
+
+    if (mcf_ret == RESULT_SUCCESS) {
+        mc.run_cmd_ret = RESULT_SUCCESS;
+        mcf_thread_wait_ind_cb();
+    }
+}
+
+/*******************************************************************************
+ * cmd:      AT+EMCFC=10,<format>,<action>,<record ID>,<number>,<config str>[,<length>],[,<value>]]
+ * response: +EMCFC:10,<format>,<action>,<mcf result>,<length>,<value>
+ * ind cb:   none
+ * mcf_cmd <-o read> <-b bin_type> <-g GID> [-i record_id] [-y array_index] [-l length]
+ * mcf_cmd <-o write> <-b bin_type> <-g GID> [-i record_id] [-y array_index] [-l length] <-v write_value>
+ *******************************************************************************/
+static void mcf_cmd_op_query_variable_value(int argc, char *argv[])
+{
+    uint32_t mipc_ret = 0, mcf_ret = 0xffffffff;
+    uint8_t action, ret_len, i;
+    char *ret_str;
+
+    if ((mc.bin_type >= MCF_CMD_BIN_TYPE_MAX) || (mc.gid == 0) || (mc.write_flag == WRITE_FLAG && mc.write_value == NULL)) {
+        log_op_error_parameter(MIPC_SYS_MCF_OP_QUERY_VARIABLE_VALUE);
+        return;
+    }
+
+    if (mc.write_flag != WRITE_FLAG) {
+        action = (mc.bin_type == MCF_CMD_BIN_TYPE_DEFAULT_BIN) ? MCF_CMD_VARIABLE_ACT_READ_OTA : MCF_CMD_VARIABLE_ACT_READ_OPOTA;
+    } else {
+        action = (mc.bin_type == MCF_CMD_BIN_TYPE_DEFAULT_BIN) ? MCF_CMD_VARIABLE_ACT_WRITE_OTA : MCF_CMD_VARIABLE_ACT_WRITE_OPOTA;
+    }
+
+    msg_req_ptr = mipc_msg_init(MIPC_SYS_MCF_REQ, mc.sim_ps_id);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_OP, MIPC_SYS_MCF_OP_QUERY_VARIABLE_VALUE);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_FORMAT, MCF_CMD_QUERY_VARIABLE_FORM_GID);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_ACTION, action);
+    mipc_msg_add_tlv_uint32(msg_req_ptr, MIPC_SYS_MCF_REQ_T_NUM, mc.gid);
+    mipc_msg_add_tlv_uint16(msg_req_ptr, MIPC_SYS_MCF_REQ_T_REC_ID, mc.record_id);
+    mipc_msg_add_tlv(msg_req_ptr, MIPC_SYS_MCF_REQ_T_CONFIG, strlen(mc.array_index)+1, mc.array_index);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_LEN, mc.data_length);
+    if (mc.write_flag == WRITE_FLAG) {
+        mipc_msg_add_tlv(msg_req_ptr, MIPC_SYS_MCF_REQ_T_VALUE, mc.real_write_length, mc.write_value);
+    }
+
+    msg_cnf_ptr = mipc_msg_sync(msg_req_ptr);
+    mipc_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_T_RESULT, MIPC_RESULT_FAILURE);
+    if (mipc_ret == MIPC_RESULT_SUCCESS) {
+        printf("MCF cmd SUCCESS op=\"%s\" mcf_result=%u bin_type=%u",
+                mcf_get_map_str(mipc_msg_get_val_uint8(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_OP, 0xff)+mc.write_flag, cmd_map, CMD_MAP_LEN),
+                mcf_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_MCF_RESULT, 0xffffffff),
+                (mipc_msg_get_val_uint8(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_ACTION, 0xff)%2 == 0) ? MCF_CMD_BIN_TYPE_DEFAULT_BIN : MCF_CMD_BIN_TYPE_CARRIER_BIN);
+        if (mcf_ret == RESULT_SUCCESS) {
+            mc.run_cmd_ret = RESULT_SUCCESS;
+            ret_len = mipc_msg_get_val_uint8(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_LEN, 0xff);
+            printf(" length=%u", ret_len);
+            if (mc.write_flag != WRITE_FLAG) {
+                ret_str = (char*)mipc_msg_get_val_ptr(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_VALUE, NULL);
+                printf(" value=\"");
+                for (i=0;i<ret_len;i++) {
+                    printf("%02X", *(ret_str + i));
+                }
+                printf("\"");
+            }
+        }
+        printf("\n");
+    } else {
+        log_mipc_result_fail(mipc_ret);
+    }
+}
+
+/*******************************************************************************
+ * cmd:      AT+EMCFC=11,<config_type>,<path_type>,<config1 str>
+ * response: +EMCFC:11,<MCF result>
+ * ind cb:   none
+ * mcf cmd:  mcf_cmd <-o merge> <-b bin_type> <-p path_folder> <-f file_name>
+ *******************************************************************************/
+static void mcf_cmd_op_assign_combined_path(int argc, char *argv[])
+{
+    uint32_t mipc_ret = 0, mcf_ret = 0xffffffff;
+
+    if ((mc.bin_type >= MCF_CMD_BIN_TYPE_MAX) || (mc.path_folder_idx >= MCF_CMD_PATH_TYPE_MAX) || (mc.file_name == NULL)) {
+        log_op_error_parameter(MIPC_SYS_MCF_OP_ASSIGN_COMBINED_PATH);
+        return;
+    }
+
+    msg_req_ptr = mipc_msg_init(MIPC_SYS_MCF_REQ, mc.sim_ps_id);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_OP, MIPC_SYS_MCF_OP_ASSIGN_COMBINED_PATH);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_CONFIG_TYPE, mc.bin_type);
+    mipc_msg_add_tlv_uint8(msg_req_ptr, MIPC_SYS_MCF_REQ_T_PATH_TYPE, mc.path_folder_idx);
+    mipc_msg_add_tlv(msg_req_ptr, MIPC_SYS_MCF_REQ_T_CONFIG1, strlen(mc.file_name)+1, mc.file_name);
+    msg_cnf_ptr = mipc_msg_sync(msg_req_ptr);
+
+    mipc_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_T_RESULT, MIPC_RESULT_FAILURE);
+    if (mipc_ret == MIPC_RESULT_SUCCESS) {
+        printf("MCF cmd SUCCESS op=\"%s\" mcf_result=%u\n",
+                mcf_get_map_str(mipc_msg_get_val_uint8(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_OP, 0xff), cmd_map, CMD_MAP_LEN),
+                mcf_ret = mipc_msg_get_val_uint32(msg_cnf_ptr, MIPC_SYS_MCF_CNF_T_MCF_RESULT, 0xffffffff));
+        if (mcf_ret == RESULT_SUCCESS) {
+            mc.run_cmd_ret = RESULT_SUCCESS;
+        }
+    } else {
+        log_mipc_result_fail(mipc_ret);
+    }
+}
+
+static void mcf_system_reboot(void)
+{
+    printf("MCF system reboot\n");
+    system("reboot");
+}
+
+int main(int argc, char *argv[])
+{
+    mcf_cmd_parameters_init();
+    mcf_cmd_parameters_parser(argc, argv);
+    if (mc.opnum != PARA_INT8_ERROE_MAX)
+    {
+        mcf_mipc_init();
+        switch (mc.opnum) {
+            case MIPC_SYS_MCF_OP_GET_APPLIED_FILE_PATH:
+                mcf_cmd_op_get_applied_file_path(argc, argv);
+                break;
+            case MIPC_SYS_MCF_OP_DUMP_LID_DATA:
+                mcf_cmd_op_dump_lid_data(argc, argv);
+                break;
+            case MIPC_SYS_MCF_OP_SET_FILE_PATH_AND_AUTO_SELECT_BIN:
+                mcf_cmd_op_set_file_path_and_auto_select_bin(argc, argv);
+                break;
+            case MIPC_SYS_MCF_OP_UPDATE_OPOTA_FILE:
+                mcf_cmd_op_update_opota_file(argc, argv);
+                break;
+            case MIPC_SYS_MCF_OP_QUERY_VARIABLE_VALUE:
+                mcf_cmd_op_query_variable_value(argc, argv);
+                break;
+            case MIPC_SYS_MCF_OP_ASSIGN_COMBINED_PATH:
+                mcf_cmd_op_assign_combined_path(argc, argv);
+                break;
+            case 99:
+                mcf_system_reboot();
+            default:
+                break;
+        }
+        mcf_mipc_deinit();
+    }
+    mcf_cmd_parameters_free();
+    return mc.run_cmd_ret;
+}
+
diff --git a/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_custom/mipc.release.tar.gz b/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_custom/mipc.release.tar.gz
old mode 100644
new mode 100755
index 128cc21..a20cb06
--- a/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_custom/mipc.release.tar.gz
+++ b/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_custom/mipc.release.tar.gz
Binary files differ
diff --git a/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_wide_temp_custom/mipc.release.tar.gz b/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_wide_temp_custom/mipc.release.tar.gz
old mode 100644
new mode 100755
index 128cc21..268ff16
--- a/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_wide_temp_custom/mipc.release.tar.gz
+++ b/src/telephonyware/3.0/mipc/mt2735_ivt_nlwg_wide_temp_custom/mipc.release.tar.gz
Binary files differ
diff --git a/src/telephonyware/3.0/mipc/mt6890_evb_nlwg_custom/mipc.release.tar.gz b/src/telephonyware/3.0/mipc/mt6890_evb_nlwg_custom/mipc.release.tar.gz
new file mode 100755
index 0000000..0680522
--- /dev/null
+++ b/src/telephonyware/3.0/mipc/mt6890_evb_nlwg_custom/mipc.release.tar.gz
Binary files differ
diff --git a/src/telephonyware/3.0/mtk_nvram/src/libfile_op/libfile_op.c b/src/telephonyware/3.0/mtk_nvram/src/libfile_op/libfile_op.c
old mode 100644
new mode 100755
index 0de1590..815e641
--- a/src/telephonyware/3.0/mtk_nvram/src/libfile_op/libfile_op.c
+++ b/src/telephonyware/3.0/mtk_nvram/src/libfile_op/libfile_op.c
@@ -5599,7 +5599,7 @@
 
 //-----------------------------------------------------------------------------
 bool FileOp_BackupDataToFiles(int * iFileMask, bool bWorkForBinRegion) {
-	DIR *dir;
+	DIR *dir = NULL;
 	struct dirent *entry;
 	struct stat statbuf;
 	const char* lpSrcDirName = NULL;
diff --git a/src/telephonyware/3.0/netagent/src/libnetagent/MdEventHandler.h b/src/telephonyware/3.0/netagent/src/libnetagent/MdEventHandler.h
old mode 100644
new mode 100755
index d0ec5c4..a8a1e3e
--- a/src/telephonyware/3.0/netagent/src/libnetagent/MdEventHandler.h
+++ b/src/telephonyware/3.0/netagent/src/libnetagent/MdEventHandler.h
@@ -60,7 +60,7 @@
 //xxx.xxx.xxx.xxx.xxx.xxx.xxx.xxx.xxx.xxx.xxx.xxx.xxx.xxx.xxx.xxx

 

 #define INVALID_TRANS_ID -1

-#define UCI_CONFIG_FILE "/etc/config/system"

+#define UCI_CONFIG_FILE "/etc/config/radio_property"

 

 void onEifIndCallback(mipc_msg_t *msg_ptr, void *priv_ptr);

 void onEIpPortCallback(mipc_msg_t *msg_ptr, void *priv_ptr);

diff --git a/src/telephonyware/3.0/netagent/src/libnetagent/nautils/common/sysutils/NetlinkEvent.cpp b/src/telephonyware/3.0/netagent/src/libnetagent/nautils/common/sysutils/NetlinkEvent.cpp
old mode 100644
new mode 100755
index 3d4d3a1..87fd5ce
--- a/src/telephonyware/3.0/netagent/src/libnetagent/nautils/common/sysutils/NetlinkEvent.cpp
+++ b/src/telephonyware/3.0/netagent/src/libnetagent/nautils/common/sysutils/NetlinkEvent.cpp
@@ -69,7 +69,7 @@
 #define SLOGE(fmt, ...) syslog(LOG_ERR, fmt, ##__VA_ARGS__)
 #endif
 
-#define UCI_CONFIG_FILE "/etc/config/system"
+#define UCI_CONFIG_FILE "/etc/config/radio_property"
 
 void clearRaInfoFlag(char *buff);
 // remark due to not support mtk_properties