[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(¶mLayerInfo, 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, ¶mLayerInfo, 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, ®istry);
-}
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, ©_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, ©_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, ×tamp, &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, ×);
+
+ /* 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,
+ ¬ificationIterator);
+
+ //* 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 = <ð_phy0>;
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <ð_default>;
- pinctrl-1 = <ð_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 = <ð_smi_mdio_pinctl>;
pinctrl-2 = <ð_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 = <ð_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 = <ð_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 = <ðsys>;
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(ð->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(ð->mii_bus->mdio_lock);
}
u32 mt7530_mdio_r32(struct mtk_eth *eth, u32 reg)
{
u16 high, low;
+ mutex_lock(ð->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(ð->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(ð->mii_bus->mdio_lock);
*read_data = _mtk_mdio_read(eth, phy_addr, phy_register);
+ mutex_unlock(ð->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(ð->mii_bus->mdio_lock);
_mtk_mdio_write(eth, phy_addr, phy_register, write_data);
+ mutex_unlock(ð->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 = ð->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 = ð->rx_ring[i];
if (ring->calc_idx_update) {
@@ -1116,9 +1199,6 @@
mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
}
}
- } else {
- ring = ð->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(ð->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(ð->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(ð->dma_refcnt, 1);
}
else
refcount_inc(ð->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(ð->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(ð->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(ð->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(ð->tx_napi);
//napi_enable(ð->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(ð->h_dest[0])) {
+ is_multicast_ether_addr(ð->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(ð->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(ð->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, ×pec) == -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