Upgrade rmi4utils to v1.3.5. am: a2d9eb82cb am: 961d4093c9

Original change: https://android-review.googlesource.com/c/platform/external/rmi4utils/+/1740215

Change-Id: Ifbae6a1341d021f76063a007990a4577c893d263
diff --git a/Application.mk b/Application.mk
index 5dd4457..04ddf2b 100644
--- a/Application.mk
+++ b/Application.mk
@@ -1,4 +1,4 @@
 APP_BUILD_SCRIPT := $(call my-dir)/Android.mk
-APP_STL := stlport_static
+APP_STL := c++_static
 APP_PLATFORM := android-21
-APP_ABI := armeabi armeabi-v7a arm64-v8a
\ No newline at end of file
+APP_ABI := armeabi-v7a arm64-v8a
diff --git a/METADATA b/METADATA
index 381a966..6cd8a37 100644
--- a/METADATA
+++ b/METADATA
@@ -4,5 +4,5 @@
     type: GIT
     value: "https://github.com/aduggan/rmi4utils.git"
   }
-  version: "1.2.0"
+  version: "v1.3.5"
 }
diff --git a/README b/README
index 4e1c94d..02e3e03 100644
--- a/README
+++ b/README
@@ -5,7 +5,6 @@
 This tool depends on HIDRAW being compiled into the Android device's kernel. This may not be enabled by default. When developing on platforms you may need to rebuild the kernel to enable it.
 
 Then:
-Install the latest verison of the Android NDK.
-Copy from the kernel source include/linux/hid.h and include/linux/hidraw.h to $(ANDROID_NDK)/platforms/android-19/arch-arm/usr/include/linux/
+Install the latest version of the Android NDK, and add it to your PATH.
 Then run:
-$ make android
\ No newline at end of file
+$ make android
diff --git a/f54test/Android.bp b/f54test/Android.bp
index 71851d2..177fc15 100644
--- a/f54test/Android.bp
+++ b/f54test/Android.bp
@@ -19,6 +19,7 @@
         "-Wall",
         "-Werror",
         "-Wno-sometimes-uninitialized",
+        "-Wno-unused-private-field",
         "-Wno-unused-parameter",
     ],
     static_libs: ["rmidevice"],
diff --git a/f54test/f54test.cpp b/f54test/f54test.cpp
index 7c43574..4b4f6b1 100644
--- a/f54test/f54test.cpp
+++ b/f54test/f54test.cpp
@@ -34,6 +34,8 @@
 #define RMI_F01_STATUS_CODE(status)		((status) & 0x0f)
 /* Indicates that flash programming is enabled (bootloader mode). */
 #define RMI_F01_STATUS_BOOTLOADER(status)	(!!((status) & 0x40))
+#define NO_SLEEP_OFF (0 << 2)
+#define NO_SLEEP_ON (1 << 2)
 
 /*
  * Sleep mode controls power management on the device and affects all
@@ -91,6 +93,10 @@
 	if (retval != TEST_SUCCESS)
 		return retval;
 
+	retval = DoPreparation();
+	if (retval != TEST_SUCCESS)
+		return retval;
+
 	data = (unsigned char)m_reportType;
 	retval = m_device.Write(m_f54.GetDataBase(), &data, 1);
 	if (retval < 0)
@@ -145,6 +151,7 @@
 	case F54_TRX_SHORTS:
 	case F54_ABS_RAW_CAP:
 	case F54_ABS_DELTA_CAP:
+	case F54_GUARD_PIN_SHORT:
 		m_reportType = report_type;
 		return SetF54ReportSize(report_type);
 	default:
@@ -159,6 +166,7 @@
 	int retval;
 	unsigned char tx = m_txAssigned;
 	unsigned char rx = m_rxAssigned;
+	char buf[256];
 
 	switch (report_type) {
 	case F54_8BIT_IMAGE:
@@ -223,7 +231,14 @@
 	case F54_ABS_DELTA_CAP:
 		m_reportSize = 4 * (tx + rx);
 		break;
+	case F54_GUARD_PIN_SHORT:
+		sprintf(buf, "F54_GUARD_PIN_SHORT\n");
+		m_display.Output(buf);
+		m_reportSize = GUARD_PIN_SHORT_DATA_SIZE;
+		break;
 	default:
+		sprintf(buf, "invalid report type\n");
+		m_display.Output(buf);
 		m_reportSize = 0;
 		return TEST_FAIL_INVALID_PARAMETER;
 	}
@@ -534,6 +549,213 @@
 		offset += 1;
 	}
 
+	/* query 39 */
+	if (m_f54Query_38.has_query39) {
+		retval = m_device.Read(query_addr + offset,
+					m_f54Query_39.data,
+					sizeof(m_f54Query_39.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 40 */
+	if (m_f54Query_39.has_query40) {
+		retval = m_device.Read(query_addr + offset,
+				m_f54Query_40.data,
+				sizeof(m_f54Query_40.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 41 */
+	if (m_f54Query_40.has_ctrl163_query41)
+		offset += 1;
+
+	/* query 42 */
+	if (m_f54Query_40.has_ctrl165_query42)
+		offset += 1;
+
+	/* query 43 */
+	if (m_f54Query_40.has_query43) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_43.data,
+				sizeof(m_f54Query_43.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	if (m_f54Query_43.has_ctrl172_query44_query45)
+		offset += 2;
+
+	/* query 46 */
+	if (m_f54Query_43.has_query46) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_46.data,
+				sizeof(m_f54Query_46.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 47 */
+	if (m_f54Query_46.has_query47) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_47.data,
+				sizeof(m_f54Query_47.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 48 reserved */
+
+	/* query 49 */
+	if (m_f54Query_47.has_query49) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_49.data,
+				sizeof(m_f54Query_49.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 50 */
+	if (m_f54Query_49.has_query50) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_50.data,
+				sizeof(m_f54Query_50.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 51 */
+	if (m_f54Query_50.has_query51) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_51.data,
+				sizeof(m_f54Query_51.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 53 54 */
+	if (m_f54Query_51.has_query53_query54_ctrl198)
+		offset += 2;
+
+	/* query 55 */
+	if (m_f54Query_51.has_query55) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_55.data,
+				sizeof(m_f54Query_55.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 56 */
+	if (m_f54Query_55.has_query56)
+		offset += 1;
+
+	/* query 57 */
+	if (m_f54Query_55.has_query57) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_57.data,
+				sizeof(m_f54Query_57.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 58 */
+	if (m_f54Query_57.has_query58) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_58.data,
+				sizeof(m_f54Query_58.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 59 */
+	if (m_f54Query_58.has_query59)
+		offset += 1;
+
+	/* query 60 */
+	if (m_f54Query_58.has_query60)
+		offset += 1;
+
+	/* query 61 */
+	if (m_f54Query_58.has_query61) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_61.data,
+				sizeof(m_f54Query_61.data));
+		if (retval < 0)
+			return retval;
+			offset += 1;
+	}
+
+	/* query 62 63 */
+	if (m_f54Query_61.has_ctrl215_query62_query63)
+		offset += 2;
+
+	/* query 64 */
+	if (m_f54Query_61.has_query64) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_64.data,
+				sizeof(m_f54Query_64.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 65 */
+	if (m_f54Query_64.has_query65) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_65.data,
+				sizeof(m_f54Query_65.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 66 */
+	if (m_f54Query_65.has_query66_ctrl231)
+		offset += 1;
+
+	/* query 67 */
+	if (m_f54Query_65.has_query67) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_67.data,
+				sizeof(m_f54Query_67.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 68 */
+	if (m_f54Query_67.has_query68) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_68.data,
+				sizeof(m_f54Query_68.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
+	/* query 69 */
+	if (m_f54Query_68.has_query69) {
+		m_device.Read(query_addr + offset,
+				m_f54Query_69.data,
+				sizeof(m_f54Query_69.data));
+		if (retval < 0)
+			return retval;
+		offset += 1;
+	}
+
 	return TEST_SUCCESS;;
 }
 
@@ -1213,6 +1435,129 @@
 		m_f54Control.reg_149.address = reg_addr;
 		reg_addr += CONTROL_149_SIZE;
 	}
+	/* control 150 */
+	if (m_f54Query_38.has_ctrl150)
+		reg_addr += CONTROL_150_SIZE;
+
+	/* control 151 */
+	if (m_f54Query_38.has_ctrl151)
+		reg_addr += CONTROL_151_SIZE;
+
+	/* control 152 */
+	if (m_f54Query_38.has_ctrl152)
+		reg_addr += CONTROL_152_SIZE;
+
+	/* control 153 */
+	if (m_f54Query_38.has_ctrl153)
+		reg_addr += CONTROL_153_SIZE;
+
+	/* control 154 */
+	if (m_f54Query_39.has_ctrl154)
+		reg_addr += CONTROL_154_SIZE;
+
+	/* control 155 */
+	if (m_f54Query_39.has_ctrl155)
+		reg_addr += CONTROL_155_SIZE;
+
+	/* control 156 */
+	if (m_f54Query_39.has_ctrl156)
+		reg_addr += CONTROL_156_SIZE;
+
+	/* controls 157 158 */
+	if (m_f54Query_39.has_ctrl157_ctrl158)
+		reg_addr += CONTROL_157_158_SIZE;
+
+	/* controls 159 to 162 reserved */
+
+	/* control 163 */
+	if (m_f54Query_40.has_ctrl163_query41)
+		reg_addr += CONTROL_163_SIZE;
+
+	/* control 164 reserved */
+
+	/* control 165 */
+	if (m_f54Query_40.has_ctrl165_query42)
+		reg_addr += CONTROL_165_SIZE;
+
+	/* control 166 */
+	if (m_f54Query_40.has_ctrl166)
+		reg_addr += CONTROL_166_SIZE;
+
+	/* control 167 */
+	if (m_f54Query_40.has_ctrl167)
+		reg_addr += CONTROL_167_SIZE;
+
+	/* control 168 */
+	if (m_f54Query_40.has_ctrl168)
+		reg_addr += CONTROL_168_SIZE;
+
+	/* control 169 */
+	if (m_f54Query_40.has_ctrl169)
+		reg_addr += CONTROL_169_SIZE;
+
+	/* control 170 reserved */
+
+	/* control 171 */
+	if (m_f54Query_43.has_ctrl171)
+		reg_addr += CONTROL_171_SIZE;
+
+	/* control 172 */
+	if (m_f54Query_43.has_ctrl172_query44_query45)
+		reg_addr += CONTROL_172_SIZE;
+
+	/* control 173 */
+	if (m_f54Query_43.has_ctrl173)
+		reg_addr += CONTROL_173_SIZE;
+
+	/* control 174 */
+	if (m_f54Query_43.has_ctrl174)
+		reg_addr += CONTROL_174_SIZE;
+
+	/* control 175 */
+	if (m_f54Query_43.has_ctrl175)
+		reg_addr += CONTROL_175_SIZE;
+
+	/* control 176 */
+	if (m_f54Query_46.has_ctrl176)
+		reg_addr += CONTROL_176_SIZE;
+
+	/* controls 177 178 */
+	if (m_f54Query_46.has_ctrl177_ctrl178)
+		reg_addr += CONTROL_177_178_SIZE;
+
+	/* control 179 */
+	if (m_f54Query_46.has_ctrl179)
+		reg_addr += CONTROL_179_SIZE;
+
+	/* controls 180 to 181 reserved */
+
+	/* control 182 */
+	if (m_f54Query_47.has_ctrl182)
+		reg_addr += CONTROL_182_SIZE;
+
+	/* control 183 */
+	if (m_f54Query_47.has_ctrl183)
+		reg_addr += CONTROL_183_SIZE;
+
+	/* control 184 reserved */
+
+	/* control 185 */
+	if (m_f54Query_47.has_ctrl185)
+		reg_addr += CONTROL_185_SIZE;
+
+	/* control 186 */
+	if (m_f54Query_47.has_ctrl186)
+		reg_addr += CONTROL_186_SIZE;
+
+	/* control 187 */
+	if (m_f54Query_47.has_ctrl187)
+		reg_addr += CONTROL_187_SIZE;
+
+	/* control 188 */
+	if (m_f54Query_49.has_ctrl188) {
+		m_f54Control.reg_188.address = reg_addr;
+		reg_addr += CONTROL_188_SIZE;
+	}
 
 	return TEST_SUCCESS;
 }
@@ -1400,17 +1745,127 @@
 	return retval;
 }
 
+#define disable_cbc(ctrl_num)\
+do {\
+	retval = m_device.Read(\
+			m_f54Control.ctrl_num.address,\
+			m_f54Control.ctrl_num.data,\
+			sizeof(m_f54Control.ctrl_num.data));\
+	if (retval < 0) {\
+		return retval;\
+	} \
+	m_f54Control.ctrl_num.cbc_tx_carrier_selection = 0;\
+	retval = m_device.Write(\
+			m_f54Control.ctrl_num.address,\
+			m_f54Control.ctrl_num.data,\
+			sizeof(m_f54Control.ctrl_num.data));\
+	if (retval < 0) {\
+		return retval;\
+	} \
+} while (0)
+
+int F54Test::DoPreparation()
+{
+	int retval;
+	unsigned char value;
+	unsigned char zero = 0x00;
+	unsigned char device_ctrl;
+
+	retval = m_device.Read(m_f54.GetControlBase(),
+			&device_ctrl,
+			sizeof(device_ctrl));
+	if (retval < 0) {
+		return retval;
+	}
+
+	device_ctrl |= NO_SLEEP_ON;
+
+	retval = m_device.Write(m_f54.GetControlBase(),
+			&device_ctrl,
+			sizeof(device_ctrl));
+	if (retval < 0) {
+		return retval;
+	}
+
+	switch (m_reportType) {
+	case F54_16BIT_IMAGE:
+	case F54_RAW_16BIT_IMAGE:
+	case F54_SENSOR_SPEED:
+	case F54_ADC_RANGE:
+	case F54_ABS_RAW_CAP:
+	case F54_ABS_DELTA_CAP:
+		break;
+	default:
+		if (m_f54Query.touch_controller_family == 1)
+			disable_cbc(reg_7);
+		else if (m_f54Query.has_ctrl88)
+			disable_cbc(reg_88);
+
+		if (m_f54Query.has_0d_acquisition_control)
+			disable_cbc(reg_57);
+
+		if ((m_f54Query.has_query15) &&
+				(m_f54Query_15.has_query25) &&
+				(m_f54Query_25.has_query27) &&
+				(m_f54Query_27.has_query29) &&
+				(m_f54Query_29.has_query30) &&
+				(m_f54Query_30.has_query32) &&
+				(m_f54Query_32.has_query33) &&
+				(m_f54Query_33.has_query36) &&
+				(m_f54Query_36.has_query38) &&
+				(m_f54Query_38.has_ctrl149)) {
+			retval = m_device.Write(m_f54Control.reg_149.address,
+					&zero,
+					sizeof(m_f54Control.reg_149.data));
+			if (retval < 0) {
+				return retval;
+			}
+		}
+
+		if (m_f54Query.has_signal_clarity) {
+			retval = m_device.Read(m_f54Control.reg_41.address,
+					&value,
+					sizeof(m_f54Control.reg_41.data));
+			if (retval < 0) {
+				return retval;
+			}
+			value |= 0x01;
+			retval = m_device.Write(m_f54Control.reg_41.address,
+					&value,
+					sizeof(m_f54Control.reg_41.data));
+			if (retval < 0) {
+				return retval;
+			}
+		}
+
+		retval = DoF54Command(COMMAND_FORCE_UPDATE);
+		if (retval < 0) {
+			return retval;
+		}
+
+		retval = DoF54Command(COMMAND_FORCE_CAL);
+		if (retval < 0) {
+			return retval;
+		}
+	}
+	return TEST_SUCCESS;
+}
+
 int F54Test::ShowF54Report()
 {
 	unsigned int ii;
 	unsigned int jj;
+	unsigned int kk;
 	unsigned int tx_num = m_txAssigned;
 	unsigned int rx_num = m_rxAssigned;
 	char *report_data_8;
 	short *report_data_16;
 	int *report_data_32;
 	unsigned int *report_data_u32;
+	unsigned char *report_data_u8;
 	char buf[256];
+	bool rt26_result = true;
+	unsigned char rt26_ng_num;
 
 	switch (m_reportType) {
 	case F54_8BIT_IMAGE:
@@ -1550,6 +2005,68 @@
 		m_display.Output(buf);
 		
 		break;
+	case F54_GUARD_PIN_SHORT:
+		report_data_u8 = (unsigned char *)m_reportData;
+		sprintf(buf, "Guard Pin Short Test:\n");
+		m_display.Output(buf);
+		for (ii = 0; ii < GUARD_PIN_SHORT_DATA_SIZE; ii++) {
+			sprintf(buf, "%03d: 0x%02x\n", ii, *(report_data_u8 + ii));
+			m_display.Output(buf);
+		}
+		sprintf(buf, "\n");
+		m_display.Output(buf);
+
+		if (report_data_u8[GUARD_PIN_SHORT_DATA_SIZE - 1] & 0xC0)
+			sprintf(buf, "Failed: pin %d\n",
+					(report_data_u8[GUARD_PIN_SHORT_DATA_SIZE - 1] & 0xC0) >> 7);
+		else
+			sprintf(buf, "Pass\n");
+		m_display.Output(buf);
+
+		break;
+	case F54_TRX_SHORTS:
+		report_data_u8 = (unsigned char *)m_reportData;
+		sprintf(buf, "Trx Short Test:\n");
+		m_display.Output(buf);
+
+		for (ii = 0; ii < m_reportSize; ii++) {
+			sprintf(buf, "%03d: 0x%02x\n", ii, *(report_data_u8 + ii));
+			m_display.Output(buf);
+		}
+		sprintf(buf, "\n");
+		m_display.Output(buf);
+
+		for (ii = 0; ii < m_reportSize; ii++) {
+			if (report_data_u8[ii] != 0) {
+				for (jj = 0; jj < sizeof(char); jj++) {
+					if (report_data_u8[ii] & (1 << jj)) {
+						rt26_ng_num = ii * 8 + jj;
+						for (kk = 0; kk < m_txAssigned; kk++) {
+							if (rt26_ng_num == m_txAssignment[kk]) {
+								rt26_result = false;
+								sprintf(buf, "Failed on %d\n", rt26_ng_num);
+								m_display.Output(buf);
+							}
+						}
+						for (kk = 0; kk < m_rxAssigned; kk++) {
+							if (rt26_ng_num == m_rxAssignment[kk]) {
+								rt26_result = false;
+								sprintf(buf, "Failed on %d\n", rt26_ng_num);
+								m_display.Output(buf);
+							}
+						}
+					}
+				}
+			}
+		}
+
+		if (rt26_result) {
+			sprintf(buf, "Pass\n");
+			m_display.Output(buf);
+		}
+
+		break;
+
 	default:
 		for (ii = 0; ii < m_reportSize; ii++) {
 			sprintf(buf, "%03d: 0x%02x\n",
diff --git a/f54test/f54test.h b/f54test/f54test.h
index 6842cba..bc0b496 100644
--- a/f54test/f54test.h
+++ b/f54test/f54test.h
@@ -143,10 +143,39 @@
 #define CONTROL_147_SIZE 1
 #define CONTROL_148_SIZE 1
 #define CONTROL_149_SIZE 1
+#define CONTROL_150_SIZE 1
+#define CONTROL_151_SIZE 1
+#define CONTROL_152_SIZE 1
+#define CONTROL_153_SIZE 1
+#define CONTROL_154_SIZE 1
+#define CONTROL_155_SIZE 1
+#define CONTROL_156_SIZE 1
+#define CONTROL_157_158_SIZE 2
+#define CONTROL_163_SIZE 1
+#define CONTROL_165_SIZE 1
+#define CONTROL_166_SIZE 1
+#define CONTROL_167_SIZE 1
+#define CONTROL_168_SIZE 1
+#define CONTROL_169_SIZE 1
+#define CONTROL_171_SIZE 1
+#define CONTROL_172_SIZE 1
+#define CONTROL_173_SIZE 1
+#define CONTROL_174_SIZE 1
+#define CONTROL_175_SIZE 1
+#define CONTROL_176_SIZE 1
+#define CONTROL_177_178_SIZE 2
+#define CONTROL_179_SIZE 1
+#define CONTROL_182_SIZE 1
+#define CONTROL_183_SIZE 1
+#define CONTROL_185_SIZE 1
+#define CONTROL_186_SIZE 1
+#define CONTROL_187_SIZE 1
+#define CONTROL_188_SIZE 1
 
 #define HIGH_RESISTANCE_DATA_SIZE 6
 #define FULL_RAW_CAP_MIN_MAX_DATA_SIZE 4
-#define TRX_OPEN_SHORT_DATA_SIZE 7
+#define TRX_OPEN_SHORT_DATA_SIZE 15
+#define GUARD_PIN_SHORT_DATA_SIZE 15
 
 enum f54_report_types {
 	F54_8BIT_IMAGE = 1,
@@ -171,6 +200,7 @@
 	F54_TRX_SHORTS = 26,
 	F54_ABS_RAW_CAP = 38,
 	F54_ABS_DELTA_CAP = 40,
+	F54_GUARD_PIN_SHORT = 50,
 	INVALID_REPORT_TYPE = -1,
 };
 
@@ -493,16 +523,281 @@
 			unsigned char has_ctrl147:1;
 			unsigned char has_ctrl148:1;
 			unsigned char has_ctrl149:1;
-			unsigned char f54_query38_b3:1;
-			unsigned char f54_query38_b4:1;
-			unsigned char f54_query38_b5:1;
-			unsigned char f54_query38_b6:1;
-			unsigned char f54_query38_b7:1;
+			unsigned char has_ctrl150:1;
+			unsigned char has_ctrl151:1;
+			unsigned char has_ctrl152:1;
+			unsigned char has_ctrl153:1;
+			unsigned char has_query39:1;
 		} __attribute__((packed));
 		unsigned char data[1];
 	};
 };
 
+struct f54_query_39 {
+	union {
+		struct {
+			unsigned char has_ctrl154:1;
+			unsigned char has_ctrl155:1;
+			unsigned char has_ctrl156:1;
+			unsigned char has_ctrl160:1;
+			unsigned char has_ctrl157_ctrl158:1;
+			unsigned char f54_query39_b5__6:2;
+			unsigned char has_query40:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_40 {
+	union {
+		struct {
+			unsigned char has_ctrl169:1;
+			unsigned char has_ctrl163_query41:1;
+			unsigned char f54_query40_b2:1;
+			unsigned char has_ctrl165_query42:1;
+			unsigned char has_ctrl166:1;
+			unsigned char has_ctrl167:1;
+			unsigned char has_ctrl168:1;
+			unsigned char has_query43:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_43 {
+	union {
+		struct {
+			unsigned char f54_query43_b0__1:2;
+			unsigned char has_ctrl171:1;
+			unsigned char has_ctrl172_query44_query45:1;
+			unsigned char has_ctrl173:1;
+			unsigned char has_ctrl174:1;
+			unsigned char has_ctrl175:1;
+			unsigned char has_query46:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_46 {
+	union {
+		struct {
+			unsigned char has_ctrl176:1;
+			unsigned char has_ctrl177_ctrl178:1;
+			unsigned char has_ctrl179:1;
+			unsigned char f54_query46_b3:1;
+			unsigned char has_data27:1;
+			unsigned char has_data28:1;
+			unsigned char f54_query46_b6:1;
+			unsigned char has_query47:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_47 {
+	union {
+		struct {
+			unsigned char f54_query47_b0:1;
+			unsigned char has_ctrl182:1;
+			unsigned char has_ctrl183:1;
+			unsigned char f54_query47_b3:1;
+			unsigned char has_ctrl185:1;
+			unsigned char has_ctrl186:1;
+			unsigned char has_ctrl187:1;
+			unsigned char has_query49:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_49 {
+	union {
+		struct {
+			unsigned char f54_query49_b0__1:2;
+			unsigned char has_ctrl188:1;
+			unsigned char has_data31:1;
+			unsigned char f54_query49_b4__6:3;
+			unsigned char has_query50:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_50 {
+	union {
+		struct {
+			unsigned char f54_query50_b0__6:7;
+			unsigned char has_query51:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_51 {
+	union {
+		struct {
+			unsigned char f54_query51_b0__4:5;
+			unsigned char has_query53_query54_ctrl198:1;
+			unsigned char has_ctrl199:1;
+			unsigned char has_query55:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_55 {
+	union {
+		struct {
+			unsigned char has_query56:1;
+			unsigned char has_data33_data34:1;
+			unsigned char has_alt_report_rate:1;
+			unsigned char has_ctrl200:1;
+			unsigned char has_ctrl201_ctrl202:1;
+			unsigned char has_ctrl203:1;
+			unsigned char has_ctrl204:1;
+			unsigned char has_query57:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_57 {
+	union {
+		struct {
+			unsigned char has_ctrl205:1;
+			unsigned char has_ctrl206:1;
+			unsigned char has_usb_bulk_read:1;
+			unsigned char has_ctrl207:1;
+			unsigned char has_ctrl208:1;
+			unsigned char has_ctrl209:1;
+			unsigned char has_ctrl210:1;
+			unsigned char has_query58:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_58 {
+	union {
+		struct {
+			unsigned char has_query59:1;
+			unsigned char has_query60:1;
+			unsigned char has_ctrl211:1;
+			unsigned char has_ctrl212:1;
+			unsigned char has_hybrid_abs_tx_axis_filtering:1;
+			unsigned char has_hybrid_abs_tx_interpolation:1;
+			unsigned char has_ctrl213:1;
+			unsigned char has_query61:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_61 {
+	union {
+		struct {
+			unsigned char has_ctrl214:1;
+			unsigned char has_ctrl215_query62_query63:1;
+			unsigned char f54_query_61_b2:1;
+			unsigned char has_ctrl216:1;
+			unsigned char has_ctrl217:1;
+			unsigned char has_misc_host_ctrl:1;
+			unsigned char hybrid_abs_buttons:1;
+			unsigned char has_query64:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_64 {
+	union {
+		struct {
+			unsigned char has_ctrl101_sub1:1;
+			unsigned char has_ctrl220:1;
+			unsigned char has_ctrl221:1;
+			unsigned char has_ctrl222:1;
+			unsigned char has_ctrl219_sub1:1;
+			unsigned char has_ctrl103_sub3:1;
+			unsigned char has_ctrl224_ctrl226_ctrl227:1;
+			unsigned char has_query65:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_65 {
+	union {
+		struct {
+			unsigned char f54_query_65_b0__1:2;
+			unsigned char has_ctrl101_sub2:1;
+			unsigned char f54_query_65_b3__4:2;
+			unsigned char has_query66_ctrl231:1;
+			unsigned char has_ctrl232:1;
+			unsigned char has_query67:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_67 {
+	union {
+		struct {
+			unsigned char has_abs_doze_spatial_filter_en:1;
+			unsigned char has_abs_doze_avg_filter_enhancement_en:1;
+			unsigned char has_single_display_pulse:1;
+			unsigned char f54_query_67_b3__4:2;
+			unsigned char has_ctrl235_ctrl236:1;
+			unsigned char f54_query_67_b6:1;
+			unsigned char has_query68:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_68 {
+	union {
+		struct {
+			unsigned char f54_query_68_b0:1;
+			unsigned char has_ctrl238:1;
+			unsigned char has_ctrl238_sub1:1;
+			unsigned char has_ctrl238_sub2:1;
+			unsigned char has_ctrl239:1;
+			unsigned char has_freq_filter_bw_ext:1;
+			unsigned char is_tddi_hic:1;
+			unsigned char has_query69:1;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_query_69 {
+	union {
+		struct {
+			unsigned char has_ctrl240_sub0:1;
+			unsigned char has_ctrl240_sub1_sub2:1;
+			unsigned char has_ctrl240_sub3:1;
+			unsigned char has_ctrl240_sub4:1;
+			unsigned char f54_query_69_b4__7:4;
+		} __attribute__((packed));
+		unsigned char data[1];
+	};
+};
+
+struct f54_data_31 {
+	union {
+		struct {
+			unsigned char is_calibration_crc:1;
+			unsigned char calibration_crc:1;
+			unsigned char short_test_row_number:5;
+		} __attribute__((packed));
+		struct {
+			unsigned char data[1];
+			unsigned short address;
+		} __attribute__((packed));
+	};
+};
+
 struct f54_control_7 {
 	union {
 		struct {
@@ -602,6 +897,23 @@
 	};
 };
 
+struct f54_control_188 {
+	union {
+		struct {
+			unsigned char start_calibration:1;
+			unsigned char start_is_calibration:1;
+			unsigned char frequency:2;
+			unsigned char start_production_test:1;
+			unsigned char short_test_calibration:1;
+			unsigned char f54_ctrl188_b7:1;
+		} __attribute__((packed));
+		struct {
+			unsigned char data[1];
+			unsigned short address;
+		} __attribute__((packed));
+	};
+};
+
 struct f54_control {
 	struct f54_control_7 reg_7;
 	struct f54_control_41 reg_41;
@@ -609,8 +921,10 @@
 	struct f54_control_88 reg_88;
 	struct f54_control_110 reg_110;
 	struct f54_control_149 reg_149;
+	struct f54_control_188 reg_188;
 };
 
+
 struct f55_query {
 	union {
 		struct {
@@ -663,6 +977,7 @@
 	int WaitForF54CommandCompletion();
 	int ReadF54Report();
 	int ShowF54Report();
+	int DoPreparation();
 
 private:
 	RMIDevice & m_device;
@@ -687,9 +1002,26 @@
 	f54_query_35 m_f54Query_35;
 	f54_query_36 m_f54Query_36;
 	f54_query_38 m_f54Query_38;
+	f54_query_39 m_f54Query_39;
+	f54_query_40 m_f54Query_40;
+	f54_query_43 m_f54Query_43;
+	f54_query_46 m_f54Query_46;
+	f54_query_47 m_f54Query_47;
+	f54_query_49 m_f54Query_49;
+	f54_query_50 m_f54Query_50;
+	f54_query_51 m_f54Query_51;
+	f54_query_55 m_f54Query_55;
+	f54_query_57 m_f54Query_57;
+	f54_query_58 m_f54Query_58;
+	f54_query_61 m_f54Query_61;
+	f54_query_64 m_f54Query_64;
+	f54_query_65 m_f54Query_65;
+	f54_query_67 m_f54Query_67;
+	f54_query_68 m_f54Query_68;
+	f54_query_69 m_f54Query_69;
 
 	f54_control m_f54Control;
-
+	f54_data_31 m_f54Data_31;
 	f55_query m_f55Query;
 
 	f54_report_types m_reportType;
diff --git a/f54test/main.cpp b/f54test/main.cpp
index d0cf8f7..9b6486a 100644
--- a/f54test/main.cpp
+++ b/f54test/main.cpp
@@ -34,7 +34,7 @@
 #include "f54test.h"
 #include "display.h"
 
-#define F54TEST_GETOPTS	"hd:r:cn"
+#define F54TEST_GETOPTS	"hd:r:cnt:"
 
 static bool stopRequested;
 
@@ -46,12 +46,12 @@
 	fprintf(stdout, "\t-r, --report_type\tReport type.\n");
 	fprintf(stdout, "\t-c, --continuous\tContinuous mode.\n");
 	fprintf(stdout, "\t-n, --no_reset\tDo not reset after the report.\n");
+	fprintf(stdout, "\t-t, --device-type\t\t\tFilter by device type [touchpad or touchscreen].\n");
 }
 
-int RunF54Test(const char * deviceFile, f54_report_types reportType, bool continuousMode, bool noReset)
+int RunF54Test(RMIDevice & rmidevice, f54_report_types reportType, bool continuousMode, bool noReset)
 {
 	int rc;
-	HIDDevice rmidevice;
 	Display * display;
 
 	if (continuousMode)
@@ -65,10 +65,6 @@
 
 	display->Clear();
 
-	rc = rmidevice.Open(deviceFile);
-	if (rc)
-		return rc;
-
 	F54Test f54Test(rmidevice, *display);
 
 	rc = f54Test.Prepare(reportType);
@@ -85,8 +81,6 @@
 	if (!noReset)
 		rmidevice.Reset();
 
-	rmidevice.Close();
-
 	delete display;
 
 	return rc;
@@ -109,13 +103,14 @@
 		{"report_type", 1, NULL, 'r'},
 		{"continuous", 0, NULL, 'c'},
 		{"no_reset", 0, NULL, 'n'},
+		{"device-type", 1, NULL, 't'},
 		{0, 0, 0, 0},
 	};
-	struct dirent * devDirEntry;
-	DIR * devDir;
 	f54_report_types reportType = F54_16BIT_IMAGE;
 	bool continuousMode = false;
 	bool noReset = false;
+	HIDDevice device;
+	enum RMIDeviceType deviceType = RMI_DEVICE_TYPE_ANY;
 
 	while ((opt = getopt_long(argc, argv, F54TEST_GETOPTS, long_options, &index)) != -1) {
 		switch (opt) {
@@ -134,6 +129,12 @@
 			case 'n':
 				noReset = true;
 				break;
+			case 't':
+				if (!strcasecmp(optarg, "touchpad"))
+					deviceType = RMI_DEVICE_TYPE_TOUCHPAD;
+				else if (!strcasecmp(optarg, "touchscreen"))
+					deviceType = RMI_DEVICE_TYPE_TOUCHSCREEN;
+				break;
 			default:
 				break;
 
@@ -148,38 +149,16 @@
 	}
 
 	if (deviceName) {
-		rc = RunF54Test(deviceName, reportType, continuousMode, noReset);
-		if (rc)
-			return rc;
-
-		return rc;
-	} else {
-		char rawDevice[PATH_MAX];
-		char deviceFile[PATH_MAX];
-		bool found = false;
-
-		devDir = opendir("/dev");
-		if (!devDir)
-			return -1;
-
-		while ((devDirEntry = readdir(devDir)) != NULL) {
-			if (strstr(devDirEntry->d_name, "hidraw")) {
-				strncpy(rawDevice, devDirEntry->d_name, PATH_MAX);
-				snprintf(deviceFile, PATH_MAX, "/dev/%s", devDirEntry->d_name);
-				rc = RunF54Test(deviceFile, reportType, continuousMode, noReset);
-				if (rc != 0) {
-					continue;
-				} else {
-					found = true;
-					break;
-				}
-			}
+		rc = device.Open(deviceName);
+		if (rc) {
+			fprintf(stderr, "%s: failed to initialize rmi device (%d): %s\n", argv[0], errno,
+				strerror(errno));
+			return 1;
 		}
-		closedir(devDir);
-
-		if (!found)
-			return rc;
+	} else {
+		if (!device.FindDevice(deviceType))
+			return 1;
 	}
 
-	return 0;
+	return RunF54Test(device, reportType, continuousMode, noReset);
 }
diff --git a/f54test/testutil.cpp b/f54test/testutil.cpp
index 6de56b1..a49307c 100644
--- a/f54test/testutil.cpp
+++ b/f54test/testutil.cpp
@@ -41,30 +41,4 @@
 const char * test_err_to_string(int err)
 {
 	return test_error_str[err];
-}
-
-unsigned long extract_long(const unsigned char *data)
-{
-	return (unsigned long)data [0]
-		+ (unsigned long)data [1] * 0x100
-		+ (unsigned long)data [2] * 0x10000
-		+ (unsigned long)data [3] * 0x1000000;
-}
-
-unsigned short extract_short(const unsigned char *data)
-{
-	return (unsigned long)data [0]
-		+ (unsigned long)data [1] * 0x100;
-}
-
-const char * StripPath(const char * path, ssize_t size)
-{
-	int i;
-	const char * str;
-
-	for (i = size - 1, str = &path[size - 1]; i > 0; --i, --str)
-		if (path[i - 1] == '/')
-			break;
-
-	return str;
-}
+}
\ No newline at end of file
diff --git a/f54test/testutil.h b/f54test/testutil.h
index 3004299..d7c1433 100644
--- a/f54test/testutil.h
+++ b/f54test/testutil.h
@@ -41,6 +41,5 @@
 
 unsigned long extract_long(const unsigned char *data);
 unsigned short extract_short(const unsigned char *data);
-const char * StripPath(const char * path, ssize_t size);
 
 #endif // _TESTUTIL_H_
diff --git a/rmi4update/Android.bp b/rmi4update/Android.bp
index a7269c5..e3ba434 100644
--- a/rmi4update/Android.bp
+++ b/rmi4update/Android.bp
@@ -19,6 +19,7 @@
         "-Wall",
         "-Werror",
         "-Wno-unused-parameter",
+        "-Wno-unused-private-field",
     ],
     static_libs: ["rmidevice"],
 }
diff --git a/rmi4update/firmware_image.cpp b/rmi4update/firmware_image.cpp
old mode 100644
new mode 100755
index babce56..6cc18c0
--- a/rmi4update/firmware_image.cpp
+++ b/rmi4update/firmware_image.cpp
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 
+#include "rmidevice.h"
 #include "firmware_image.h"
 
 using namespace std;
@@ -43,6 +44,66 @@
 	return checksum;
 }
 
+void FirmwareImage::ParseHierarchicalImg()
+{
+	struct container_descriptor *descriptor;
+	int numOfCntrs;
+	int ii;
+	unsigned int addr;
+	unsigned int offset;
+	unsigned int length;
+	unsigned char *content;
+	unsigned short container_id;
+
+	m_cntrAddr = extract_long(&m_memBlock[RMI_IMG_V10_CNTR_ADDR_OFFSET]);
+	descriptor = (struct container_descriptor *)(m_memBlock + m_cntrAddr);
+	offset = extract_long(descriptor->content_address);
+	numOfCntrs = extract_long(descriptor->content_length) / 4;
+
+	for (ii = 0; ii < numOfCntrs; ii++) {
+		addr = extract_long(m_memBlock + offset);
+		offset += 4;
+		descriptor = (struct container_descriptor *)(m_memBlock + addr);
+		container_id = descriptor->container_id[0] |
+				descriptor->container_id[1] << 8;
+		content = m_memBlock + extract_long(descriptor->content_address);
+		length = extract_long(descriptor->content_length);
+		switch (container_id) {
+		case BL_CONTAINER:
+			m_bootloaderVersion = *content;
+			break;
+		case UI_CONTAINER:
+		case CORE_CODE_CONTAINER:
+			m_firmwareData = content;
+			m_firmwareSize = length;
+			break;
+		case FLASH_CONFIG_CONTAINER:
+			m_flashConfigData = content;
+			m_flashConfigSize = length;
+			break;
+		case UI_CONFIG_CONTAINER:
+		case CORE_CONFIG_CONTAINER:
+			m_configData = content;
+			m_configSize = length;
+			break;
+		case PERMANENT_CONFIG_CONTAINER:
+		case GUEST_SERIALIZATION_CONTAINER:
+			m_lockdownData = content;
+			m_lockdownSize = length;
+			break;
+		case GENERAL_INFORMATION_CONTAINER:
+			m_io = true;
+			m_packageID = extract_long(content);
+			m_firmwareBuildID = extract_long(content + 4);
+			memcpy(m_productID, (content + 0x18), RMI_PRODUCT_ID_LENGTH);
+			m_productID[RMI_PRODUCT_ID_LENGTH] = 0;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
 int FirmwareImage::Initialize(const char * filename)
 {
 	if (!filename)
@@ -120,6 +181,9 @@
 			m_lockdownSize = RMI_IMG_LOCKDOWN_V5_SIZE;
 			m_lockdownData = &m_memBlock[RMI_IMG_LOCKDOWN_V5_OFFSET];
 			break;
+		case 16:
+			ParseHierarchicalImg();
+			break;
 		default:
 			return UPDATE_FAIL_UNSUPPORTED_IMAGE_VERSION;
 	}
diff --git a/rmi4update/firmware_image.h b/rmi4update/firmware_image.h
old mode 100644
new mode 100755
index 1c91324..3ce1c59
--- a/rmi4update/firmware_image.h
+++ b/rmi4update/firmware_image.h
@@ -43,6 +43,53 @@
 #define RMI_IMG_LOCKDOWN_V5_OFFSET		0xB0
 #define RMI_IMG_LOCKDOWN_V5_SIZE		0x50
 
+// Leon add for BL_V7
+#define RMI_IMG_V10_CNTR_ADDR_OFFSET		0x0C
+
+struct container_descriptor {
+	unsigned char content_checksum[4];
+	unsigned char container_id[2];
+	unsigned char minor_version;
+	unsigned char major_version;
+	unsigned char reserved_08;
+	unsigned char reserved_09;
+	unsigned char reserved_0a;
+	unsigned char reserved_0b;
+	unsigned char container_option_flags[4];
+	unsigned char content_options_length[4];
+	unsigned char content_options_address[4];
+	unsigned char content_length[4];
+	unsigned char content_address[4];
+};
+
+enum container_id {
+	TOP_LEVEL_CONTAINER = 0,
+	UI_CONTAINER,
+	UI_CONFIG_CONTAINER,
+	BL_CONTAINER,
+	BL_IMAGE_CONTAINER,
+	BL_CONFIG_CONTAINER,
+	BL_LOCKDOWN_INFO_CONTAINER,
+	PERMANENT_CONFIG_CONTAINER,
+	GUEST_CODE_CONTAINER,
+	BL_PROTOCOL_DESCRIPTOR_CONTAINER,
+	UI_PROTOCOL_DESCRIPTOR_CONTAINER,
+	RMI_SELF_DISCOVERY_CONTAINER,
+	RMI_PAGE_CONTENT_CONTAINER,
+	GENERAL_INFORMATION_CONTAINER,
+	DEVICE_CONFIG_CONTAINER,
+	FLASH_CONFIG_CONTAINER,
+	GUEST_SERIALIZATION_CONTAINER,
+	GLOBAL_PARAMETERS_CONTAINER,
+	CORE_CODE_CONTAINER,
+	CORE_CONFIG_CONTAINER,
+	DISPLAY_CONFIG_CONTAINER,
+	EXTERNAL_TOUCH_AFE_CONFIG_CONTAINER,
+	UTILITY_CONTAINER,
+	UTILITY_PARAMETER_CONTAINER,
+};
+// BL_V7 end
+
 class FirmwareImage
 {
 public:
@@ -54,9 +101,11 @@
 					unsigned long deviceConfigSize);
 	unsigned char * GetFirmwareData() { return m_firmwareData; }
 	unsigned char * GetConfigData() { return m_configData; }
+	unsigned char * GetFlashConfigData() { return m_flashConfigData; }
 	unsigned char * GetLockdownData() { return m_lockdownData; }
 	unsigned long GetFirmwareSize() { return m_firmwareSize; }
 	unsigned long GetConfigSize() { return m_configSize; }
+	unsigned long GetFlashConfigSize() { return m_flashConfigSize; }
 	unsigned long GetLockdownSize() { return m_lockdownSize; }
 	unsigned long GetFirmwareID() { return m_firmwareBuildID; }
 	bool HasIO() { return m_io; }
@@ -65,11 +114,13 @@
 private:
 	unsigned long Checksum(unsigned short * data, unsigned long len);
 	void PrintHeaderInfo();
+	void ParseHierarchicalImg();	// BL_V7
 
 private:
 	unsigned long m_checksum;
 	unsigned long m_firmwareSize;
 	unsigned long m_configSize;
+	unsigned long m_flashConfigSize;
 	unsigned long m_lockdownSize;
 	long m_imageSize;
 	unsigned long m_firmwareBuildID;
@@ -81,8 +132,10 @@
 
 	unsigned char * m_firmwareData;
 	unsigned char * m_configData;
+	unsigned char * m_flashConfigData;
 	unsigned char * m_lockdownData;
 	unsigned char * m_memBlock;
+	unsigned long m_cntrAddr;	// BL_V7
 };
 
 #endif // _FIRMWAREIMAGE_H_
diff --git a/rmi4update/main.cpp b/rmi4update/main.cpp
old mode 100644
new mode 100755
index 11146e1..a710764
--- a/rmi4update/main.cpp
+++ b/rmi4update/main.cpp
@@ -32,20 +32,22 @@
 #include "rmi4update.h"
 
 #define VERSION_MAJOR		1
-#define VERSION_MINOR		2
-#define VERSION_SUBMINOR	0
+#define VERSION_MINOR		3
+#define VERSION_SUBMINOR	5
 
-#define RMI4UPDATE_GETOPTS	"hfd:plv"
+#define RMI4UPDATE_GETOPTS	"hfd:t:pclv"
 
 void printHelp(const char *prog_name)
 {
 	fprintf(stdout, "Usage: %s [OPTIONS] FIRMWAREFILE\n", prog_name);
-	fprintf(stdout, "\t-h, --help\tPrint this message\n");
-	fprintf(stdout, "\t-f, --force\tForce updating firmware even it the image provided is older\n\t\t\tthen the current firmware on the device.\n");
-	fprintf(stdout, "\t-d, --device\thidraw device file associated with the device being updated.\n");
-	fprintf(stdout, "\t-p, --fw-props\tPrint the firmware properties.\n");
-	fprintf(stdout, "\t-l, --lockdown\tPerform lockdown.\n");
-	fprintf(stdout, "\t-v, --version\tPrint version number.\n");
+	fprintf(stdout, "\t-h, --help\t\tPrint this message\n");
+	fprintf(stdout, "\t-f, --force\t\tForce updating firmware even it the image provided is older\n\t\t\t\tthen the current firmware on the device.\n");
+	fprintf(stdout, "\t-d, --device\t\thidraw device file associated with the device being updated.\n");
+	fprintf(stdout, "\t-p, --fw-props\t\tPrint the firmware properties.\n");
+	fprintf(stdout, "\t-c, --config-id\t\tPrint the config id.\n");
+	fprintf(stdout, "\t-l, --lockdown\t\tPerform lockdown.\n");
+	fprintf(stdout, "\t-v, --version\t\tPrint version number.\n");
+	fprintf(stdout, "\t-t, --device-type\tFilter by device type [touchpad or touchscreen].\n");
 }
 
 void printVersion()
@@ -54,24 +56,7 @@
 		VERSION_MAJOR, VERSION_MINOR, VERSION_SUBMINOR);
 }
 
-int UpdateDevice(FirmwareImage & image, bool force, bool performLockdown, const char * deviceFile)
-{
-	HIDDevice rmidevice;
-	int rc;
-
-	rc = rmidevice.Open(deviceFile);
-	if (rc)
-		return rc;
-
-	RMI4Update update(rmidevice, image);
-	rc = update.UpdateFirmware(force, performLockdown);
-	if (rc != UPDATE_SUCCESS)
-		return rc;
-
-	return rc;
-}
-
-int GetFirmwareProps(const char * deviceFile, std::string &props)
+int GetFirmwareProps(const char * deviceFile, std::string &props, bool configid)
 {
 	HIDDevice rmidevice;
 	int rc = UPDATE_SUCCESS;
@@ -84,12 +69,16 @@
 	rmidevice.ScanPDT(0x1);
 	rmidevice.QueryBasicProperties();
 
-	ss << rmidevice.GetFirmwareVersionMajor() << "."
-		<< rmidevice.GetFirmwareVersionMinor() << "."
-		<< std::hex << rmidevice.GetFirmwareID();
+	if (configid) {
+		ss << std::hex << rmidevice.GetConfigID();
+	} else {
+		ss << rmidevice.GetFirmwareVersionMajor() << "."
+			<< rmidevice.GetFirmwareVersionMinor() << "."
+			<< rmidevice.GetFirmwareID();
 
-	if (rmidevice.InBootloader())
-		ss << " bootloader";
+		if (rmidevice.InBootloader())
+			ss << " bootloader";
+	}
 
 	props = ss.str();
 
@@ -110,14 +99,17 @@
 		{"force", 0, NULL, 'f'},
 		{"device", 1, NULL, 'd'},
 		{"fw-props", 0, NULL, 'p'},
+		{"config-id", 0, NULL, 'c'},
 		{"lockdown", 0, NULL, 'l'},
 		{"version", 0, NULL, 'v'},
+		{"device-type", 1, NULL, 't'},
 		{0, 0, 0, 0},
 	};
-	struct dirent * devDirEntry;
-	DIR * devDir;
 	bool printFirmwareProps = false;
+	bool printConfigid = false;
 	bool performLockdown = false;
+	HIDDevice device;
+	enum RMIDeviceType deviceType = RMI_DEVICE_TYPE_ANY;
 
 	while ((opt = getopt_long(argc, argv, RMI4UPDATE_GETOPTS, long_options, &index)) != -1) {
 		switch (opt) {
@@ -133,9 +125,19 @@
 			case 'p':
 				printFirmwareProps = true;
 				break;
+			case 'c':
+				printFirmwareProps = true;
+				printConfigid = true;
+				break;
 			case 'l':
 				performLockdown = true;
 				break;
+			case 't':
+				if (!strcasecmp((const char *)optarg, "touchpad"))
+					deviceType = RMI_DEVICE_TYPE_TOUCHPAD;
+				else if (!strcasecmp((const char *)optarg, "touchscreen"))
+					deviceType = RMI_DEVICE_TYPE_TOUCHSCREEN;
+				break;
 			case 'v':
 				printVersion();
 				return 0;
@@ -152,7 +154,7 @@
 			fprintf(stderr, "Specifiy which device to query\n");
 			return 1;
 		}
-		rc = GetFirmwareProps(deviceName, props);
+		rc = GetFirmwareProps(deviceName, props, printConfigid);
 		if (rc) {
 			fprintf(stderr, "Failed to read properties from device: %s\n", update_err_to_string(rc));
 			return 1;
@@ -175,35 +177,25 @@
 	}
 
 	if (deviceName) {
-		rc = UpdateDevice(image, force, performLockdown, deviceName);
-
-		return rc;
-	} else {
-		char deviceFile[PATH_MAX];
-		bool found = false;
-
-		devDir = opendir("/dev");
-		if (!devDir)
-			return -1;
-
-		while ((devDirEntry = readdir(devDir)) != NULL) {
-			if (strstr(devDirEntry->d_name, "hidraw")) {
-				char rawDevice[PATH_MAX];
-				strncpy(rawDevice, devDirEntry->d_name, PATH_MAX);
-				snprintf(deviceFile, PATH_MAX, "/dev/%s", devDirEntry->d_name);
-				rc = UpdateDevice(image, force, performLockdown, deviceFile);
-				if (rc != 0) {
-					continue;
-				} else {
-					found = true;
-					break;
-				}
-			}
+		 rc = device.Open(deviceName);
+		 if (rc) {
+			fprintf(stderr, "%s: failed to initialize rmi device (%d): %s\n", argv[0], errno,
+				strerror(errno));
+			return 1;
 		}
-		closedir(devDir);
+	} else {
+		if (!device.FindDevice(deviceType))
+			return 1;
+	}
 
-		if (!found)
-			return rc;
+
+	RMI4Update update(device, image);
+	rc = update.UpdateFirmware(force, performLockdown);
+
+	if (rc != UPDATE_SUCCESS)
+	{
+		device.Reset();
+		return 1;
 	}
 
 	return 0;
diff --git a/rmi4update/rmi4update.cpp b/rmi4update/rmi4update.cpp
old mode 100644
new mode 100755
index 6c267bc..19eadb5
--- a/rmi4update/rmi4update.cpp
+++ b/rmi4update/rmi4update.cpp
@@ -23,7 +23,8 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
-
+#include <fcntl.h>
+#include <linux/input.h>
 #include "rmi4update.h"
 
 #define RMI_F34_QUERY_SIZE		7
@@ -58,6 +59,7 @@
 
 #define RMI_F34_ENABLE_WAIT_MS 300
 #define RMI_F34_ERASE_WAIT_MS (5 * 1000)
+#define RMI_F34_ERASE_V8_WAIT_MS (10000)
 #define RMI_F34_IDLE_WAIT_MS 500
 
 /* Most recent device status event */
@@ -67,6 +69,9 @@
 /* The device has lost its configuration for some reason. */
 #define RMI_F01_STATUS_UNCONFIGURED(status)	(!!((status) & 0x80))
 
+/* Indicates that flash programming is enabled V7(bootloader mode). */
+#define RMI_F01_STATUS_BOOTLOADER_v7(status) (!!((status) & 0x80))
+
 /*
  * Sleep mode controls power management on the device and affects all
  * functions of the device.
@@ -91,7 +96,6 @@
 	long long int duration_us = 0;
 	int rc;
 	const unsigned char eraseAll = RMI_F34_ERASE_ALL;
-
 	rc = FindUpdateFunctions();
 	if (rc != UPDATE_SUCCESS)
 		return rc;
@@ -119,15 +123,65 @@
 	rc = ReadF34Queries();
 	if (rc != UPDATE_SUCCESS)
 		return rc;
-
 	rc = m_firmwareImage.VerifyImageMatchesDevice(GetFirmwareSize(), GetConfigSize());
 	if (rc != UPDATE_SUCCESS)
 		return rc;
 
-	rc = EnterFlashProgramming();
-	if (rc != UPDATE_SUCCESS) {
-		fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
-		goto reset;
+	if (m_f34.GetFunctionVersion() == 0x02) {
+		fprintf(stdout, "Enable Flash V7+...\n");
+		rc = EnterFlashProgrammingV7();
+		if (rc != UPDATE_SUCCESS) {
+			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+			goto reset;
+		}
+		fprintf(stdout, "Enable Flash done V7+...\n");
+
+		if (!m_IsErased){
+			fprintf(stdout, "Erasing FW V7+...\n");
+			rc = EraseFirmwareV7();
+			if (rc != UPDATE_SUCCESS) {
+				fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+				goto reset;
+			}
+			fprintf(stdout, "Erasing FW done V7+...\n");
+		}
+		if(m_bootloaderID[1] == 8){
+			if (m_firmwareImage.GetFlashConfigData()) {
+				fprintf(stdout, "Writing flash configuration V8...\n");
+				rc = WriteFlashConfigV7();
+				if (rc != UPDATE_SUCCESS) {
+					fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+					goto reset;
+				}
+				fprintf(stdout, "Writing flash config done V8...\n");
+			}
+		}
+		if (m_firmwareImage.GetFirmwareData()) {
+			fprintf(stdout, "Writing firmware V7+...\n");
+			rc = WriteFirmwareV7();
+			if (rc != UPDATE_SUCCESS) {
+				fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+				goto reset;
+			}
+			fprintf(stdout, "Writing firmware done V7+...\n");
+		}
+		if (m_firmwareImage.GetConfigData()) {
+			fprintf(stdout, "Writing core configuration V7+...\n");
+			rc = WriteCoreConfigV7();
+			if (rc != UPDATE_SUCCESS) {
+				fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+				goto reset;
+			}
+			fprintf(stdout, "Writing core config done V7+...\n");
+			goto reset;
+		}
+		
+	} else {
+		rc = EnterFlashProgramming();
+		if (rc != UPDATE_SUCCESS) {
+			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+			goto reset;
+		}
 	}
 
 	if (performLockdown && m_unlocked) {
@@ -151,7 +205,6 @@
 			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
 			goto reset;
 		}
-		
 	}
 
 	rc = WriteBootloaderID();
@@ -208,7 +261,24 @@
 
 reset:
 	m_device.Reset();
+rebind:
 	m_device.RebindDriver();
+	if(!m_device.CheckABSEvent())
+	{
+		goto rebind;
+	}
+
+	// In order to print out new PR
+	rc = FindUpdateFunctions();
+	if (rc != UPDATE_SUCCESS)
+		return rc;
+
+	rc = m_device.QueryBasicProperties();
+	if (rc < 0)
+		return UPDATE_FAIL_QUERY_BASIC_PROPERTIES;
+	fprintf(stdout, "Device Properties:\n");
+	m_device.PrintProperties();
+
 	return rc;
 
 }
@@ -239,6 +309,204 @@
 	return UPDATE_SUCCESS;
 }
 
+int RMI4Update::rmi4update_poll()
+{
+	unsigned char f34_status;
+	unsigned short dataAddr = m_f34.GetDataBase();
+	int rc;
+
+	rc = m_device.Read(dataAddr, &f34_status, sizeof(unsigned char));
+	if (rc != sizeof(unsigned char))
+		return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+	m_flashStatus = f34_status & 0x1F;
+	m_inBLmode = f34_status & 0x80;
+	if(!m_flashStatus)
+		rc = m_device.Read(dataAddr + 4, &m_flashCmd, sizeof(unsigned char));
+
+	return 0;
+}
+
+int RMI4Update::ReadFlashConfig()
+{
+	int rc;
+	int transaction_count, remain_block;
+	unsigned char *flash_cfg;
+	int transfer_leng = 0;
+	int read_leng = 0;
+	int offset = 0;
+	unsigned char trans_leng_buf[2];
+	unsigned char cmd_buf[1];
+	unsigned char off[2] = {0, 0};
+	unsigned char partition_id = FLASH_CONFIG_PARTITION;
+	unsigned short dataAddr = m_f34.GetDataBase();
+	int i;
+	int retry = 0;
+	unsigned char *data_temp;
+	struct partition_tbl *partition_temp;
+
+	flash_cfg = (unsigned char *)malloc(m_blockSize * m_flashConfigLength);
+	memset(flash_cfg, 0, m_blockSize * m_flashConfigLength);
+	partition_temp = (partition_tbl *)malloc(sizeof(struct partition_tbl));
+	memset(partition_temp, 0, sizeof(struct partition_tbl));
+	/* calculate the count */
+	remain_block = (m_flashConfigLength % m_payloadLength);
+	transaction_count = (m_flashConfigLength / m_payloadLength);
+
+	if (remain_block > 0)
+		transaction_count++;
+
+	/* set partition id for bootloader 7 */
+	rc = m_device.Write(dataAddr + 1, &partition_id, sizeof(partition_id));
+	if (rc != sizeof(partition_id))
+		return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+	rc = m_device.Write(dataAddr + 2, off, sizeof(off));
+	if (rc != sizeof(off))
+		return UPDATE_FAIL_WRITE_INITIAL_ZEROS;
+
+	for (i = 0; i < transaction_count; i++)
+	{
+		if ((i == (transaction_count -1)) && (remain_block > 0))
+			transfer_leng = remain_block;
+		else
+			transfer_leng = m_payloadLength;
+
+		// Set Transfer Length
+		trans_leng_buf[0] = (unsigned char)(transfer_leng & 0xFF);
+		trans_leng_buf[1] = (unsigned char)((transfer_leng & 0xFF00) >> 8);
+		rc = m_device.Write(dataAddr + 3, trans_leng_buf, sizeof(trans_leng_buf));
+		if (rc != sizeof(trans_leng_buf))
+			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+		// Set Command to Read
+		cmd_buf[0] = (unsigned char)CMD_V7_READ;
+		rc = m_device.Write(dataAddr + 4, cmd_buf, sizeof(cmd_buf));
+		if (rc != sizeof(cmd_buf))
+			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+		//Wait for completion
+		do {
+			Sleep(20);
+			rmi4update_poll();
+			if (m_flashStatus == SUCCESS){
+				break;
+			}
+			retry++;
+		} while(retry < 20);
+
+		read_leng = transfer_leng * m_blockSize;
+		data_temp = (unsigned char *) malloc(sizeof(char) * read_leng);
+		rc = m_device.Read(dataAddr + 5, data_temp, sizeof(char) * read_leng);
+		if (rc != ((ssize_t)sizeof(char) * read_leng))
+			return UPDATE_FAIL_READ_F34_QUERIES;
+
+		memcpy(flash_cfg + offset, data_temp, sizeof(char) * read_leng);
+		offset += read_leng;
+		free(data_temp);
+	}
+
+	// Initialize as NULL here to avoid segmentation fault.
+	m_partitionConfig = NULL;
+	m_partitionCore = NULL;
+	m_partitionGuest = NULL;
+
+	/* parse the config length */
+	for (i = 2; i < m_blockSize * m_flashConfigLength; i = i + 8)
+	{
+		memcpy(partition_temp->data ,flash_cfg + i, sizeof(struct partition_tbl));
+		if (partition_temp->partition_id == CORE_CONFIG_PARTITION)
+		{
+			m_partitionConfig = (partition_tbl *) malloc(sizeof(struct partition_tbl));
+			memcpy(m_partitionConfig ,partition_temp, sizeof(struct partition_tbl));
+			memset(partition_temp, 0, sizeof(struct partition_tbl));
+			fprintf(stdout, "CORE_CONFIG_PARTITION is found\n");
+		}
+		else if (partition_temp->partition_id == CORE_CODE_PARTITION)
+		{
+			m_partitionCore = (partition_tbl *) malloc(sizeof(struct partition_tbl));
+			memcpy(m_partitionCore ,partition_temp, sizeof(struct partition_tbl));
+			memset(partition_temp, 0, sizeof(struct partition_tbl));
+			fprintf(stdout, "CORE_CODE_PARTITION is found\n");
+		}
+		else if (partition_temp->partition_id == GUEST_CODE_PARTITION)
+		{
+			m_partitionGuest = (partition_tbl *) malloc(sizeof(struct partition_tbl));
+			memcpy(m_partitionGuest ,partition_temp, sizeof(struct partition_tbl));
+			memset(partition_temp, 0, sizeof(struct partition_tbl));
+			fprintf(stdout, "GUEST_CODE_PARTITION is found\n");
+		}
+		else if (partition_temp->partition_id == NONE_PARTITION)
+			break;
+	}
+
+	if (flash_cfg)
+		free(flash_cfg);
+
+	if (partition_temp)
+		free(partition_temp);
+
+	m_fwBlockCount = m_partitionCore ? m_partitionCore->partition_len : 0;
+	m_configBlockCount = m_partitionConfig ? m_partitionConfig->partition_len : 0;
+	m_guestBlockCount = m_partitionGuest ? m_partitionGuest->partition_len : 0;
+	fprintf(stdout, "F34 fw blocks:     %d\n", m_fwBlockCount);
+	fprintf(stdout, "F34 config blocks: %d\n", m_configBlockCount);
+	fprintf(stdout, "F34 guest blocks:     %d\n", m_guestBlockCount);
+	fprintf(stdout, "\n");
+
+	m_guestData = (unsigned char *) malloc(m_guestBlockCount * m_blockSize);
+	memset(m_guestData, 0, m_guestBlockCount * m_blockSize);
+	memset(m_guestData + m_guestBlockCount * m_blockSize -4, 0, 4);
+	return UPDATE_SUCCESS;
+}
+
+int RMI4Update::ReadF34QueriesV7()
+{
+	int rc;
+	struct f34_v7_query_0 query_0;
+	struct f34_v7_query_1_7 query_1_7;
+	unsigned char idStr[3];
+	unsigned short queryAddr = m_f34.GetQueryBase();
+	unsigned char offset;
+
+	rc = m_device.Read(queryAddr, query_0.data, sizeof(query_0.data));
+	if (rc != sizeof(query_0.data))
+		return UPDATE_FAIL_READ_BOOTLOADER_ID;
+
+	offset = query_0.subpacket_1_size + 1;
+	rc = m_device.Read(queryAddr + offset, query_1_7.data, sizeof(query_1_7.data));
+	if (rc != sizeof(query_1_7.data))
+		return UPDATE_FAIL_READ_BOOTLOADER_ID;
+
+	m_bootloaderID[0] = query_1_7.bl_minor_revision;
+	m_bootloaderID[1] = query_1_7.bl_major_revision;
+	m_hasConfigID = query_0.has_config_id;
+	m_blockSize = query_1_7.block_size_15_8 << 8 |
+			query_1_7.block_size_7_0;
+	m_flashConfigLength = query_1_7.flash_config_length_15_8 << 8 |
+				query_1_7.flash_config_length_7_0;
+	m_payloadLength = query_1_7.payload_length_15_8 << 8 |
+			query_1_7.payload_length_7_0;
+	m_buildID = query_1_7.bl_fw_id_7_0 |
+			query_1_7.bl_fw_id_15_8 << 8 |
+			query_1_7.bl_fw_id_23_16 << 16 |
+			query_1_7.bl_fw_id_31_24 << 24;
+
+	idStr[0] = m_bootloaderID[0];
+	idStr[1] = m_bootloaderID[1];
+	idStr[2] = 0;
+
+	fprintf(stdout, "F34 bootloader id: %s (%#04x %#04x)\n", idStr, m_bootloaderID[0],
+		m_bootloaderID[1]);
+	fprintf(stdout, "F34 has config id: %d\n", m_hasConfigID);
+	fprintf(stdout, "F34 unlocked:      %d\n", m_unlocked);
+	fprintf(stdout, "F34 block size:    %d\n", m_blockSize);
+	fprintf(stdout, "F34 flash cfg leng:%d\n", m_flashConfigLength);
+	fprintf(stdout, "F34 payload length:%d\n", m_payloadLength);
+	fprintf(stdout, "F34 build id:      %lu\n", m_buildID);
+
+	return ReadFlashConfig();
+}
+
 int RMI4Update::ReadF34Queries()
 {
 	int rc;
@@ -248,7 +516,9 @@
 	unsigned short f34Version = m_f34.GetFunctionVersion();
 	unsigned short querySize;
 
-	if (f34Version == 0x1)
+	if (f34Version == 0x2)
+		return ReadF34QueriesV7();
+	else if (f34Version == 0x1)
 		querySize = 8;
 	else
 		querySize = 2;
@@ -365,6 +635,530 @@
 	return UPDATE_SUCCESS;
 }
 
+int RMI4Update::WriteFirmwareV7()
+{
+	int transaction_count, remain_block;
+	int transfer_leng = 0;
+	int offset = 0;
+	unsigned char trans_leng_buf[2];
+	unsigned char cmd_buf[1];
+	unsigned char off[2] = {0, 0};
+	unsigned char partition_id;
+	int i;
+	int retry = 0;
+	unsigned char *data_temp;
+	int rc;
+	unsigned short left_bytes;
+	unsigned short write_size;
+	unsigned short max_write_size;
+	unsigned short dataAddr = m_f34.GetDataBase();
+
+	/* calculate the count */
+	partition_id = CORE_CODE_PARTITION;
+	remain_block = (m_fwBlockCount % m_payloadLength);
+	transaction_count = (m_fwBlockCount / m_payloadLength);
+	if (remain_block > 0)
+		transaction_count++;
+
+	/* set partition id for bootloader 7 */
+	rc = m_device.Write(dataAddr + 1, &partition_id, sizeof(partition_id));
+	if (rc != sizeof(partition_id))
+		return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+	rc = m_device.Write(dataAddr + 2, off, sizeof(off));
+	if (rc != sizeof(off))
+		return UPDATE_FAIL_WRITE_INITIAL_ZEROS;
+
+	for (i = 0; i < transaction_count; i++)
+	{
+		if ((i == (transaction_count -1)) && (remain_block > 0))
+			transfer_leng = remain_block;
+		else
+			transfer_leng = m_payloadLength;
+
+		// Set Transfer Length
+		trans_leng_buf[0] = (unsigned char)(transfer_leng & 0xFF);
+		trans_leng_buf[1] = (unsigned char)((transfer_leng & 0xFF00) >> 8);
+
+		rc = m_device.Write(dataAddr + 3, trans_leng_buf, sizeof(trans_leng_buf));
+		if (rc != sizeof(trans_leng_buf))
+			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+		// Set Command to Write
+		cmd_buf[0] = (unsigned char)CMD_V7_WRITE;
+		rc = m_device.Write(dataAddr + 4, cmd_buf, sizeof(cmd_buf));
+		if (rc != sizeof(cmd_buf))
+			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+		max_write_size = 16;
+		if (max_write_size >= transfer_leng * m_blockSize)
+			max_write_size = transfer_leng * m_blockSize;
+		else if (max_write_size > m_blockSize)
+			max_write_size -= max_write_size % m_blockSize;
+		else
+			max_write_size = m_blockSize;
+
+		left_bytes = transfer_leng * m_blockSize;
+		do {
+			if (left_bytes / max_write_size)
+				write_size = max_write_size;
+			else
+				write_size = left_bytes;
+
+			data_temp = (unsigned char *) malloc(sizeof(unsigned char) * write_size);
+			memcpy(data_temp, m_firmwareImage.GetFirmwareData() + offset, sizeof(char) * write_size);
+			rc = m_device.Write(dataAddr + 5, data_temp, sizeof(char) * write_size);
+			if (rc != ((ssize_t)sizeof(char) * write_size)) {
+				fprintf(stdout, "err write_size = %d; rc = %d\n", write_size, rc);
+				return UPDATE_FAIL_READ_F34_QUERIES;
+			}
+
+			offset += write_size;
+			left_bytes -= write_size;
+			free(data_temp);
+		} while (left_bytes);
+
+		// Sleep 100 ms and wait for attention.
+		Sleep(100);
+		rc = WaitForIdle(RMI_F34_IDLE_WAIT_MS, false);
+		if (rc != UPDATE_SUCCESS) {
+			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
+		}
+
+		//Wait for completion
+		do {
+			Sleep(20);
+			rmi4update_poll();
+			if (m_flashStatus == SUCCESS){
+				break;
+
+			}
+			retry++;
+		} while(retry < 20);
+
+		if (m_flashStatus != SUCCESS) {
+			fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
+			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
+		}
+
+	}
+	return UPDATE_SUCCESS;
+}
+
+int RMI4Update::WriteCoreConfigV7()
+{
+	int transaction_count, remain_block;
+	int transfer_leng = 0;
+	int offset = 0;
+	unsigned char trans_leng_buf[2];
+	unsigned char cmd_buf[1];
+	unsigned char off[2] = {0, 0};
+	unsigned char partition_id;
+	unsigned short dataAddr = m_f34.GetDataBase();
+	unsigned short left_bytes;
+	unsigned short write_size;
+	unsigned short max_write_size;
+	int rc;
+	int i;
+	int retry = 0;
+	unsigned char *data_temp;
+
+	/* calculate the count */
+	partition_id = CORE_CONFIG_PARTITION;
+	remain_block = (m_configBlockCount % m_payloadLength);
+	transaction_count = (m_configBlockCount / m_payloadLength);
+	if (remain_block > 0)
+		transaction_count++;
+
+	/* set partition id for bootloader 7 */
+	rc = m_device.Write(dataAddr + 1, &partition_id, sizeof(partition_id));
+	if (rc != sizeof(partition_id))
+		return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+	rc = m_device.Write(dataAddr + 2, off, sizeof(off));
+	if (rc != sizeof(off))
+		return UPDATE_FAIL_WRITE_INITIAL_ZEROS;
+
+	for (i = 0; i < transaction_count; i++)
+	{
+		if ((i == (transaction_count -1)) && (remain_block > 0))
+			transfer_leng = remain_block;
+		else
+			transfer_leng = m_payloadLength;
+
+		// Set Transfer Length
+		trans_leng_buf[0] = (unsigned char)(transfer_leng & 0xFF);
+		trans_leng_buf[1] = (unsigned char)((transfer_leng & 0xFF00) >> 8);
+
+		rc = m_device.Write(dataAddr + 3, trans_leng_buf, sizeof(trans_leng_buf));
+		if (rc != sizeof(trans_leng_buf))
+			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+		// Set Command to Write
+		cmd_buf[0] = (unsigned char)CMD_V7_WRITE;
+		rc = m_device.Write(dataAddr + 4, cmd_buf, sizeof(cmd_buf));
+		if (rc != sizeof(cmd_buf))
+			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+		max_write_size = 16;
+		if (max_write_size >= transfer_leng * m_blockSize)
+			max_write_size = transfer_leng * m_blockSize;
+		else if (max_write_size > m_blockSize)
+			max_write_size -= max_write_size % m_blockSize;
+		else
+			max_write_size = m_blockSize;
+
+		left_bytes = transfer_leng * m_blockSize;
+
+		do {
+			if (left_bytes / max_write_size)
+				write_size = max_write_size;
+			else
+				write_size = left_bytes;
+
+			data_temp = (unsigned char *) malloc(sizeof(unsigned char) * write_size);
+			memcpy(data_temp, m_firmwareImage.GetConfigData() + offset, sizeof(char) * write_size);
+			rc = m_device.Write(dataAddr + 5, data_temp, sizeof(char) * write_size);
+			if (rc != ((ssize_t)sizeof(char) * write_size)) {
+				return UPDATE_FAIL_READ_F34_QUERIES;
+			}
+
+			offset += write_size;
+			left_bytes -= write_size;
+			free(data_temp);
+		} while (left_bytes);
+
+		// Wait for attention.
+		rc = WaitForIdle(RMI_F34_IDLE_WAIT_MS, false);
+		if (rc != UPDATE_SUCCESS) {
+			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
+		}
+
+		//Wait for completion
+		do {
+			Sleep(20);
+			rmi4update_poll();
+			if (m_flashStatus == SUCCESS){
+				break;
+			}
+			retry++;
+		} while(retry < 20);
+
+		if (m_flashStatus != SUCCESS) {
+			fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
+			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
+		}
+
+	}
+	return UPDATE_SUCCESS;
+}
+
+int RMI4Update::WriteFlashConfigV7()
+{
+	int transaction_count, remain_block;
+	int transfer_leng = 0;
+	int offset = 0;
+	unsigned char trans_leng_buf[2];
+	unsigned char cmd_buf[1];
+	unsigned char off[2] = {0, 0};
+	unsigned char partition_id;
+	unsigned short dataAddr = m_f34.GetDataBase();
+	unsigned short left_bytes;
+	unsigned short write_size;
+	unsigned short max_write_size;
+	int rc;
+	int i;
+	int retry = 0;
+	unsigned char *data_temp;
+	unsigned short FlashConfigBlockCount;
+
+	/* calculate the count */
+	partition_id = FLASH_CONFIG_PARTITION;
+
+	FlashConfigBlockCount = m_firmwareImage.GetFlashConfigSize() / m_blockSize;
+
+	remain_block = (FlashConfigBlockCount % m_payloadLength);
+	transaction_count = (FlashConfigBlockCount / m_payloadLength);
+	if (remain_block > 0)
+		transaction_count++;
+
+	/* set partition id for bootloader 7 */
+	rc = m_device.Write(dataAddr + 1, &partition_id, sizeof(partition_id));
+	if (rc != sizeof(partition_id))
+		return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+	rc = m_device.Write(dataAddr + 2, off, sizeof(off));
+	if (rc != sizeof(off))
+		return UPDATE_FAIL_WRITE_INITIAL_ZEROS;
+
+	for (i = 0; i < transaction_count; i++)
+	{
+		if ((i == (transaction_count -1)) && (remain_block > 0))
+			transfer_leng = remain_block;
+		else
+			transfer_leng = m_payloadLength;
+
+		// Set Transfer Length
+		trans_leng_buf[0] = (unsigned char)(transfer_leng & 0xFF);
+		trans_leng_buf[1] = (unsigned char)((transfer_leng & 0xFF00) >> 8);
+
+		rc = m_device.Write(dataAddr + 3, trans_leng_buf, sizeof(trans_leng_buf));
+		if (rc != sizeof(trans_leng_buf))
+			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+		// Set Command to Write
+		cmd_buf[0] = (unsigned char)CMD_V7_WRITE;
+		rc = m_device.Write(dataAddr + 4, cmd_buf, sizeof(cmd_buf));
+		if (rc != sizeof(cmd_buf))
+			return UPDATE_FAIL_WRITE_FLASH_COMMAND;
+
+		max_write_size = 16;
+		if (max_write_size >= transfer_leng * m_blockSize)
+			max_write_size = transfer_leng * m_blockSize;
+		else if (max_write_size > m_blockSize)
+			max_write_size -= max_write_size % m_blockSize;
+		else
+			max_write_size = m_blockSize;
+
+		left_bytes = transfer_leng * m_blockSize;
+
+		do {
+			if (left_bytes / max_write_size)
+				write_size = max_write_size;
+			else
+				write_size = left_bytes;
+
+			data_temp = (unsigned char *) malloc(sizeof(unsigned char) * write_size);
+			memcpy(data_temp, m_firmwareImage.GetFlashConfigData() + offset, sizeof(char) * write_size);
+			rc = m_device.Write(dataAddr + 5, data_temp, sizeof(char) * write_size);
+			if (rc != ((ssize_t)sizeof(char) * write_size)) {
+				fprintf(stdout, "err write_size = %d; rc = %d\n", write_size, rc);
+				return UPDATE_FAIL_READ_F34_QUERIES;
+			}
+
+			offset += write_size;
+			left_bytes -= write_size;
+			free(data_temp);
+		} while (left_bytes);
+
+		// Wair for attention.
+		rc = WaitForIdle(RMI_F34_IDLE_WAIT_MS, false);
+		if (rc != UPDATE_SUCCESS) {
+			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
+		}
+
+		//Wait for completion
+		do {
+			Sleep(20);
+			rmi4update_poll();
+			if (m_flashStatus == SUCCESS){
+				break;
+			}
+			retry++;
+		} while(retry < 20);
+
+		if (m_flashStatus != SUCCESS) {
+			fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
+			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
+		}
+
+	}
+	return UPDATE_SUCCESS;
+}
+
+int RMI4Update::EraseFirmwareV7()
+{
+	unsigned char erase_cmd[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+	int retry = 0;
+	int rc;
+
+	/* set partition id for bootloader 7 */
+	erase_cmd[0] = CORE_CODE_PARTITION;
+	/* write bootloader id */
+	erase_cmd[6] = m_bootloaderID[0];
+	erase_cmd[7] = m_bootloaderID[1];
+	if(m_bootloaderID[1] == 8){
+		/* Set Command to Erase AP for BL8*/
+		erase_cmd[5] = (unsigned char)CMD_V7_ERASE_AP;
+	} else {
+		/* Set Command to Erase AP for BL7*/
+		erase_cmd[5] = (unsigned char)CMD_V7_ERASE;
+	}
+	
+	fprintf(stdout, "Erase command : ");
+	for(int i = 0 ;i<8;i++){
+		fprintf(stdout, "%d ", erase_cmd[i]);
+	}
+	fprintf(stdout, "\n");
+
+	rmi4update_poll();
+	if (!m_inBLmode)
+		return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
+	if(m_bootloaderID[1] == 8){
+		// For BL8 device, we need hold 1 seconds after querying
+		// F34 status to avoid not get attention by following giving 
+		// erase command.
+		Sleep(1000);
+	}
+
+	rc = m_device.Write(m_f34.GetDataBase() + 1, erase_cmd, sizeof(erase_cmd));
+	if (rc != sizeof(erase_cmd))
+		return UPDATE_FAIL_WRITE_F01_CONTROL_0;
+
+	Sleep(100);
+
+	//Wait from ATTN
+	if(m_bootloaderID[1] == 8){
+		// Wait for attention for BL8 device.
+		rc = WaitForIdle(RMI_F34_ERASE_V8_WAIT_MS, false);
+		if (rc != UPDATE_SUCCESS) {
+			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
+		}
+	}
+	do {
+		Sleep(20);
+		rmi4update_poll();
+		if (m_flashStatus == SUCCESS){
+			break;
+		}
+		retry++;
+	} while(retry < 20);
+
+	if (m_flashStatus != SUCCESS) {
+		fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
+		return UPDATE_FAIL_WRITE_F01_CONTROL_0;
+	}
+ 
+	if(m_bootloaderID[1] == 7){
+		// For BL7, we need erase config partition.
+		fprintf(stdout, "Start to erase config\n");
+		erase_cmd[0] = CORE_CONFIG_PARTITION;
+		erase_cmd[6] = m_bootloaderID[0];
+		erase_cmd[7] = m_bootloaderID[1];
+		erase_cmd[5] = (unsigned char)CMD_V7_ERASE;
+
+		Sleep(100);
+		rmi4update_poll();
+		if (!m_inBLmode)
+		  return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
+
+		rc = m_device.Write(m_f34.GetDataBase() + 1, erase_cmd, sizeof(erase_cmd));
+		if (rc != sizeof(erase_cmd))
+			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
+
+		//Wait from ATTN
+		Sleep(100);
+
+		rc = WaitForIdle(RMI_F34_ERASE_WAIT_MS, true);
+		if (rc != UPDATE_SUCCESS) {
+			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
+		}
+
+
+		do {
+			Sleep(20);
+			rmi4update_poll();
+			if (m_flashStatus == SUCCESS){
+				break;
+			}
+			retry++;
+		} while(retry < 20);
+
+		if (m_flashStatus != SUCCESS) {
+			fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
+			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
+		}
+	}
+
+	return UPDATE_SUCCESS;
+}
+
+int RMI4Update::EnterFlashProgrammingV7()
+{
+	int rc;
+	unsigned char f34_status;
+	rc = m_device.Read(m_f34.GetDataBase(), &f34_status, sizeof(unsigned char));
+	m_inBLmode = f34_status & 0x80;
+	if(!m_inBLmode){
+		fprintf(stdout, "Not in BL mode, going to BL mode...\n");
+		unsigned char EnterCmd[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+		int retry = 0;
+
+		/* set partition id for bootloader 7 */
+		EnterCmd[0] = BOOTLOADER_PARTITION;
+
+		/* write bootloader id */
+		EnterCmd[6] = m_bootloaderID[0];
+		EnterCmd[7] = m_bootloaderID[1];
+
+		// Set Command to EnterBL
+		EnterCmd[5] = (unsigned char)CMD_V7_ENTER_BL;
+
+		rc = m_device.Write(m_f34.GetDataBase() + 1, EnterCmd, sizeof(EnterCmd));
+		if (rc != sizeof(EnterCmd))
+			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
+
+		rc = WaitForIdle(RMI_F34_ENABLE_WAIT_MS, false);
+		if (rc != UPDATE_SUCCESS) {
+			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+			return UPDATE_FAIL_TIMEOUT_WAITING_FOR_ATTN;
+		}
+
+		//Wait from ATTN
+		do {
+			Sleep(20);
+			rmi4update_poll();
+			if (m_flashStatus == SUCCESS){
+				break;
+			}
+			retry++;
+		} while(retry < 20);
+
+		if (m_flashStatus != SUCCESS) {
+			fprintf(stdout, "err flash_status = %d\n", m_flashStatus);
+			return UPDATE_FAIL_WRITE_F01_CONTROL_0;
+		}
+
+		Sleep(RMI_F34_ENABLE_WAIT_MS);
+
+		fprintf(stdout, "%s\n", __func__);
+		rmi4update_poll();
+		if (!m_inBLmode)
+			return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
+
+	} else
+		fprintf(stdout, "Already in BL mode, skip...\n");
+
+	if(m_device.GetDeviceType() != RMI_DEVICE_TYPE_TOUCHPAD) {
+		// workaround for touchscreen only
+		fprintf(stdout, "Erase in BL mode\n");
+		rc = EraseFirmwareV7();
+		if (rc != UPDATE_SUCCESS) {
+			fprintf(stderr, "%s: %s\n", __func__, update_err_to_string(rc));
+			return UPDATE_FAIL_ERASE_ALL;
+		}
+		fprintf(stdout, "Erase in BL mode end\n");
+		m_device.RebindDriver();
+	}
+
+	Sleep(RMI_F34_ENABLE_WAIT_MS);
+
+	rc = FindUpdateFunctions();
+	if (rc != UPDATE_SUCCESS)
+		return rc;
+
+	rc = ReadF34Queries();
+	if (rc != UPDATE_SUCCESS)
+		return rc;
+
+	return UPDATE_SUCCESS;
+}
+
 int RMI4Update::EnterFlashProgramming()
 {
 	int rc;
@@ -381,7 +1175,10 @@
 		return UPDATE_FAIL_ENABLE_FLASH_PROGRAMMING;
 
 	Sleep(RMI_F34_ENABLE_WAIT_MS);
-	m_device.RebindDriver();
+	if(m_device.GetDeviceType() != RMI_DEVICE_TYPE_TOUCHPAD) {
+		fprintf(stdout, "not TouchPad, rebind driver here\n");
+		m_device.RebindDriver();
+	}
 	rc = WaitForIdle(0);
 	if (rc != UPDATE_SUCCESS)
 		return UPDATE_FAIL_NOT_IN_IDLE_STATE;
@@ -398,8 +1195,15 @@
 	if (rc != 1)
 		return UPDATE_FAIL_READ_DEVICE_STATUS;
 
-	if (!RMI_F01_STATUS_BOOTLOADER(m_deviceStatus))
-		return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
+	if(m_f34.GetFunctionVersion() > 0x1){
+		if (!RMI_F01_STATUS_BOOTLOADER_v7(m_deviceStatus))
+			return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
+		fprintf(stdout, "Already in BL mode V7\n");
+	} else {
+		if (!RMI_F01_STATUS_BOOTLOADER(m_deviceStatus))
+			return UPDATE_FAIL_DEVICE_NOT_IN_BOOTLOADER;
+		fprintf(stdout, "Already in BL mode\n");
+	}
 
 	rc = ReadF34Queries();
 	if (rc != UPDATE_SUCCESS)
@@ -487,7 +1291,7 @@
 		tv.tv_usec = (timeout_ms % 1000) * 1000;
 
 		rc = m_device.WaitForAttention(&tv, m_f34.GetInterruptMask());
-		if (rc == -ETIMEDOUT)
+		if (rc == -ETIMEDOUT){
 			/*
 			 * If for some reason we are not getting attention reports for HID devices
 			 * then we can still continue after the timeout and read F34 status
@@ -495,7 +1299,8 @@
 			 * will be slow. If this message shows up a lot then something is wrong
 			 * with receiving attention reports and that should be fixed.
 			 */
-			fprintf(stderr, "Timed out waiting for attn report\n");
+			fprintf(stderr, "RMI4Update::WaitForIdle Timed out waiting for attn report\n");
+		}
 	}
 
 	if (rc <= 0 || readF34OnSucess) {
@@ -505,18 +1310,18 @@
 
 		if (!m_f34Status && !m_f34Command) {
 			if (!m_programEnabled) {
-				fprintf(stderr, "Bootloader is idle but program_enabled bit isn't set.\n");
+				fprintf(stderr, "RMI4Update::WaitForIdle Bootloader is idle but program_enabled bit isn't set.\n");
 				return UPDATE_FAIL_PROGRAMMING_NOT_ENABLED;
 			} else {
 				return UPDATE_SUCCESS;
 			}
 		}
-
-		fprintf(stderr, "ERROR: Waiting for idle status.\n");
-		fprintf(stderr, "Command: %#04x\n", m_f34Command);
-		fprintf(stderr, "Status:  %#04x\n", m_f34Status);
-		fprintf(stderr, "Enabled: %d\n", m_programEnabled);
-		fprintf(stderr, "Idle:    %d\n", !m_f34Command && !m_f34Status);
+		fprintf(stderr, "RMI4Update::WaitForIdle\n");
+		fprintf(stderr, "  ERROR: Waiting for idle status.\n");
+		fprintf(stderr, "  Command: %#04x\n", m_f34Command);
+		fprintf(stderr, "  Status:  %#04x\n", m_f34Status);
+		fprintf(stderr, "  Enabled: %d\n", m_programEnabled);
+		fprintf(stderr, "  Idle:    %d\n", !m_f34Command && !m_f34Status);
 
 		return UPDATE_FAIL_NOT_IN_IDLE_STATE;
 	}
diff --git a/rmi4update/rmi4update.h b/rmi4update/rmi4update.h
old mode 100644
new mode 100755
index eaad0f6..b9de4ec
--- a/rmi4update/rmi4update.h
+++ b/rmi4update/rmi4update.h
@@ -23,20 +23,157 @@
 
 #define RMI_BOOTLOADER_ID_SIZE		2
 
+// leon add
+enum v7_status {
+	SUCCESS = 0x00,
+	DEVICE_NOT_IN_BOOTLOADER_MODE,
+	INVALID_PARTITION,
+	INVALID_COMMAND,
+	INVALID_BLOCK_OFFSET,
+	INVALID_TRANSFER,
+	NOT_ERASED,
+	FLASH_PROGRAMMING_KEY_INCORRECT,
+	BAD_PARTITION_TABLE,
+	CHECKSUM_FAILED,
+	FLASH_HARDWARE_FAILURE = 0x1f,
+};
+
+enum v7_partition_id {
+	NONE_PARTITION = 0x00,
+	BOOTLOADER_PARTITION = 0x01,
+	DEVICE_CONFIG_PARTITION,
+	FLASH_CONFIG_PARTITION,
+	MANUFACTURING_BLOCK_PARTITION,
+	GUEST_SERIALIZATION_PARTITION,
+	GLOBAL_PARAMETERS_PARTITION,
+	CORE_CODE_PARTITION,
+	CORE_CONFIG_PARTITION,
+	GUEST_CODE_PARTITION,
+	DISPLAY_CONFIG_PARTITION,
+	EXTERNAL_TOUCH_AFE_CONFIG_PARTITION,
+	UTILITY_PARAMETER_PARTITION,
+};
+
+enum v7_flash_command {
+	CMD_V7_IDLE = 0x00,
+	CMD_V7_ENTER_BL,
+	CMD_V7_READ,
+	CMD_V7_WRITE,
+	CMD_V7_ERASE,
+	CMD_V7_ERASE_AP,
+	CMD_V7_SENSOR_ID,
+};
+
+enum bl_version {
+	BL_V5 = 5,
+	BL_V6 = 6,
+	BL_V7 = 7,
+	BL_V8 = 8,
+};
+
+struct f34_v7_query_0 {
+	union {
+		struct {
+			unsigned char subpacket_1_size:3;
+			unsigned char has_config_id:1;
+			unsigned char f34_query0_b4:1;
+			unsigned char has_thqa:1;
+			unsigned char f34_query0_b6__7:2;
+		} __attribute__((packed));;
+		unsigned char data[1];
+	};
+};
+
+struct f34_v7_query_1_7 {
+	union {
+		struct {
+			/* query 1 */
+			unsigned char bl_minor_revision;
+			unsigned char bl_major_revision;
+
+			/* query 2 */
+			unsigned char bl_fw_id_7_0;
+			unsigned char bl_fw_id_15_8;
+			unsigned char bl_fw_id_23_16;
+			unsigned char bl_fw_id_31_24;
+
+			/* query 3 */
+			unsigned char minimum_write_size;
+			unsigned char block_size_7_0;
+			unsigned char block_size_15_8;
+			unsigned char flash_page_size_7_0;
+			unsigned char flash_page_size_15_8;
+
+			/* query 4 */
+			unsigned char adjustable_partition_area_size_7_0;
+			unsigned char adjustable_partition_area_size_15_8;
+
+			/* query 5 */
+			unsigned char flash_config_length_7_0;
+			unsigned char flash_config_length_15_8;
+
+			/* query 6 */
+			unsigned char payload_length_7_0;
+			unsigned char payload_length_15_8;
+
+			/* query 7 */
+			unsigned char f34_query7_b0:1;
+			unsigned char has_bootloader:1;
+			unsigned char has_device_config:1;
+			unsigned char has_flash_config:1;
+			unsigned char has_manufacturing_block:1;
+			unsigned char has_guest_serialization:1;
+			unsigned char has_global_parameters:1;
+			unsigned char has_core_code:1;
+			unsigned char has_core_config:1;
+			unsigned char has_guest_code:1;
+			unsigned char has_display_config:1;
+			unsigned char f34_query7_b11__15:5;
+			unsigned char f34_query7_b16__23;
+			unsigned char f34_query7_b24__31;
+		} __attribute__((packed));;
+		unsigned char data[21];
+	};
+};
+
+struct partition_tbl
+{
+	union {
+		struct {
+			unsigned short partition_id;
+			unsigned short partition_len;
+			unsigned short partition_addr;
+			unsigned short partition_prop;
+		} __attribute__((packed));;
+		unsigned char data[8];
+	};
+};
+// leon end
+
 class RMI4Update
 {
 public:
 	RMI4Update(RMIDevice & device, FirmwareImage & firmwareImage) : m_device(device), 
 			m_firmwareImage(firmwareImage), m_writeBlockWithCmd(true)
-	{}
+	{
+		m_IsErased = false;
+	}
 	int UpdateFirmware(bool force = false, bool performLockdown = false);
 
 private:
 	int DisableNonessentialInterupts();
 	int FindUpdateFunctions();
+	int ReadFlashConfig();
+	int rmi4update_poll();
+	int ReadF34QueriesV7();
 	int ReadF34Queries();
 	int ReadF34Controls();
 	int WriteBootloaderID();
+	int EnterFlashProgrammingV7();
+	int EraseFirmwareV7();
+	int WriteFirmwareV7();
+	int WriteCoreConfigV7();
+	int WriteFlashConfigV7();
 	int EnterFlashProgramming();
 	int WriteBlocks(unsigned char *block, unsigned short count, unsigned char cmd);
 	int WaitForIdle(int timeout_ms, bool readF34OnSucess = true);
@@ -66,8 +203,24 @@
 	unsigned short m_blockSize;
 	unsigned short m_fwBlockCount;
 	unsigned short m_configBlockCount;
+	/* for BL_V7 */
+	unsigned short m_flashConfigLength;
+	unsigned short m_payloadLength;
+	unsigned short m_guestBlockCount;
+	struct partition_tbl *m_partitionCore;
+	struct partition_tbl *m_partitionConfig;
+	struct partition_tbl *m_partitionGuest;
+	unsigned char m_flashStatus;
+	unsigned char m_flashCmd;
+	unsigned char m_inBLmode;
+	unsigned long m_buildID;
+	unsigned char *m_guestData;
+	/* BL_V7 end */
 
 	unsigned short m_f34StatusAddr;
+	enum bl_version m_blVersion;
+
+	bool m_IsErased;
 };
 
 #endif // _RMI4UPDATE_H_
diff --git a/rmi4update/updateutil.cpp b/rmi4update/updateutil.cpp
index df070a6..1d654cd 100644
--- a/rmi4update/updateutil.cpp
+++ b/rmi4update/updateutil.cpp
@@ -57,29 +57,3 @@
 {
 	return update_error_str[err];
 }
-
-unsigned long extract_long(const unsigned char *data)
-{
-	return (unsigned long)data [0]
-		+ (unsigned long)data [1] * 0x100
-		+ (unsigned long)data [2] * 0x10000
-		+ (unsigned long)data [3] * 0x1000000;
-}
-
-unsigned short extract_short(const unsigned char *data)
-{
-	return (unsigned long)data [0]
-		+ (unsigned long)data [1] * 0x100;
-}
-
-const char * StripPath(const char * path, ssize_t size)
-{
-	int i;
-	const char * str;
-
-	for (i = size - 1, str = &path[size - 1]; i > 0; --i, --str)
-		if (path[i - 1] == '/')
-			break;
-
-	return str;
-}
\ No newline at end of file
diff --git a/rmi4update/updateutil.h b/rmi4update/updateutil.h
index 6907781..59f1a08 100644
--- a/rmi4update/updateutil.h
+++ b/rmi4update/updateutil.h
@@ -54,8 +54,4 @@
 
 const char * update_err_to_string(int err);
 
-unsigned long extract_long(const unsigned char *data);
-unsigned short extract_short(const unsigned char *data);
-const char * StripPath(const char * path, ssize_t size);
-
 #endif // _UPDATEUTIL_H_
\ No newline at end of file
diff --git a/rmidevice/Android.bp b/rmidevice/Android.bp
index 6d67f4c..9b6ec71 100644
--- a/rmidevice/Android.bp
+++ b/rmidevice/Android.bp
@@ -10,14 +10,16 @@
 cc_library_static {
     name: "rmidevice",
     srcs: [
-        "rmifunction.cpp",
-        "rmidevice.cpp",
         "hiddevice.cpp",
+        "rmidevice.cpp",
+        "rmifunction.cpp",
+        "util.cpp",
     ],
     cflags: [
         "-Wall",
         "-Werror",
         "-Wno-unused-parameter",
+        "-Wno-unused-variable",
     ],
     export_include_dirs: ["."],
 }
diff --git a/rmidevice/Makefile b/rmidevice/Makefile
index 35aec55..d9f32cc 100644
--- a/rmidevice/Makefile
+++ b/rmidevice/Makefile
@@ -3,7 +3,7 @@
 RANLIB ?= ranlib
 CPPFLAGS += -I../include -I./include
 CXXFLAGS += -fPIC -Wall
-RMIDEVICESRC = rmifunction.cpp rmidevice.cpp hiddevice.cpp
+RMIDEVICESRC = rmifunction.cpp rmidevice.cpp hiddevice.cpp util.cpp
 RMIDEVICEOBJ = $(RMIDEVICESRC:.cpp=.o)
 LIBNAME = librmidevice.so
 STATIC_LIBNAME = librmidevice.a
diff --git a/rmidevice/hiddevice.cpp b/rmidevice/hiddevice.cpp
old mode 100644
new mode 100755
index 7ebf5fd..709559d
--- a/rmidevice/hiddevice.cpp
+++ b/rmidevice/hiddevice.cpp
@@ -31,6 +31,7 @@
 #include <linux/hidraw.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <sys/inotify.h>
 
 #include "hiddevice.h"
 
@@ -40,12 +41,6 @@
 #define RMI_ATTN_REPORT_ID                  0xc // Input Report
 #define RMI_SET_RMI_MODE_REPORT_ID          0xf // Feature Report
 
-enum rmi_hid_mode_type {
-	HID_RMI4_MODE_MOUSE                     = 0,
-	HID_RMI4_MODE_ATTN_REPORTS              = 1,
-	HID_RMI4_MODE_NO_PACKED_ATTN_REPORTS    = 2,
-};
-
 enum hid_report_type {
 	HID_REPORT_TYPE_UNKNOWN			= 0x0,
 	HID_REPORT_TYPE_INPUT			= 0x81,
@@ -71,6 +66,8 @@
 {
 	int rc;
 	int desc_size;
+	std::string hidDeviceName;
+	std::string hidDriverName;
 
 	if (!filename)
 		return -EINVAL;
@@ -84,58 +81,80 @@
 
 	rc = ioctl(m_fd, HIDIOCGRDESCSIZE, &desc_size);
 	if (rc < 0)
-		return rc;
+		goto error;
 	
 	m_rptDesc.size = desc_size;
 	rc = ioctl(m_fd, HIDIOCGRDESC, &m_rptDesc);
 	if (rc < 0)
-		return rc;
+		goto error;
 	
 	rc = ioctl(m_fd, HIDIOCGRAWINFO, &m_info);
 	if (rc < 0)
-		return rc;
+		goto error;
 
 	if (m_info.vendor != SYNAPTICS_VENDOR_ID) {
 		errno = -ENODEV;
-		return -1;
+		rc = -1;
+		goto error;
 	}
 
-	ParseReportSizes();
+	ParseReportDescriptor();
 
 	m_inputReport = new unsigned char[m_inputReportSize]();
 	if (!m_inputReport) {
 		errno = -ENOMEM;
-		return -1;
+		rc = -1;
+		goto error;
 	}
 
 	m_outputReport = new unsigned char[m_outputReportSize]();
 	if (!m_outputReport) {
 		errno = -ENOMEM;
-		return -1;
+		rc = -1;
+		goto error;
 	}
 
 	m_readData = new unsigned char[m_inputReportSize]();
 	if (!m_readData) {
 		errno = -ENOMEM;
-		return -1;
+		rc = -1;
+		goto error;
 	}
 
 	m_attnData = new unsigned char[m_inputReportSize]();
 	if (!m_attnData) {
 		errno = -ENOMEM;
-		return -1;
+		rc = -1;
+		goto error;
 	}
 
 	m_deviceOpen = true;
 
-	rc = SetMode(HID_RMI4_MODE_ATTN_REPORTS);
-	if (rc)
-		return -1;
+	// Determine which mode the device is currently running in based on the current HID driver
+	// hid-rmi indicated RMI Mode 1 all others would be Mode 0
+	if (LookupHidDeviceName(m_info.bustype, m_info.vendor, m_info.product, hidDeviceName)) {
+		if (LookupHidDriverName(hidDeviceName, hidDriverName)) {
+			if (hidDriverName == "hid-rmi")
+				m_initialMode = HID_RMI4_MODE_ATTN_REPORTS;
+		}
+	}
+
+	if (m_initialMode != m_mode) {
+		rc = SetMode(m_mode);
+		if (rc) {
+			rc = -1;
+			goto error;
+		}
+	}
 
 	return 0;
+
+error:
+	Close();
+	return rc;
 }
 
-void HIDDevice::ParseReportSizes()
+void HIDDevice::ParseReportDescriptor()
 {
 	bool isVendorSpecific = false;
 	bool isReport = false;
@@ -143,10 +162,18 @@
 	int reportSize = 0;
 	int reportCount = 0;
 	enum hid_report_type hidReportType = HID_REPORT_TYPE_UNKNOWN;
+	bool inCollection = false;
 
 	for (unsigned int i = 0; i < m_rptDesc.size; ++i) {
+		if (m_rptDesc.value[i] == 0xc0) {
+			inCollection = false;
+			isVendorSpecific = false;
+			isReport = false;
+			continue;
+		}
+
 		if (isVendorSpecific) {
-			if (m_rptDesc.value[i] == 0x85 || m_rptDesc.value[i] == 0xc0) {
+			if (m_rptDesc.value[i] == 0x85) {
 				if (isReport) {
 					// finish up data on the previous report
 					totalReportSize = (reportSize * reportCount) >> 3;
@@ -173,13 +200,7 @@
 				reportCount = 0;
 				hidReportType = HID_REPORT_TYPE_UNKNOWN;
 
-				if (m_rptDesc.value[i] == 0x85)
-					isReport = true;
-				else
-					isReport = false;
-
-				if (m_rptDesc.value[i] == 0xc0)
-					isVendorSpecific = false;
+				isReport = true;
 			}
 
 			if (isReport) {
@@ -209,12 +230,52 @@
 			}
 		}
 
-		if (i + 2 >= m_rptDesc.size)
-			return;
-		if (m_rptDesc.value[i] == 0x06 && m_rptDesc.value[i + 1] == 0x00
-						&& m_rptDesc.value[i + 2] == 0xFF) {
-			isVendorSpecific = true;
-			i += 2;
+		if (!inCollection) {
+			switch (m_rptDesc.value[i]) {
+				case 0x00:
+				case 0x01:
+				case 0x02:
+				case 0x03:
+				case 0x04:
+					inCollection = true;
+					break;
+				case 0x05:
+					inCollection = true;
+
+					if (i + 3 >= m_rptDesc.size)
+						break;
+
+					// touchscreens with active pen have a Generic Mouse collection
+					// so stop searching if we have already found the touchscreen digitizer
+					// usage.
+					if (m_deviceType == RMI_DEVICE_TYPE_TOUCHSCREEN)
+						break;
+				
+					if (m_rptDesc.value[i + 1] == 0x01) {
+						if (m_rptDesc.value[i + 2] == 0x09 && m_rptDesc.value[i + 3] == 0x02)
+							m_deviceType = RMI_DEVICE_TYPE_TOUCHPAD;
+					} else if (m_rptDesc.value[i + 1] == 0x0d) {
+						if (m_rptDesc.value[i + 2] == 0x09 && m_rptDesc.value[i + 3] == 0x04)
+							m_deviceType = RMI_DEVICE_TYPE_TOUCHSCREEN;
+						// for Precision Touch Pad
+						else if (m_rptDesc.value[i + 2] == 0x09 && m_rptDesc.value[i + 3] == 0x05)
+							m_deviceType = RMI_DEVICE_TYPE_TOUCHPAD;
+					}
+					i += 3;
+					break;
+				case 0x06:
+					inCollection = true;
+					if (i + 2 >= m_rptDesc.size)
+						break;
+
+					if (m_rptDesc.value[i + 1] == 0x00 && m_rptDesc.value[i + 2] == 0xFF)
+						isVendorSpecific = true;
+					i += 2;
+					break;
+				default:
+					break;
+
+			}
 		}
 	}
 }
@@ -277,12 +338,14 @@
 			if (rc > 0 && reportId == RMI_READ_DATA_REPORT_ID) {
 				if (static_cast<ssize_t>(m_inputReportSize) <
 				    std::max(HID_RMI4_READ_INPUT_COUNT,
-					     HID_RMI4_READ_INPUT_DATA))
+					     HID_RMI4_READ_INPUT_DATA)){
 					return -1;
+				}
 				bytesInDataReport = m_readData[HID_RMI4_READ_INPUT_COUNT];
 				if (bytesInDataReport > bytesToRequest
-				    || bytesReadPerRequest + bytesInDataReport > len)
+				    || bytesReadPerRequest + bytesInDataReport > len){
 					return -1;
+				}
 				memcpy(buf + bytesReadPerRequest, &m_readData[HID_RMI4_READ_INPUT_DATA],
 					bytesInDataReport);
 				bytesReadPerRequest += bytesInDataReport;
@@ -345,10 +408,14 @@
 
 void HIDDevice::Close()
 {
+	RMIDevice::Close();
+
 	if (!m_deviceOpen)
 		return;
 
-	SetMode(HID_RMI4_MODE_MOUSE);
+	if (m_initialMode != m_mode)
+		SetMode(m_initialMode);
+
 	m_deviceOpen = false;
 	close(m_fd);
 	m_fd = -1;
@@ -527,10 +594,15 @@
 // Print protocol specific device information
 void HIDDevice::PrintDeviceInfo()
 {
+	enum RMIDeviceType deviceType = GetDeviceType();
+
 	fprintf(stdout, "HID device info:\nBus: %s Vendor: 0x%04x Product: 0x%04x\n",
 		m_info.bustype == BUS_I2C ? "I2C" : "USB", m_info.vendor, m_info.product);
 	fprintf(stdout, "Report sizes: input: %ld output: %ld\n", (unsigned long)m_inputReportSize,
 		(unsigned long)m_outputReportSize);
+	if (deviceType)
+		fprintf(stdout, "device type: %s\n", deviceType == RMI_DEVICE_TYPE_TOUCHSCREEN ?
+			"touchscreen" : "touchpad");
 }
 
 bool WriteDeviceNameToFile(const char * file, const char * str)
@@ -555,76 +627,159 @@
 
 	return close(fd) == 0 && size == static_cast<ssize_t>(strlen(str));
 }
+static const char * const absval[6] = { "Value", "Min  ", "Max  ", "Fuzz ", "Flat ", "Resolution "};
+#define KEY_MAX			0x2ff
+#define EV_MAX			0x1f
+#define BITS_PER_LONG (sizeof(long) * 8)
+#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
+#define OFF(x)  ((x)%BITS_PER_LONG)
+#define BIT(x)  (1UL<<OFF(x))
+#define LONG(x) ((x)/BITS_PER_LONG)
+#define test_bit(bit, array)	((array[LONG(bit)] >> OFF(bit)) & 1)
+#define DEV_INPUT_EVENT "/dev/input"
+#define EVENT_DEV_NAME "event"
+/**
+ * Filter for the AutoDevProbe scandir on /dev/input.
+ *
+ * @param dir The current directory entry provided by scandir.
+ *
+ * @return Non-zero if the given directory entry starts with "event", or zero
+ * otherwise.
+ */
+static int is_event_device(const struct dirent *dir) {
+	return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
+}
 
+bool HIDDevice::CheckABSEvent()
+{
+	int fd=-1;
+	unsigned int type;
+	int abs[6] = {0};
+	int k;
+	struct dirent **namelist;
+	int i, ndev, devnum, match;
+	char *filename;
+	int max_device = 0;
+    char input_event_name[PATH_MAX];
+	unsigned long bit[EV_MAX][NBITS(KEY_MAX)];
+
+
+#ifdef __BIONIC__
+	// Android's libc doesn't have the GNU versionsort extension.
+	ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, alphasort);
+#else
+	ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, versionsort);
+#endif
+	if (ndev <= 0)
+		return false;
+	for (i = 0; i < ndev; i++)
+	{
+		char fname[64];
+		int fd = -1;
+		char name[256] = "???";
+
+		snprintf(fname, sizeof(fname),
+			 "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
+		fd = open(fname, O_RDONLY);
+		if (fd < 0)
+			continue;
+		ioctl(fd, EVIOCGNAME(sizeof(name)), name);
+		//fprintf(stderr, "%s:	%s\n", fname, name);
+		close(fd);
+
+		if(strstr(name, m_transportDeviceName.c_str()+4))
+		{
+			snprintf(input_event_name, sizeof(fname), "%s", fname);
+		}
+		free(namelist[i]);
+	}
+	
+	if ((fd = open(input_event_name, O_RDONLY)) < 0) {
+		if (errno == EACCES && getuid() != 0)
+			fprintf(stderr, "No access right \n");
+	}
+	memset(bit, 0, sizeof(bit));
+	ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]);
+	for (type = 0; type < EV_MAX; type++) {
+		if (test_bit(type, bit[0]) && type == EV_ABS) {
+			ioctl(fd, EVIOCGBIT(type, KEY_MAX), bit[type]);
+			if (test_bit(ABS_X, bit[type])) {
+				ioctl(fd, EVIOCGABS(ABS_X), abs);
+				if(abs[2] == 0) //maximum
+				{
+					Sleep(1000);
+					return false;
+				}
+			}
+		}
+	}
+	return true;
+}
 void HIDDevice::RebindDriver()
 {
 	int bus = m_info.bustype;
 	int vendor = m_info.vendor;
 	int product = m_info.product;
 	std::string hidDeviceName;
-	std::string transportDeviceName;
-	std::string driverPath;
 	std::string bindFile;
 	std::string unbindFile;
 	std::string hidrawFile;
-	struct stat stat_buf;
+	int notifyFd;
+	int wd;
 	int rc;
-	int i;
-
 	Close();
 
-	if (!LookupHidDeviceName(bus, vendor, product, hidDeviceName)) {
-		fprintf(stderr, "Failed to find HID device name for the specified device: bus (0x%x) vendor: (0x%x) product: (0x%x)\n",
-			bus, vendor, product);
+	notifyFd = inotify_init();
+	if (notifyFd < 0) {
+		fprintf(stderr, "Failed to initialize inotify\n");
 		return;
 	}
 
-	if (!FindTransportDevice(bus, hidDeviceName, transportDeviceName, driverPath)) {
-		fprintf(stderr, "Failed to find the transport device / driver for %s\n", hidDeviceName.c_str());
+	wd = inotify_add_watch(notifyFd, "/dev", IN_CREATE);
+	if (wd < 0) {
+		fprintf(stderr, "Failed to add watcher for /dev\n");
 		return;
 	}
 
-	bindFile = driverPath + "bind";
-	unbindFile = driverPath + "unbind";
+	if (m_transportDeviceName == "") {
+		if (!LookupHidDeviceName(bus, vendor, product, hidDeviceName)) {
+			fprintf(stderr, "Failed to find HID device name for the specified device: bus (0x%x) vendor: (0x%x) product: (0x%x)\n",
+				bus, vendor, product);
+			return;
+		}
 
-	if (!WriteDeviceNameToFile(unbindFile.c_str(), transportDeviceName.c_str())) {
+		if (!FindTransportDevice(bus, hidDeviceName, m_transportDeviceName, m_driverPath)) {
+			fprintf(stderr, "Failed to find the transport device / driver for %s\n", hidDeviceName.c_str());
+			return;
+		}
+
+	}
+ 
+	bindFile = m_driverPath + "bind";
+	unbindFile = m_driverPath + "unbind";
+
+	Sleep(500);
+	if (!WriteDeviceNameToFile(unbindFile.c_str(), m_transportDeviceName.c_str())) {
 		fprintf(stderr, "Failed to unbind HID device %s: %s\n",
-			transportDeviceName.c_str(), strerror(errno));
+			m_transportDeviceName.c_str(), strerror(errno));
 		return;
 	}
-
-	if (!WriteDeviceNameToFile(bindFile.c_str(), transportDeviceName.c_str())) {
+	Sleep(500);
+	if (!WriteDeviceNameToFile(bindFile.c_str(), m_transportDeviceName.c_str())) {
 		fprintf(stderr, "Failed to bind HID device %s: %s\n",
-			transportDeviceName.c_str(), strerror(errno));
+			m_transportDeviceName.c_str(), strerror(errno));
 		return;
 	}
 
-	// The hid device id has changed since this is now a new hid device. Now we have to look up the new name.
-	if (!LookupHidDeviceName(bus, vendor, product, hidDeviceName)) {
-		fprintf(stderr, "Failed to find HID device name for the specified device: bus (0x%x) vendor: (0x%x) product: (0x%x)\n",
-			bus, vendor, product);
-		return;
+	if (WaitForHidRawDevice(notifyFd, hidrawFile)) {
+		rc = Open(hidrawFile.c_str());
+		if (rc)
+			fprintf(stderr, "Failed to open device (%s) during rebind: %d: errno: %s (%d)\n",
+					hidrawFile.c_str(), rc, strerror(errno), errno);
 	}
-
-	if (!FindHidRawFile(hidDeviceName, hidrawFile)) {
-		fprintf(stderr, "Failed to find the hidraw device file for %s\n", hidDeviceName.c_str());
-		return;
-	}
-
-	for (i = 0; i < 200; i++) {
-		rc = stat(hidrawFile.c_str(), &stat_buf);
-		if (!rc)
-			break;
-		Sleep(5);
-	}
-
-	rc = Open(hidrawFile.c_str());
-	if (rc)
-		fprintf(stderr, "Failed to open device (%s) during rebind: %d: errno: %s (%d)\n",
-				hidrawFile.c_str(), rc, strerror(errno), errno);
 }
 
-bool HIDDevice::FindTransportDevice(int bus, std::string & hidDeviceName,
+bool HIDDevice::FindTransportDevice(uint32_t bus, std::string & hidDeviceName,
 			std::string & transportDeviceName, std::string & driverPath)
 {
 	std::string devicePrefix = "/sys/bus/";
@@ -638,7 +793,15 @@
 
 	if (bus == BUS_I2C) {
 		devicePrefix += "i2c/";
-		driverPath = devicePrefix + "drivers/i2c_hid/";
+		// From new patch released on 2020/11, i2c_hid would be renamed as i2c_hid_acpi,
+		// and also need backward compatible.
+		std::string driverPathTemp = devicePrefix + "drivers/i2c_hid/";
+		DIR *driverPathtest = opendir(driverPathTemp.c_str());
+		if(!driverPathtest) {
+			driverPath = devicePrefix + "drivers/i2c_hid_acpi/";
+		} else {
+			driverPath = devicePrefix + "drivers/i2c_hid/";
+		}
 	} else {
 		devicePrefix += "usb/";
 		driverPath = devicePrefix + "drivers/usbhid/";
@@ -685,14 +848,14 @@
 	return deviceFound;
 }
 
-bool HIDDevice::LookupHidDeviceName(int bus, int vendorId, int productId, std::string & deviceName)
+bool HIDDevice::LookupHidDeviceName(uint32_t bus, int16_t vendorId, int16_t productId, std::string & deviceName)
 {
 	bool ret = false;
 	struct dirent * devDirEntry;
 	DIR * devDir;
 	char devicePrefix[15];
 
-	snprintf(devicePrefix, 15, "%04X:%04X:%04X", bus, vendorId, productId);
+	snprintf(devicePrefix, 15, "%04X:%04X:%04X", bus, (vendorId & 0xFFFF), (productId & 0xFFFF));
 
 	devDir = opendir("/sys/bus/hid/devices");
 	if (!devDir)
@@ -710,27 +873,128 @@
 	return ret;
 }
 
-bool HIDDevice::FindHidRawFile(std::string & deviceName, std::string & hidrawFile)
+bool HIDDevice::LookupHidDriverName(std::string &deviceName, std::string &driverName)
 {
 	bool ret = false;
-	char hidrawDir[PATH_MAX];
-	struct dirent * devDirEntry;
+	ssize_t sz;
+	char link[PATH_MAX];
+	std::string driverLink = "/sys/bus/hid/devices/" + deviceName + "/driver";
+
+	sz = readlink(driverLink.c_str(), link, PATH_MAX);
+	if (sz == -1)
+		return ret;
+
+	link[sz] = 0;
+
+	driverName = std::string(StripPath(link, PATH_MAX));
+
+	return true;
+}
+
+bool HIDDevice::WaitForHidRawDevice(int notifyFd, std::string & hidrawFile)
+{
+	struct timeval timeout;
+	fd_set fds;
+	int rc;
+	ssize_t eventBytesRead;
+	int eventBytesAvailable;
+	size_t sz;
+	char link[PATH_MAX];
+	std::string transportDeviceName;
+	std::string driverPath;
+	std::string hidDeviceName;
+	int offset = 0;
+
+	for (;;) {
+		FD_ZERO(&fds);
+		FD_SET(notifyFd, &fds);
+
+		timeout.tv_sec = 20;
+		timeout.tv_usec = 0;
+
+		rc = select(notifyFd + 1, &fds, NULL, NULL, &timeout);
+		if (rc < 0) {
+			if (errno == -EINTR)
+				continue;
+
+			return false;
+		}
+
+		if (rc == 0) {
+			return false;
+		}
+
+		if (FD_ISSET(notifyFd, &fds)) {
+			struct inotify_event * event;
+
+			rc = ioctl(notifyFd, FIONREAD, &eventBytesAvailable);
+			if (rc < 0) {
+				continue;
+			}
+
+			char buf[eventBytesAvailable];
+
+			eventBytesRead = read(notifyFd, buf, eventBytesAvailable);
+			if (eventBytesRead < 0) {
+				continue;
+			}
+
+			while (offset < eventBytesRead) {
+				event = (struct inotify_event *)&buf[offset];
+
+				if (!strncmp(event->name, "hidraw", 6)) {
+					std::string classPath = std::string("/sys/class/hidraw/")
+												+ event->name + "/device";
+					sz = readlink(classPath.c_str(), link, PATH_MAX);
+					link[sz] = 0;
+
+					hidDeviceName = std::string(link).substr(9, 19);
+
+					if (!FindTransportDevice(m_info.bustype, hidDeviceName, transportDeviceName, driverPath)) {
+						fprintf(stderr, "Failed to find the transport device / driver for %s\n", hidDeviceName.c_str());
+						continue;
+					}
+
+					if (transportDeviceName == m_transportDeviceName) {
+						hidrawFile = std::string("/dev/") + event->name;
+						return true;
+					}
+				}
+
+				offset += sizeof(struct inotify_event) + event->len;
+			}
+		}
+	}
+}
+
+bool HIDDevice::FindDevice(enum RMIDeviceType type)
+{
 	DIR * devDir;
-
-	snprintf(hidrawDir, PATH_MAX, "/sys/bus/hid/devices/%s/hidraw", deviceName.c_str());
-
-	devDir = opendir(hidrawDir);
+	struct dirent * devDirEntry;
+	char deviceFile[PATH_MAX];
+	bool found = false;
+	int rc;
+	devDir = opendir("/dev");
 	if (!devDir)
-		return false;
+		return -1;
 
 	while ((devDirEntry = readdir(devDir)) != NULL) {
-		if (!strncmp(devDirEntry->d_name, "hidraw", 6)) {
-			hidrawFile = std::string("/dev/") + devDirEntry->d_name;
-			ret = true;
-			break;
+		if (strstr(devDirEntry->d_name, "hidraw")) {
+			snprintf(deviceFile, PATH_MAX, "/dev/%s", devDirEntry->d_name);
+			fprintf(stdout, "Got device : /dev/%s\n", devDirEntry->d_name);
+			rc = Open(deviceFile);
+			if (rc != 0) {
+				continue;
+			} else if (type != RMI_DEVICE_TYPE_ANY && GetDeviceType() != type) {
+				Close();
+				continue;
+			} else {
+				found = true;
+				break;
+			}
 		}
 	}
 	closedir(devDir);
-
-	return ret;
+	
+	return found;
 }
diff --git a/rmidevice/hiddevice.h b/rmidevice/hiddevice.h
old mode 100644
new mode 100755
index 05a11fa..b947f62
--- a/rmidevice/hiddevice.h
+++ b/rmidevice/hiddevice.h
@@ -20,8 +20,15 @@
 
 #include <linux/hidraw.h>
 #include <string>
+#include <stdint.h>
 #include "rmidevice.h"
 
+enum rmi_hid_mode_type {
+	HID_RMI4_MODE_MOUSE                     = 0,
+	HID_RMI4_MODE_ATTN_REPORTS              = 1,
+	HID_RMI4_MODE_NO_PACKED_ATTN_REPORTS    = 2,
+};
+
 class HIDDevice : public RMIDevice
 {
 public:
@@ -30,7 +37,11 @@
 		      m_inputReportSize(0),
 		      m_outputReportSize(0),
 		      m_featureReportSize(0),
-		      m_deviceOpen(false)
+		      m_deviceOpen(false),
+		      m_mode(HID_RMI4_MODE_ATTN_REPORTS),
+		      m_initialMode(HID_RMI4_MODE_MOUSE),
+		      m_transportDeviceName(""),
+		      m_driverPath("")
 	{}
 	virtual int Open(const char * filename);
 	virtual int Read(unsigned short addr, unsigned char *buf,
@@ -48,6 +59,9 @@
 
 	virtual void PrintDeviceInfo();
 
+	virtual bool FindDevice(enum RMIDeviceType type = RMI_DEVICE_TYPE_ANY);
+	virtual bool CheckABSEvent();
+
 private:
 	int m_fd;
 
@@ -67,21 +81,23 @@
 
 	bool m_deviceOpen;
 
-	enum mode_type {
-		HID_RMI4_MODE_MOUSE			= 0,
-		HID_RMI4_MODE_ATTN_REPORTS		= 1,
-		HID_RMI4_MODE_NO_PACKED_ATTN_REPORTS	= 2,
-	};
+	rmi_hid_mode_type m_mode;
+	rmi_hid_mode_type m_initialMode;
+
+	std::string m_transportDeviceName;
+	std::string m_driverPath;
 
 	int GetReport(int *reportId, struct timeval * timeout = NULL);
 	void PrintReport(const unsigned char *report);
-	void ParseReportSizes();
+	void ParseReportDescriptor();
+
+	bool WaitForHidRawDevice(int notifyFd, std::string & hidraw);
 
 	// static HID utility functions
-	static bool LookupHidDeviceName(int bus, int vendorId, int productId, std::string &deviceName);
-	static bool FindTransportDevice(int bus, std::string & hidDeviceName,
+	static bool LookupHidDeviceName(uint32_t bus, int16_t vendorId, int16_t productId, std::string &deviceName);
+	static bool LookupHidDriverName(std::string &deviceName, std::string &driverName);
+	static bool FindTransportDevice(uint32_t bus, std::string & hidDeviceName,
 					std::string & transportDeviceName, std::string & driverPath);
-	static bool FindHidRawFile(std::string & hidDeviceName, std::string & hidrawFile);
  };
 
 #endif /* _HIDDEVICE_H_ */
diff --git a/rmidevice/rmidevice.cpp b/rmidevice/rmidevice.cpp
index 71bafa0..15335f9 100644
--- a/rmidevice/rmidevice.cpp
+++ b/rmidevice/rmidevice.cpp
@@ -50,6 +50,7 @@
 #define RMI_DEVICE_F01_QRY43_01_BUILD_ID       (1 << 1)
 
 #define PACKAGE_ID_BYTES			4
+#define CONFIG_ID_BYTES				4
 #define BUILD_ID_BYTES				3
 
 #define RMI_F01_CMD_DEVICE_RESET	1
@@ -75,10 +76,13 @@
 {
 	int rc;
 	unsigned char basicQuery[RMI_DEVICE_F01_BASIC_QUERY_LEN];
+	unsigned char configid[CONFIG_ID_BYTES];
 	unsigned short queryAddr;
+	unsigned short controlAddr;
 	unsigned char infoBuf[4];
 	unsigned short prodInfoAddr;
 	RMIFunction f01;
+	RMIFunction f34;
 
 	SetRMIPage(0x00);
 
@@ -187,9 +191,30 @@
 			}
 		}
 	}
+
+	if (GetFunction(f34, 0x34)) {
+		controlAddr = f34.GetControlBase();
+		rc = Read(controlAddr, configid, CONFIG_ID_BYTES);
+		if (rc < 0 || rc < CONFIG_ID_BYTES) {
+			fprintf(stderr, "Failed to read the config id: %s\n", strerror(errno));
+			return rc;
+		}
+		m_configID = (configid[0] << 24 | configid[1] << 16
+				| configid[2] << 8 | configid[3]) & 0xFFFFFFFF;
+	}
+
 	return 0;
 }
 
+void RMIDevice::Close()
+{
+	m_functionList.clear();
+	m_bCancel = false;
+	m_bytesPerReadRequest = 0;
+	m_page = -1;
+	m_deviceType = RMI_DEVICE_TYPE_ANY;
+}
+
 void RMIDevice::PrintProperties()
 {
 	fprintf(stdout, "manufacturerID:\t\t%d\n", m_manufacturerID);
@@ -320,43 +345,4 @@
 		return !!(status & 0x40);
 	}
 	return true;
-}
-
-long long diff_time(struct timespec *start, struct timespec *end)
-{
-	long long diff;
-	diff = (end->tv_sec - start->tv_sec) * 1000 * 1000;
-	diff += (end->tv_nsec - start->tv_nsec) / 1000;
-	return diff;
-}
-
-int Sleep(int ms)
-{
-	struct timespec ts;
-	struct timespec rem;
-
-	ts.tv_sec = ms / 1000;
-	ts.tv_nsec = (ms % 1000) * 1000 * 1000;
-	for (;;) {
-		if (nanosleep(&ts, &rem) == 0) {
-			break;
-		} else {
-			if (errno == EINTR) {
-				ts = rem;
-				continue;
-			}
-			return -1;
-		}
-	}
-	return 0;
-}
-
-void print_buffer(const unsigned char *buf, unsigned int len)
-{
-	for (unsigned int i = 0; i < len; ++i) {
-		fprintf(stdout, "0x%02X ", buf[i]);
-		if (i % 8 == 7)
-			fprintf(stdout, "\n");
-	}
-	fprintf(stdout, "\n");
-}
+}
\ No newline at end of file
diff --git a/rmidevice/rmidevice.h b/rmidevice/rmidevice.h
index 48de72b..9bfe849 100644
--- a/rmidevice/rmidevice.h
+++ b/rmidevice/rmidevice.h
@@ -27,10 +27,17 @@
 
 #define RMI_INTERUPT_SOURCES_ALL_MASK	0xFFFFFFFF
 
+enum RMIDeviceType {
+	RMI_DEVICE_TYPE_ANY             = 0,
+	RMI_DEVICE_TYPE_TOUCHPAD,
+	RMI_DEVICE_TYPE_TOUCHSCREEN,
+};
+
 class RMIDevice
 {
 public:
-	RMIDevice() : m_functionList(), m_sensorID(0), m_bCancel(false), m_bytesPerReadRequest(0), m_page(-1)
+	RMIDevice() : m_functionList(), m_sensorID(0), m_bCancel(false), m_bytesPerReadRequest(0), m_page(-1),
+		      m_deviceType(RMI_DEVICE_TYPE_ANY)
 	{}
 	virtual ~RMIDevice() {}
 	virtual int Open(const char * filename) = 0;
@@ -44,11 +51,13 @@
 	virtual int GetAttentionReport(struct timeval * timeout, unsigned int source_mask,
 					unsigned char *buf, unsigned int *len)
 	{ return -1; /* Unsupported */ }
-	virtual void Close() = 0;
+	virtual void Close();
 	virtual void Cancel() { m_bCancel = true; }
 	virtual void RebindDriver() = 0;
+	virtual bool CheckABSEvent() = 0;
 
 	unsigned long GetFirmwareID() { return m_buildID; }
+	unsigned long GetConfigID() { return m_configID; }
 	int GetFirmwareVersionMajor() { return m_firmwareVersionMajor; }
 	int GetFirmwareVersionMinor() { return m_firmwareVersionMinor; }
 	virtual int QueryBasicProperties();
@@ -69,6 +78,9 @@
 
 	unsigned int GetNumInterruptRegs() { return m_numInterruptRegs; }
 
+	virtual bool FindDevice(enum RMIDeviceType type = RMI_DEVICE_TYPE_ANY) = 0;
+	enum RMIDeviceType GetDeviceType() { return m_deviceType; }
+
 protected:
 	std::vector<RMIFunction> m_functionList;
 	unsigned char m_manufacturerID;
@@ -82,6 +94,7 @@
 	unsigned short m_packageID;
 	unsigned short m_packageRev;
 	unsigned long m_buildID;
+	unsigned long m_configID;
 	unsigned char m_sensorID;
 	unsigned long m_boardID;
 
@@ -101,10 +114,15 @@
 	int m_page;
 
 	unsigned int m_numInterruptRegs;
- };
+
+	enum RMIDeviceType m_deviceType;
+};
 
 /* Utility Functions */
 long long diff_time(struct timespec *start, struct timespec *end);
 int Sleep(int ms);
 void print_buffer(const unsigned char *buf, unsigned int len);
+unsigned long extract_long(const unsigned char *data);
+unsigned short extract_short(const unsigned char *data);
+const char * StripPath(const char * path, ssize_t size);
 #endif /* _RMIDEVICE_H_ */
diff --git a/rmidevice/util.cpp b/rmidevice/util.cpp
new file mode 100644
index 0000000..64b1c1c
--- /dev/null
+++ b/rmidevice/util.cpp
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <time.h>
+
+long long diff_time(struct timespec *start, struct timespec *end)
+{
+	long long diff;
+	diff = (end->tv_sec - start->tv_sec) * 1000 * 1000;
+	diff += (end->tv_nsec - start->tv_nsec) / 1000;
+	return diff;
+}
+
+int Sleep(int ms)
+{
+	struct timespec ts;
+	struct timespec rem;
+
+	ts.tv_sec = ms / 1000;
+	ts.tv_nsec = (ms % 1000) * 1000 * 1000;
+	for (;;) {
+		if (nanosleep(&ts, &rem) == 0) {
+			break;
+		} else {
+			if (errno == EINTR) {
+				ts = rem;
+				continue;
+			}
+			return -1;
+		}
+	}
+	return 0;
+}
+
+void print_buffer(const unsigned char *buf, unsigned int len)
+{
+	for (unsigned int i = 0; i < len; ++i) {
+		fprintf(stdout, "0x%02X ", buf[i]);
+		if (i % 8 == 7)
+			fprintf(stdout, "\n");
+	}
+	fprintf(stdout, "\n");
+}
+
+
+const char * StripPath(const char * path, ssize_t size)
+{
+	int i;
+	const char * str;
+
+	for (i = size - 1, str = &path[size - 1]; i > 0; --i, --str)
+		if (path[i - 1] == '/')
+			break;
+
+	return str;
+}
+
+unsigned long extract_long(const unsigned char *data)
+{
+	return (unsigned long)data [0]
+		+ (unsigned long)data [1] * 0x100
+		+ (unsigned long)data [2] * 0x10000
+		+ (unsigned long)data [3] * 0x1000000;
+}
+
+unsigned short extract_short(const unsigned char *data)
+{
+	return (unsigned long)data [0]
+		+ (unsigned long)data [1] * 0x100;
+}
\ No newline at end of file
diff --git a/rmihidtool/main.cpp b/rmihidtool/main.cpp
index 0fc2b1a..a2d0643 100644
--- a/rmihidtool/main.cpp
+++ b/rmihidtool/main.cpp
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <dirent.h>
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
@@ -34,13 +35,14 @@
 
 #include "hiddevice.h"
 
-#define RMI4UPDATE_GETOPTS      "hp:ir:w:foambde"
+#define RMI4UPDATE_GETOPTS      "hp:ir:w:foambd:ecnt:"
 
  enum rmihidtool_cmd {
 	RMIHIDTOOL_CMD_INTERACTIVE,
 	RMIHIDTOOL_CMD_READ,
 	RMIHIDTOOL_CMD_WRITE,
 	RMIHIDTOOL_CMD_FW_ID,
+	RMIHIDTOOL_CMD_CF_ID,
 	RMIHIDTOOL_CMD_PROPS,
 	RMIHIDTOOL_CMD_ATTN,
 	RMIHIDTOOL_CMD_PRINT_FUNCTIONS,
@@ -56,17 +58,20 @@
 {
 	fprintf(stdout, "Usage: %s [OPTIONS] DEVICEFILE\n", prog_name);
 	fprintf(stdout, "\t-h, --help\t\t\t\tPrint this message\n");
+	fprintf(stdout, "\t-d, --device\t\t\t\thidraw device file associated with the device.\n");
 	fprintf(stdout, "\t-p, --protocol [protocol]\t\tSet which transport prototocl to use.\n");
 	fprintf(stdout, "\t-i, --interactive\t\t\tRun in interactive mode.\n");
 	fprintf(stdout, "\t-r, --read [address] [length]\t\tRead registers starting at the address.\n");
-	fprintf(stdout, "\t-r, --write [address] [length] [data]\tWrite registers starting at the address.\n");
+	fprintf(stdout, "\t-w, --write [address] [length] [data]\tWrite registers starting at the address.\n");
 	fprintf(stdout, "\t-f, --firmware-id\t\t\tPrint the firmware id\n");
+	fprintf(stdout, "\t-c, --config-id\t\t\t\tPrint the config id\n");
 	fprintf(stdout, "\t-o, --props\t\t\t\tPrint device properties\n");
 	fprintf(stdout, "\t-a, --attention\t\t\t\tPrint attention reports until control + c\n");
 	fprintf(stdout, "\t-m, --print-functions\t\t\tPrint RMI4 functions for the device.\n");
 	fprintf(stdout, "\t-b, --rebind-driver\t\t\tRebind the driver to force an update of device properties.\n");
-	fprintf(stdout, "\t-d, --device-info\t\t\tPrint protocol specific information about the device.\n");
+	fprintf(stdout, "\t-n, --device-info\t\t\tPrint protocol specific information about the device.\n");
 	fprintf(stdout, "\t-e, --reset-device\t\t\tReset the device.\n");
+	fprintf(stdout, "\t-t, --device-type\t\t\tFilter by device type [touchpad or touchscreen].\n");
 }
 
 void print_cmd_usage()
@@ -117,6 +122,8 @@
 
 	for (;;) {
 		fprintf(stdout, "\n");
+		device->PrintDeviceInfo();
+		fprintf(stdout, "\n");
 		print_cmd_usage();
 		char input[256];
 
@@ -201,23 +208,28 @@
 	struct sigaction sig_cleanup_action;
 	int opt;
 	int index;
+	char *deviceName = NULL;
 	RMIDevice *device;
 	const char *protocol = "HID";
 	unsigned char report[256];
 	char token[256];
+	enum RMIDeviceType deviceType = RMI_DEVICE_TYPE_ANY;
 	static struct option long_options[] = {
 		{"help", 0, NULL, 'h'},
+		{"device", 1, NULL, 'd'},
 		{"protocol", 1, NULL, 'p'},
 		{"interactive", 0, NULL, 'i'},
 		{"read", 1, NULL, 'r'},
 		{"write", 1, NULL, 'w'},
 		{"firmware-id", 0, NULL, 'f'},
+		{"config-id", 0, NULL, 'c'},
 		{"props", 0, NULL, 'o'},
 		{"attention", 0, NULL, 'a'},
 		{"print-functions", 0, NULL, 'm'},
 		{"rebind-driver", 0, NULL, 'b'},
-		{"device-info", 0, NULL, 'd'},
+		{"device-info", 0, NULL, 'n'},
 		{"reset-device", 0, NULL, 'e'},
+		{"device-type", 1, NULL, 't'},
 		{0, 0, 0, 0},
 	};
 	enum rmihidtool_cmd cmd = RMIHIDTOOL_CMD_INTERACTIVE;
@@ -241,6 +253,9 @@
 			case 'p':
 				protocol = optarg;
 				break;
+			case 'd':
+				deviceName = optarg;
+				break;
 			case 'i':
 				cmd = RMIHIDTOOL_CMD_INTERACTIVE;
 				break;
@@ -257,6 +272,9 @@
 			case 'f':
 				cmd = RMIHIDTOOL_CMD_FW_ID;
 				break;
+			case 'c':
+				cmd = RMIHIDTOOL_CMD_CF_ID;
+				break;
 			case 'o':
 				cmd = RMIHIDTOOL_CMD_PROPS;
 				break;
@@ -269,12 +287,18 @@
 			case 'b':
 				cmd = RMIHIDTOOL_CMD_REBIND_DRIVER;
 				break;
-			case 'd':
+			case 'n':
 				cmd = RMIHIDTOOL_CMD_PRINT_DEVICE_INFO;
 				break;
 			case 'e':
 				cmd = RMIHIDTOOL_CMD_RESET_DEVICE;
 				break;
+			case 't':
+				if (!strcasecmp(optarg, "touchpad"))
+					deviceType = RMI_DEVICE_TYPE_TOUCHPAD;
+				else if (!strcasecmp(optarg, "touchscreen"))
+					deviceType = RMI_DEVICE_TYPE_TOUCHSCREEN;
+				break;
 			default:
 				print_help(argv[0]);
 				return 0;
@@ -290,16 +314,21 @@
 		return -1;
 	}
 
-	if (optind >= argc) {
+	if (optind != argc) {
 		print_help(argv[0]);
 		return -1;
 	}
 
-	rc = device->Open(argv[optind++]);
-	if (rc) {
-		fprintf(stderr, "%s: failed to initialize rmi device (%d): %s\n", argv[0], errno,
-			strerror(errno));
-		return 1;
+	if (deviceName) {
+		rc = device->Open(deviceName);
+		if (rc) {
+			fprintf(stderr, "%s: failed to initialize rmi device (%d): %s\n", argv[0], errno,
+				strerror(errno));
+			return 1;
+		}
+	} else {
+		if (!device->FindDevice(deviceType))
+			return -1;
 	}
 
 	g_device = device;
@@ -333,6 +362,11 @@
 			device->QueryBasicProperties();
 			fprintf(stdout, "firmware id: %lu\n", device->GetFirmwareID());
 			break;
+		case RMIHIDTOOL_CMD_CF_ID:
+			device->ScanPDT();
+			device->QueryBasicProperties();
+			fprintf(stdout, "config id: %08lx\n", device->GetConfigID());
+			break;
 		case RMIHIDTOOL_CMD_PROPS:
 			device->ScanPDT();
 			device->QueryBasicProperties();