baiji: add tp driver

Bug: 130678563
Signed-off-by: duyahui<duyahui@xiaomi.com>
Change-Id: I4d5178aa4a645205002e71410ddecbd0ac89239b
diff --git a/tp/Kbuild b/tp/Kbuild
new file mode 100644
index 0000000..900c757
--- /dev/null
+++ b/tp/Kbuild
@@ -0,0 +1,38 @@
+#
+# Kernel build touch panel modules.
+#
+ifeq ($(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5),m)
+
+ccflags-y += -DCONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5 \
+		-DCONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE \
+		-DCONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT \
+		-DCONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_I2C \
+		-DCONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MT_B
+
+TP_DIR := cyttsp5
+
+TP_INC := -I$(TP_ROOT)/$(TP_DIR)
+TP_OBJS := $(TP_DIR)/cyttsp5_core.o \
+		$(TP_DIR)/cyttsp5_mt_common.o \
+		$(TP_DIR)/cyttsp5_mtb.o \
+		$(TP_DIR)/cyttsp5_devtree.o \
+		$(TP_DIR)/cyttsp5_platform.o \
+		$(TP_DIR)/cyttsp5_i2c.o
+
+TP_ACCESS_OBJS := $(TP_DIR)/cyttsp5_device_access.o
+
+TP_UPDATE_OBJS := $(TP_DIR)/cyttsp5_loader.o
+
+obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5) += $(MODNAME).o
+$(MODNAME)-y := $(TP_OBJS)
+
+obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS) += $(MODNAME)_access.o
+$(MODNAME)_access-y := $(TP_ACCESS_OBJS)
+
+obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER) += $(MODNAME)_loader.o
+$(MODNAME)_loader-y := $(TP_UPDATE_OBJS)
+
+endif
+
+# Fix build for GCC 4.7
+EXTRA_CFLAGS += -Wno-maybe-uninitialized -Wno-unused-function
diff --git a/tp/Makefile b/tp/Makefile
new file mode 100644
index 0000000..d065a39
--- /dev/null
+++ b/tp/Makefile
@@ -0,0 +1,21 @@
+default: all

+

+KBUILD_OPTIONS := TP_ROOT=$(shell cd $(KERNEL_SRC); readlink -e $(M))

+KBUILD_OPTIONS += MODNAME?=private-drivers-tp_cyttsp5

+

+TP_SELECT := CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5=m \

+			CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER=m \

+			CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS=m

+

+KBUILD_OPTIONS += $(TP_SELECT)

+

+all:

+	$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)

+

+modules_install:

+	$(MAKE) INSTALL_MOD_STRIP=1 M=$(M) -C $(KERNEL_SRC) modules_install

+

+clean::

+	rm -f *.o *.ko *.mod.c *.mod.o *~ .*.cmd Module.symvers

+	rm -rf .tmp_versions

+

diff --git a/tp/cyttsp5/cyttsp5_btn.c b/tp/cyttsp5/cyttsp5_btn.c
new file mode 100644
index 0000000..52c0eb8
--- /dev/null
+++ b/tp/cyttsp5/cyttsp5_btn.c
@@ -0,0 +1,369 @@
+/*
+ * cyttsp5_btn.c
+ * Parade TrueTouch(TM) Standard Product V5 CapSense Reports Module.
+ * For use with Parade touchscreen controllers.
+ * Supported parts include:
+ * CYTMA5XX
+ * CYTMA448
+ * CYTMA445A
+ * CYTT21XXX
+ * CYTT31XXX
+ *
+ * Copyright (C) 2015 Parade Technologies
+ * Copyright (C) 2012-2015 Cypress Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
+ *
+ */
+
+#include "cyttsp5_regs.h"
+
+#define CYTTSP5_BTN_NAME "cyttsp5_btn"
+
+static inline void cyttsp5_btn_key_action(struct cyttsp5_btn_data *bd,
+	int btn_no, int btn_state)
+{
+	struct device *dev = bd->dev;
+	struct cyttsp5_sysinfo *si = bd->si;
+
+	if (!si->btn[btn_no].enabled ||
+			si->btn[btn_no].state == btn_state)
+		return;
+
+	si->btn[btn_no].state = btn_state;
+	input_report_key(bd->input, si->btn[btn_no].key_code, btn_state);
+	input_sync(bd->input);
+
+	parade_debug(dev, DEBUG_LEVEL_1, "%s: btn=%d key_code=%d %s\n",
+		__func__, btn_no, si->btn[btn_no].key_code,
+		btn_state == CY_BTN_PRESSED ?
+			"PRESSED" : "RELEASED");
+}
+
+static void cyttsp5_get_btn_touches(struct cyttsp5_btn_data *bd)
+{
+	struct cyttsp5_sysinfo *si = bd->si;
+	int num_btns = si->num_btns;
+	int cur_btn;
+	int cur_btn_state;
+
+	for (cur_btn = 0; cur_btn < num_btns; cur_btn++) {
+		/* Get current button state */
+		cur_btn_state = (si->xy_data[0] >> (cur_btn * CY_BITS_PER_BTN))
+				& CY_NUM_BTN_EVENT_ID;
+
+		cyttsp5_btn_key_action(bd, cur_btn, cur_btn_state);
+	}
+}
+
+static void cyttsp5_btn_lift_all(struct cyttsp5_btn_data *bd)
+{
+	struct cyttsp5_sysinfo *si = bd->si;
+	int i;
+
+	if (!si || si->num_btns == 0)
+		return;
+
+	for (i = 0; i < si->num_btns; i++)
+		cyttsp5_btn_key_action(bd, i, CY_BTN_RELEASED);
+}
+
+#ifdef VERBOSE_DEBUG
+static void cyttsp5_log_btn_data(struct cyttsp5_btn_data *bd)
+{
+	struct device *dev = bd->dev;
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	u8 *pr_buf = cd->pr_buf;
+	struct cyttsp5_sysinfo *si = bd->si;
+	int cur;
+	int value;
+
+	for (cur = 0; cur < si->num_btns; cur++) {
+		pr_buf[0] = 0;
+		if (si->xy_data[0] & (1 << cur))
+			value = 1;
+		else
+			value = 0;
+		snprintf(pr_buf, CY_MAX_PRBUF_SIZE, "btn_rec[%d]=0x", cur);
+		snprintf(pr_buf, CY_MAX_PRBUF_SIZE, "%s%X (%02X)",
+			pr_buf, value,
+			le16_to_cpu(si->xy_data[1 + cur * 2]));
+
+		parade_debug(dev, DEBUG_LEVEL_2, "%s: %s\n", __func__, pr_buf);
+	}
+}
+#endif
+
+/* read xy_data for all current CapSense button touches */
+static int cyttsp5_xy_worker(struct cyttsp5_btn_data *bd)
+{
+	struct cyttsp5_sysinfo *si = bd->si;
+
+	/* extract button press/release touch information */
+	if (si->num_btns > 0) {
+		cyttsp5_get_btn_touches(bd);
+#ifdef VERBOSE_DEBUG
+		/* log button press/release touch information */
+		cyttsp5_log_btn_data(bd);
+#endif
+	}
+
+	return 0;
+}
+
+static int cyttsp5_btn_attention(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_btn_data *bd = &cd->bd;
+	int rc;
+
+	if (bd->si->xy_mode[2] != bd->si->desc.btn_report_id)
+		return 0;
+
+	/* core handles handshake */
+	mutex_lock(&bd->btn_lock);
+	rc = cyttsp5_xy_worker(bd);
+	mutex_unlock(&bd->btn_lock);
+	if (rc < 0)
+		dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
+
+	return rc;
+}
+
+static int cyttsp5_startup_attention(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_btn_data *bd = &cd->bd;
+
+	mutex_lock(&bd->btn_lock);
+	cyttsp5_btn_lift_all(bd);
+	mutex_unlock(&bd->btn_lock);
+
+	return 0;
+}
+
+static int cyttsp5_btn_suspend_attention(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_btn_data *bd = &cd->bd;
+
+	mutex_lock(&bd->btn_lock);
+	cyttsp5_btn_lift_all(bd);
+	bd->is_suspended = true;
+	mutex_unlock(&bd->btn_lock);
+
+	pm_runtime_put(dev);
+
+	return 0;
+}
+
+static int cyttsp5_btn_resume_attention(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_btn_data *bd = &cd->bd;
+
+	pm_runtime_get(dev);
+
+	mutex_lock(&bd->btn_lock);
+	bd->is_suspended = false;
+	mutex_unlock(&bd->btn_lock);
+
+	return 0;
+}
+
+static int cyttsp5_btn_open(struct input_dev *input)
+{
+	struct device *dev = input->dev.parent;
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_btn_data *bd = &cd->bd;
+
+	pm_runtime_get_sync(dev);
+
+	mutex_lock(&bd->btn_lock);
+	bd->is_suspended = false;
+	mutex_unlock(&bd->btn_lock);
+
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: setup subscriptions\n", __func__);
+
+	/* set up touch call back */
+	_cyttsp5_subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_BTN_NAME,
+		cyttsp5_btn_attention, CY_MODE_OPERATIONAL);
+
+	/* set up startup call back */
+	_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_BTN_NAME,
+		cyttsp5_startup_attention, 0);
+
+	/* set up suspend call back */
+	_cyttsp5_subscribe_attention(dev, CY_ATTEN_SUSPEND, CYTTSP5_BTN_NAME,
+		cyttsp5_btn_suspend_attention, 0);
+
+	/* set up resume call back */
+	_cyttsp5_subscribe_attention(dev, CY_ATTEN_RESUME, CYTTSP5_BTN_NAME,
+		cyttsp5_btn_resume_attention, 0);
+
+	return 0;
+}
+
+static void cyttsp5_btn_close(struct input_dev *input)
+{
+	struct device *dev = input->dev.parent;
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_btn_data *bd = &cd->bd;
+
+	_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_BTN_NAME,
+		cyttsp5_btn_attention, CY_MODE_OPERATIONAL);
+
+	_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_BTN_NAME,
+		cyttsp5_startup_attention, 0);
+
+	_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_SUSPEND, CYTTSP5_BTN_NAME,
+		cyttsp5_btn_suspend_attention, 0);
+
+	_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_RESUME, CYTTSP5_BTN_NAME,
+		cyttsp5_btn_resume_attention, 0);
+
+	mutex_lock(&bd->btn_lock);
+	if (!bd->is_suspended) {
+		pm_runtime_put(dev);
+		bd->is_suspended = true;
+	}
+	mutex_unlock(&bd->btn_lock);
+}
+
+static int cyttsp5_setup_input_device(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_btn_data *bd = &cd->bd;
+	int i;
+	int rc;
+
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: Initialize event signals\n",
+		__func__);
+	__set_bit(EV_KEY, bd->input->evbit);
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: Number of buttons %d\n",
+		__func__, bd->si->num_btns);
+	for (i = 0; i < bd->si->num_btns; i++) {
+		parade_debug(dev, DEBUG_LEVEL_2, "%s: btn:%d keycode:%d\n",
+			__func__, i, bd->si->btn[i].key_code);
+		__set_bit(bd->si->btn[i].key_code, bd->input->keybit);
+	}
+
+	rc = input_register_device(bd->input);
+	if (rc < 0)
+		dev_err(dev, "%s: Error, failed register input device r=%d\n",
+			__func__, rc);
+	else
+		bd->input_device_registered = true;
+
+	return rc;
+}
+
+static int cyttsp5_setup_input_attention(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_btn_data *bd = &cd->bd;
+	int rc;
+
+	bd->si = _cyttsp5_request_sysinfo(dev);
+	if (!bd->si)
+		return -1;
+
+	rc = cyttsp5_setup_input_device(dev);
+
+	_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_BTN_NAME,
+		cyttsp5_setup_input_attention, 0);
+
+	return rc;
+}
+
+int cyttsp5_btn_probe(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_btn_data *bd = &cd->bd;
+	struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
+	struct cyttsp5_btn_platform_data *btn_pdata;
+	int rc = 0;
+
+	if (!pdata || !pdata->btn_pdata) {
+		dev_err(dev, "%s: Missing platform data\n", __func__);
+		rc = -ENODEV;
+		goto error_no_pdata;
+	}
+	btn_pdata = pdata->btn_pdata;
+
+	mutex_init(&bd->btn_lock);
+	bd->dev = dev;
+	bd->pdata = btn_pdata;
+
+	/* Create the input device and register it. */
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: Create the input device and register it\n",
+		__func__);
+	bd->input = input_allocate_device();
+	if (!bd->input) {
+		dev_err(dev, "%s: Error, failed to allocate input device\n",
+			__func__);
+		rc = -ENODEV;
+		goto error_alloc_failed;
+	}
+
+	if (bd->pdata->inp_dev_name)
+		bd->input->name = bd->pdata->inp_dev_name;
+	else
+		bd->input->name = CYTTSP5_BTN_NAME;
+	scnprintf(bd->phys, sizeof(bd->phys), "%s/input%d", dev_name(dev),
+			cd->phys_num++);
+	bd->input->phys = bd->phys;
+	bd->input->dev.parent = bd->dev;
+	bd->input->open = cyttsp5_btn_open;
+	bd->input->close = cyttsp5_btn_close;
+	input_set_drvdata(bd->input, bd);
+
+	/* get sysinfo */
+	bd->si = _cyttsp5_request_sysinfo(dev);
+
+	if (bd->si) {
+		rc = cyttsp5_setup_input_device(dev);
+		if (rc)
+			goto error_init_input;
+	} else {
+		dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
+			__func__, bd->si);
+		_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP,
+			CYTTSP5_BTN_NAME, cyttsp5_setup_input_attention, 0);
+	}
+
+	return 0;
+
+error_init_input:
+	input_free_device(bd->input);
+error_alloc_failed:
+error_no_pdata:
+	dev_err(dev, "%s failed.\n", __func__);
+	return rc;
+}
+
+int cyttsp5_btn_release(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_btn_data *bd = &cd->bd;
+
+	if (bd->input_device_registered) {
+		input_unregister_device(bd->input);
+	} else {
+		input_free_device(bd->input);
+		_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
+			CYTTSP5_BTN_NAME, cyttsp5_setup_input_attention, 0);
+	}
+
+	return 0;
+}
diff --git a/tp/cyttsp5/cyttsp5_core.c b/tp/cyttsp5/cyttsp5_core.c
new file mode 100644
index 0000000..60a686e
--- /dev/null
+++ b/tp/cyttsp5/cyttsp5_core.c
@@ -0,0 +1,6411 @@
+/*
+ * cyttsp5_core.c
+ * Parade TrueTouch(TM) Standard Product V5 Core Module.
+ * For use with Parade touchscreen controllers.
+ * Supported parts include:
+ * CYTMA5XX
+ * CYTMA448
+ * CYTMA445A
+ * CYTT21XXX
+ * CYTT31XXX
+ *
+ * Copyright (C) 2015 Parade Technologies
+ * Copyright (C) 2012-2015 Cypress Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
+ *
+ */
+
+#include "cyttsp5_regs.h"
+#include <linux/kthread.h>
+
+#define CY_CORE_STARTUP_RETRY_COUNT		3
+
+MODULE_FIRMWARE(CY_FW_FILE_NAME);
+
+static const char *cy_driver_core_name = CYTTSP5_CORE_NAME;
+static const char *cy_driver_core_version = CY_DRIVER_VERSION;
+static const char *cy_driver_core_date = CY_DRIVER_DATE;
+static bool cyttsp5_first_probe = true;
+static bool is_cyttsp5_probe_success;
+
+extern int init_tp_fm_info(u16 version_info_num, char* version_info_str, char *name);
+
+static const struct cyttsp5_bus_ops *cyttsp5_bus_ops_save;
+
+extern struct cyttsp5_loader_platform_data _cyttsp5_loader_platform_data_1;
+extern struct cyttsp5_loader_platform_data _cyttsp5_loader_platform_data_2;
+
+struct cyttsp5_hid_field {
+	int report_count;
+	int report_size;
+	int size; /* report_count * report_size */
+	int offset;
+	int data_type;
+	int logical_min;
+	int logical_max;
+	/* Usage Page (Hi 16 bit) + Usage (Lo 16 bit) */
+	u32 usage_page;
+	u32 collection_usage_pages[CY_HID_MAX_COLLECTIONS];
+	struct cyttsp5_hid_report *report;
+	bool record_field;
+};
+
+struct cyttsp5_hid_report {
+	u8 id;
+	u8 type;
+	int size;
+	struct cyttsp5_hid_field *fields[CY_HID_MAX_FIELDS];
+	int num_fields;
+	int record_field_index;
+	int header_size;
+	int record_size;
+	u32 usage_page;
+};
+
+struct atten_node {
+	struct list_head node;
+	char *id;
+	struct device *dev;
+
+	int (*func)(struct device *);
+	int mode;
+};
+
+struct param_node {
+	struct list_head node;
+	u8 id;
+	u32 value;
+	u8 size;
+};
+
+struct module_node {
+	struct list_head node;
+	struct cyttsp5_module *module;
+	void *data;
+};
+
+struct cyttsp5_hid_cmd {
+	u8 opcode;
+	u8 report_type;
+	union {
+		u8 report_id;
+		u8 power_state;
+	};
+	u8 has_data_register;
+	size_t write_length;
+	u8 *write_buf;
+	u8 *read_buf;
+	u8 wait_interrupt;
+	u8 reset_cmd;
+	u16 timeout_ms;
+};
+
+struct cyttsp5_hid_output {
+	u8 cmd_type;
+	u16 length;
+	u8 command_code;
+	size_t write_length;
+	u8 *write_buf;
+	u8 novalidate;
+	u8 reset_expected;
+	u16 timeout_ms;
+};
+
+#define SET_CMD_OPCODE(byte, opcode) SET_CMD_LOW(byte, opcode)
+#define SET_CMD_REPORT_TYPE(byte, type) SET_CMD_HIGH(byte, ((type) << 4))
+#define SET_CMD_REPORT_ID(byte, id) SET_CMD_LOW(byte, id)
+
+#define HID_OUTPUT_APP_COMMAND(command) \
+	.cmd_type = HID_OUTPUT_CMD_APP, \
+	.command_code = command
+
+#define HID_OUTPUT_BL_COMMAND(command) \
+	.cmd_type = HID_OUTPUT_CMD_BL, \
+	.command_code = command
+
+#ifdef VERBOSE_DEBUG
+void cyttsp5_pr_buf(struct device *dev, u8 *dptr, int size,
+		const char *data_name)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	u8 *pr_buf = cd->pr_buf;
+	int i, k;
+	const char fmt[] = "%02X ";
+	int max;
+
+	if (!size)
+		return;
+
+	max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED);
+
+	pr_buf[0] = 0;
+	for (i = k = 0; i < size && k < max; i++, k += 3)
+		scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, dptr[i]);
+
+	if (size) {
+		parade_debug(dev, DEBUG_LEVEL_2, "%s:  %s[0..%d]=%s%s\n",
+			__func__, data_name,
+			size - 1, pr_buf, size <= max ? "" : CY_PR_TRUNCATED);
+	} else {
+		parade_debug(dev, DEBUG_LEVEL_2, "%s:  %s[]\n",
+			__func__, data_name);
+	}
+}
+EXPORT_SYMBOL_GPL(cyttsp5_pr_buf);
+#endif
+
+#ifdef TTHE_TUNER_SUPPORT
+static int tthe_print(struct cyttsp5_core_data *cd, u8 *buf, int buf_len,
+		const u8 *data_name)
+{
+	int len = strlen(data_name);
+	int i, n;
+	u8 *p;
+	int remain;
+	u8 data_name_with_time_stamp[100];
+
+	if (cd->show_timestamp) {
+		sprintf(data_name_with_time_stamp, "[%u] %s",
+			jiffies_to_msecs(jiffies), data_name);
+		data_name = data_name_with_time_stamp;
+		len = strlen(data_name);
+	}
+
+	mutex_lock(&cd->tthe_lock);
+	if (!cd->tthe_buf)
+		goto exit;
+
+	if (cd->tthe_buf_len + (len + buf_len) > CY_MAX_PRBUF_SIZE)
+		goto exit;
+
+	if (len + buf_len == 0)
+		goto exit;
+
+	remain = CY_MAX_PRBUF_SIZE - cd->tthe_buf_len;
+	if (remain < len)
+		len = remain;
+
+	p = cd->tthe_buf + cd->tthe_buf_len;
+	memcpy(p, data_name, len);
+	cd->tthe_buf_len += len;
+	p += len;
+	remain -= len;
+
+	*p = 0;
+	for (i = 0; i < buf_len; i++) {
+		n = scnprintf(p, remain, "%02X ", buf[i]);
+		if (!n)
+			break;
+		p += n;
+		remain -= n;
+		cd->tthe_buf_len += n;
+	}
+
+	n = scnprintf(p, remain, "\n");
+	if (!n)
+		cd->tthe_buf[cd->tthe_buf_len] = 0;
+	cd->tthe_buf_len += n;
+	wake_up(&cd->wait_q);
+exit:
+	mutex_unlock(&cd->tthe_lock);
+	return 0;
+}
+
+static int _cyttsp5_request_tthe_print(struct device *dev, u8 *buf,
+		int buf_len, const u8 *data_name)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	return tthe_print(cd, buf, buf_len, data_name);
+}
+#endif
+
+/*
+ * cyttsp5_platform_detect_read()
+ *
+ * This function is passed to platform detect
+ * function to perform a read operation
+ */
+static int cyttsp5_platform_detect_read(struct device *dev, void *buf, int size)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	return cyttsp5_adap_read_default(cd, buf, size);
+}
+
+/* Must be called with cd->hid_report_lock acquired */
+static struct cyttsp5_hid_report *cyttsp5_get_hid_report_(
+		struct cyttsp5_core_data *cd, u8 report_type, u8 report_id,
+		bool create)
+{
+	struct cyttsp5_hid_report *report = NULL;
+	int i;
+
+	/* Look for created reports */
+	for (i = 0; i < cd->num_hid_reports; i++) {
+		if (cd->hid_reports[i]->type == report_type
+				&& cd->hid_reports[i]->id == report_id) {
+			return cd->hid_reports[i];
+		}
+	}
+
+	/* Create a new report */
+	if (create && cd->num_hid_reports < CY_HID_MAX_REPORTS) {
+		report = kzalloc(sizeof(struct cyttsp5_hid_report),
+				GFP_KERNEL);
+		if (!report)
+			return NULL;
+
+		report->type = report_type;
+		report->id = report_id;
+		cd->hid_reports[cd->num_hid_reports++] = report;
+	}
+
+	return report;
+}
+
+/* Must be called with cd->hid_report_lock acquired */
+static void cyttsp5_free_hid_reports_(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_hid_report *report;
+	int i, j;
+
+	for (i = 0; i < cd->num_hid_reports; i++) {
+		report = cd->hid_reports[i];
+		for (j = 0; j < report->num_fields; j++)
+			kfree(report->fields[j]);
+		kfree(report);
+		cd->hid_reports[i] = NULL;
+	}
+
+	cd->num_hid_reports = 0;
+}
+
+static void cyttsp5_free_hid_reports(struct cyttsp5_core_data *cd)
+{
+	mutex_lock(&cd->hid_report_lock);
+	cyttsp5_free_hid_reports_(cd);
+	mutex_unlock(&cd->hid_report_lock);
+}
+
+/* Must be called with cd->hid_report_lock acquired */
+static struct cyttsp5_hid_field *cyttsp5_create_hid_field_(
+		struct cyttsp5_hid_report *report)
+{
+	struct cyttsp5_hid_field *field;
+
+	if (!report)
+		return NULL;
+
+	if (report->num_fields == CY_HID_MAX_FIELDS)
+		return NULL;
+
+	field = kzalloc(sizeof(struct cyttsp5_hid_field), GFP_KERNEL);
+	if (!field)
+		return NULL;
+
+	field->report = report;
+
+	report->fields[report->num_fields++] = field;
+
+	return field;
+}
+
+static int cyttsp5_add_parameter(struct cyttsp5_core_data *cd,
+		u8 param_id, u32 param_value, u8 param_size)
+{
+	struct param_node *param, *param_new;
+
+	/* Check if parameter exists */
+	spin_lock(&cd->spinlock);
+	list_for_each_entry(param, &cd->param_list, node) {
+		if (param->id == param_id) {
+			/* Update parameter */
+			param->value = param_value;
+			parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: Update parameter id:%d value:%d size:%d\n",
+				 __func__, param_id, param_value, param_size);
+			goto exit_unlock;
+		}
+	}
+	spin_unlock(&cd->spinlock);
+
+	param_new = kzalloc(sizeof(*param_new), GFP_KERNEL);
+	if (!param_new)
+		return -ENOMEM;
+
+	param_new->id = param_id;
+	param_new->value = param_value;
+	param_new->size = param_size;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: Add parameter id:%d value:%d size:%d\n",
+		__func__, param_id, param_value, param_size);
+
+	spin_lock(&cd->spinlock);
+	list_add(&param_new->node, &cd->param_list);
+exit_unlock:
+	spin_unlock(&cd->spinlock);
+
+	return 0;
+}
+
+int request_exclusive(struct cyttsp5_core_data *cd, void *ownptr,
+		int timeout_ms)
+{
+	int t = msecs_to_jiffies(timeout_ms);
+	bool with_timeout = (timeout_ms != 0);
+
+	mutex_lock(&cd->system_lock);
+	if (!cd->exclusive_dev && cd->exclusive_waits == 0) {
+		cd->exclusive_dev = ownptr;
+		goto exit;
+	}
+
+	cd->exclusive_waits++;
+wait:
+	mutex_unlock(&cd->system_lock);
+	if (with_timeout) {
+		t = wait_event_timeout(cd->wait_q, !cd->exclusive_dev, t);
+		if (IS_TMO(t)) {
+			dev_err(cd->dev, "%s: tmo waiting exclusive access\n",
+				__func__);
+			return -ETIME;
+		}
+	} else {
+		wait_event(cd->wait_q, !cd->exclusive_dev);
+	}
+	mutex_lock(&cd->system_lock);
+	if (cd->exclusive_dev)
+		goto wait;
+	cd->exclusive_dev = ownptr;
+	cd->exclusive_waits--;
+exit:
+	mutex_unlock(&cd->system_lock);
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: request_exclusive ok=%p\n",
+		__func__, ownptr);
+
+	return 0;
+}
+
+static int release_exclusive_(struct cyttsp5_core_data *cd, void *ownptr)
+{
+	if (cd->exclusive_dev != ownptr)
+		return -EINVAL;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: exclusive_dev %p freed\n",
+		__func__, cd->exclusive_dev);
+	cd->exclusive_dev = NULL;
+	wake_up(&cd->wait_q);
+	return 0;
+}
+
+/*
+ * returns error if was not owned
+ */
+int release_exclusive(struct cyttsp5_core_data *cd, void *ownptr)
+{
+	int rc;
+
+	mutex_lock(&cd->system_lock);
+	rc = release_exclusive_(cd, ownptr);
+	mutex_unlock(&cd->system_lock);
+
+	return rc;
+}
+
+static int cyttsp5_hid_exec_cmd_(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_cmd *hid_cmd)
+{
+	int rc;
+	u8 *cmd;
+	u8 cmd_length;
+	u8 cmd_offset = 0;
+
+	cmd_length = 2 /* command register */
+		+ 2    /* command */
+		+ (hid_cmd->report_id >= 0XF ? 1 : 0)   /* Report ID */
+		+ (hid_cmd->has_data_register ? 2 : 0)	/* Data register */
+		+ hid_cmd->write_length;                /* Data length */
+
+	cmd = kzalloc(cmd_length, GFP_KERNEL);
+	if (!cmd)
+		return -ENOMEM;
+
+	/* Set Command register */
+	memcpy(&cmd[cmd_offset], &cd->hid_desc.command_register,
+			sizeof(cd->hid_desc.command_register));
+	cmd_offset += sizeof(cd->hid_desc.command_register);
+
+	/* Set Command */
+	SET_CMD_REPORT_TYPE(cmd[cmd_offset], hid_cmd->report_type);
+
+	if (hid_cmd->report_id >= 0XF)
+		SET_CMD_REPORT_ID(cmd[cmd_offset], 0xF);
+	else
+		SET_CMD_REPORT_ID(cmd[cmd_offset], hid_cmd->report_id);
+	cmd_offset++;
+
+	SET_CMD_OPCODE(cmd[cmd_offset], hid_cmd->opcode);
+	cmd_offset++;
+
+	if (hid_cmd->report_id >= 0XF) {
+		cmd[cmd_offset] = hid_cmd->report_id;
+		cmd_offset++;
+	}
+
+	/* Set Data register */
+	if (hid_cmd->has_data_register) {
+		memcpy(&cmd[cmd_offset], &cd->hid_desc.data_register,
+				sizeof(cd->hid_desc.data_register));
+		cmd_offset += sizeof(cd->hid_desc.data_register);
+	}
+
+	/* Set Data */
+	if (hid_cmd->write_length && hid_cmd->write_buf) {
+		memcpy(&cmd[cmd_offset], hid_cmd->write_buf,
+				hid_cmd->write_length);
+		cmd_offset += hid_cmd->write_length;
+	}
+
+	cyttsp5_pr_buf(cd->dev, cmd, cmd_length, "exec_command");
+
+	rc = cyttsp5_adap_write_read_specific(cd, cmd_length, cmd,
+			hid_cmd->read_buf);
+	if (rc)
+		dev_err(cd->dev, "%s: Fail cyttsp5_adap_transfer\n", __func__);
+
+	kfree(cmd);
+	return rc;
+}
+
+static int cyttsp5_hid_exec_cmd_and_wait_(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_cmd *hid_cmd)
+{
+	int rc;
+	int t;
+	u16 timeout_ms;
+	int *cmd_state;
+
+	if (hid_cmd->reset_cmd)
+		cmd_state = &cd->hid_reset_cmd_state;
+	else
+		cmd_state = &cd->hid_cmd_state;
+
+	if (hid_cmd->wait_interrupt) {
+		mutex_lock(&cd->system_lock);
+		*cmd_state = 1;
+		mutex_unlock(&cd->system_lock);
+	}
+
+	rc = cyttsp5_hid_exec_cmd_(cd, hid_cmd);
+	if (rc) {
+		if (hid_cmd->wait_interrupt)
+			goto error;
+
+		goto exit;
+	}
+
+	if (!hid_cmd->wait_interrupt)
+		goto exit;
+
+	if (hid_cmd->timeout_ms)
+		timeout_ms = hid_cmd->timeout_ms;
+	else
+		timeout_ms = CY_HID_RESET_TIMEOUT;
+
+	t = wait_event_timeout(cd->wait_q, (*cmd_state == 0),
+			msecs_to_jiffies(timeout_ms));
+	if (IS_TMO(t)) {
+		dev_err(cd->dev, "%s: HID output cmd execution timed out\n",
+			__func__);
+		rc = -ETIME;
+		goto error;
+	}
+
+	goto exit;
+
+error:
+	mutex_lock(&cd->system_lock);
+	*cmd_state = 0;
+	mutex_unlock(&cd->system_lock);
+
+exit:
+	return rc;
+}
+
+static int cyttsp5_hid_cmd_reset_(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_hid_cmd hid_cmd = {
+		.opcode = HID_CMD_RESET,
+		.wait_interrupt = 1,
+		.reset_cmd = 1,
+		.timeout_ms = CY_HID_RESET_TIMEOUT,
+	};
+
+	return cyttsp5_hid_exec_cmd_and_wait_(cd, &hid_cmd);
+}
+
+static int cyttsp5_hid_cmd_reset(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_cmd_reset_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int cyttsp5_hid_cmd_set_power_(struct cyttsp5_core_data *cd,
+		u8 power_state)
+{
+	int rc;
+	struct cyttsp5_hid_cmd hid_cmd = {
+		.opcode = HID_CMD_SET_POWER,
+		.wait_interrupt = 1,
+		.timeout_ms = CY_HID_SET_POWER_TIMEOUT,
+	};
+	hid_cmd.power_state = power_state;
+
+	rc =  cyttsp5_hid_exec_cmd_and_wait_(cd, &hid_cmd);
+	if (rc) {
+		dev_err(cd->dev, "%s: Failed to set power to state:%d\n",
+				__func__, power_state);
+	       return rc;
+	}
+
+	/* validate */
+	if ((cd->response_buf[2] != HID_RESPONSE_REPORT_ID)
+			|| ((cd->response_buf[3] & 0x3) != power_state)
+			|| ((cd->response_buf[4] & 0xF) != HID_CMD_SET_POWER))
+		rc = -EINVAL;
+
+	return rc;
+}
+
+static int cyttsp5_hid_cmd_set_power(struct cyttsp5_core_data *cd,
+		u8 power_state)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_cmd_set_power_(cd, power_state);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static const u16 crc_table[16] = {
+	0x0000, 0x1021, 0x2042, 0x3063,
+	0x4084, 0x50a5, 0x60c6, 0x70e7,
+	0x8108, 0x9129, 0xa14a, 0xb16b,
+	0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+};
+
+static u16 _cyttsp5_compute_crc(u8 *buf, u32 size)
+{
+	u16 remainder = 0xFFFF;
+	u16 xor_mask = 0x0000;
+	u32 index;
+	u32 byte_value;
+	u32 table_index;
+	u32 crc_bit_width = sizeof(u16) * 8;
+
+	/* Divide the message by polynomial, via the table. */
+	for (index = 0; index < size; index++) {
+		byte_value = buf[index];
+		table_index = ((byte_value >> 4) & 0x0F)
+			^ (remainder >> (crc_bit_width - 4));
+		remainder = crc_table[table_index] ^ (remainder << 4);
+		table_index = (byte_value & 0x0F)
+			^ (remainder >> (crc_bit_width - 4));
+		remainder = crc_table[table_index] ^ (remainder << 4);
+	}
+
+	/* Perform the final remainder CRC. */
+	return remainder ^ xor_mask;
+}
+
+static int cyttsp5_hid_output_validate_bl_response(
+		struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_output *hid_output)
+{
+	u16 size;
+	u16 crc;
+	u8 status;
+
+	size = get_unaligned_le16(&cd->response_buf[0]);
+
+	if (hid_output->reset_expected && !size)
+		return 0;
+
+	if (cd->response_buf[HID_OUTPUT_RESPONSE_REPORT_OFFSET]
+			!= HID_BL_RESPONSE_REPORT_ID) {
+		dev_err(cd->dev, "%s: HID output response, wrong report_id\n",
+			__func__);
+		return -EPROTO;
+	}
+
+	if (cd->response_buf[4] != HID_OUTPUT_BL_SOP) {
+		dev_err(cd->dev, "%s: HID output response, wrong SOP\n",
+			__func__);
+		return -EPROTO;
+	}
+
+	if (cd->response_buf[size - 1] != HID_OUTPUT_BL_EOP) {
+		dev_err(cd->dev, "%s: HID output response, wrong EOP\n",
+			__func__);
+		return -EPROTO;
+	}
+
+	crc = _cyttsp5_compute_crc(&cd->response_buf[4], size - 7);
+	if (cd->response_buf[size - 3] != LOW_BYTE(crc)
+			|| cd->response_buf[size - 2] != HI_BYTE(crc)) {
+		dev_err(cd->dev, "%s: HID output response, wrong CRC 0x%X\n",
+			__func__, crc);
+		return -EPROTO;
+	}
+
+	status = cd->response_buf[5];
+	if (status) {
+		dev_err(cd->dev, "%s: HID output response, ERROR:%d\n",
+			__func__, status);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+static int cyttsp5_hid_output_validate_app_response(
+		struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_output *hid_output)
+{
+	int command_code;
+	u16 size;
+
+	size = get_unaligned_le16(&cd->response_buf[0]);
+
+	if (hid_output->reset_expected && !size)
+		return 0;
+
+	if (cd->response_buf[HID_OUTPUT_RESPONSE_REPORT_OFFSET]
+			!= HID_APP_RESPONSE_REPORT_ID) {
+		dev_err(cd->dev, "%s: HID output response, wrong report_id\n",
+			__func__);
+		return -EPROTO;
+	}
+
+	command_code = cd->response_buf[HID_OUTPUT_RESPONSE_CMD_OFFSET]
+		& HID_OUTPUT_RESPONSE_CMD_MASK;
+	if (command_code != hid_output->command_code) {
+		dev_err(cd->dev,
+			"%s: HID output response, wrong command_code:%X\n",
+			__func__, command_code);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+static void cyttsp5_check_set_parameter(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_output *hid_output, bool raw)
+{
+	u8 *param_buf;
+	u32 param_value = 0;
+	u8 param_size;
+	u8 param_id;
+	int i = 0;
+
+	if (!(cd->cpdata->flags & CY_CORE_FLAG_RESTORE_PARAMETERS))
+		return;
+
+	/* Check command input for Set Parameter command */
+	if (raw && hid_output->length >= 10 && hid_output->length <= 13
+			&& !memcmp(&hid_output->write_buf[0],
+					&cd->hid_desc.output_register,
+					sizeof(cd->hid_desc.output_register))
+			&& hid_output->write_buf[4] ==
+					HID_APP_OUTPUT_REPORT_ID
+			&& hid_output->write_buf[6] ==
+					HID_OUTPUT_SET_PARAM)
+		param_buf = &hid_output->write_buf[7];
+	else if (!raw && hid_output->cmd_type == HID_OUTPUT_CMD_APP
+			&& hid_output->command_code == HID_OUTPUT_SET_PARAM
+			&& hid_output->write_length >= 3
+			&& hid_output->write_length <= 6)
+		param_buf = &hid_output->write_buf[0];
+	else
+		return;
+
+	/* Get parameter ID, size and value */
+	param_id = param_buf[0];
+	param_size = param_buf[1];
+	if (param_size > 4) {
+		dev_err(cd->dev, "%s: Invalid parameter size\n", __func__);
+		return;
+	}
+
+	param_buf = &param_buf[2];
+	while (i < param_size)
+		param_value += *(param_buf++) << (8 * i++);
+
+	/* Check command response for Set Parameter command */
+	if (cd->response_buf[2] != HID_APP_RESPONSE_REPORT_ID
+			|| (cd->response_buf[4] & HID_OUTPUT_CMD_MASK) !=
+				HID_OUTPUT_SET_PARAM
+			|| cd->response_buf[5] != param_id
+			|| cd->response_buf[6] != param_size) {
+		dev_err(cd->dev, "%s: Set Parameter command not successful\n",
+			__func__);
+		return;
+	}
+
+	cyttsp5_add_parameter(cd, param_id, param_value, param_size);
+}
+
+static void cyttsp5_check_command(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_output *hid_output, bool raw)
+{
+	cyttsp5_check_set_parameter(cd, hid_output, raw);
+}
+
+static int cyttsp5_hid_output_validate_response(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_output *hid_output)
+{
+	if (hid_output->cmd_type == HID_OUTPUT_CMD_BL)
+		return cyttsp5_hid_output_validate_bl_response(cd, hid_output);
+
+	return cyttsp5_hid_output_validate_app_response(cd, hid_output);
+
+}
+
+static int cyttsp5_hid_send_output_user_(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_output *hid_output)
+{
+	int rc;
+
+	if (!hid_output->length || !hid_output->write_buf)
+		return -EINVAL;
+
+	rc = cyttsp5_adap_write_read_specific(cd, hid_output->length,
+			hid_output->write_buf, NULL);
+	if (rc)
+		dev_err(cd->dev, "%s: Fail cyttsp5_adap_transfer\n", __func__);
+
+	return rc;
+}
+
+static int cyttsp5_hid_send_output_user_and_wait_(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_output *hid_output)
+{
+	int rc;
+	int t;
+
+	mutex_lock(&cd->system_lock);
+	cd->hid_cmd_state = HID_OUTPUT_USER_CMD + 1;
+	mutex_unlock(&cd->system_lock);
+
+	rc = cyttsp5_hid_send_output_user_(cd, hid_output);
+	if (rc)
+		goto error;
+
+	t = wait_event_timeout(cd->wait_q, (cd->hid_cmd_state == 0),
+			msecs_to_jiffies(CY_HID_OUTPUT_USER_TIMEOUT));
+	if (IS_TMO(t)) {
+		dev_err(cd->dev, "%s: HID output cmd execution timed out\n",
+			__func__);
+		rc = -ETIME;
+		goto error;
+	}
+
+	cyttsp5_check_command(cd, hid_output, true);
+
+	goto exit;
+
+error:
+	mutex_lock(&cd->system_lock);
+	cd->hid_cmd_state = 0;
+	mutex_unlock(&cd->system_lock);
+
+exit:
+	return rc;
+}
+
+static int cyttsp5_hid_send_output_(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_output *hid_output)
+{
+	int rc;
+	u8 *cmd;
+	u16 length;
+	u8 report_id;
+	u8 cmd_offset = 0;
+	u16 crc;
+	u8 cmd_allocated = 0;
+
+	switch (hid_output->cmd_type) {
+	case HID_OUTPUT_CMD_APP:
+		report_id = HID_APP_OUTPUT_REPORT_ID;
+		length = 5;
+		break;
+	case HID_OUTPUT_CMD_BL:
+		report_id = HID_BL_OUTPUT_REPORT_ID;
+		length = 11 /* 5 + SOP + LEN(2) + CRC(2) + EOP */;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	length += hid_output->write_length;
+
+	if (length + 2 > CYTTSP5_PREALLOCATED_CMD_BUFFER) {
+		cmd = kzalloc(length + 2, GFP_KERNEL);
+		if (!cmd)
+			return -ENOMEM;
+		cmd_allocated = 1;
+	} else {
+		cmd = cd->cmd_buf;
+	}
+
+	/* Set Output register */
+	memcpy(&cmd[cmd_offset], &cd->hid_desc.output_register,
+			sizeof(cd->hid_desc.output_register));
+	cmd_offset += sizeof(cd->hid_desc.output_register);
+
+	cmd[cmd_offset++] = LOW_BYTE(length);
+	cmd[cmd_offset++] = HI_BYTE(length);
+	cmd[cmd_offset++] = report_id;
+	cmd[cmd_offset++] = 0x0; /* reserved */
+	if (hid_output->cmd_type == HID_OUTPUT_CMD_BL)
+		cmd[cmd_offset++] = HID_OUTPUT_BL_SOP;
+	cmd[cmd_offset++] = hid_output->command_code;
+
+	/* Set Data Length for bootloader */
+	if (hid_output->cmd_type == HID_OUTPUT_CMD_BL) {
+		cmd[cmd_offset++] = LOW_BYTE(hid_output->write_length);
+		cmd[cmd_offset++] = HI_BYTE(hid_output->write_length);
+	}
+	/* Set Data */
+	if (hid_output->write_length && hid_output->write_buf) {
+		memcpy(&cmd[cmd_offset], hid_output->write_buf,
+				hid_output->write_length);
+		cmd_offset += hid_output->write_length;
+	}
+	if (hid_output->cmd_type == HID_OUTPUT_CMD_BL) {
+		crc = _cyttsp5_compute_crc(&cmd[6],
+				hid_output->write_length + 4);
+		cmd[cmd_offset++] = LOW_BYTE(crc);
+		cmd[cmd_offset++] = HI_BYTE(crc);
+		cmd[cmd_offset++] = HID_OUTPUT_BL_EOP;
+	}
+
+	cyttsp5_pr_buf(cd->dev, cmd, length + 2, "command");
+	rc = cyttsp5_adap_write_read_specific(cd, length + 2, cmd, NULL);
+	if (rc)
+		dev_err(cd->dev, "%s: Fail cyttsp5_adap_transfer\n", __func__);
+
+	if (cmd_allocated)
+		kfree(cmd);
+	return rc;
+}
+
+static int cyttsp5_hid_send_output_and_wait_(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_output *hid_output)
+{
+	int rc;
+	int t;
+#ifdef VERBOSE_DEBUG
+	u16 size;
+#endif
+	u16 timeout_ms;
+
+	mutex_lock(&cd->system_lock);
+	cd->hid_cmd_state = hid_output->command_code + 1;
+	mutex_unlock(&cd->system_lock);
+
+	if (hid_output->timeout_ms)
+		timeout_ms = hid_output->timeout_ms;
+	else
+		timeout_ms = CY_HID_OUTPUT_TIMEOUT;
+
+	rc = cyttsp5_hid_send_output_(cd, hid_output);
+	if (rc)
+		goto error;
+
+
+	t = wait_event_timeout(cd->wait_q, (cd->hid_cmd_state == 0),
+			msecs_to_jiffies(timeout_ms));
+	if (IS_TMO(t)) {
+		dev_err(cd->dev, "%s: HID output cmd execution timed out\n",
+			__func__);
+		rc = -ETIME;
+		goto error;
+	}
+
+	if (!hid_output->novalidate)
+		rc = cyttsp5_hid_output_validate_response(cd, hid_output);
+
+	cyttsp5_check_command(cd, hid_output, false);
+
+#ifdef VERBOSE_DEBUG
+	size = get_unaligned_le16(&cd->response_buf[0]);
+	cyttsp5_pr_buf(cd->dev, cd->response_buf, size, "return_buf");
+#endif
+
+	goto exit;
+
+error:
+	mutex_lock(&cd->system_lock);
+	cd->hid_cmd_state = 0;
+	mutex_unlock(&cd->system_lock);
+exit:
+	return rc;
+}
+
+static int cyttsp5_hid_output_null_(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_NULL),
+	};
+
+	return cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+}
+
+static int cyttsp5_hid_output_null(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_null_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int cyttsp5_hid_output_start_bootloader_(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_START_BOOTLOADER),
+		.timeout_ms = CY_HID_OUTPUT_START_BOOTLOADER_TIMEOUT,
+		.reset_expected = 1,
+	};
+
+	return cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+}
+
+static int cyttsp5_hid_output_start_bootloader(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_start_bootloader_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_start_bl(struct device *dev, int protect)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_start_bootloader(cd);
+
+	return cyttsp5_hid_output_start_bootloader_(cd);
+}
+
+static void cyttsp5_si_get_cydata(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_cydata *cydata = &cd->sysinfo.cydata;
+	struct cyttsp5_cydata_dev *cydata_dev =
+		(struct cyttsp5_cydata_dev *)
+		&cd->response_buf[HID_SYSINFO_CYDATA_OFFSET];
+
+	cydata->pip_ver_major = cydata_dev->pip_ver_major;
+	cydata->pip_ver_minor = cydata_dev->pip_ver_minor;
+	cydata->bl_ver_major = cydata_dev->bl_ver_major;
+	cydata->bl_ver_minor = cydata_dev->bl_ver_minor;
+	cydata->fw_ver_major = cydata_dev->fw_ver_major;
+	cydata->fw_ver_minor = cydata_dev->fw_ver_minor;
+
+	cydata->fw_pid = get_unaligned_le16(&cydata_dev->fw_pid);
+	cydata->fw_ver_conf = get_unaligned_le16(&cydata_dev->fw_ver_conf);
+	cydata->post_code = get_unaligned_le16(&cydata_dev->post_code);
+	cydata->revctrl = get_unaligned_le32(&cydata_dev->revctrl);
+	cydata->jtag_id_l = get_unaligned_le16(&cydata_dev->jtag_si_id_l);
+	cydata->jtag_id_h = get_unaligned_le16(&cydata_dev->jtag_si_id_h);
+
+	memcpy(cydata->mfg_id, cydata_dev->mfg_id, CY_NUM_MFGID);
+
+	cyttsp5_pr_buf(cd->dev, (u8 *)cydata_dev,
+			sizeof(struct cyttsp5_cydata_dev), "sysinfo_cydata");
+}
+
+static void cyttsp5_si_get_sensing_conf_data(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_sensing_conf_data *scd = &cd->sysinfo.sensing_conf_data;
+	struct cyttsp5_sensing_conf_data_dev *scd_dev =
+		(struct cyttsp5_sensing_conf_data_dev *)
+		&cd->response_buf[HID_SYSINFO_SENSING_OFFSET];
+
+	scd->electrodes_x = scd_dev->electrodes_x;
+	scd->electrodes_y = scd_dev->electrodes_y;
+	scd->origin_x = scd_dev->origin_x;
+	scd->origin_y = scd_dev->origin_y;
+
+	/* PIP 1.4 (001-82649 *Q) add X_IS_TX bit in X_ORG */
+	if (scd->origin_x & 0x02) {
+		scd->tx_num = scd->electrodes_x;
+		scd->rx_num = scd->electrodes_y;
+	} else {
+		scd->tx_num = scd->electrodes_y;
+		scd->rx_num = scd->electrodes_x;
+	}
+
+	scd->panel_id = scd_dev->panel_id;
+	scd->btn = scd_dev->btn;
+	scd->scan_mode = scd_dev->scan_mode;
+	scd->max_tch = scd_dev->max_num_of_tch_per_refresh_cycle;
+
+	scd->res_x = get_unaligned_le16(&scd_dev->res_x);
+	scd->res_y = get_unaligned_le16(&scd_dev->res_y);
+	scd->max_z = get_unaligned_le16(&scd_dev->max_z);
+	scd->len_x = get_unaligned_le16(&scd_dev->len_x);
+	scd->len_y = get_unaligned_le16(&scd_dev->len_y);
+
+	cyttsp5_pr_buf(cd->dev, (u8 *)scd_dev,
+			sizeof(struct cyttsp5_sensing_conf_data_dev),
+			"sensing_conf_data");
+}
+
+static int cyttsp5_si_setup(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_sysinfo *si = &cd->sysinfo;
+	int max_tch = si->sensing_conf_data.max_tch;
+
+	if (!si->xy_data)
+		si->xy_data = kzalloc(max_tch * si->desc.tch_record_size,
+				GFP_KERNEL);
+	if (!si->xy_data)
+		return -ENOMEM;
+
+	if (!si->xy_mode)
+		si->xy_mode = kzalloc(si->desc.tch_header_size, GFP_KERNEL);
+	if (!si->xy_mode) {
+		kfree(si->xy_data);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int cyttsp5_si_get_btn_data(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_sysinfo *si = &cd->sysinfo;
+	int num_btns = 0;
+	int num_defined_keys;
+	u16 *key_table;
+	int btn;
+	int i;
+	int rc = 0;
+	unsigned int btns = cd->response_buf[HID_SYSINFO_BTN_OFFSET]
+		& HID_SYSINFO_BTN_MASK;
+	size_t btn_keys_size;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: get btn data\n", __func__);
+
+	for (i = 0; i < HID_SYSINFO_MAX_BTN; i++) {
+		if (btns & (1 << i))
+			num_btns++;
+	}
+	si->num_btns = num_btns;
+
+	if (num_btns) {
+		btn_keys_size = num_btns * sizeof(struct cyttsp5_btn);
+		if (!si->btn)
+			si->btn = kzalloc(btn_keys_size, GFP_KERNEL);
+		if (!si->btn)
+			return -ENOMEM;
+
+		if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS] == NULL)
+			num_defined_keys = 0;
+		else if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS]->data == NULL)
+			num_defined_keys = 0;
+		else
+			num_defined_keys = cd->cpdata->sett
+				[CY_IC_GRPNUM_BTN_KEYS]->size;
+
+		for (btn = 0; btn < num_btns && btn < num_defined_keys; btn++) {
+			key_table = (u16 *)cd->cpdata->sett
+				[CY_IC_GRPNUM_BTN_KEYS]->data;
+			si->btn[btn].key_code = key_table[btn];
+			si->btn[btn].enabled = true;
+		}
+		for (; btn < num_btns; btn++) {
+			si->btn[btn].key_code = KEY_RESERVED;
+			si->btn[btn].enabled = true;
+		}
+
+		return rc;
+	}
+
+	kfree(si->btn);
+	si->btn = NULL;
+	return rc;
+}
+
+static void cyttsp5_si_put_log_data(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_sysinfo *si = &cd->sysinfo;
+	struct cyttsp5_cydata *cydata = &si->cydata;
+	struct cyttsp5_sensing_conf_data *scd = &si->sensing_conf_data;
+	int i;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: pip_ver_major =0x%02X (%d)\n",
+		__func__, cydata->pip_ver_major, cydata->pip_ver_major);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: pip_ver_minor =0x%02X (%d)\n",
+		__func__, cydata->pip_ver_minor, cydata->pip_ver_minor);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: fw_pid =0x%04X (%d)\n",
+		__func__, cydata->fw_pid, cydata->fw_pid);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: fw_ver_major =0x%02X (%d)\n",
+		__func__, cydata->fw_ver_major, cydata->fw_ver_major);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: fw_ver_minor =0x%02X (%d)\n",
+		__func__, cydata->fw_ver_minor, cydata->fw_ver_minor);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: revctrl =0x%08X (%d)\n",
+		__func__, cydata->revctrl, cydata->revctrl);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: fw_ver_conf =0x%04X (%d)\n",
+		__func__, cydata->fw_ver_conf, cydata->fw_ver_conf);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: bl_ver_major =0x%02X (%d)\n",
+		__func__, cydata->bl_ver_major, cydata->bl_ver_major);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: bl_ver_minor =0x%02X (%d)\n",
+		__func__, cydata->bl_ver_minor, cydata->bl_ver_minor);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: jtag_id_h =0x%04X (%d)\n",
+		__func__, cydata->jtag_id_h, cydata->jtag_id_h);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: jtag_id_l =0x%04X (%d)\n",
+		__func__, cydata->jtag_id_l, cydata->jtag_id_l);
+	for (i = 0; i < CY_NUM_MFGID; i++)
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: mfg_id[%d] =0x%02X (%d)\n",
+		__func__, i, cydata->mfg_id[i], cydata->mfg_id[i]);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: post_code =0x%04X (%d)\n",
+		__func__, cydata->post_code, cydata->post_code);
+
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: electrodes_x =0x%02X (%d)\n",
+		__func__, scd->electrodes_x, scd->electrodes_x);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: electrodes_y =0x%02X (%d)\n",
+		__func__, scd->electrodes_y, scd->electrodes_y);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: len_x =0x%04X (%d)\n",
+		__func__, scd->len_x, scd->len_x);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: len_y =0x%04X (%d)\n",
+		__func__, scd->len_y, scd->len_y);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: res_x =0x%04X (%d)\n",
+		__func__, scd->res_x, scd->res_x);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: res_y =0x%04X (%d)\n",
+		__func__, scd->res_y, scd->res_y);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: max_z =0x%04X (%d)\n",
+		__func__, scd->max_z, scd->max_z);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: origin_x =0x%02X (%d)\n",
+		__func__, scd->origin_x, scd->origin_x);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: origin_y =0x%02X (%d)\n",
+		__func__, scd->origin_y, scd->origin_y);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: panel_id =0x%02X (%d)\n",
+		__func__, scd->panel_id, scd->panel_id);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: btn =0x%02X (%d)\n",
+		__func__, scd->btn, scd->btn);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: scan_mode =0x%02X (%d)\n",
+		__func__, scd->scan_mode, scd->scan_mode);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: max_num_of_tch_per_refresh_cycle =0x%02X (%d)\n",
+		__func__, scd->max_tch, scd->max_tch);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: xy_mode =%p\n",
+		__func__, si->xy_mode);
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: xy_data =%p\n",
+		__func__, si->xy_data);
+}
+
+static int cyttsp5_get_sysinfo_regs(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_sysinfo *si = &cd->sysinfo;
+	int rc;
+
+	rc = cyttsp5_si_get_btn_data(cd);
+	if (rc < 0)
+		return rc;
+
+	cyttsp5_si_get_cydata(cd);
+
+	cyttsp5_si_get_sensing_conf_data(cd);
+
+	cyttsp5_si_setup(cd);
+
+	cyttsp5_si_put_log_data(cd);
+
+	si->ready = true;
+	return rc;
+}
+
+static void cyttsp5_free_si_ptrs(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_sysinfo *si = &cd->sysinfo;
+
+	kfree(si->btn);
+	kfree(si->xy_mode);
+	kfree(si->xy_data);
+}
+
+static int cyttsp5_hid_output_get_sysinfo_(struct cyttsp5_core_data *cd)
+{
+	int rc;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_GET_SYSINFO),
+		.timeout_ms = CY_HID_OUTPUT_GET_SYSINFO_TIMEOUT,
+	};
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	rc = cyttsp5_get_sysinfo_regs(cd);
+	if (rc)
+		cyttsp5_free_si_ptrs(cd);
+
+	return rc;
+}
+
+static int cyttsp5_hid_output_get_sysinfo(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_get_sysinfo_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int cyttsp5_hid_output_suspend_scanning_(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_SUSPEND_SCANNING),
+	};
+
+	return cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+}
+
+static int cyttsp5_hid_output_suspend_scanning(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_suspend_scanning_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_suspend_scanning(struct device *dev,
+		int protect)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_suspend_scanning(cd);
+
+	return cyttsp5_hid_output_suspend_scanning_(cd);
+}
+
+static int cyttsp5_hid_output_resume_scanning_(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_RESUME_SCANNING),
+	};
+
+	return cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+}
+
+static int cyttsp5_hid_output_resume_scanning(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_resume_scanning_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_resume_scanning(struct device *dev,
+		int protect)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_resume_scanning(cd);
+
+	return cyttsp5_hid_output_resume_scanning_(cd);
+}
+
+static int cyttsp5_hid_output_get_param_(struct cyttsp5_core_data *cd,
+		u8 param_id, u32 *value)
+{
+	int write_length = 1;
+	u8 param[1] = { param_id };
+	u8 read_param_id;
+	int param_size;
+	u8 *ptr;
+	int rc;
+	int i;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_GET_PARAM),
+		.write_length = write_length,
+		.write_buf = param,
+	};
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	read_param_id = cd->response_buf[5];
+	if (read_param_id != param_id)
+		return -EPROTO;
+
+	param_size = cd->response_buf[6];
+	ptr = &cd->response_buf[7];
+	*value = 0;
+	for (i = 0; i < param_size; i++)
+		*value += ptr[i] << (i * 8);
+	return 0;
+}
+
+static int cyttsp5_hid_output_get_param(struct cyttsp5_core_data *cd,
+		u8 param_id, u32 *value)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_get_param_(cd, param_id, value);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+int _cyttsp5_request_hid_output_get_param(struct device *dev,
+		int protect, u8 param_id, u32 *value)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_get_param(cd, param_id, value);
+
+	return cyttsp5_hid_output_get_param_(cd, param_id, value);
+}
+
+static int cyttsp5_hid_output_set_param_(struct cyttsp5_core_data *cd,
+		u8 param_id, u32 value, u8 size)
+{
+	u8 write_buf[6];
+	u8 *ptr = &write_buf[2];
+	int rc;
+	int i;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_SET_PARAM),
+		.write_buf = write_buf,
+	};
+
+	write_buf[0] = param_id;
+	write_buf[1] = size;
+	for (i = 0; i < size; i++) {
+		ptr[i] = value & 0xFF;
+		value = value >> 8;
+	}
+
+	hid_output.write_length = 2 + size;
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	if (param_id != cd->response_buf[5] || size != cd->response_buf[6])
+		return -EPROTO;
+
+	return 0;
+}
+
+static int cyttsp5_hid_output_set_param(struct cyttsp5_core_data *cd,
+		u8 param_id, u32 value, u8 size)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_set_param_(cd, param_id, value, size);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+int _cyttsp5_request_hid_output_set_param(struct device *dev,
+		int protect, u8 param_id, u32 value, u8  size)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_set_param(cd, param_id, value, size);
+
+	return cyttsp5_hid_output_set_param_(cd, param_id, value, size);
+}
+
+static int cyttsp5_hid_output_enter_easywake_state_(
+		struct cyttsp5_core_data *cd, u8 data, u8 *return_data)
+{
+	int write_length = 1;
+	u8 param[1] = { data };
+	int rc;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_ENTER_EASYWAKE_STATE),
+		.write_length = write_length,
+		.write_buf = param,
+	};
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	*return_data = cd->response_buf[5];
+	return rc;
+}
+
+static int cyttsp5_hid_output_verify_config_block_crc_(
+		struct cyttsp5_core_data *cd, u8 ebid, u8 *status,
+		u16 *calculated_crc, u16 *stored_crc)
+{
+	int write_length = 1;
+	u8 param[1] = { ebid };
+	u8 *ptr;
+	int rc;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_VERIFY_CONFIG_BLOCK_CRC),
+		.write_length = write_length,
+		.write_buf = param,
+	};
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	ptr = &cd->response_buf[5];
+	*status = ptr[0];
+	*calculated_crc = get_unaligned_le16(&ptr[1]);
+	*stored_crc = get_unaligned_le16(&ptr[3]);
+	return 0;
+}
+
+static int cyttsp5_hid_output_verify_config_block_crc(
+		struct cyttsp5_core_data *cd, u8 ebid, u8 *status,
+		u16 *calculated_crc, u16 *stored_crc)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_verify_config_block_crc_(cd, ebid, status,
+			calculated_crc, stored_crc);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_verify_config_block_crc(
+		struct device *dev, int protect, u8 ebid, u8 *status,
+		u16 *calculated_crc, u16 *stored_crc)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_verify_config_block_crc(cd, ebid,
+				status, calculated_crc, stored_crc);
+
+	return cyttsp5_hid_output_verify_config_block_crc_(cd, ebid,
+			status, calculated_crc, stored_crc);
+}
+
+static int cyttsp5_hid_output_get_config_row_size_(struct cyttsp5_core_data *cd,
+		u16 *row_size)
+{
+	int rc;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_GET_CONFIG_ROW_SIZE),
+	};
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	*row_size = get_unaligned_le16(&cd->response_buf[5]);
+	return 0;
+}
+
+static int cyttsp5_hid_output_get_config_row_size(struct cyttsp5_core_data *cd,
+		u16 *row_size)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_get_config_row_size_(cd, row_size);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_get_config_row_size(struct device *dev,
+		int protect, u16 *row_size)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_get_config_row_size(cd, row_size);
+
+	return cyttsp5_hid_output_get_config_row_size_(cd, row_size);
+}
+
+static int cyttsp5_hid_output_read_conf_block_(struct cyttsp5_core_data *cd,
+		u16 row_number, u16 length, u8 ebid, u8 *read_buf, u16 *crc)
+{
+	int read_ebid;
+	int read_length;
+	int status;
+	int rc;
+	int write_length = 5;
+	u8 write_buf[5];
+	u8 cmd_offset = 0;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_READ_CONF_BLOCK),
+		.write_length = write_length,
+		.write_buf = write_buf,
+	};
+
+	write_buf[cmd_offset++] = LOW_BYTE(row_number);
+	write_buf[cmd_offset++] = HI_BYTE(row_number);
+	write_buf[cmd_offset++] = LOW_BYTE(length);
+	write_buf[cmd_offset++] = HI_BYTE(length);
+	write_buf[cmd_offset++] = ebid;
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	status = cd->response_buf[5];
+	if (status)
+		return -EINVAL;
+
+	read_ebid = cd->response_buf[6];
+	if ((read_ebid != ebid) || (cd->response_buf[9] != 0))
+		return -EPROTO;
+
+	read_length = get_unaligned_le16(&cd->response_buf[7]);
+	if (length < read_length)
+		length = read_length;
+
+	memcpy(read_buf, &cd->response_buf[10], length);
+	*crc = get_unaligned_le16(&cd->response_buf[read_length + 10]);
+
+	return 0;
+}
+
+static int cyttsp5_hid_output_read_conf_ver_(struct cyttsp5_core_data *cd,
+		u16 *config_ver)
+{
+	int rc;
+	u8 read_buf[CY_TTCONFIG_VERSION_OFFSET + CY_TTCONFIG_VERSION_SIZE];
+	u16 crc;
+
+	rc = cyttsp5_hid_output_read_conf_block_(cd, CY_TTCONFIG_VERSION_ROW,
+			CY_TTCONFIG_VERSION_OFFSET + CY_TTCONFIG_VERSION_SIZE,
+			CY_TCH_PARM_EBID, read_buf, &crc);
+	if (rc)
+		return rc;
+
+	*config_ver = get_unaligned_le16(
+				&read_buf[CY_TTCONFIG_VERSION_OFFSET]);
+
+	return 0;
+}
+
+static int cyttsp5_hid_output_write_conf_block_(struct cyttsp5_core_data *cd,
+		u16 row_number, u16 write_length, u8 ebid, u8 *write_buf,
+		u8 *security_key, u16 *actual_write_len)
+{
+	/* row_number + write_len + ebid + security_key + crc */
+	int full_write_length = 2 + 2 + 1 + write_length + 8 + 2;
+	u8 *full_write_buf;
+	u8 cmd_offset = 0;
+	u16 crc;
+	int status;
+	int rc;
+	int read_ebid;
+	u8 *data;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_WRITE_CONF_BLOCK),
+		.write_length = full_write_length,
+		.timeout_ms = CY_HID_OUTPUT_WRITE_CONF_BLOCK_TIMEOUT,
+	};
+
+	full_write_buf = kzalloc(full_write_length, GFP_KERNEL);
+	if (!full_write_buf)
+		return -ENOMEM;
+
+	hid_output.write_buf = full_write_buf;
+	full_write_buf[cmd_offset++] = LOW_BYTE(row_number);
+	full_write_buf[cmd_offset++] = HI_BYTE(row_number);
+	full_write_buf[cmd_offset++] = LOW_BYTE(write_length);
+	full_write_buf[cmd_offset++] = HI_BYTE(write_length);
+	full_write_buf[cmd_offset++] = ebid;
+	data = &full_write_buf[cmd_offset];
+	memcpy(data, write_buf, write_length);
+	cmd_offset += write_length;
+	memcpy(&full_write_buf[cmd_offset], security_key, 8);
+	cmd_offset += 8;
+	crc = _cyttsp5_compute_crc(data, write_length);
+	full_write_buf[cmd_offset++] = LOW_BYTE(crc);
+	full_write_buf[cmd_offset++] = HI_BYTE(crc);
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		goto exit;
+
+	status = cd->response_buf[5];
+	if (status) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	read_ebid = cd->response_buf[6];
+	if (read_ebid != ebid) {
+		rc = -EPROTO;
+		goto exit;
+	}
+
+	*actual_write_len = get_unaligned_le16(&cd->response_buf[7]);
+
+exit:
+	kfree(full_write_buf);
+	return rc;
+}
+
+static int cyttsp5_hid_output_write_conf_block(struct cyttsp5_core_data *cd,
+		u16 row_number, u16 write_length, u8 ebid, u8 *write_buf,
+		u8 *security_key, u16 *actual_write_len)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_write_conf_block_(cd, row_number, write_length,
+			ebid, write_buf, security_key, actual_write_len);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_write_conf_block(struct device *dev,
+		int protect, u16 row_number, u16 write_length, u8 ebid,
+		u8 *write_buf, u8 *security_key, u16 *actual_write_len)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_write_conf_block(cd, row_number,
+				write_length, ebid, write_buf, security_key,
+				actual_write_len);
+
+	return cyttsp5_hid_output_write_conf_block_(cd, row_number,
+			write_length, ebid, write_buf, security_key,
+			actual_write_len);
+}
+
+static int cyttsp5_hid_output_get_data_structure_(
+		struct cyttsp5_core_data *cd, u16 read_offset, u16 read_length,
+		u8 data_id, u8 *status, u8 *data_format, u16 *actual_read_len,
+		u8 *data)
+{
+	int rc;
+	u16 total_read_len = 0;
+	u16 read_len;
+	u16 off_buf = 0;
+	u8 write_buf[5];
+	u8 read_data_id;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_GET_DATA_STRUCTURE),
+		.write_length = 5,
+		.write_buf = write_buf,
+	};
+
+again:
+	write_buf[0] = LOW_BYTE(read_offset);
+	write_buf[1] = HI_BYTE(read_offset);
+	write_buf[2] = LOW_BYTE(read_length);
+	write_buf[3] = HI_BYTE(read_length);
+	write_buf[4] = data_id;
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	if (cd->response_buf[5] != CY_CMD_STATUS_SUCCESS)
+		goto set_status;
+
+	read_data_id = cd->response_buf[6];
+	if (read_data_id != data_id)
+		return -EPROTO;
+
+	read_len = get_unaligned_le16(&cd->response_buf[7]);
+	if (read_len && data) {
+		memcpy(&data[off_buf], &cd->response_buf[10], read_len);
+
+		total_read_len += read_len;
+
+		if (read_len < read_length) {
+			read_offset += read_len;
+			off_buf += read_len;
+			read_length -= read_len;
+			goto again;
+		}
+	}
+
+	if (data_format)
+		*data_format = cd->response_buf[9];
+	if (actual_read_len)
+		*actual_read_len = total_read_len;
+set_status:
+	if (status)
+		*status = cd->response_buf[5];
+
+	return rc;
+}
+
+static int cyttsp5_hid_output_get_data_structure(
+		struct cyttsp5_core_data *cd, u16 read_offset, u16 read_length,
+		u8 data_id, u8 *status, u8 *data_format, u16 *actual_read_len,
+		u8 *data)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_get_data_structure_(cd, read_offset,
+			read_length, data_id, status, data_format,
+			actual_read_len, data);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_get_data_structure(struct device *dev,
+		int protect, u16 read_offset, u16 read_length, u8 data_id,
+		u8 *status, u8 *data_format, u16 *actual_read_len, u8 *data)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_get_data_structure(cd,
+				read_offset, read_length, data_id, status,
+				data_format, actual_read_len, data);
+
+	return cyttsp5_hid_output_get_data_structure_(cd,
+			read_offset, read_length, data_id, status,
+			data_format, actual_read_len, data);
+}
+
+static int cyttsp5_hid_output_run_selftest_(
+		struct cyttsp5_core_data *cd, u8 test_id,
+		u8 write_idacs_to_flash, u8 *status, u8 *summary_result,
+		u8 *results_available)
+{
+	int rc;
+	u8 write_buf[2];
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_RUN_SELF_TEST),
+		.write_length = 2,
+		.write_buf = write_buf,
+		.timeout_ms = CY_HID_OUTPUT_RUN_SELF_TEST_TIMEOUT,
+	};
+
+	write_buf[0] = test_id;
+	write_buf[1] = write_idacs_to_flash;
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	if (status)
+		*status = cd->response_buf[5];
+	if (summary_result)
+		*summary_result = cd->response_buf[6];
+	if (results_available)
+		*results_available = cd->response_buf[7];
+
+	return rc;
+}
+
+static int cyttsp5_hid_output_run_selftest(
+		struct cyttsp5_core_data *cd, u8 test_id,
+		u8 write_idacs_to_flash, u8 *status, u8 *summary_result,
+		u8 *results_available)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_run_selftest_(cd, test_id,
+			write_idacs_to_flash, status, summary_result,
+			results_available);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_run_selftest(struct device *dev,
+		int protect, u8 test_id, u8 write_idacs_to_flash, u8 *status,
+		u8 *summary_result, u8 *results_available)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_run_selftest(cd, test_id,
+				write_idacs_to_flash, status, summary_result,
+				results_available);
+
+	return cyttsp5_hid_output_run_selftest_(cd, test_id,
+			write_idacs_to_flash, status, summary_result,
+			results_available);
+}
+
+static int cyttsp5_hid_output_get_selftest_result_(
+		struct cyttsp5_core_data *cd, u16 read_offset, u16 read_length,
+		u8 test_id, u8 *status, u16 *actual_read_len, u8 *data)
+{
+	int rc;
+	u16 total_read_len = 0;
+	u16 read_len;
+	u16 off_buf = 0;
+	u8 write_buf[5];
+	u8 read_test_id;
+	bool repeat;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_GET_SELF_TEST_RESULT),
+		.write_length = 5,
+		.write_buf = write_buf,
+	};
+
+	/*
+	 * Do not repeat reading for Auto Shorts test
+	 * when PIP version < 1.3
+	 */
+	repeat = IS_PIP_VER_GE(&cd->sysinfo, 1, 3)
+			|| test_id != CY_ST_ID_AUTOSHORTS;
+
+again:
+	write_buf[0] = LOW_BYTE(read_offset);
+	write_buf[1] = HI_BYTE(read_offset);
+	write_buf[2] = LOW_BYTE(read_length);
+	write_buf[3] = HI_BYTE(read_length);
+	write_buf[4] = test_id;
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	if (cd->response_buf[5] != CY_CMD_STATUS_SUCCESS)
+		goto set_status;
+
+	read_test_id = cd->response_buf[6];
+	if (read_test_id != test_id)
+		return -EPROTO;
+
+	read_len = get_unaligned_le16(&cd->response_buf[7]);
+	if (read_len && data) {
+		memcpy(&data[off_buf], &cd->response_buf[10], read_len);
+
+		total_read_len += read_len;
+
+		if (repeat && read_len < read_length) {
+			read_offset += read_len;
+			off_buf += read_len;
+			read_length -= read_len;
+			goto again;
+		}
+	}
+
+	if (actual_read_len)
+		*actual_read_len = total_read_len;
+set_status:
+	if (status)
+		*status = cd->response_buf[5];
+
+	return rc;
+}
+
+static int cyttsp5_hid_output_get_selftest_result(
+		struct cyttsp5_core_data *cd, u16 read_offset, u16 read_length,
+		u8 test_id, u8 *status, u16 *actual_read_len, u8 *data)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_get_selftest_result_(cd, read_offset,
+			read_length, test_id, status, actual_read_len, data);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_get_selftest_result(struct device *dev,
+		int protect, u16 read_offset, u16 read_length, u8 test_id,
+		u8 *status, u16 *actual_read_len, u8 *data)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_get_selftest_result(cd, read_offset,
+				read_length, test_id, status, actual_read_len,
+				data);
+
+	return cyttsp5_hid_output_get_selftest_result_(cd, read_offset,
+			read_length, test_id, status, actual_read_len,
+			data);
+}
+
+static int cyttsp5_hid_output_calibrate_idacs_(struct cyttsp5_core_data *cd,
+		u8 mode, u8 *status)
+{
+	int rc;
+	int write_length = 1;
+	u8 write_buf[1];
+	u8 cmd_offset = 0;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_CALIBRATE_IDACS),
+		.write_length = write_length,
+		.write_buf = write_buf,
+		.timeout_ms = CY_HID_OUTPUT_CALIBRATE_IDAC_TIMEOUT,
+	};
+
+	write_buf[cmd_offset++] = mode;
+	rc =  cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	*status = cd->response_buf[5];
+	if (*status)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int cyttsp5_hid_output_calibrate_idacs(struct cyttsp5_core_data *cd,
+		u8 mode, u8 *status)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_calibrate_idacs_(cd, mode, status);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_calibrate_idacs(struct device *dev,
+		int protect, u8 mode, u8 *status)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_calibrate_idacs(cd, mode, status);
+
+	return cyttsp5_hid_output_calibrate_idacs_(cd, mode, status);
+}
+
+static int cyttsp5_hid_output_initialize_baselines_(
+		struct cyttsp5_core_data *cd, u8 test_id, u8 *status)
+{
+	int rc;
+	int write_length = 1;
+	u8 write_buf[1];
+	u8 cmd_offset = 0;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_INITIALIZE_BASELINES),
+		.write_length = write_length,
+		.write_buf = write_buf,
+	};
+
+	write_buf[cmd_offset++] = test_id;
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	*status = cd->response_buf[5];
+	if (*status)
+		return -EINVAL;
+
+	return rc;
+}
+
+static int cyttsp5_hid_output_initialize_baselines(struct cyttsp5_core_data *cd,
+		u8 test_id, u8 *status)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_initialize_baselines_(cd, test_id, status);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_initialize_baselines(struct device *dev,
+		int protect, u8 test_id, u8 *status)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_initialize_baselines(cd, test_id,
+				status);
+
+	return cyttsp5_hid_output_initialize_baselines_(cd, test_id, status);
+}
+
+static int cyttsp5_hid_output_exec_panel_scan_(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_EXEC_PANEL_SCAN),
+	};
+
+	return cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+}
+
+static int cyttsp5_hid_output_exec_panel_scan(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_exec_panel_scan_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_exec_panel_scan(struct device *dev,
+		int protect)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_exec_panel_scan(cd);
+
+	return cyttsp5_hid_output_exec_panel_scan_(cd);
+}
+
+/* @response: set none NULL only if all response required including header */
+static int cyttsp5_hid_output_retrieve_panel_scan_(
+		struct cyttsp5_core_data *cd, u16 read_offset, u16 read_count,
+		u8 data_id, u8 *response, u8 *config, u16 *actual_read_len,
+		u8 *read_buf)
+{
+	int status;
+	u8 read_data_id;
+	int rc;
+	int write_length = 5;
+	u8 write_buf[5];
+	u8 cmd_offset = 0;
+	u8 data_elem_size;
+	int size;
+	int data_size;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_APP_COMMAND(HID_OUTPUT_RETRIEVE_PANEL_SCAN),
+		.write_length = write_length,
+		.write_buf = write_buf,
+	};
+
+	write_buf[cmd_offset++] = LOW_BYTE(read_offset);
+	write_buf[cmd_offset++] = HI_BYTE(read_offset);
+	write_buf[cmd_offset++] = LOW_BYTE(read_count);
+	write_buf[cmd_offset++] = HI_BYTE(read_count);
+	write_buf[cmd_offset++] = data_id;
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	status = cd->response_buf[5];
+	if (status)
+		return -EINVAL;
+
+	read_data_id = cd->response_buf[6];
+	if (read_data_id != data_id)
+		return -EPROTO;
+
+	size = get_unaligned_le16(&cd->response_buf[0]);
+	*actual_read_len = get_unaligned_le16(&cd->response_buf[7]);
+	*config = cd->response_buf[9];
+
+	data_elem_size = *config & 0x07;
+	data_size = *actual_read_len * data_elem_size;
+
+	if (read_buf)
+		memcpy(read_buf, &cd->response_buf[10], data_size);
+	if (response)
+		memcpy(response, cd->response_buf, size);
+	return rc;
+}
+
+static int cyttsp5_hid_output_retrieve_panel_scan(
+		struct cyttsp5_core_data *cd, u16 read_offset, u16 read_count,
+		u8 data_id, u8 *response, u8 *config, u16 *actual_read_len,
+		u8 *read_buf)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_retrieve_panel_scan_(cd, read_offset,
+			read_count, data_id, response, config,
+			actual_read_len, read_buf);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_retrieve_panel_scan(struct device *dev,
+		int protect, u16 read_offset, u16 read_count, u8 data_id,
+		u8 *response, u8 *config, u16 *actual_read_len, u8 *read_buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_retrieve_panel_scan(cd,
+				read_offset, read_count, data_id, response,
+				config, actual_read_len, read_buf);
+
+	return cyttsp5_hid_output_retrieve_panel_scan_(cd,
+			read_offset, read_count, data_id, response,
+			config, actual_read_len, read_buf);
+}
+
+static int cyttsp5_hid_output_user_cmd_(struct cyttsp5_core_data *cd,
+		u16 read_len, u8 *read_buf, u16 write_len, u8 *write_buf,
+		u16 *actual_read_len)
+{
+	int rc;
+	u16 size;
+#ifdef TTHE_TUNER_SUPPORT
+	int command_code = 0;
+	int len;
+#endif
+	struct cyttsp5_hid_output hid_output = {
+		.length = write_len,
+		.write_buf = write_buf,
+	};
+
+	rc = cyttsp5_hid_send_output_user_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	size = get_unaligned_le16(&cd->response_buf[0]);
+	if (size == 0)
+		size = 2;
+
+	if (size > read_len) {
+		*actual_read_len = 0;
+		return -EINVAL;
+	}
+
+	memcpy(read_buf, cd->response_buf, size);
+	*actual_read_len = size;
+
+#ifdef TTHE_TUNER_SUPPORT
+	/* print up to cmd code */
+	len = HID_OUTPUT_CMD_OFFSET + 1;
+	if (write_len < len)
+		len = write_len;
+	else
+		command_code = write_buf[HID_OUTPUT_CMD_OFFSET]
+			& HID_OUTPUT_CMD_MASK;
+
+	/* Do not print for EXEC_PANEL_SCAN & RETRIEVE_PANEL_SCAN commands */
+	if (command_code != HID_OUTPUT_EXEC_PANEL_SCAN
+			&& command_code != HID_OUTPUT_RETRIEVE_PANEL_SCAN)
+		tthe_print(cd, write_buf, len, "CMD=");
+#endif
+
+	return 0;
+}
+
+static int cyttsp5_get_config_ver_(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_sysinfo *si = &cd->sysinfo;
+	int rc;
+	u16 config_ver = 0;
+
+	rc = cyttsp5_hid_output_suspend_scanning_(cd);
+	if (rc)
+		goto error;
+
+	rc = cyttsp5_hid_output_read_conf_ver_(cd, &config_ver);
+	if (rc)
+		goto exit;
+
+	si->cydata.fw_ver_conf = config_ver;
+
+exit:
+	cyttsp5_hid_output_resume_scanning_(cd);
+error:
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: CONFIG_VER:%04X\n",
+		__func__, config_ver);
+	return rc;
+}
+
+static int cyttsp5_hid_output_user_cmd(struct cyttsp5_core_data *cd,
+		u16 read_len, u8 *read_buf, u16 write_len, u8 *write_buf,
+		u16 *actual_read_len)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_user_cmd_(cd, read_len, read_buf,
+			write_len, write_buf, actual_read_len);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_user_cmd(struct device *dev,
+		int protect, u16 read_len, u8 *read_buf, u16 write_len,
+		u8 *write_buf, u16 *actual_read_len)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_user_cmd(cd, read_len, read_buf,
+				write_len, write_buf, actual_read_len);
+
+	return cyttsp5_hid_output_user_cmd_(cd, read_len, read_buf,
+			write_len, write_buf, actual_read_len);
+}
+
+static int cyttsp5_hid_output_bl_get_information_(struct cyttsp5_core_data *cd,
+		u8 *return_data)
+{
+	int rc;
+	int data_len;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_BL_COMMAND(HID_OUTPUT_BL_GET_INFO),
+	};
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc)
+		return rc;
+
+	data_len = get_unaligned_le16(&cd->input_buf[6]);
+	if (!data_len)
+		return -EPROTO;
+
+	memcpy(return_data, &cd->response_buf[8], data_len);
+
+	return 0;
+}
+
+static int cyttsp5_hid_output_bl_get_information(struct cyttsp5_core_data *cd,
+		u8 *return_data)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_bl_get_information_(cd, return_data);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_bl_get_information(struct device *dev,
+		int protect, u8 *return_data)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_bl_get_information(cd, return_data);
+
+	return cyttsp5_hid_output_bl_get_information_(cd, return_data);
+}
+
+static int cyttsp5_hid_output_bl_initiate_bl_(struct cyttsp5_core_data *cd,
+		u16 key_size, u8 *key_buf, u16 row_size, u8 *metadata_row_buf)
+{
+	u16 write_length = key_size + row_size;
+	u8 *write_buf;
+	int rc;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_BL_COMMAND(HID_OUTPUT_BL_INITIATE_BL),
+		.write_length = write_length,
+		.timeout_ms = CY_HID_OUTPUT_BL_INITIATE_BL_TIMEOUT,
+	};
+
+	write_buf = kzalloc(write_length, GFP_KERNEL);
+	if (!write_buf)
+		return -ENOMEM;
+
+	hid_output.write_buf = write_buf;
+
+	if (key_size)
+		memcpy(write_buf, key_buf, key_size);
+
+	if (row_size)
+		memcpy(&write_buf[key_size], metadata_row_buf, row_size);
+
+	rc =  cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+
+	kfree(write_buf);
+	return rc;
+}
+
+static int cyttsp5_hid_output_bl_initiate_bl(struct cyttsp5_core_data *cd,
+		u16 key_size, u8 *key_buf, u16 row_size, u8 *metadata_row_buf)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_bl_initiate_bl_(cd, key_size, key_buf,
+			row_size, metadata_row_buf);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_bl_initiate_bl(struct device *dev,
+		int protect, u16 key_size, u8 *key_buf, u16 row_size,
+		u8 *metadata_row_buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_bl_initiate_bl(cd, key_size, key_buf,
+				row_size, metadata_row_buf);
+
+	return cyttsp5_hid_output_bl_initiate_bl_(cd, key_size, key_buf,
+			row_size, metadata_row_buf);
+}
+
+static int cyttsp5_hid_output_bl_program_and_verify_(
+		struct cyttsp5_core_data *cd, u16 data_len, u8 *data_buf)
+{
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_BL_COMMAND(HID_OUTPUT_BL_PROGRAM_AND_VERIFY),
+		.write_length = data_len,
+		.write_buf = data_buf,
+		.timeout_ms = CY_HID_OUTPUT_BL_PROGRAM_AND_VERIFY_TIMEOUT,
+	};
+
+	return cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+}
+
+static int cyttsp5_hid_output_bl_program_and_verify(
+		struct cyttsp5_core_data *cd, u16 data_len, u8 *data_buf)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_bl_program_and_verify_(cd, data_len, data_buf);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_bl_program_and_verify(
+		struct device *dev, int protect, u16 data_len, u8 *data_buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_bl_program_and_verify(cd, data_len,
+				data_buf);
+
+	return cyttsp5_hid_output_bl_program_and_verify_(cd, data_len,
+			data_buf);
+}
+
+static int cyttsp5_hid_output_bl_verify_app_integrity_(
+		struct cyttsp5_core_data *cd, u8 *result)
+{
+	int rc;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_BL_COMMAND(HID_OUTPUT_BL_VERIFY_APP_INTEGRITY),
+	};
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc) {
+		*result = 0;
+		return rc;
+	}
+
+	*result = cd->response_buf[8];
+	return 0;
+}
+
+static int cyttsp5_hid_output_bl_verify_app_integrity(
+		struct cyttsp5_core_data *cd, u8 *result)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_bl_verify_app_integrity_(cd, result);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_bl_verify_app_integrity(
+		struct device *dev, int protect, u8 *result)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_bl_verify_app_integrity(cd, result);
+
+	return cyttsp5_hid_output_bl_verify_app_integrity_(cd, result);
+}
+
+static int cyttsp5_hid_output_bl_launch_app_(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_BL_COMMAND(HID_OUTPUT_BL_LAUNCH_APP),
+		.reset_expected = 1,
+	};
+
+	return cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+}
+
+static int cyttsp5_hid_output_bl_launch_app(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_bl_launch_app_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_launch_app(struct device *dev,
+		int protect)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_bl_launch_app(cd);
+
+	return cyttsp5_hid_output_bl_launch_app_(cd);
+}
+
+static int cyttsp5_hid_output_bl_get_panel_id_(
+		struct cyttsp5_core_data *cd, u8 *panel_id)
+{
+	int rc;
+	struct cyttsp5_hid_output hid_output = {
+		HID_OUTPUT_BL_COMMAND(HID_OUTPUT_BL_GET_PANEL_ID),
+	};
+
+	rc = cyttsp5_hid_send_output_and_wait_(cd, &hid_output);
+	if (rc == -EPROTO && cd->response_buf[5] == ERROR_COMMAND) {
+		parade_debug(cd->dev, DEBUG_LEVEL_1,
+			"%s: Get Panel ID command not supported\n",
+			__func__);
+		*panel_id = PANEL_ID_NOT_ENABLED;
+		return 0;
+	} else if (rc < 0) {
+		dev_err(cd->dev, "%s: Error on Get Panel ID command\n",
+			__func__);
+		return rc;
+	}
+
+	*panel_id = cd->response_buf[8];
+	return 0;
+}
+
+static int cyttsp5_hid_output_bl_get_panel_id(
+		struct cyttsp5_core_data *cd, u8 *panel_id)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_hid_output_bl_get_panel_id_(cd, panel_id);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_hid_output_bl_get_panel_id(
+		struct device *dev, int protect, u8 *panel_id)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_hid_output_bl_get_panel_id(cd, panel_id);
+
+	return cyttsp5_hid_output_bl_get_panel_id_(cd, panel_id);
+}
+
+static int cyttsp5_get_hid_descriptor_(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_desc *desc)
+{
+	struct device *dev = cd->dev;
+	int rc;
+	int t;
+	u8 cmd[2];
+
+	/* Read HID descriptor length and version */
+	mutex_lock(&cd->system_lock);
+	cd->hid_cmd_state = 1;
+	mutex_unlock(&cd->system_lock);
+
+	/* Set HID descriptor register */
+	memcpy(cmd, &cd->hid_core.hid_desc_register,
+		sizeof(cd->hid_core.hid_desc_register));
+
+	rc = cyttsp5_adap_write_read_specific(cd, 2, cmd, NULL);
+	if (rc) {
+		dev_err(dev, "%s: failed to get HID descriptor length and version, rc=%d\n",
+			__func__, rc);
+		goto error;
+	}
+
+	t = wait_event_timeout(cd->wait_q, (cd->hid_cmd_state == 0),
+			msecs_to_jiffies(CY_HID_GET_HID_DESCRIPTOR_TIMEOUT));
+	if (IS_TMO(t)) {
+		dev_err(cd->dev, "%s: HID get descriptor timed out\n",
+			__func__);
+		rc = -ETIME;
+		goto error;
+	}
+
+	memcpy((u8 *)desc, cd->response_buf, sizeof(struct cyttsp5_hid_desc));
+
+	/* Check HID descriptor length and version */
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: HID len:%X HID ver:%X\n",
+		__func__,
+		le16_to_cpu(desc->hid_desc_len),
+		le16_to_cpu(desc->bcd_version));
+
+	if (le16_to_cpu(desc->hid_desc_len) != sizeof(*desc) ||
+		le16_to_cpu(desc->bcd_version) != CY_HID_VERSION) {
+		dev_err(dev, "%s: Unsupported HID version\n", __func__);
+		return -ENODEV;
+	}
+
+	goto exit;
+
+error:
+	mutex_lock(&cd->system_lock);
+	cd->hid_cmd_state = 0;
+	mutex_unlock(&cd->system_lock);
+exit:
+	return rc;
+}
+
+static int cyttsp5_get_hid_descriptor(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_desc *desc)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_get_hid_descriptor_(cd, desc);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_request_get_hid_desc(struct device *dev, int protect)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (protect)
+		return cyttsp5_get_hid_descriptor(cd, &cd->hid_desc);
+
+	return cyttsp5_get_hid_descriptor_(cd, &cd->hid_desc);
+}
+
+static int cyttsp5_hw_soft_reset(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	if (cd->hid_desc.hid_desc_len == 0) {
+		rc = cyttsp5_get_hid_descriptor_(cd, &cd->hid_desc);
+		if (rc < 0)
+			return rc;
+	}
+
+	rc = cyttsp5_hid_cmd_reset_(cd);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: FAILED to execute SOFT reset\n",
+				__func__);
+		return rc;
+	}
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: execute SOFT reset\n",
+		__func__);
+	return 0;
+}
+
+static int cyttsp5_hw_hard_reset(struct cyttsp5_core_data *cd)
+{
+	if (cd->cpdata->xres) {
+		cd->cpdata->xres(cd->cpdata, cd->dev);
+		parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: execute HARD reset\n",
+			__func__);
+		return 0;
+	}
+	dev_err(cd->dev, "%s: FAILED to execute HARD reset\n", __func__);
+	return -ENODEV;
+}
+
+static int cyttsp5_hw_reset(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	mutex_lock(&cd->system_lock);
+	rc = cyttsp5_hw_hard_reset(cd);
+	mutex_unlock(&cd->system_lock);
+	if (rc == -ENODEV)
+		rc = cyttsp5_hw_soft_reset(cd);
+	return rc;
+}
+
+static inline int get_hid_item_data(u8 *data, int item_size)
+{
+	if (item_size == 1)
+		return (int)*data;
+	else if (item_size == 2)
+		return (int)get_unaligned_le16(data);
+	else if (item_size == 4)
+		return (int)get_unaligned_le32(data);
+	return 0;
+}
+
+static int parse_report_descriptor(struct cyttsp5_core_data *cd,
+		u8 *report_desc, size_t len)
+{
+	struct cyttsp5_hid_report *report;
+	struct cyttsp5_hid_field *field;
+	u8 *buf = report_desc;
+	u8 *end = buf + len;
+	int rc = 0;
+	int offset = 0;
+	int i;
+	u8 report_type;
+	u32 up_usage;
+	/* Global items */
+	u8 report_id = 0;
+	u16 usage_page = 0;
+	int report_count = 0;
+	int report_size = 0;
+	int logical_min = 0;
+	int logical_max = 0;
+	/* Local items */
+	u16 usage = 0;
+	/* Main items - Collection stack */
+	u32 collection_usages[CY_HID_MAX_NESTED_COLLECTIONS] = {0};
+	u8 collection_types[CY_HID_MAX_NESTED_COLLECTIONS] = {0};
+	/* First collection for header, second for report */
+	int logical_collection_count = 0;
+	int collection_nest = 0;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: Report descriptor length: %u\n",
+		__func__, (u32)len);
+
+	mutex_lock(&cd->hid_report_lock);
+	cyttsp5_free_hid_reports_(cd);
+
+	while (buf < end) {
+		int item_type;
+		int item_size;
+		int item_tag;
+		u8 *data;
+
+		/* Get Item */
+		item_size = HID_GET_ITEM_SIZE(buf[0]);
+		if (item_size == 3)
+			item_size = 4;
+		item_type = HID_GET_ITEM_TYPE(buf[0]);
+		item_tag = HID_GET_ITEM_TAG(buf[0]);
+
+		data = ++buf;
+		buf += item_size;
+
+		/* Process current item */
+		switch (item_type) {
+		case HID_ITEM_TYPE_GLOBAL:
+			switch (item_tag) {
+			case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+				if (item_size != 1) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				report_id = get_hid_item_data(data, item_size);
+				offset = 0;
+				logical_collection_count = 0;
+				break;
+			case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+				if (item_size == 0 || item_size == 4) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				usage_page = (u16)get_hid_item_data(data,
+						item_size);
+				break;
+			case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+				if (item_size == 0) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				logical_min = get_hid_item_data(data,
+						item_size);
+				break;
+			case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+				if (item_size == 0) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				logical_max = get_hid_item_data(data,
+						item_size);
+				break;
+			case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+				if (item_size == 0) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				report_count = get_hid_item_data(data,
+						item_size);
+				break;
+			case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+				if (item_size == 0) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				report_size = get_hid_item_data(data,
+						item_size);
+				break;
+			default:
+				dev_info(cd->dev,
+					"%s: Unrecognized Global tag %d\n",
+					__func__, item_tag);
+			}
+			break;
+		case HID_ITEM_TYPE_LOCAL:
+			switch (item_tag) {
+			case HID_LOCAL_ITEM_TAG_USAGE:
+				if (item_size == 0 || item_size == 4) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				usage = (u16)get_hid_item_data(data,
+						item_size);
+				break;
+			case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+				if (item_size == 0) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				/* usage_min = */
+				get_hid_item_data(data, item_size);
+				break;
+			case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+				if (item_size == 0) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				/* usage_max = */
+				get_hid_item_data(data, item_size);
+				break;
+			default:
+				dev_info(cd->dev,
+					"%s: Unrecognized Local tag %d\n",
+					__func__, item_tag);
+			}
+			break;
+		case HID_ITEM_TYPE_MAIN:
+			switch (item_tag) {
+			case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+				if (item_size != 1) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				if (CY_HID_MAX_NESTED_COLLECTIONS ==
+						collection_nest) {
+					rc = -EINVAL;
+					goto exit;
+				}
+
+				up_usage = usage_page << 16 | usage;
+
+				/* Update collection stack */
+				collection_usages[collection_nest] = up_usage;
+				collection_types[collection_nest] =
+					get_hid_item_data(data, item_size);
+
+				if (collection_types[collection_nest] ==
+						HID_COLLECTION_LOGICAL)
+					logical_collection_count++;
+
+				collection_nest++;
+				break;
+			case HID_MAIN_ITEM_TAG_END_COLLECTION:
+				if (item_size != 0) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				if (--collection_nest < 0) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				break;
+			case HID_MAIN_ITEM_TAG_INPUT:
+				report_type = HID_INPUT_REPORT;
+				goto continue_main_item;
+			case HID_MAIN_ITEM_TAG_OUTPUT:
+				report_type = HID_OUTPUT_REPORT;
+				goto continue_main_item;
+			case HID_MAIN_ITEM_TAG_FEATURE:
+				report_type = HID_FEATURE_REPORT;
+continue_main_item:
+				if (item_size != 1) {
+					rc = -EINVAL;
+					goto exit;
+				}
+
+				up_usage = usage_page << 16 | usage;
+
+				/* Get or create report */
+				report = cyttsp5_get_hid_report_(cd,
+						report_type, report_id, true);
+				if (!report) {
+					rc = -ENOMEM;
+					goto exit;
+				}
+				if (!report->usage_page && collection_nest > 0)
+					report->usage_page =
+						collection_usages
+							[collection_nest - 1];
+
+				/* Create field */
+				field = cyttsp5_create_hid_field_(report);
+				if (!field) {
+					rc = -ENOMEM;
+					goto exit;
+				}
+
+				field->report_count = report_count;
+				field->report_size = report_size;
+				field->size = report_count * report_size;
+				field->offset = offset;
+				field->data_type =
+					get_hid_item_data(data, item_size);
+				field->logical_min = logical_min;
+				field->logical_max = logical_max;
+				field->usage_page = up_usage;
+
+				for (i = 0; i < collection_nest; i++) {
+					field->collection_usage_pages
+							[collection_types[i]] =
+						collection_usages[i];
+				}
+
+				/* Update report's header or record size */
+				if (logical_collection_count == 1) {
+					report->header_size += field->size;
+				} else if (logical_collection_count == 2) {
+					field->record_field = true;
+					field->offset -= report->header_size;
+					/* Set record field index */
+					if (report->record_field_index == 0)
+						report->record_field_index =
+							report->num_fields - 1;
+					report->record_size += field->size;
+				}
+
+				report->size += field->size;
+
+				offset += field->size;
+				break;
+			default:
+				dev_info(cd->dev, "%s: Unrecognized Main tag %d\n",
+					__func__, item_tag);
+			}
+
+			/* Reset all local items */
+			usage = 0;
+			break;
+		}
+	}
+
+	if (buf != end) {
+		dev_err(cd->dev, "%s: Report descriptor length invalid\n",
+			__func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (collection_nest) {
+		dev_err(cd->dev, "%s: Unbalanced collection items (%d)\n",
+			__func__, collection_nest);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+exit:
+	if (rc)
+		cyttsp5_free_hid_reports_(cd);
+	mutex_unlock(&cd->hid_report_lock);
+	return rc;
+}
+
+static struct cyttsp5_hid_field *find_report_desc_field(
+		struct cyttsp5_core_data *cd, u32 usage_page,
+		u32 collection_usage_page)
+{
+	struct cyttsp5_hid_report *report = NULL;
+	struct cyttsp5_hid_field *field = NULL;
+	int i;
+	int j;
+	u32 field_cup;
+	u32 field_up;
+
+	for (i = 0; i < cd->num_hid_reports; i++) {
+		report = cd->hid_reports[i];
+		for (j = 0; j < report->num_fields; j++) {
+			field = report->fields[j];
+			field_cup = field->collection_usage_pages
+				[HID_COLLECTION_LOGICAL];
+			field_up = field->usage_page;
+			if (field_cup == collection_usage_page
+					&& field_up == usage_page) {
+				return field;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static int fill_tch_abs(struct cyttsp5_tch_abs_params *tch_abs,
+		struct cyttsp5_hid_field *field)
+{
+	tch_abs->ofs = field->offset / 8;
+	tch_abs->size = field->report_size / 8;
+	if (field->report_size % 8)
+		tch_abs->size += 1;
+	tch_abs->min = 0;
+	tch_abs->max = 1 << field->report_size;
+	tch_abs->bofs = field->offset - (tch_abs->ofs << 3);
+
+	return 0;
+}
+
+static struct cyttsp5_hid_report *find_report_desc(struct cyttsp5_core_data *cd,
+		u32 usage_page)
+{
+	struct cyttsp5_hid_report *report = NULL;
+	int i;
+
+	for (i = 0; i < cd->num_hid_reports; i++) {
+		if (cd->hid_reports[i]->usage_page == usage_page) {
+			report = cd->hid_reports[i];
+			break;
+		}
+	}
+
+	return report;
+}
+
+static int setup_report_descriptor(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_sysinfo *si = &cd->sysinfo;
+	struct cyttsp5_hid_report *report;
+	struct cyttsp5_hid_field *field;
+	int i;
+	u32 tch_collection_usage_page = HID_CY_TCH_COL_USAGE_PG;
+	u32 btn_collection_usage_page = HID_CY_BTN_COL_USAGE_PG;
+
+	for (i = CY_TCH_X; i < CY_TCH_NUM_ABS; i++) {
+		field = find_report_desc_field(cd,
+				cyttsp5_tch_abs_field_map[i],
+				tch_collection_usage_page);
+		if (field) {
+			parade_debug(cd->dev, DEBUG_LEVEL_2,
+				" Field %p: rep_cnt:%d rep_sz:%d off:%d data:%02X min:%d max:%d usage_page:%08X\n",
+				field, field->report_count, field->report_size,
+				field->offset, field->data_type,
+				field->logical_min, field->logical_max,
+				field->usage_page);
+			fill_tch_abs(&si->tch_abs[i], field);
+			si->tch_abs[i].report = 1;
+			parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: ofs:%u size:%u min:%u max:%u bofs:%u report:%d",
+				cyttsp5_tch_abs_string[i],
+				(u32)si->tch_abs[i].ofs,
+				(u32)si->tch_abs[i].size,
+				(u32)si->tch_abs[i].min,
+				(u32)si->tch_abs[i].max,
+				(u32)si->tch_abs[i].bofs,
+				si->tch_abs[i].report);
+
+		} else {
+			si->tch_abs[i].report = 0;
+		}
+	}
+	for (i = CY_TCH_TIME; i < CY_TCH_NUM_HDR; i++) {
+		field = find_report_desc_field(cd,
+				cyttsp5_tch_hdr_field_map[i],
+				tch_collection_usage_page);
+		if (field) {
+			parade_debug(cd->dev, DEBUG_LEVEL_2,
+				" Field %p: rep_cnt:%d rep_sz:%d off:%d data:%02X min:%d max:%d usage_page:%08X\n",
+				field, field->report_count, field->report_size,
+				field->offset, field->data_type,
+				field->logical_min, field->logical_max,
+				field->usage_page);
+			fill_tch_abs(&si->tch_hdr[i], field);
+			si->tch_hdr[i].report = 1;
+			parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: ofs:%u size:%u min:%u max:%u bofs:%u report:%d",
+				cyttsp5_tch_hdr_string[i],
+				(u32)si->tch_hdr[i].ofs,
+				(u32)si->tch_hdr[i].size,
+				(u32)si->tch_hdr[i].min,
+				(u32)si->tch_hdr[i].max,
+				(u32)si->tch_hdr[i].bofs,
+				si->tch_hdr[i].report);
+
+		} else {
+			si->tch_hdr[i].report = 0;
+		}
+	}
+
+	report = find_report_desc(cd, tch_collection_usage_page);
+	if (report) {
+		si->desc.tch_report_id = report->id;
+		si->desc.tch_record_size = report->record_size / 8;
+		si->desc.tch_header_size = (report->header_size / 8) + 3;
+	} else {
+		si->desc.tch_report_id = HID_TOUCH_REPORT_ID;
+		si->desc.tch_record_size = TOUCH_REPORT_SIZE;
+		si->desc.tch_header_size = TOUCH_INPUT_HEADER_SIZE;
+	}
+
+	report = find_report_desc(cd, btn_collection_usage_page);
+	if (report)
+		si->desc.btn_report_id = report->id;
+	else
+		si->desc.btn_report_id = HID_BTN_REPORT_ID;
+
+	for (i = 0; i < cd->num_hid_reports; i++) {
+		struct cyttsp5_hid_report *report = cd->hid_reports[i];
+
+		switch (report->id) {
+		case HID_WAKEUP_REPORT_ID:
+			cd->features.easywake = 1;
+			break;
+		case HID_NOISE_METRIC_REPORT_ID:
+			cd->features.noise_metric = 1;
+			break;
+		case HID_TRACKING_HEATMAP_REPOR_ID:
+			cd->features.tracking_heatmap = 1;
+			break;
+		case HID_SENSOR_DATA_REPORT_ID:
+			cd->features.sensor_data = 1;
+			break;
+		default:
+			break;
+		}
+	}
+
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "Features: easywake:%d noise_metric:%d tracking_heatmap:%d sensor_data:%d\n",
+		cd->features.easywake, cd->features.noise_metric,
+		cd->features.tracking_heatmap,
+		cd->features.sensor_data);
+
+	return 0;
+}
+
+static int cyttsp5_get_report_descriptor_(struct cyttsp5_core_data *cd)
+{
+	struct device *dev = cd->dev;
+	u8 cmd[2];
+	int rc;
+	int t;
+
+	/* Read report descriptor length and version */
+	mutex_lock(&cd->system_lock);
+	cd->hid_cmd_state = 1;
+	mutex_unlock(&cd->system_lock);
+
+	/* Set report descriptor register */
+	memcpy(cmd, &cd->hid_desc.report_desc_register,
+		sizeof(cd->hid_desc.report_desc_register));
+
+	rc = cyttsp5_adap_write_read_specific(cd, 2, cmd, NULL);
+	if (rc) {
+		dev_err(dev, "%s: failed to get HID descriptor length and version, rc=%d\n",
+			__func__, rc);
+		goto error;
+	}
+
+	t = wait_event_timeout(cd->wait_q, (cd->hid_cmd_state == 0),
+		msecs_to_jiffies(CY_HID_GET_REPORT_DESCRIPTOR_TIMEOUT));
+	if (IS_TMO(t)) {
+		dev_err(cd->dev, "%s: HID get descriptor timed out\n",
+			__func__);
+		rc = -ETIME;
+		goto error;
+	}
+
+	cyttsp5_pr_buf(cd->dev, cd->response_buf,
+		cd->hid_core.hid_report_desc_len, "Report Desc");
+
+	rc = parse_report_descriptor(cd, cd->response_buf + 3,
+		get_unaligned_le16(&cd->response_buf[0]) - 3);
+	if (rc) {
+		dev_err(cd->dev, "%s: Error parsing report descriptor r=%d\n",
+			__func__, rc);
+	}
+
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: %d reports found in descriptor\n",
+		__func__, cd->num_hid_reports);
+
+	for (t = 0; t < cd->num_hid_reports; t++) {
+		struct cyttsp5_hid_report *report = cd->hid_reports[t];
+		int j;
+
+		parade_debug(cd->dev, DEBUG_LEVEL_2,
+			"Report %d: type:%d id:%02X size:%d fields:%d rec_fld_index:%d hdr_sz:%d rec_sz:%d usage_page:%08X\n",
+			t, report->type, report->id,
+			report->size, report->num_fields,
+			report->record_field_index, report->header_size,
+			report->record_size, report->usage_page);
+
+		for (j = 0; j < report->num_fields; j++) {
+			struct cyttsp5_hid_field *field = report->fields[j];
+
+			parade_debug(cd->dev, DEBUG_LEVEL_2,
+				" Field %d: rep_cnt:%d rep_sz:%d off:%d data:%02X min:%d max:%d usage_page:%08X\n",
+				j, field->report_count, field->report_size,
+				field->offset, field->data_type,
+				field->logical_min, field->logical_max,
+				field->usage_page);
+
+			parade_debug(cd->dev, DEBUG_LEVEL_2, "  Collections Phys:%08X App:%08X Log:%08X\n",
+				field->collection_usage_pages
+					[HID_COLLECTION_PHYSICAL],
+				field->collection_usage_pages
+					[HID_COLLECTION_APPLICATION],
+				field->collection_usage_pages
+					[HID_COLLECTION_LOGICAL]);
+		}
+	}
+
+	rc = setup_report_descriptor(cd);
+
+	/* Free it for now */
+	cyttsp5_free_hid_reports_(cd);
+
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: %d reports found in descriptor\n",
+		__func__, cd->num_hid_reports);
+
+	goto exit;
+
+error:
+	mutex_lock(&cd->system_lock);
+	cd->hid_cmd_state = 0;
+	mutex_unlock(&cd->system_lock);
+exit:
+	return rc;
+}
+
+static int cyttsp5_get_mode(struct cyttsp5_core_data *cd,
+		struct cyttsp5_hid_desc *desc)
+{
+	if (desc->packet_id == CY_HID_APP_REPORT_ID)
+		return CY_MODE_OPERATIONAL;
+	else if (desc->packet_id == CY_HID_BL_REPORT_ID)
+		return CY_MODE_BOOTLOADER;
+
+	return CY_MODE_UNKNOWN;
+}
+
+static int _cyttsp5_request_get_mode(struct device *dev, int protect, u8 *mode)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	int rc;
+
+	if (protect)
+		rc = cyttsp5_get_hid_descriptor(cd, &cd->hid_desc);
+	else
+		rc = cyttsp5_get_hid_descriptor_(cd, &cd->hid_desc);
+
+	if (rc)
+		*mode = CY_MODE_UNKNOWN;
+	else
+		*mode = cyttsp5_get_mode(cd, &cd->hid_desc);
+
+	return rc;
+}
+
+static void cyttsp5_queue_startup_(struct cyttsp5_core_data *cd)
+{
+	if (cd->startup_state == STARTUP_NONE) {
+		cd->startup_state = STARTUP_QUEUED;
+		schedule_work(&cd->startup_work);
+		dev_info(cd->dev, "%s: cyttsp5_startup queued\n", __func__);
+	} else {
+		parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: startup_state = %d\n",
+			__func__, cd->startup_state);
+	}
+}
+
+static void cyttsp5_queue_startup(struct cyttsp5_core_data *cd)
+{
+	mutex_lock(&cd->system_lock);
+	cyttsp5_queue_startup_(cd);
+	mutex_unlock(&cd->system_lock);
+}
+
+static void call_atten_cb(struct cyttsp5_core_data *cd,
+		enum cyttsp5_atten_type type, int mode)
+{
+	struct atten_node *atten, *atten_n;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: check list type=%d mode=%d\n",
+		__func__, type, mode);
+	spin_lock(&cd->spinlock);
+	list_for_each_entry_safe(atten, atten_n,
+			&cd->atten_list[type], node) {
+		if (!mode || atten->mode & mode) {
+			spin_unlock(&cd->spinlock);
+			parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: attention for '%s'",
+				__func__, dev_name(atten->dev));
+			atten->func(atten->dev);
+			spin_lock(&cd->spinlock);
+		}
+	}
+	spin_unlock(&cd->spinlock);
+}
+
+static void cyttsp5_start_wd_timer(struct cyttsp5_core_data *cd)
+{
+	if (!cd->watchdog_interval)
+		return;
+
+	mod_timer(&cd->watchdog_timer, jiffies +
+			msecs_to_jiffies(cd->watchdog_interval));
+}
+
+static void cyttsp5_stop_wd_timer(struct cyttsp5_core_data *cd)
+{
+	if (!cd->watchdog_interval)
+		return;
+
+	/*
+	 * Ensure we wait until the watchdog timer
+	 * running on a different CPU finishes
+	 */
+	del_timer_sync(&cd->watchdog_timer);
+	cancel_work_sync(&cd->watchdog_work);
+	del_timer_sync(&cd->watchdog_timer);
+}
+
+static int start_fw_upgrade(void *data)
+{
+	struct cyttsp5_core_data *cd = (struct cyttsp5_core_data *)data;
+
+	call_atten_cb(cd, CY_ATTEN_LOADER, 0);
+	return 0;
+}
+
+static void cyttsp5_watchdog_work(struct work_struct *work)
+{
+	struct cyttsp5_core_data *cd =
+			container_of(work, struct cyttsp5_core_data,
+					watchdog_work);
+	int rc;
+	 /*fix CDT207254
+	*if found the current sleep_state is SS_SLEEPING
+	*then no need to request_exclusive, directly return
+	*/
+	if (cd->sleep_state == SS_SLEEPING)
+		return;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		goto queue_startup;
+	}
+
+	rc = cyttsp5_hid_output_null_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+queue_startup:
+	if (rc) {
+		dev_err(cd->dev,
+			"%s: failed to access device in watchdog timer r=%d\n",
+			__func__, rc);
+
+		/* Already tried FW upgrade because of watchdog but failed */
+		if (cd->startup_retry_count > CY_WATCHDOG_RETRY_COUNT)
+			return;
+
+		if (cd->startup_retry_count++ < CY_WATCHDOG_RETRY_COUNT)
+			cyttsp5_queue_startup(cd);
+		else
+			kthread_run(start_fw_upgrade, cd, "cyttp5_loader");
+
+		return;
+	}
+
+	cyttsp5_start_wd_timer(cd);
+}
+
+static void cyttsp5_watchdog_timer(unsigned long handle)
+{
+	struct cyttsp5_core_data *cd = (struct cyttsp5_core_data *)handle;
+
+	if (!cd)
+		return;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: Watchdog timer triggered\n",
+		__func__);
+
+	if (!work_pending(&cd->watchdog_work))
+		schedule_work(&cd->watchdog_work);
+}
+
+static int cyttsp5_put_device_into_easy_wakeup_(struct cyttsp5_core_data *cd)
+{
+	int rc;
+	u8 status = 0;
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: enter\n",
+			__func__);
+	mutex_lock(&cd->system_lock);
+	cd->wait_until_wake = 0;
+	mutex_unlock(&cd->system_lock);
+
+	rc = cyttsp5_hid_output_enter_easywake_state_(cd,
+			cd->easy_wakeup_gesture, &status);
+	if (rc || status == 0)
+		return -EBUSY;
+
+	return rc;
+}
+
+static int cyttsp5_put_device_into_deep_sleep_(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: enter\n",
+			__func__);
+
+	rc = cyttsp5_hid_cmd_set_power_(cd, HID_POWER_SLEEP);
+	if (rc)
+		rc = -EBUSY;
+	return rc;
+}
+
+static int cyttsp5_put_device_into_deep_sleep(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_put_device_into_deep_sleep_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+
+	return rc;
+}
+
+
+static int _cyttsp5_request_put_device_into_deep_sleep(
+	struct device *dev,	int protect)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	int rc;
+
+	/* Ensure watchdog and startup works stopped */
+	cyttsp5_stop_wd_timer(cd);
+	cancel_work_sync(&cd->startup_work);
+	cyttsp5_stop_wd_timer(cd);
+
+	if (protect)
+		rc = cyttsp5_put_device_into_deep_sleep(cd);
+
+	rc = cyttsp5_put_device_into_deep_sleep_(cd);
+
+	mutex_lock(&cd->system_lock);
+	cd->sleep_state = SS_SLEEP_ON;
+	mutex_unlock(&cd->system_lock);
+
+	return rc;
+}
+
+static int cyttsp5_put_device_into_sleep_(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	if (IS_DEEP_SLEEP_CONFIGURED(cd->easy_wakeup_gesture))
+		rc = cyttsp5_put_device_into_deep_sleep_(cd);
+	else
+		rc = cyttsp5_put_device_into_easy_wakeup_(cd);
+
+	return rc;
+}
+
+static int cyttsp5_core_poweroff_device_(struct cyttsp5_core_data *cd)
+{
+	int rc;
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: enter\n",
+			__func__);
+
+	if (cd->irq_enabled) {
+		cd->irq_enabled = false;
+		disable_irq_nosync(cd->irq);
+	}
+
+	rc = cd->cpdata->power(cd->cpdata, 0, cd->dev, 0);
+	if (rc < 0)
+		dev_err(cd->dev, "%s: HW Power down fails r=%d\n",
+				__func__, rc);
+	return rc;
+}
+
+static int cyttsp5_core_sleep_(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	mutex_lock(&cd->system_lock);
+	if (cd->sleep_state == SS_SLEEP_OFF) {
+		cd->sleep_state = SS_SLEEPING;
+	} else {
+		mutex_unlock(&cd->system_lock);
+		return 1;
+	}
+	mutex_unlock(&cd->system_lock);
+
+	/* Ensure watchdog and startup works stopped */
+	cyttsp5_stop_wd_timer(cd);
+	cancel_work_sync(&cd->startup_work);
+	cyttsp5_stop_wd_timer(cd);
+
+	if (cd->cpdata->flags & CY_CORE_FLAG_POWEROFF_ON_SLEEP)
+		rc = cyttsp5_core_poweroff_device_(cd);
+	else
+		rc = cyttsp5_put_device_into_sleep_(cd);
+
+	mutex_lock(&cd->system_lock);
+	cd->sleep_state = SS_SLEEP_ON;
+	mutex_unlock(&cd->system_lock);
+
+	return rc;
+}
+
+static int cyttsp5_core_sleep(struct cyttsp5_core_data *cd)
+{
+	int rc;
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_core_sleep_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+	else
+		parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: pass release exclusive\n",
+			__func__);
+
+	return rc;
+}
+
+static int cyttsp5_wakeup_host(struct cyttsp5_core_data *cd)
+{
+#ifndef EASYWAKE_TSG6
+	/* TSG5 EasyWake */
+	int rc = 0;
+	int event_id;
+	int size = get_unaligned_le16(&cd->input_buf[0]);
+
+	/* Validate report */
+	if (size != 4 || cd->input_buf[2] != 4)
+		rc = -EINVAL;
+
+	cd->wake_initiated_by_device = 1;
+	event_id = cd->input_buf[3];
+
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: e=%d, rc=%d\n",
+		__func__, event_id, rc);
+
+	if (rc) {
+		cyttsp5_core_sleep_(cd);
+		goto exit;
+	}
+
+	/* attention WAKE */
+	call_atten_cb(cd, CY_ATTEN_WAKE, 0);
+exit:
+	return rc;
+#else
+	/* TSG6 FW1.3 EasyWake */
+	int rc = 0;
+	int i = 0;
+	int report_length;
+
+	/* Validate report */
+	if (cd->input_buf[2] != 4)
+		rc = -EINVAL;
+
+	cd->wake_initiated_by_device = 1;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: rc=%d\n", __func__, rc);
+
+	if (rc) {
+		cyttsp5_core_sleep_(cd);
+		goto exit;
+	}
+
+	/* Get gesture id and gesture data length */
+	cd->gesture_id = cd->input_buf[3];
+	report_length = (cd->input_buf[1] << 8) | (cd->input_buf[0]);
+	cd->gesture_data_length = report_length - 4;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: gesture_id = %d, gesture_data_length = %d\n",
+		__func__, cd->gesture_id, cd->gesture_data_length);
+
+	for (i = 0; i < cd->gesture_data_length; i++)
+		cd->gesture_data[i] = cd->input_buf[4 + i];
+
+	/* attention WAKE */
+	call_atten_cb(cd, CY_ATTEN_WAKE, 0);
+exit:
+	return rc;
+#endif
+}
+
+static void cyttsp5_get_touch_axis(struct cyttsp5_core_data *cd,
+	int *axis, int size, int max, u8 *data, int bofs)
+{
+	int nbyte;
+	int next;
+
+	for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
+		*axis = *axis + ((data[next] >> bofs) << (nbyte * 8));
+		next++;
+	}
+
+	*axis &= max - 1;
+}
+
+static int move_tracking_hetmap_data(struct cyttsp5_core_data *cd,
+	struct cyttsp5_sysinfo *si)
+{
+#ifdef TTHE_TUNER_SUPPORT
+	int size = get_unaligned_le16(&cd->input_buf[0]);
+
+	if (size)
+		tthe_print(cd, cd->input_buf, size, "THM=");
+#endif
+	memcpy(si->xy_mode, cd->input_buf, SENSOR_HEADER_SIZE);
+	return 0;
+}
+
+static int move_sensor_data(struct cyttsp5_core_data *cd,
+	struct cyttsp5_sysinfo *si)
+{
+#ifdef TTHE_TUNER_SUPPORT
+	int size = get_unaligned_le16(&cd->input_buf[0]);
+
+	if (size)
+		tthe_print(cd, cd->input_buf, size, "sensor_monitor=");
+#endif
+	memcpy(si->xy_mode, cd->input_buf, SENSOR_HEADER_SIZE);
+	return 0;
+}
+
+static int move_button_data(struct cyttsp5_core_data *cd,
+	struct cyttsp5_sysinfo *si)
+{
+#ifdef TTHE_TUNER_SUPPORT
+	int size = get_unaligned_le16(&cd->input_buf[0]);
+
+	if (size)
+		tthe_print(cd, cd->input_buf, size, "OpModeData=");
+#endif
+	memcpy(si->xy_mode, cd->input_buf, BTN_INPUT_HEADER_SIZE);
+	cyttsp5_pr_buf(cd->dev, (u8 *)si->xy_mode, BTN_INPUT_HEADER_SIZE,
+			"xy_mode");
+
+	memcpy(si->xy_data, &cd->input_buf[BTN_INPUT_HEADER_SIZE],
+			BTN_REPORT_SIZE);
+	cyttsp5_pr_buf(cd->dev, (u8 *)si->xy_data, BTN_REPORT_SIZE, "xy_data");
+	return 0;
+}
+
+static int move_touch_data(struct cyttsp5_core_data *cd,
+	struct cyttsp5_sysinfo *si)
+{
+	int max_tch = si->sensing_conf_data.max_tch;
+	int num_cur_tch;
+	int length;
+	struct cyttsp5_tch_abs_params *tch = &si->tch_hdr[CY_TCH_NUM];
+#ifdef TTHE_TUNER_SUPPORT
+	int size = get_unaligned_le16(&cd->input_buf[0]);
+
+	if (size)
+		tthe_print(cd, cd->input_buf, size, "OpModeData=");
+#endif
+
+	memcpy(si->xy_mode, cd->input_buf, si->desc.tch_header_size);
+	cyttsp5_pr_buf(cd->dev, (u8 *)si->xy_mode, si->desc.tch_header_size,
+			"xy_mode");
+
+	cyttsp5_get_touch_axis(cd, &num_cur_tch, tch->size,
+			tch->max, si->xy_mode + 3 + tch->ofs, tch->bofs);
+	if (unlikely(num_cur_tch > max_tch))
+		num_cur_tch = max_tch;
+
+	length = num_cur_tch * si->desc.tch_record_size;
+
+	memcpy(si->xy_data, &cd->input_buf[si->desc.tch_header_size], length);
+	cyttsp5_pr_buf(cd->dev, (u8 *)si->xy_data, length, "xy_data");
+	return 0;
+}
+
+static int parse_touch_input(struct cyttsp5_core_data *cd, int size)
+{
+	struct cyttsp5_sysinfo *si = &cd->sysinfo;
+	int report_id = cd->input_buf[2];
+	int rc = -EINVAL;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: Received touch report\n",
+		__func__);
+	if (!si->ready) {
+		dev_err(cd->dev,
+			"%s: Need system information to parse touches\n",
+			__func__);
+		return 0;
+	}
+
+	if (!si->xy_mode || !si->xy_data)
+		return rc;
+
+	if (report_id == si->desc.tch_report_id)
+		rc = move_touch_data(cd, si);
+	else if (report_id == si->desc.btn_report_id)
+		rc = move_button_data(cd, si);
+	else if (report_id == HID_SENSOR_DATA_REPORT_ID)
+		rc = move_sensor_data(cd, si);
+	else if (report_id == HID_TRACKING_HEATMAP_REPOR_ID)
+		rc = move_tracking_hetmap_data(cd, si);
+
+	if (rc)
+		return rc;
+
+	/* attention IRQ */
+	call_atten_cb(cd, CY_ATTEN_IRQ, cd->mode);
+
+	return 0;
+}
+
+static int parse_command_input(struct cyttsp5_core_data *cd, int size)
+{
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: Received cmd interrupt\n",
+		__func__);
+
+	memcpy(cd->response_buf, cd->input_buf, size);
+
+	mutex_lock(&cd->system_lock);
+	cd->hid_cmd_state = 0;
+	mutex_unlock(&cd->system_lock);
+	wake_up(&cd->wait_q);
+
+	return 0;
+}
+
+static int cyttsp5_parse_input(struct cyttsp5_core_data *cd)
+{
+	int report_id;
+	int is_command = 0;
+	int size;
+
+	size = get_unaligned_le16(&cd->input_buf[0]);
+
+	/* check reset */
+	if (size == 0) {
+		parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: Reset complete\n",
+			__func__);
+		memcpy(cd->response_buf, cd->input_buf, 2);
+		mutex_lock(&cd->system_lock);
+		if (!cd->hid_reset_cmd_state && !cd->hid_cmd_state) {
+			mutex_unlock(&cd->system_lock);
+			parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: Device Initiated Reset\n",
+				__func__);
+			return 0;
+		}
+
+		cd->hid_reset_cmd_state = 0;
+		if (cd->hid_cmd_state == HID_OUTPUT_START_BOOTLOADER + 1
+				|| cd->hid_cmd_state ==
+					HID_OUTPUT_BL_LAUNCH_APP + 1
+				|| cd->hid_cmd_state ==
+					HID_OUTPUT_USER_CMD + 1)
+			cd->hid_cmd_state = 0;
+		wake_up(&cd->wait_q);
+		mutex_unlock(&cd->system_lock);
+		return 0;
+	} else if (size == 2 || size >= CY_PIP_1P7_EMPTY_BUF)
+		/*
+		 * Before PIP 1.7, empty buffer is 0x0002;
+		 * From PIP 1.7, empty buffer is 0xFFXX
+		 */
+		return 0;
+
+	report_id = cd->input_buf[2];
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: report_id:%X\n",
+		__func__, report_id);
+
+	/* Check wake-up report */
+	if (report_id == HID_WAKEUP_REPORT_ID) {
+		cyttsp5_wakeup_host(cd);
+		return 0;
+	}
+
+	/* update watchdog expire time */
+	mod_timer_pending(&cd->watchdog_timer, jiffies +
+			msecs_to_jiffies(cd->watchdog_interval));
+
+	if (report_id != cd->sysinfo.desc.tch_report_id
+			&& report_id != cd->sysinfo.desc.btn_report_id
+			&& report_id != HID_SENSOR_DATA_REPORT_ID
+			&& report_id != HID_TRACKING_HEATMAP_REPOR_ID)
+		is_command = 1;
+
+	if (unlikely(is_command)) {
+		parse_command_input(cd, size);
+		return 0;
+	}
+	parse_touch_input(cd, size);
+	return 0;
+}
+
+static int cyttsp5_read_input(struct cyttsp5_core_data *cd)
+{
+	struct device *dev = cd->dev;
+	int rc;
+	int t;
+	//struct cyttsp5_mt_data *md = &cd->md;
+	/* added as workaround to CDT170960: easywake failure */
+	/* Interrupt for easywake, wait for bus controller to wake */
+	mutex_lock(&cd->system_lock);
+	if (!IS_DEEP_SLEEP_CONFIGURED(cd->easy_wakeup_gesture)) {
+		if (cd->sleep_state == SS_SLEEP_ON) {
+			mutex_unlock(&cd->system_lock);
+			if (!dev->power.is_suspended)
+				goto read;
+			t = wait_event_timeout(cd->wait_q,
+					(cd->wait_until_wake == 1),
+					msecs_to_jiffies(2000));
+			if (IS_TMO(t))
+				cyttsp5_queue_startup(cd);
+			goto read;
+		}
+	}
+	mutex_unlock(&cd->system_lock);
+
+read:
+	rc = cyttsp5_adap_read_default_nosize(cd, cd->input_buf, CY_MAX_INPUT);
+	if (rc) {
+		dev_err(dev, "%s: Error getting report, r=%d\n",
+				__func__, rc);
+		return rc;
+	}
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: Read input successfully\n",
+		__func__);
+	return rc;
+}
+
+static  bool cyttsp5_check_irq_asserted(struct cyttsp5_core_data *cd)
+{
+#ifdef ENABLE_WORKAROUND_FOR_GLITCH_AFTER_BL_LAUNCH_APP
+	/*
+	 * Workaround for FW defect, CDT165308
+	 * bl_launch app creates a glitch in IRQ line
+	 */
+	if (cd->hid_cmd_state == HID_OUTPUT_BL_LAUNCH_APP + 1
+			&& cd->cpdata->irq_stat){
+		/*
+		 * in X1S panel and GC1546 panel, the width for the INT
+		 * glitch is about 4us,the normal INT width of response
+		 * will last more than 200us, so use 10us delay
+		 * for distinguish the glitch the normal INT is enough.
+		 */
+		udelay(10);
+		if (cd->cpdata->irq_stat(cd->cpdata, cd->dev)
+			!= CY_IRQ_ASSERTED_VALUE)
+			return false;
+	}
+#endif
+	return true;
+}
+
+
+static irqreturn_t cyttsp5_irq(int irq, void *handle)
+{
+	struct cyttsp5_core_data *cd = handle;
+	int rc;
+
+	if (!cyttsp5_check_irq_asserted(cd))
+		return IRQ_HANDLED;
+
+	rc = cyttsp5_read_input(cd);
+	if (!rc)
+		cyttsp5_parse_input(cd);
+
+	return IRQ_HANDLED;
+}
+
+int _cyttsp5_subscribe_attention(struct device *dev,
+	enum cyttsp5_atten_type type, char *id, int (*func)(struct device *),
+	int mode)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct atten_node *atten, *atten_new;
+
+	atten_new = kzalloc(sizeof(*atten_new), GFP_KERNEL);
+	if (!atten_new)
+		return -ENOMEM;
+
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s from '%s'\n", __func__,
+		dev_name(cd->dev));
+
+	spin_lock(&cd->spinlock);
+	list_for_each_entry(atten, &cd->atten_list[type], node) {
+		if (atten->id == id && atten->mode == mode) {
+			spin_unlock(&cd->spinlock);
+			kfree(atten_new);
+			parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: %s=%p %s=%d\n",
+				 __func__,
+				 "already subscribed attention",
+				 dev, "mode", mode);
+
+			return 0;
+		}
+	}
+
+	atten_new->id = id;
+	atten_new->dev = dev;
+	atten_new->mode = mode;
+	atten_new->func = func;
+
+	list_add(&atten_new->node, &cd->atten_list[type]);
+	spin_unlock(&cd->spinlock);
+
+	return 0;
+}
+
+int _cyttsp5_unsubscribe_attention(struct device *dev,
+	enum cyttsp5_atten_type type, char *id, int (*func)(struct device *),
+	int mode)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct atten_node *atten, *atten_n;
+
+	spin_lock(&cd->spinlock);
+	list_for_each_entry_safe(atten, atten_n, &cd->atten_list[type], node) {
+		if (atten->id == id && atten->mode == mode) {
+			list_del(&atten->node);
+			spin_unlock(&cd->spinlock);
+			kfree(atten);
+			parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: %s=%p %s=%d\n",
+				__func__,
+				"unsub for atten->dev", atten->dev,
+				"atten->mode", atten->mode);
+			return 0;
+		}
+	}
+	spin_unlock(&cd->spinlock);
+
+	return -ENODEV;
+}
+
+static int _cyttsp5_request_exclusive(struct device *dev,
+		int timeout_ms)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	return request_exclusive(cd, (void *)dev, timeout_ms);
+}
+
+static int _cyttsp5_release_exclusive(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	return release_exclusive(cd, (void *)dev);
+}
+
+static int cyttsp5_reset(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	/* reset hardware */
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: reset hw...\n", __func__);
+	rc = cyttsp5_hw_reset(cd);
+	if (rc < 0)
+		dev_err(cd->dev, "%s: %s dev='%s' r=%d\n", __func__,
+			"Fail hw reset", dev_name(cd->dev), rc);
+	return rc;
+}
+
+static int cyttsp5_reset_and_wait(struct cyttsp5_core_data *cd)
+{
+	int rc;
+	int t;
+
+	mutex_lock(&cd->system_lock);
+	cd->hid_reset_cmd_state = 1;
+	mutex_unlock(&cd->system_lock);
+
+	rc = cyttsp5_reset(cd);
+	if (rc < 0)
+		goto error;
+
+	t = wait_event_timeout(cd->wait_q, (cd->hid_reset_cmd_state == 0),
+			msecs_to_jiffies(CY_HID_RESET_TIMEOUT));
+	if (IS_TMO(t)) {
+		dev_err(cd->dev, "%s: reset timed out\n",
+			__func__);
+		rc = -ETIME;
+		goto error;
+	}
+
+	goto exit;
+
+error:
+	mutex_lock(&cd->system_lock);
+	cd->hid_reset_cmd_state = 0;
+	mutex_unlock(&cd->system_lock);
+exit:
+	return rc;
+}
+
+/*
+ * returns err if refused or timeout(core uses fixed timeout period) occurs;
+ * blocks until ISR occurs
+ */
+static int _cyttsp5_request_reset(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	int rc;
+
+	mutex_lock(&cd->system_lock);
+	cd->hid_reset_cmd_state = 1;
+	mutex_unlock(&cd->system_lock);
+
+	rc = cyttsp5_reset(cd);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: Error on h/w reset r=%d\n",
+			__func__, rc);
+		mutex_lock(&cd->system_lock);
+		cd->hid_reset_cmd_state = 0;
+		mutex_unlock(&cd->system_lock);
+	}
+
+	return rc;
+}
+
+/*
+ * returns err if refused ; if no error then restart has completed
+ * and system is in normal operating mode
+ */
+static int _cyttsp5_request_restart(struct device *dev, bool wait)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	cyttsp5_queue_startup(cd);
+
+	if (wait)
+		wait_event(cd->wait_q, cd->startup_state == STARTUP_NONE);
+
+	return 0;
+}
+
+/*
+ * returns NULL if sysinfo has not been acquired from the device yet
+ */
+struct cyttsp5_sysinfo *_cyttsp5_request_sysinfo(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (cd->sysinfo.ready)
+		return &cd->sysinfo;
+
+	return NULL;
+}
+
+static struct cyttsp5_loader_platform_data *_cyttsp5_request_loader_pdata(
+		struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	return cd->pdata->loader_pdata;
+}
+
+static int _cyttsp5_request_start_wd(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	cyttsp5_start_wd_timer(cd);
+	return 0;
+}
+
+static int _cyttsp5_request_stop_wd(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	cyttsp5_stop_wd_timer(cd);
+	return 0;
+}
+
+static int cyttsp5_core_wake_device_from_deep_sleep_(
+		struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = cyttsp5_hid_cmd_set_power_(cd, HID_POWER_ON);
+	if (rc)
+		rc =  -EAGAIN;
+
+	/* Prevent failure on sequential wake/sleep requests from OS */
+	msleep(20);
+
+	return rc;
+}
+
+static int cyttsp5_core_wake_device_(struct cyttsp5_core_data *cd)
+{
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: enter\n",
+				__func__);
+
+	if (!IS_DEEP_SLEEP_CONFIGURED(cd->easy_wakeup_gesture)) {
+		mutex_lock(&cd->system_lock);
+		cd->wait_until_wake = 1;
+		mutex_unlock(&cd->system_lock);
+		wake_up(&cd->wait_q);
+		msleep(20);
+
+		if (cd->wake_initiated_by_device) {
+			cd->wake_initiated_by_device = 0;
+			return 0;
+		}
+	}
+
+	return cyttsp5_core_wake_device_from_deep_sleep_(cd);
+}
+
+static int cyttsp5_restore_parameters_(struct cyttsp5_core_data *cd)
+{
+	struct param_node *param;
+	int rc = 0;
+
+	if (!(cd->cpdata->flags & CY_CORE_FLAG_RESTORE_PARAMETERS))
+		goto exit;
+
+	spin_lock(&cd->spinlock);
+	list_for_each_entry(param, &cd->param_list, node) {
+		spin_unlock(&cd->spinlock);
+		parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: Parameter id:%d value:%d\n",
+			 __func__, param->id, param->value);
+		rc = cyttsp5_hid_output_set_param_(cd, param->id,
+				param->value, param->size);
+		if (rc)
+			goto exit;
+		spin_lock(&cd->spinlock);
+	}
+	spin_unlock(&cd->spinlock);
+exit:
+	return rc;
+}
+
+static int _fast_startup(struct cyttsp5_core_data *cd)
+{
+	int retry = CY_CORE_STARTUP_RETRY_COUNT;
+	int rc;
+
+reset:
+	if (retry != CY_CORE_STARTUP_RETRY_COUNT)
+		parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: Retry %d\n",
+			__func__, CY_CORE_STARTUP_RETRY_COUNT - retry);
+
+	rc = cyttsp5_get_hid_descriptor_(cd, &cd->hid_desc);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: Error on getting HID descriptor r=%d\n",
+			__func__, rc);
+		if (retry--)
+			goto reset;
+		goto exit;
+	}
+	cd->mode = cyttsp5_get_mode(cd, &cd->hid_desc);
+
+	if (cd->mode == CY_MODE_BOOTLOADER) {
+		dev_info(cd->dev, "%s: Bootloader mode\n", __func__);
+		rc = cyttsp5_hid_output_bl_launch_app_(cd);
+		if (rc < 0) {
+			dev_err(cd->dev, "%s: Error on launch app r=%d\n",
+				__func__, rc);
+			if (retry--)
+				goto reset;
+			goto exit;
+		}
+		rc = cyttsp5_get_hid_descriptor_(cd, &cd->hid_desc);
+		if (rc < 0) {
+			dev_err(cd->dev,
+				"%s: Error on getting HID descriptor r=%d\n",
+				__func__, rc);
+			if (retry--)
+				goto reset;
+			goto exit;
+		}
+		cd->mode = cyttsp5_get_mode(cd, &cd->hid_desc);
+		if (cd->mode == CY_MODE_BOOTLOADER) {
+			if (retry--)
+				goto reset;
+			goto exit;
+		}
+	}
+
+	rc = cyttsp5_restore_parameters_(cd);
+	if (rc)
+		dev_err(cd->dev, "%s: failed to restore parameters rc=%d\n",
+			__func__, rc);
+
+exit:
+	return rc;
+}
+
+static int cyttsp5_core_poweron_device_(struct cyttsp5_core_data *cd)
+{
+	struct device *dev = cd->dev;
+	int rc;
+
+	rc = cd->cpdata->power(cd->cpdata, 1, dev, 0);
+	if (rc < 0) {
+		dev_err(dev, "%s: HW Power up fails r=%d\n", __func__, rc);
+		goto exit;
+	}
+
+	if (!cd->irq_enabled) {
+		cd->irq_enabled = true;
+		enable_irq(cd->irq);
+	}
+
+	rc = _fast_startup(cd);
+exit:
+	return rc;
+}
+
+static int _cyttsp5_request_core_wake_device(struct device *dev,	int protect)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	int rc;
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: enter\n",
+			__func__);
+
+	mutex_lock(&cd->system_lock);
+	if (cd->sleep_state == SS_SLEEP_ON) {
+		cd->sleep_state = SS_WAKING;
+	} else {
+		mutex_unlock(&cd->system_lock);
+		return 1;
+	}
+	mutex_unlock(&cd->system_lock);
+
+	if (protect) {
+		rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+		if (rc < 0) {
+			dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+			return rc;
+		}
+
+		rc = cyttsp5_core_wake_device_from_deep_sleep_(cd);
+
+		if (release_exclusive(cd, cd->dev) < 0)
+			dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+		else
+			parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: pass release exclusive\n",
+			__func__);
+	}
+
+	rc = cyttsp5_core_wake_device_from_deep_sleep_(cd);
+
+	mutex_lock(&cd->system_lock);
+	cd->sleep_state = SS_SLEEP_OFF;
+	mutex_unlock(&cd->system_lock);
+
+	cyttsp5_start_wd_timer(cd);
+	return rc;
+}
+
+
+static int cyttsp5_core_wake_(struct cyttsp5_core_data *cd)
+{
+	int rc;
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: enter\n",
+			__func__);
+
+	mutex_lock(&cd->system_lock);
+	if (cd->sleep_state == SS_SLEEP_ON) {
+		cd->sleep_state = SS_WAKING;
+	} else {
+		mutex_unlock(&cd->system_lock);
+		return 1;
+	}
+	mutex_unlock(&cd->system_lock);
+
+	if (cd->cpdata->flags & CY_CORE_FLAG_POWEROFF_ON_SLEEP)
+		rc = cyttsp5_core_poweron_device_(cd);
+	else
+		rc = cyttsp5_core_wake_device_(cd);
+
+	mutex_lock(&cd->system_lock);
+	cd->sleep_state = SS_SLEEP_OFF;
+	mutex_unlock(&cd->system_lock);
+
+	cyttsp5_start_wd_timer(cd);
+	return rc;
+}
+
+static int cyttsp5_core_wake(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		return rc;
+	}
+
+	rc = cyttsp5_core_wake_(cd);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+	else
+		parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: pass release exclusive\n",
+			__func__);
+
+	return rc;
+}
+
+static int cyttsp5_get_ic_crc_(struct cyttsp5_core_data *cd, u8 ebid)
+{
+	struct cyttsp5_sysinfo *si = &cd->sysinfo;
+	int rc;
+	u8 status;
+	u16 calculated_crc = 0;
+	u16 stored_crc = 0;
+
+	rc = cyttsp5_hid_output_suspend_scanning_(cd);
+	if (rc)
+		goto error;
+
+	rc = cyttsp5_hid_output_verify_config_block_crc_(cd, ebid, &status,
+			&calculated_crc, &stored_crc);
+	if (rc)
+		goto exit;
+
+	if (status) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	si->ttconfig.crc = stored_crc;
+
+exit:
+	cyttsp5_hid_output_resume_scanning_(cd);
+error:
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: CRC: ebid:%d, crc:0x%04X\n",
+		__func__, ebid, si->ttconfig.crc);
+	return rc;
+}
+
+static int cyttsp5_check_and_deassert_int(struct cyttsp5_core_data *cd)
+{
+	u16 size;
+	u8 buf[2];
+	u8 *p;
+	u8 retry = 3;
+	int rc;
+
+	do {
+		rc = cyttsp5_adap_read_default(cd, buf, 2);
+		if (rc < 0)
+			return rc;
+		size = get_unaligned_le16(&buf[0]);
+
+		if (size == 2 || size == 0 || size >= CY_PIP_1P7_EMPTY_BUF)
+			return 0;
+
+		p = kzalloc(size, GFP_KERNEL);
+		if (!p)
+			return -ENOMEM;
+
+		rc = cyttsp5_adap_read_default(cd, p, size);
+		kfree(p);
+		if (rc < 0)
+			return rc;
+	} while (retry--);
+
+	return -EINVAL;
+}
+
+static int cyttsp5_startup_(struct cyttsp5_core_data *cd, bool reset)
+{
+	int retry = CY_CORE_STARTUP_RETRY_COUNT;
+	int rc;
+	bool detected = false;
+
+#ifdef TTHE_TUNER_SUPPORT
+	tthe_print(cd, NULL, 0, "enter startup");
+#endif
+
+	cyttsp5_stop_wd_timer(cd);
+
+reset:
+	if (retry != CY_CORE_STARTUP_RETRY_COUNT)
+		parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: Retry %d\n",
+			__func__, CY_CORE_STARTUP_RETRY_COUNT - retry);
+
+	rc = cyttsp5_check_and_deassert_int(cd);
+
+	if (reset || retry != CY_CORE_STARTUP_RETRY_COUNT) {
+		/* reset hardware */
+		rc = cyttsp5_reset_and_wait(cd);
+		if (rc < 0) {
+			dev_err(cd->dev, "%s: Error on h/w reset r=%d\n",
+					__func__, rc);
+			if (retry--)
+				goto reset;
+			goto exit;
+		}
+	}
+
+	rc = cyttsp5_get_hid_descriptor_(cd, &cd->hid_desc);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: Error on getting HID descriptor r=%d\n",
+			__func__, rc);
+		if (retry--)
+			goto reset;
+		goto exit;
+	}
+	cd->mode = cyttsp5_get_mode(cd, &cd->hid_desc);
+
+	detected = true;
+
+	/* Switch to bootloader mode to get Panel ID */
+	if (cd->mode == CY_MODE_OPERATIONAL) {
+		rc = cyttsp5_hid_output_start_bootloader_(cd);
+		if (rc < 0) {
+			dev_err(cd->dev, "%s: Error on start bootloader r=%d\n",
+				__func__, rc);
+			if (retry--)
+				goto reset;
+			goto exit;
+		}
+		dev_info(cd->dev, "%s: Bootloader mode\n", __func__);
+	}
+
+	cyttsp5_hid_output_bl_get_panel_id_(cd, &cd->panel_id);
+
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: Panel ID: 0x%02X\n",
+		__func__, cd->panel_id);
+
+	rc = cyttsp5_hid_output_bl_launch_app_(cd);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: Error on launch app r=%d\n",
+			__func__, rc);
+		if (retry--)
+			goto reset;
+		goto exit;
+	}
+
+	rc = cyttsp5_get_hid_descriptor_(cd, &cd->hid_desc);
+	if (rc < 0) {
+		dev_err(cd->dev,
+			"%s: Error on getting HID descriptor r=%d\n",
+			__func__, rc);
+		if (retry--)
+			goto reset;
+		goto exit;
+	}
+	cd->mode = cyttsp5_get_mode(cd, &cd->hid_desc);
+	if (cd->mode == CY_MODE_BOOTLOADER) {
+		if (retry--)
+			goto reset;
+		goto exit;
+	}
+
+	mutex_lock(&cd->system_lock);
+	/* Read descriptor lengths */
+	cd->hid_core.hid_report_desc_len =
+		le16_to_cpu(cd->hid_desc.report_desc_len);
+	cd->hid_core.hid_max_input_len =
+		le16_to_cpu(cd->hid_desc.max_input_len);
+	cd->hid_core.hid_max_output_len =
+		le16_to_cpu(cd->hid_desc.max_output_len);
+
+	cd->mode = cyttsp5_get_mode(cd, &cd->hid_desc);
+	if (cd->mode == CY_MODE_OPERATIONAL)
+		dev_info(cd->dev, "%s: Operational mode\n", __func__);
+	else if (cd->mode == CY_MODE_BOOTLOADER)
+		dev_info(cd->dev, "%s: Bootloader mode\n", __func__);
+	else if (cd->mode == CY_MODE_UNKNOWN) {
+		dev_err(cd->dev, "%s: Unknown mode\n", __func__);
+		rc = -ENODEV;
+		mutex_unlock(&cd->system_lock);
+		if (retry--)
+			goto reset;
+		goto exit;
+	}
+	mutex_unlock(&cd->system_lock);
+
+	dev_info(cd->dev, "%s: Reading report descriptor\n", __func__);
+	rc = cyttsp5_get_report_descriptor_(cd);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: Error on getting report descriptor r=%d\n",
+			__func__, rc);
+		if (retry--)
+			goto reset;
+		goto exit;
+	}
+
+	if (!cd->features.easywake)
+		cd->easy_wakeup_gesture = CY_CORE_EWG_NONE;
+
+	rc = cyttsp5_hid_output_get_sysinfo_(cd);
+	if (rc) {
+		dev_err(cd->dev, "%s: Error on getting sysinfo r=%d\n",
+			__func__, rc);
+		if (retry--)
+			goto reset;
+		goto exit;
+	}
+
+	dev_info(cd->dev, "cyttsp5 Protocol Version: %d.%d\n",
+			cd->sysinfo.cydata.pip_ver_major,
+			cd->sysinfo.cydata.pip_ver_minor);
+
+	/* Read config version directly if PIP version < 1.2 */
+	if (!IS_PIP_VER_GE(&cd->sysinfo, 1, 2)) {
+		rc = cyttsp5_get_config_ver_(cd);
+		if (rc)
+			dev_err(cd->dev, "%s: failed to read config version rc=%d\n",
+				__func__, rc);
+	}
+
+	rc = cyttsp5_get_ic_crc_(cd, CY_TCH_PARM_EBID);
+	if (rc)
+		dev_err(cd->dev, "%s: failed to crc data rc=%d\n",
+			__func__, rc);
+
+	rc = cyttsp5_restore_parameters_(cd);
+	if (rc)
+		dev_err(cd->dev, "%s: failed to restore parameters rc=%d\n",
+			__func__, rc);
+
+	/* attention startup */
+	call_atten_cb(cd, CY_ATTEN_STARTUP, 0);
+
+exit:
+	if (!rc)
+		cd->startup_retry_count = 0;
+
+	cyttsp5_start_wd_timer(cd);
+
+	if (!detected)
+		rc = -ENODEV;
+
+#ifdef TTHE_TUNER_SUPPORT
+	tthe_print(cd, NULL, 0, "exit startup");
+#endif
+
+	return rc;
+}
+
+static int cyttsp5_startup(struct cyttsp5_core_data *cd, bool reset)
+{
+	int rc;
+
+	mutex_lock(&cd->system_lock);
+	cd->startup_state = STARTUP_RUNNING;
+	mutex_unlock(&cd->system_lock);
+
+	rc = request_exclusive(cd, cd->dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+				__func__, cd->exclusive_dev, cd->dev);
+		goto exit;
+	}
+
+	rc = cyttsp5_startup_(cd, reset);
+
+	if (release_exclusive(cd, cd->dev) < 0)
+		/* Don't return fail code, mode is already changed. */
+		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+	else
+		parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: pass release exclusive\n",
+			__func__);
+
+exit:
+	mutex_lock(&cd->system_lock);
+	cd->startup_state = STARTUP_NONE;
+	mutex_unlock(&cd->system_lock);
+
+	/* Wake the waiters for end of startup */
+	wake_up(&cd->wait_q);
+
+	return rc;
+}
+
+static void cyttsp5_startup_work_function(struct work_struct *work)
+{
+	struct cyttsp5_core_data *cd =  container_of(work,
+		struct cyttsp5_core_data, startup_work);
+	int rc;
+
+	rc = cyttsp5_startup(cd, true);
+	if (rc < 0)
+		dev_err(cd->dev, "%s: Fail queued startup r=%d\n",
+			__func__, rc);
+}
+
+/*
+ * CONFIG_PM_RUNTIME option is removed in 3.19.0.
+ */
+#if defined(CONFIG_PM_RUNTIME) || \
+		(KERNEL_VERSION(3, 19, 0) <= LINUX_VERSION_CODE)
+static int cyttsp5_core_rt_suspend(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	int rc;
+
+	rc = cyttsp5_core_sleep(cd);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on sleep\n", __func__);
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static int cyttsp5_core_rt_resume(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	int rc;
+	parade_debug(cd->dev, DEBUG_LEVEL_2, "%s: enter\n",
+			__func__);
+
+	rc = cyttsp5_core_wake(cd);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on wake\n", __func__);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_PM_SLEEP)
+static int cyttsp5_core_suspend(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	//cyttsp5_core_sleep(cd);
+
+	if (IS_DEEP_SLEEP_CONFIGURED(cd->easy_wakeup_gesture))
+		return 0;
+
+	/*
+	 * This will not prevent resume
+	 * Required to prevent interrupts before i2c awake
+	 */
+	disable_irq(cd->irq);
+	cd->irq_disabled = 1;
+
+	if (device_may_wakeup(dev)) {
+		parade_debug(dev, DEBUG_LEVEL_2, "%s Device MAY wakeup\n",
+			__func__);
+		if (!enable_irq_wake(cd->irq))
+			cd->irq_wake = 1;
+	} else {
+		parade_debug(dev, DEBUG_LEVEL_1, "%s Device MAY NOT wakeup\n",
+			__func__);
+	}
+
+	return 0;
+}
+
+static int cyttsp5_core_resume(struct device *dev)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	if (IS_DEEP_SLEEP_CONFIGURED(cd->easy_wakeup_gesture))
+		goto exit;
+
+	/*
+	 * I2C bus pm does not call suspend if device runtime suspended
+	 * This flag is cover that case
+	 */
+	if (cd->irq_disabled) {
+		enable_irq(cd->irq);
+		cd->irq_disabled = 0;
+	}
+
+	if (device_may_wakeup(dev)) {
+		parade_debug(dev, DEBUG_LEVEL_2, "%s Device MAY wakeup\n",
+			__func__);
+		if (cd->irq_wake) {
+			disable_irq_wake(cd->irq);
+			cd->irq_wake = 0;
+		}
+	} else {
+		parade_debug(dev, DEBUG_LEVEL_1, "%s Device MAY NOT wakeup\n",
+			__func__);
+	}
+
+exit:
+	//cyttsp5_core_wake(cd);
+
+	return 0;
+}
+#endif
+
+#if NEED_SUSPEND_NOTIFIER
+static int cyttsp5_pm_notifier(struct notifier_block *nb,
+		unsigned long action, void *data)
+{
+	struct cyttsp5_core_data *cd = container_of(nb,
+			struct cyttsp5_core_data, pm_notifier);
+
+	if (action == PM_SUSPEND_PREPARE) {
+		parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: Suspend prepare\n",
+			__func__);
+
+		/*
+		 * If not runtime PM suspended, either call runtime
+		 * PM suspend callback or wait until it finishes
+		 */
+		if (!pm_runtime_suspended(cd->dev))
+			pm_runtime_suspend(cd->dev);
+
+		(void) cyttsp5_core_suspend(cd->dev);
+	}
+
+	return NOTIFY_DONE;
+}
+#endif
+
+const struct dev_pm_ops cyttsp5_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(cyttsp5_core_suspend, cyttsp5_core_resume)
+	SET_RUNTIME_PM_OPS(cyttsp5_core_rt_suspend, cyttsp5_core_rt_resume,
+			NULL)
+};
+EXPORT_SYMBOL_GPL(cyttsp5_pm_ops);
+
+/*
+ * Show Firmware version via sysfs
+ */
+static ssize_t cyttsp5_ic_ver_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct cyttsp5_cydata *cydata = &cd->sysinfo.cydata;
+
+	return sprintf(buf,
+		"%s: 0x%02X\n"
+		"%s: 0x%02X\n"
+		"%s: 0x%08X\n"
+		"%s: 0x%04X\n"
+		"%s: 0x%02X\n"
+		"%s: 0x%02X\n"
+		"%s: 0x%02X\n"
+		"%s: 0x%02X\n",
+		"Firmware Major Version", cydata->fw_ver_major,
+		"Firmware Minor Version", cydata->fw_ver_minor,
+		"Revision Control Number", cydata->revctrl,
+		"Firmware Configuration Version", cydata->fw_ver_conf,
+		"Bootloader Major Version", cydata->bl_ver_major,
+		"Bootloader Minor Version", cydata->bl_ver_minor,
+		"Protocol Major Version", cydata->pip_ver_major,
+		"Protocol Minor Version", cydata->pip_ver_minor);
+}
+
+/*
+ * Show Driver version via sysfs
+ */
+static ssize_t cyttsp5_drv_ver_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, CY_MAX_PRBUF_SIZE,
+		"Driver: %s\nVersion: %s\nDate: %s\n",
+		cy_driver_core_name, cy_driver_core_version,
+		cy_driver_core_date);
+}
+
+/*
+ * HW reset via sysfs
+ */
+static ssize_t cyttsp5_hw_reset_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	int rc;
+
+	rc = cyttsp5_startup(cd, true);
+	if (rc < 0)
+		dev_err(dev, "%s: HW reset failed r=%d\n",
+			__func__, rc);
+
+	return size;
+}
+
+/*
+ * Show IRQ status via sysfs
+ */
+static ssize_t cyttsp5_hw_irq_stat_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	int retval;
+
+	if (cd->cpdata->irq_stat) {
+		retval = cd->cpdata->irq_stat(cd->cpdata, dev);
+		switch (retval) {
+		case 0:
+			return snprintf(buf, CY_MAX_PRBUF_SIZE,
+				"Interrupt line is LOW.\n");
+		case 1:
+			return snprintf(buf, CY_MAX_PRBUF_SIZE,
+				"Interrupt line is HIGH.\n");
+		default:
+			return snprintf(buf, CY_MAX_PRBUF_SIZE,
+				"Function irq_stat() returned %d.\n", retval);
+		}
+	}
+
+	return snprintf(buf, CY_MAX_PRBUF_SIZE,
+		"Function irq_stat() undefined.\n");
+}
+
+/*
+ * Show IRQ enable/disable status via sysfs
+ */
+static ssize_t cyttsp5_drv_irq_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	ssize_t ret;
+
+	mutex_lock(&cd->system_lock);
+	if (cd->irq_enabled)
+		ret = snprintf(buf, CY_MAX_PRBUF_SIZE,
+			"Driver interrupt is ENABLED\n");
+	else
+		ret = snprintf(buf, CY_MAX_PRBUF_SIZE,
+			"Driver interrupt is DISABLED\n");
+	mutex_unlock(&cd->system_lock);
+
+	return ret;
+}
+
+/*
+ * Enable/disable IRQ via sysfs
+ */
+static ssize_t cyttsp5_drv_irq_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	unsigned long value;
+	int retval = 0;
+
+	retval = kstrtoul(buf, 10, &value);
+	if (retval < 0) {
+		dev_err(dev, "%s: Invalid value\n", __func__);
+		goto cyttsp5_drv_irq_store_error_exit;
+	}
+
+	mutex_lock(&cd->system_lock);
+	switch (value) {
+	case 0:
+		if (cd->irq_enabled) {
+			cd->irq_enabled = false;
+			/* Disable IRQ */
+			disable_irq_nosync(cd->irq);
+			dev_info(dev, "%s: Driver IRQ now disabled\n",
+				__func__);
+		} else
+			dev_info(dev, "%s: Driver IRQ already disabled\n",
+				__func__);
+		break;
+
+	case 1:
+		if (cd->irq_enabled == false) {
+			cd->irq_enabled = true;
+			/* Enable IRQ */
+			enable_irq(cd->irq);
+			dev_info(dev, "%s: Driver IRQ now enabled\n",
+				__func__);
+		} else
+			dev_info(dev, "%s: Driver IRQ already enabled\n",
+				__func__);
+		break;
+
+	default:
+		dev_err(dev, "%s: Invalid value\n", __func__);
+	}
+	mutex_unlock(&(cd->system_lock));
+
+cyttsp5_drv_irq_store_error_exit:
+
+	return size;
+}
+
+/*
+ * Gets user input from sysfs and parse it
+ * return size of parsed output buffer
+ */
+
+#define CY_MAX_CONFIG_BYTES_DEC    256
+#define CYTTSP5_INPUT_ELEM_SZ_DEC 10
+
+static int cyttsp5_ic_parse_input_dec(struct device *dev, const char *buf,
+		size_t buf_size, u32 *ic_buf, size_t ic_buf_size)
+{
+	const char *pbuf = buf;
+	unsigned long value;
+	char scan_buf[CYTTSP5_INPUT_ELEM_SZ_DEC];
+	u32 i = 0;
+	u32 j;
+	int last = 0;
+	int ret;
+
+	parade_debug(dev, DEBUG_LEVEL_1, "%s: pbuf=%p buf=%p size=%zu %s=%zu buf=%s\n",
+		__func__, pbuf, buf, buf_size, "scan buf size",
+		(size_t)CYTTSP5_INPUT_ELEM_SZ_DEC, buf);
+
+	while (pbuf <= (buf + buf_size)) {
+		if (i >= CY_MAX_CONFIG_BYTES_DEC) {
+			dev_err(dev, "%s: %s size=%d max=%d\n", __func__,
+					"Max cmd size exceeded", i,
+					CY_MAX_CONFIG_BYTES_DEC);
+			return -EINVAL;
+		}
+		if (i >= ic_buf_size) {
+			dev_err(dev, "%s: %s size=%d buf_size=%zu\n", __func__,
+					"Buffer size exceeded", i, ic_buf_size);
+			return -EINVAL;
+		}
+		while (((*pbuf == ' ') || (*pbuf == ','))
+				&& (pbuf < (buf + buf_size))) {
+			last = *pbuf;
+			pbuf++;
+		}
+
+		if (pbuf >= (buf + buf_size))
+			break;
+
+		memset(scan_buf, 0, CYTTSP5_INPUT_ELEM_SZ_DEC);
+		if ((last == ',') && (*pbuf == ',')) {
+			dev_err(dev, "%s: %s \",,\" not allowed.\n", __func__,
+					"Invalid data format.");
+			return -EINVAL;
+		}
+		for (j = 0; j < (CYTTSP5_INPUT_ELEM_SZ_DEC - 1)
+				&& (pbuf < (buf + buf_size))
+				&& (*pbuf != ' ')
+				&& (*pbuf != ','); j++) {
+			last = *pbuf;
+			scan_buf[j] = *pbuf++;
+		}
+		ret = kstrtoul(scan_buf, 10, &value);
+		if (ret < 0) {
+			dev_err(dev, "%s: Invalid data format.\n", __func__);
+			return ret;
+		}
+
+		ic_buf[i] = value;
+		i++;
+	}
+
+	return i;
+}
+
+/*
+ * Debugging options via sysfs
+ */
+static ssize_t cyttsp5_drv_debug_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	unsigned long value;
+	int rc;
+	u8 return_data[8];
+	static u8 wd_disabled;
+	u32 input_data[2];
+	int length;
+
+	/*maximal input two data*/
+	length = cyttsp5_ic_parse_input_dec(dev, buf, size, input_data,
+			3);
+	if (length <= 0) {
+		dev_err(dev, "%s: %s failed\n", __func__,
+				"cyttsp5_ic_parse_input_dec");
+		goto cyttsp5_drv_debug_store_exit;
+	}
+	value = input_data[0];
+
+
+	/* Start watchdog timer command */
+	if (value == CY_DBG_HID_START_WD) {
+		dev_info(dev, "%s: start watchdog (cd=%p)\n", __func__, cd);
+		wd_disabled = 0;
+		cyttsp5_start_wd_timer(cd);
+		goto cyttsp5_drv_debug_store_exit;
+	}
+
+	/* Stop watchdog timer temporarily */
+	cyttsp5_stop_wd_timer(cd);
+
+	if (value == CY_DBG_HID_STOP_WD) {
+		dev_info(dev, "%s: stop watchdog (cd=%p)\n", __func__, cd);
+		wd_disabled = 1;
+		goto cyttsp5_drv_debug_store_exit;
+	}
+
+	switch (value) {
+	case CY_DBG_SUSPEND:
+		dev_info(dev, "%s: SUSPEND (cd=%p)\n", __func__, cd);
+		rc = cyttsp5_core_sleep(cd);
+		if (rc)
+			dev_err(dev, "%s: Suspend failed rc=%d\n",
+				__func__, rc);
+		else
+			dev_info(dev, "%s: Suspend succeeded\n", __func__);
+		break;
+
+	case CY_DBG_RESUME:
+		dev_info(dev, "%s: RESUME (cd=%p)\n", __func__, cd);
+		rc = cyttsp5_core_wake(cd);
+		if (rc)
+			dev_err(dev, "%s: Resume failed rc=%d\n",
+				__func__, rc);
+		else
+			dev_info(dev, "%s: Resume succeeded\n", __func__);
+		break;
+	case CY_DBG_SOFT_RESET:
+		dev_info(dev, "%s: SOFT RESET (cd=%p)\n", __func__, cd);
+		rc = cyttsp5_hw_soft_reset(cd);
+		break;
+	case CY_DBG_RESET:
+		dev_info(dev, "%s: HARD RESET (cd=%p)\n", __func__, cd);
+		rc = cyttsp5_hw_hard_reset(cd);
+		break;
+	case CY_DBG_HID_RESET:
+		dev_info(dev, "%s: hid_reset (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_cmd_reset(cd);
+		break;
+	case CY_DBG_HID_SET_POWER_ON:
+		dev_info(dev, "%s: hid_set_power_on (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_cmd_set_power(cd, HID_POWER_ON);
+		wd_disabled = 0;
+		break;
+	case CY_DBG_HID_SET_POWER_SLEEP:
+		dev_info(dev, "%s: hid_set_power_off (cd=%p)\n", __func__, cd);
+		wd_disabled = 1;
+		cyttsp5_hid_cmd_set_power(cd, HID_POWER_SLEEP);
+		break;
+	case CY_DBG_HID_NULL:
+		dev_info(dev, "%s: hid_null (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_output_null(cd);
+		break;
+	case CY_DBG_HID_ENTER_BL:
+		dev_info(dev, "%s: start_bootloader (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_output_start_bootloader(cd);
+		break;
+	case CY_DBG_HID_SYSINFO:
+		dev_info(dev, "%s: get_sysinfo (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_output_get_sysinfo(cd);
+		break;
+	case CY_DBG_HID_SUSPEND_SCAN:
+		dev_info(dev, "%s: suspend_scanning (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_output_suspend_scanning(cd);
+		break;
+	case CY_DBG_HID_RESUME_SCAN:
+		dev_info(dev, "%s: resume_scanning (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_output_resume_scanning(cd);
+		break;
+	case HID_OUTPUT_BL_VERIFY_APP_INTEGRITY:
+		dev_info(dev, "%s: verify app integ (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_output_bl_verify_app_integrity(cd, &return_data[0]);
+		break;
+	case HID_OUTPUT_BL_GET_INFO:
+		dev_info(dev, "%s: bl get info (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_output_bl_get_information(cd, return_data);
+		break;
+	case HID_OUTPUT_BL_PROGRAM_AND_VERIFY:
+		dev_info(dev, "%s: program and verify (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_output_bl_program_and_verify(cd, 0, NULL);
+		break;
+	case HID_OUTPUT_BL_LAUNCH_APP:
+		dev_info(dev, "%s: launch app (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_output_bl_launch_app(cd);
+		break;
+	case HID_OUTPUT_BL_INITIATE_BL:
+		dev_info(dev, "%s: initiate bl (cd=%p)\n", __func__, cd);
+		cyttsp5_hid_output_bl_initiate_bl(cd, 0, NULL, 0, NULL);
+		break;
+#ifdef TTHE_TUNER_SUPPORT
+	case CY_TTHE_TUNER_EXIT:
+		cd->tthe_exit = 1;
+		wake_up(&cd->wait_q);
+		kfree(cd->tthe_buf);
+		cd->tthe_buf = NULL;
+		cd->tthe_exit = 0;
+		break;
+	case CY_TTHE_BUF_CLEAN:
+		if (cd->tthe_buf)
+			memset(cd->tthe_buf, 0, CY_MAX_PRBUF_SIZE);
+		else
+			dev_info(dev, "%s : tthe_buf not existed\n", __func__);
+		break;
+#endif
+	case CY_DBG_REPORT_LEVEL:
+		mutex_lock(&cd->system_lock);
+		cd->debug_level = input_data[1];
+		dev_info(dev, "%s: Set debug_level: %d\n",
+			__func__, cd->debug_level);
+		mutex_unlock(&(cd->system_lock));
+		break;
+	case CY_DBG_WATCHDOG_INTERVAL:
+		mutex_lock(&cd->system_lock);
+		if (input_data[1] > 0)
+			cd->watchdog_interval = input_data[1];
+		dev_info(dev, "%s: Set watchdog_interval: %d\n",
+			__func__, cd->watchdog_interval);
+		mutex_unlock(&(cd->system_lock));
+		break;
+	case CY_DBG_SHOW_TIMESTAMP:
+		mutex_lock(&cd->system_lock);
+		cd->show_timestamp = input_data[1];
+		dev_info(dev, "%s: Set show_timestamp: %d\n",
+			__func__, cd->show_timestamp);
+		mutex_unlock(&(cd->system_lock));
+		break;
+
+	default:
+		dev_err(dev, "%s: Invalid value\n", __func__);
+	}
+
+	/* Enable watchdog timer */
+	if (!wd_disabled)
+		cyttsp5_start_wd_timer(cd);
+
+cyttsp5_drv_debug_store_exit:
+	return size;
+}
+
+/*
+ * Show system status on deep sleep status via sysfs
+ */
+static ssize_t cyttsp5_sleep_status_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	ssize_t ret;
+
+	mutex_lock(&cd->system_lock);
+	if (cd->sleep_state == SS_SLEEP_ON)
+		ret = snprintf(buf, CY_MAX_PRBUF_SIZE, "off\n");
+	else
+		ret = snprintf(buf, CY_MAX_PRBUF_SIZE, "on\n");
+	mutex_unlock(&cd->system_lock);
+
+	return ret;
+}
+
+static ssize_t cyttsp5_easy_wakeup_gesture_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	ssize_t ret;
+
+	mutex_lock(&cd->system_lock);
+	ret = snprintf(buf, CY_MAX_PRBUF_SIZE, "0x%02X\n",
+			cd->easy_wakeup_gesture);
+	mutex_unlock(&cd->system_lock);
+	return ret;
+}
+
+static ssize_t cyttsp5_easy_wakeup_gesture_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	unsigned long value;
+	int ret;
+
+	if (!cd->features.easywake)
+		return -EINVAL;
+
+	ret = kstrtoul(buf, 10, &value);
+	if (ret < 0)
+		return ret;
+
+	if (value > 0xFF)
+		return -EINVAL;
+
+	pm_runtime_get_sync(dev);
+
+	mutex_lock(&cd->system_lock);
+	if (cd->sysinfo.ready && IS_PIP_VER_GE(&cd->sysinfo, 1, 2))
+		cd->easy_wakeup_gesture = (u8)value;
+	else
+		ret = -ENODEV;
+	mutex_unlock(&cd->system_lock);
+
+	pm_runtime_put(dev);
+
+	if (ret)
+		return ret;
+
+	return size;
+}
+
+#ifdef EASYWAKE_TSG6
+/*
+ * Show easywake gesture id via sysfs
+ */
+static ssize_t cyttsp5_easy_wakeup_gesture_id_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	ssize_t ret;
+
+	mutex_lock(&cd->system_lock);
+	ret = snprintf(buf, CY_MAX_PRBUF_SIZE, "0x%02X\n",
+			cd->gesture_id);
+	mutex_unlock(&cd->system_lock);
+	return ret;
+}
+
+/*
+ * Show easywake gesture data via sysfs
+ * The format:
+ * x1(LSB), x1(MSB),y1(LSB), y1(MSB),x2(LSB), x2(MSB),y2(LSB), y2(MSB),...
+ */
+static ssize_t cyttsp5_easy_wakeup_gesture_data_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	ssize_t ret = 0;
+	int i;
+
+	mutex_lock(&cd->system_lock);
+
+	for (i = 0; i < cd->gesture_data_length; i++)
+		ret += snprintf(buf + ret, CY_MAX_PRBUF_SIZE - ret,
+				"0x%02X\n", cd->gesture_data[i]);
+
+	ret += snprintf(buf + ret, CY_MAX_PRBUF_SIZE - ret,
+			"(%d bytes)\n", cd->gesture_data_length);
+
+	mutex_unlock(&cd->system_lock);
+	return ret;
+}
+#endif
+
+/* Show Panel ID via sysfs */
+static ssize_t cyttsp5_panel_id_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	ssize_t ret;
+
+	ret = snprintf(buf, CY_MAX_PRBUF_SIZE, "0x%02X\n",
+			cd->panel_id);
+	return ret;
+}
+
+/* Show platform data via sysfs */
+static ssize_t cyttsp5_platform_data_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
+	ssize_t ret;
+
+	ret = sprintf(buf,
+		"%s: %d\n"
+		"%s: %d\n"
+		"%s: %d\n"
+		"%s: %d\n"
+		"%s: %d\n"
+		"%s: %d\n"
+		"%s: %d\n"
+		"%s: %d\n"
+		"%s: %d\n"
+		"%s: %d\n"
+		"%s: %d\n"
+		"%s: %d\n",
+		"Interrupt GPIO", pdata->core_pdata->irq_gpio,
+		"Reset GPIO", pdata->core_pdata->rst_gpio,
+		"Level trigger delay (us)", pdata->core_pdata->level_irq_udelay,
+		"HID descriptor register", pdata->core_pdata->hid_desc_register,
+		"Vendor ID", pdata->core_pdata->vendor_id,
+		"Product ID", pdata->core_pdata->product_id,
+		"Easy wakeup gesture", pdata->core_pdata->easy_wakeup_gesture,
+		"Vkeys x", pdata->mt_pdata->vkeys_x,
+		"Vkeys y", pdata->mt_pdata->vkeys_y,
+		"Core data flags", pdata->core_pdata->flags,
+		"MT data flags", pdata->mt_pdata->flags,
+		"Loader data flags", pdata->loader_pdata->flags);
+	return ret;
+}
+
+static struct device_attribute attributes[] = {
+	__ATTR(ic_ver, S_IRUGO, cyttsp5_ic_ver_show, NULL),
+	__ATTR(drv_ver, S_IRUGO, cyttsp5_drv_ver_show, NULL),
+	__ATTR(hw_reset, S_IWUSR, NULL, cyttsp5_hw_reset_store),
+	__ATTR(hw_irq_stat, S_IRUSR, cyttsp5_hw_irq_stat_show, NULL),
+	__ATTR(drv_irq, S_IRUSR | S_IWUSR, cyttsp5_drv_irq_show,
+		cyttsp5_drv_irq_store),
+	__ATTR(drv_debug, S_IWUSR, NULL, cyttsp5_drv_debug_store),
+	__ATTR(sleep_status, S_IRUSR, cyttsp5_sleep_status_show, NULL),
+	__ATTR(easy_wakeup_gesture, S_IRUSR | S_IWUSR,
+		cyttsp5_easy_wakeup_gesture_show,
+		cyttsp5_easy_wakeup_gesture_store),
+#ifdef EASYWAKE_TSG6
+	__ATTR(easy_wakeup_gesture_id, S_IRUSR,
+		cyttsp5_easy_wakeup_gesture_id_show, NULL),
+	__ATTR(easy_wakeup_gesture_data, S_IRUSR,
+		cyttsp5_easy_wakeup_gesture_data_show, NULL),
+#endif
+	__ATTR(panel_id, S_IRUGO, cyttsp5_panel_id_show, NULL),
+	__ATTR(platform_data, S_IRUGO, cyttsp5_platform_data_show, NULL),
+};
+
+static int add_sysfs_interfaces(struct device *dev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(attributes); i++)
+		if (device_create_file(dev, attributes + i))
+			goto undo;
+	return 0;
+undo:
+	for (i--; i >= 0; i--)
+		device_remove_file(dev, attributes + i);
+	dev_err(dev, "%s: failed to create sysfs interface\n", __func__);
+	return -ENODEV;
+}
+
+static void remove_sysfs_interfaces(struct device *dev)
+{
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(attributes); i++)
+		device_remove_file(dev, attributes + i);
+}
+
+/*
+ * ttdl_restart via sysfs
+ */
+static ssize_t cyttsp5_ttdl_restart_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	int rc;
+	struct i2c_client *client =
+		(struct i2c_client *)container_of(dev, struct i2c_client, dev);
+
+	if (is_cyttsp5_probe_success) {
+		dev_err(dev, "%s: previous cyttsp5_probe is successful, do nothing\n",
+				__func__);
+		return size;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(dev, "%s I2C functionality not Supported\n", __func__);
+		return -EIO;
+	}
+
+#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
+	rc = cyttsp5_devtree_create_and_get_pdata(dev);
+	if (rc < 0)
+		return rc;
+#endif
+
+	rc = cyttsp5_probe(cyttsp5_bus_ops_save, &client->dev, client->irq,
+			  512);
+
+	if (!rc) {
+		is_cyttsp5_probe_success = true;
+		dev_err(dev, "%s restart successful\n", __func__);
+	} else {
+		is_cyttsp5_probe_success = false;
+		dev_err(dev, "%s: ttdl restart failed r=%d\n",
+			__func__, rc);
+	}
+
+#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
+		if (rc)
+			cyttsp5_devtree_clean_pdata(dev);
+#endif
+
+	return size;
+
+}
+static DEVICE_ATTR(ttdl_restart, S_IWUSR, NULL, cyttsp5_ttdl_restart_store);
+
+
+#ifdef TTHE_TUNER_SUPPORT
+static int tthe_debugfs_open(struct inode *inode, struct file *filp)
+{
+	struct cyttsp5_core_data *cd = inode->i_private;
+
+	filp->private_data = inode->i_private;
+
+	if (cd->tthe_buf)
+		return -EBUSY;
+
+	cd->tthe_buf = kzalloc(CY_MAX_PRBUF_SIZE, GFP_KERNEL);
+	if (!cd->tthe_buf)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int tthe_debugfs_close(struct inode *inode, struct file *filp)
+{
+	struct cyttsp5_core_data *cd = filp->private_data;
+
+	filp->private_data = NULL;
+
+	kfree(cd->tthe_buf);
+	cd->tthe_buf = NULL;
+
+	return 0;
+}
+
+static ssize_t tthe_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_core_data *cd = filp->private_data;
+	int size;
+	int ret;
+
+	wait_event_interruptible(cd->wait_q,
+			cd->tthe_buf_len != 0 || cd->tthe_exit);
+	mutex_lock(&cd->tthe_lock);
+	if (cd->tthe_exit) {
+		mutex_unlock(&cd->tthe_lock);
+		return 0;
+	}
+	if (count > cd->tthe_buf_len)
+		size = cd->tthe_buf_len;
+	else
+		size = count;
+	if (!size) {
+		mutex_unlock(&cd->tthe_lock);
+		return 0;
+	}
+
+	ret = copy_to_user(buf, cd->tthe_buf, cd->tthe_buf_len);
+	if (ret == size)
+		return -EFAULT;
+	size -= ret;
+	cd->tthe_buf_len -= size;
+	mutex_unlock(&cd->tthe_lock);
+	*ppos += size;
+	return size;
+}
+
+static const struct file_operations tthe_debugfs_fops = {
+	.open = tthe_debugfs_open,
+	.release = tthe_debugfs_close,
+	.read = tthe_debugfs_read,
+};
+#endif
+
+static struct cyttsp5_core_nonhid_cmd _cyttsp5_core_nonhid_cmd = {
+	.start_bl = _cyttsp5_request_hid_output_start_bl,
+	.suspend_scanning = _cyttsp5_request_hid_output_suspend_scanning,
+	.resume_scanning = _cyttsp5_request_hid_output_resume_scanning,
+	.get_param = _cyttsp5_request_hid_output_get_param,
+	.set_param = _cyttsp5_request_hid_output_set_param,
+	.verify_config_block_crc =
+		_cyttsp5_request_hid_output_verify_config_block_crc,
+	.get_config_row_size = _cyttsp5_request_hid_output_get_config_row_size,
+	.get_data_structure = _cyttsp5_request_hid_output_get_data_structure,
+	.run_selftest = _cyttsp5_request_hid_output_run_selftest,
+	.get_selftest_result = _cyttsp5_request_hid_output_get_selftest_result,
+	.calibrate_idacs = _cyttsp5_request_hid_output_calibrate_idacs,
+	.initialize_baselines =
+		_cyttsp5_request_hid_output_initialize_baselines,
+	.exec_panel_scan = _cyttsp5_request_hid_output_exec_panel_scan,
+	.retrieve_panel_scan = _cyttsp5_request_hid_output_retrieve_panel_scan,
+	.write_conf_block = _cyttsp5_request_hid_output_write_conf_block,
+	.user_cmd = _cyttsp5_request_hid_output_user_cmd,
+	.get_bl_info = _cyttsp5_request_hid_output_bl_get_information,
+	.initiate_bl = _cyttsp5_request_hid_output_bl_initiate_bl,
+	.launch_app = _cyttsp5_request_hid_output_launch_app,
+	.prog_and_verify = _cyttsp5_request_hid_output_bl_program_and_verify,
+	.verify_app_integrity =
+		_cyttsp5_request_hid_output_bl_verify_app_integrity,
+	.get_panel_id = _cyttsp5_request_hid_output_bl_get_panel_id,
+	.enter_deep_sleep = _cyttsp5_request_put_device_into_deep_sleep,
+	.wake_device = _cyttsp5_request_core_wake_device,
+};
+
+static struct cyttsp5_core_commands _cyttsp5_core_commands = {
+	.subscribe_attention = _cyttsp5_subscribe_attention,
+	.unsubscribe_attention = _cyttsp5_unsubscribe_attention,
+	.request_exclusive = _cyttsp5_request_exclusive,
+	.release_exclusive = _cyttsp5_release_exclusive,
+	.request_reset = _cyttsp5_request_reset,
+	.request_restart = _cyttsp5_request_restart,
+	.request_sysinfo = _cyttsp5_request_sysinfo,
+	.request_loader_pdata = _cyttsp5_request_loader_pdata,
+	.request_stop_wd = _cyttsp5_request_stop_wd,
+	.request_start_wd = _cyttsp5_request_start_wd,
+	.request_get_hid_desc = _cyttsp5_request_get_hid_desc,
+	.request_get_mode = _cyttsp5_request_get_mode,
+#ifdef TTHE_TUNER_SUPPORT
+	.request_tthe_print = _cyttsp5_request_tthe_print,
+#endif
+	.nonhid_cmd = &_cyttsp5_core_nonhid_cmd,
+};
+
+struct cyttsp5_core_commands *cyttsp5_get_commands(void)
+{
+	return &_cyttsp5_core_commands;
+}
+EXPORT_SYMBOL_GPL(cyttsp5_get_commands);
+
+static DEFINE_MUTEX(core_list_lock);
+static LIST_HEAD(core_list);
+static DEFINE_MUTEX(module_list_lock);
+static LIST_HEAD(module_list);
+static int core_number;
+
+static int cyttsp5_probe_module(struct cyttsp5_core_data *cd,
+		struct cyttsp5_module *module)
+{
+	struct module_node *module_node;
+	int rc = 0;
+
+	module_node = kzalloc(sizeof(*module_node), GFP_KERNEL);
+	if (!module_node)
+		return -ENOMEM;
+
+	module_node->module = module;
+
+	mutex_lock(&cd->module_list_lock);
+	list_add(&module_node->node, &cd->module_list);
+	mutex_unlock(&cd->module_list_lock);
+
+	rc = module->probe(cd->dev, &module_node->data);
+	if (rc) {
+		/*
+		 * Remove from the list when probe fails
+		 * in order not to call release
+		 */
+		mutex_lock(&cd->module_list_lock);
+		list_del(&module_node->node);
+		mutex_unlock(&cd->module_list_lock);
+		kfree(module_node);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+static void cyttsp5_release_module(struct cyttsp5_core_data *cd,
+		struct cyttsp5_module *module)
+{
+	struct module_node *m, *m_n;
+
+	mutex_lock(&cd->module_list_lock);
+	list_for_each_entry_safe(m, m_n, &cd->module_list, node)
+		if (m->module == module) {
+			module->release(cd->dev, m->data);
+			list_del(&m->node);
+			kfree(m);
+			break;
+		}
+	mutex_unlock(&cd->module_list_lock);
+}
+
+static void cyttsp5_probe_modules(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_module *m;
+	int rc = 0;
+
+	mutex_lock(&module_list_lock);
+	list_for_each_entry(m, &module_list, node) {
+		rc = cyttsp5_probe_module(cd, m);
+		if (rc)
+			dev_err(cd->dev, "%s: Probe fails for module %s\n",
+				__func__, m->name);
+	}
+	mutex_unlock(&module_list_lock);
+}
+
+static void cyttsp5_release_modules(struct cyttsp5_core_data *cd)
+{
+	struct cyttsp5_module *m;
+
+	mutex_lock(&module_list_lock);
+	list_for_each_entry(m, &module_list, node)
+		cyttsp5_release_module(cd, m);
+	mutex_unlock(&module_list_lock);
+}
+
+struct cyttsp5_core_data *cyttsp5_get_core_data(char *id)
+{
+	struct cyttsp5_core_data *d;
+
+	list_for_each_entry(d, &core_list, node)
+		if (!strncmp(d->core_id, id, 20))
+			return d;
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(cyttsp5_get_core_data);
+
+static void cyttsp5_add_core(struct device *dev)
+{
+	struct cyttsp5_core_data *d;
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+
+	mutex_lock(&core_list_lock);
+	list_for_each_entry(d, &core_list, node)
+		if (d->dev == dev)
+			goto unlock;
+
+	list_add(&cd->node, &core_list);
+unlock:
+	mutex_unlock(&core_list_lock);
+}
+
+static void cyttsp5_del_core(struct device *dev)
+{
+	struct cyttsp5_core_data *d, *d_n;
+
+	mutex_lock(&core_list_lock);
+	list_for_each_entry_safe(d, d_n, &core_list, node)
+		if (d->dev == dev) {
+			list_del(&d->node);
+			goto unlock;
+		}
+unlock:
+	mutex_unlock(&core_list_lock);
+}
+
+int cyttsp5_register_module(struct cyttsp5_module *module)
+{
+	struct cyttsp5_module *m;
+	struct cyttsp5_core_data *cd;
+
+	int rc = 0;
+
+	if (!module || !module->probe || !module->release)
+		return -EINVAL;
+
+	mutex_lock(&module_list_lock);
+	list_for_each_entry(m, &module_list, node)
+		if (m == module) {
+			rc = -EEXIST;
+			goto unlock;
+		}
+
+	list_add(&module->node, &module_list);
+
+	/* Probe the module for each core */
+	mutex_lock(&core_list_lock);
+	list_for_each_entry(cd, &core_list, node)
+		cyttsp5_probe_module(cd, module);
+	mutex_unlock(&core_list_lock);
+
+unlock:
+	mutex_unlock(&module_list_lock);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(cyttsp5_register_module);
+
+void cyttsp5_unregister_module(struct cyttsp5_module *module)
+{
+	struct cyttsp5_module *m, *m_n;
+	struct cyttsp5_core_data *cd;
+
+	if (!module)
+		return;
+
+	mutex_lock(&module_list_lock);
+
+	/* Release the module for each core */
+	mutex_lock(&core_list_lock);
+	list_for_each_entry(cd, &core_list, node)
+		cyttsp5_release_module(cd, module);
+	mutex_unlock(&core_list_lock);
+
+	list_for_each_entry_safe(m, m_n, &module_list, node)
+		if (m == module) {
+			list_del(&m->node);
+			break;
+		}
+
+	mutex_unlock(&module_list_lock);
+}
+EXPORT_SYMBOL_GPL(cyttsp5_unregister_module);
+
+void *cyttsp5_get_module_data(struct device *dev, struct cyttsp5_module *module)
+{
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	struct module_node *m;
+	void *data = NULL;
+
+	mutex_lock(&cd->module_list_lock);
+	list_for_each_entry(m, &cd->module_list, node)
+		if (m->module == module) {
+			data = m->data;
+			break;
+		}
+	mutex_unlock(&cd->module_list_lock);
+
+	return data;
+}
+EXPORT_SYMBOL(cyttsp5_get_module_data);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void cyttsp5_early_suspend(struct early_suspend *h)
+{
+	struct cyttsp5_core_data *cd =
+		container_of(h, struct cyttsp5_core_data, es);
+
+	call_atten_cb(cd, CY_ATTEN_SUSPEND, 0);
+}
+
+static void cyttsp5_late_resume(struct early_suspend *h)
+{
+	struct cyttsp5_core_data *cd =
+		container_of(h, struct cyttsp5_core_data, es);
+
+	call_atten_cb(cd, CY_ATTEN_RESUME, 0);
+}
+
+static void cyttsp5_setup_early_suspend(struct cyttsp5_core_data *cd)
+{
+	cd->es.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	cd->es.suspend = cyttsp5_early_suspend;
+	cd->es.resume = cyttsp5_late_resume;
+
+	register_early_suspend(&cd->es);
+}
+#elif defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+		unsigned long event, void *data)
+{
+	struct cyttsp5_core_data *cd =
+		container_of(self, struct cyttsp5_core_data, fb_notifier);
+	struct fb_event *evdata = data;
+	int *blank;
+
+	if (event != FB_EVENT_BLANK || !evdata)
+		goto exit;
+
+	blank = evdata->data;
+	if (*blank == FB_BLANK_UNBLANK) {
+		dev_info(cd->dev, "%s: UNBLANK!\n", __func__);
+		if (cd->fb_state != FB_ON) {
+			call_atten_cb(cd, CY_ATTEN_RESUME, 0);
+			cd->fb_state = FB_ON;
+		}
+	} else if (*blank == FB_BLANK_POWERDOWN || *blank == FB_BLANK_VSYNC_SUSPEND) {
+		dev_info(cd->dev, "%s: POWERDOWN OR VSYNC_SUSPEND!\n", __func__);
+		if (cd->fb_state != FB_OFF) {
+			call_atten_cb(cd, CY_ATTEN_SUSPEND, 0);
+			cd->fb_state = FB_OFF;
+		}
+	}
+
+exit:
+	return 0;
+}
+
+static void cyttsp5_setup_fb_notifier(struct cyttsp5_core_data *cd)
+{
+	int rc;
+
+	cd->fb_state = FB_ON;
+
+	cd->fb_notifier.notifier_call = fb_notifier_callback;
+
+	rc = fb_register_client(&cd->fb_notifier);
+	if (rc)
+		dev_err(cd->dev, "Unable to register fb_notifier: %d\n", rc);
+}
+#endif
+
+static int cyttsp5_setup_irq_gpio(struct cyttsp5_core_data *cd)
+{
+	struct device *dev = cd->dev;
+	unsigned long irq_flags;
+	int rc;
+
+	/* Initialize IRQ */
+	cd->irq = gpio_to_irq(cd->cpdata->irq_gpio);
+	if (cd->irq < 0)
+		return -EINVAL;
+
+	cd->irq_enabled = true;
+
+	parade_debug(dev, DEBUG_LEVEL_1, "%s: initialize threaded irq=%d\n",
+		__func__, cd->irq);
+	if (cd->cpdata->level_irq_udelay > 0)
+		/* use level triggered interrupts */
+		irq_flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
+	else
+		/* use edge triggered interrupts */
+		irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+
+	rc = request_threaded_irq(cd->irq, NULL, cyttsp5_irq, irq_flags,
+		dev_name(dev), cd);
+	if (rc < 0)
+		dev_err(dev, "%s: Error, could not request irq\n", __func__);
+
+	return rc;
+}
+
+static int _cyttsp5_mfg_value_(struct cyttsp5_core_data *cd,
+		u8 *mfg_0)
+{
+	int rc;
+	u8 read_buf[4 + 5];
+	u16 crc;
+
+	rc = cyttsp5_hid_output_read_conf_block_(cd, 0,
+			4 + 5,
+			CY_MDATA_EBID, read_buf, &crc);
+	if (rc)
+		return rc;
+
+	mfg_0[0] = read_buf[4];//MFG_VAL0
+	mfg_0[1] = read_buf[5];//MFG_VAL1
+	mfg_0[2] = read_buf[6];//MFG_VAL2
+	mfg_0[3] = read_buf[7];//MFG_VAL3
+	mfg_0[4] = read_buf[8];//MFG_VAL4
+
+	return 0;
+}
+
+
+static int cyttsp5_get_mfg_value_(struct cyttsp5_core_data *cd,u8 *mfg_0)
+{
+	int rc;
+
+	rc = cyttsp5_hid_output_suspend_scanning_(cd);
+	if (rc)
+		goto error;
+
+	rc = _cyttsp5_mfg_value_(cd, mfg_0);
+	if (rc)
+		goto exit;
+
+exit:
+	cyttsp5_hid_output_resume_scanning_(cd);
+error:
+	parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: MFG_0:%02X\n",
+			__func__, *mfg_0);
+	return rc;
+}
+
+int cyttsp5_probe(const struct cyttsp5_bus_ops *ops, struct device *dev,
+		u16 irq, size_t xfer_buf_size)
+{
+	struct cyttsp5_core_data *cd;
+	struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
+	enum cyttsp5_atten_type type;
+	int rc = 0;
+
+/*start lihongshuai@2019.4.18 for distinguish maker */
+	u8 receive_data [5];
+/*end lihongshuai@2019.4.18 for distinguish maker */
+
+/*begin lihongshuai@20190424 add for tp_info*/
+#ifdef SUPPORT_READ_TP_VERSION
+	char tp_version[50] = {0};
+	struct cyttsp5_cydata *cydata;
+#endif
+/*end lihongshuai@20190424 add for tp_info*/
+
+
+
+	/* Set default values on first probe */
+	if (cyttsp5_first_probe) {
+		cyttsp5_first_probe      = false;
+		is_cyttsp5_probe_success = false;
+		cyttsp5_bus_ops_save     = NULL;
+	}
+
+	if (!pdata || !pdata->core_pdata || !pdata->mt_pdata) {
+		dev_err(dev, "%s: Missing platform data\n", __func__);
+		rc = -ENODEV;
+		goto error_no_pdata;
+	}
+
+	if (pdata->core_pdata->flags & CY_CORE_FLAG_POWEROFF_ON_SLEEP) {
+		if (!pdata->core_pdata->power) {
+			dev_err(dev, "%s: Missing platform data function\n",
+					__func__);
+			rc = -ENODEV;
+			goto error_no_pdata;
+		}
+	}
+
+	/* get context and debug print buffers */
+	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
+	if (!cd) {
+		rc = -ENOMEM;
+		goto error_alloc_data;
+	}
+
+	/* Initialize device info */
+	cd->dev = dev;
+	cd->pdata = pdata;
+	cd->cpdata = pdata->core_pdata;
+	cd->bus_ops = ops;
+	cd->debug_level = CY_INITIAL_DEBUG_LEVEL;
+	cd->watchdog_interval = CY_WATCHDOG_TIMEOUT;
+	cd->show_timestamp = CY_INITIAL_SHOW_TIME_STAMP;
+	scnprintf(cd->core_id, 20, "%s%d", CYTTSP5_CORE_NAME, core_number++);
+
+	/* Initialize mutexes and spinlocks */
+	mutex_init(&cd->module_list_lock);
+	mutex_init(&cd->system_lock);
+	mutex_init(&cd->adap_lock);
+	mutex_init(&cd->hid_report_lock);
+	spin_lock_init(&cd->spinlock);
+
+	/* Initialize module list */
+	INIT_LIST_HEAD(&cd->module_list);
+
+	/* Initialize attention lists */
+	for (type = 0; type < CY_ATTEN_NUM_ATTEN; type++)
+		INIT_LIST_HEAD(&cd->atten_list[type]);
+
+	/* Initialize parameter list */
+	INIT_LIST_HEAD(&cd->param_list);
+
+	/* Initialize wait queue */
+	init_waitqueue_head(&cd->wait_q);
+
+	/* Initialize works */
+	INIT_WORK(&cd->startup_work, cyttsp5_startup_work_function);
+	INIT_WORK(&cd->watchdog_work, cyttsp5_watchdog_work);
+
+	/* Initialize HID specific data */
+	cd->hid_core.hid_vendor_id = (cd->cpdata->vendor_id) ?
+		cd->cpdata->vendor_id : CY_HID_VENDOR_ID;
+	cd->hid_core.hid_product_id = (cd->cpdata->product_id) ?
+		cd->cpdata->product_id : CY_HID_APP_PRODUCT_ID;
+	cd->hid_core.hid_desc_register =
+		cpu_to_le16(cd->cpdata->hid_desc_register);
+
+	/* Set platform easywake value */
+	cd->easy_wakeup_gesture = cd->cpdata->easy_wakeup_gesture;
+
+	/* Set Panel ID to Not Enabled */
+	cd->panel_id = PANEL_ID_NOT_ENABLED;
+
+	dev_set_drvdata(dev, cd);
+	cyttsp5_add_core(dev);
+
+	/*create ttdl_restart sysfs node is probe failed*/
+	if (!is_cyttsp5_probe_success)
+		device_create_file(dev, &dev_attr_ttdl_restart);
+
+	/*
+	 * Save the pointer to a global value, which will be used
+	 * in ttdl_restart function
+	 */
+	cyttsp5_bus_ops_save = ops;
+
+	/* Call platform init function */
+	if (cd->cpdata->init) {
+		parade_debug(cd->dev, DEBUG_LEVEL_1, "%s: Init HW\n", __func__);
+		rc = cd->cpdata->init(cd->cpdata, 1, cd->dev);
+	} else {
+		dev_info(cd->dev, "%s: No HW INIT function\n", __func__);
+		rc = 0;
+	}
+	if (rc < 0)
+		dev_err(cd->dev, "%s: HW Init fail r=%d\n", __func__, rc);
+
+	/* Call platform detect function */
+	if (cd->cpdata->detect) {
+		dev_info(cd->dev, "%s: Detect HW\n", __func__);
+		rc = cd->cpdata->detect(cd->cpdata, cd->dev,
+				cyttsp5_platform_detect_read);
+		if (rc) {
+			dev_info(cd->dev, "%s: No HW detected\n", __func__);
+			rc = -ENODEV;
+			goto error_detect;
+		}
+	}
+
+	/* Setup watchdog timer */
+	setup_timer(&cd->watchdog_timer, cyttsp5_watchdog_timer,
+			(unsigned long)cd);
+
+	rc = cyttsp5_setup_irq_gpio(cd);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error, could not setup IRQ\n", __func__);
+		goto error_setup_irq;
+	}
+
+	parade_debug(dev, DEBUG_LEVEL_1, "%s: add sysfs interfaces\n",
+		__func__);
+	rc = add_sysfs_interfaces(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error, fail sysfs init\n", __func__);
+		goto error_attr_create;
+	}
+
+#ifdef TTHE_TUNER_SUPPORT
+	mutex_init(&cd->tthe_lock);
+	cd->tthe_debugfs = debugfs_create_file(CYTTSP5_TTHE_TUNER_FILE_NAME,
+			0644, NULL, cd, &tthe_debugfs_fops);
+#endif
+	rc = device_init_wakeup(dev, 1);
+	if (rc < 0)
+		dev_err(dev, "%s: Error, device_init_wakeup rc:%d\n",
+				__func__, rc);
+
+	pm_runtime_get_noresume(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	/*
+	 * call startup directly to ensure that the device
+	 * is tested before leaving the probe
+	 */
+	parade_debug(dev, DEBUG_LEVEL_1, "%s: call startup\n", __func__);
+	rc = cyttsp5_startup(cd, false);
+
+	pm_runtime_put_sync(dev);
+
+	/* Do not fail probe if startup fails but the device is detected */
+	if (rc == -ENODEV) {
+		dev_err(cd->dev, "%s: Fail initial startup r=%d\n",
+			__func__, rc);
+		goto error_startup;
+	}
+
+	rc = cyttsp5_mt_probe(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error, fail mt probe\n", __func__);
+		goto error_startup;
+	}
+
+	rc = cyttsp5_btn_probe(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error, fail btn probe\n", __func__);
+		goto error_startup_mt;
+	}
+
+	rc = cyttsp5_proximity_probe(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error, fail proximity probe\n", __func__);
+		goto error_startup_btn;
+	}
+
+	/* Probe registered modules */
+	cyttsp5_probe_modules(cd);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	cyttsp5_setup_early_suspend(cd);
+#elif defined(CONFIG_FB)
+	cyttsp5_setup_fb_notifier(cd);
+#endif
+
+#if NEED_SUSPEND_NOTIFIER
+	cd->pm_notifier.notifier_call = cyttsp5_pm_notifier;
+	register_pm_notifier(&cd->pm_notifier);
+#endif
+
+/*begin lihongshuai@20190424 add for tp_info*/
+#ifdef SUPPORT_READ_TP_VERSION
+	cydata = &cd->sysinfo.cydata;
+	memset(tp_version, 0, sizeof(tp_version));
+	sprintf(tp_version, "[FW]%02X.%02X.%08X.%04X,[IC]TMA525C",
+		cydata->fw_ver_major,
+		cydata->fw_ver_minor,
+		cydata->revctrl,
+		cydata->fw_ver_conf);
+#endif
+/*end lihongshuai@20190424 add for tp_info*/
+
+/*start lihongshuai@2019.4.18 for distinguish maker */
+	memset(receive_data, 0, sizeof(receive_data));
+	cyttsp5_get_mfg_value_(cd,receive_data);
+	dev_info(dev,"lockdown info:%#2X%2X%2X%2X%2X\n",
+			receive_data[0],
+			receive_data[1],
+			receive_data[2],
+			receive_data[3],
+			receive_data[4]);
+	if(0x39 == receive_data[1]){
+		cd->pdata->loader_pdata = &_cyttsp5_loader_platform_data_1;
+#ifdef SUPPORT_READ_TP_VERSION
+		init_tp_fm_info(0, tp_version, "EDO");
+#endif
+	}else{
+		cd->pdata->loader_pdata = &_cyttsp5_loader_platform_data_2;
+#ifdef SUPPORT_READ_TP_VERSION
+		init_tp_fm_info(0, tp_version, "Truly");
+#endif
+	}
+/*end lihongshuai@2019.4.18 for distinguish maker */
+
+	is_cyttsp5_probe_success = true;
+
+	return 0;
+
+error_startup_btn:
+	cyttsp5_btn_release(dev);
+error_startup_mt:
+	cyttsp5_mt_release(dev);
+error_startup:
+	pm_runtime_disable(dev);
+#if (KERNEL_VERSION(3, 16, 0) > LINUX_VERSION_CODE)
+	device_wakeup_disable(dev);
+#endif
+	device_init_wakeup(dev, 0);
+	cancel_work_sync(&cd->startup_work);
+	cyttsp5_stop_wd_timer(cd);
+	cyttsp5_free_si_ptrs(cd);
+	remove_sysfs_interfaces(dev);
+error_attr_create:
+	free_irq(cd->irq, cd);
+	del_timer(&cd->watchdog_timer);
+error_setup_irq:
+error_detect:
+	if (cd->cpdata->init)
+		cd->cpdata->init(cd->cpdata, 0, dev);
+	cyttsp5_del_core(dev);
+	dev_set_drvdata(dev, NULL);
+	kfree(cd);
+error_alloc_data:
+error_no_pdata:
+	dev_err(dev, "%s failed.\n", __func__);
+	is_cyttsp5_probe_success = false;
+	return rc;
+}
+EXPORT_SYMBOL_GPL(cyttsp5_probe);
+
+int cyttsp5_release(struct cyttsp5_core_data *cd)
+{
+	struct device *dev = cd->dev;
+
+	/* Release successfully probed modules */
+	cyttsp5_release_modules(cd);
+
+	cyttsp5_proximity_release(dev);
+	cyttsp5_btn_release(dev);
+	cyttsp5_mt_release(dev);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&cd->es);
+#elif defined(CONFIG_FB)
+	fb_unregister_client(&cd->fb_notifier);
+#endif
+
+#if NEED_SUSPEND_NOTIFIER
+	unregister_pm_notifier(&cd->pm_notifier);
+#endif
+
+	/*
+	 * Suspend the device before freeing the startup_work and stopping
+	 * the watchdog since sleep function restarts watchdog on failure
+	 */
+	pm_runtime_suspend(dev);
+	pm_runtime_disable(dev);
+
+	cancel_work_sync(&cd->startup_work);
+
+	cyttsp5_stop_wd_timer(cd);
+
+#if (KERNEL_VERSION(3, 16, 0) > LINUX_VERSION_CODE)
+	device_wakeup_disable(dev);
+#endif
+	device_init_wakeup(dev, 0);
+
+#ifdef TTHE_TUNER_SUPPORT
+	mutex_lock(&cd->tthe_lock);
+	cd->tthe_exit = 1;
+	wake_up(&cd->wait_q);
+	mutex_unlock(&cd->tthe_lock);
+	debugfs_remove(cd->tthe_debugfs);
+#endif
+	remove_sysfs_interfaces(dev);
+	free_irq(cd->irq, cd);
+	if (cd->cpdata->init)
+		cd->cpdata->init(cd->cpdata, 0, dev);
+	dev_set_drvdata(dev, NULL);
+	cyttsp5_del_core(dev);
+	cyttsp5_free_si_ptrs(cd);
+	cyttsp5_free_hid_reports(cd);
+	kfree(cd);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cyttsp5_release);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Core Driver");
+MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");
diff --git a/tp/cyttsp5/cyttsp5_core.h b/tp/cyttsp5/cyttsp5_core.h
new file mode 100644
index 0000000..04e5199
--- /dev/null
+++ b/tp/cyttsp5/cyttsp5_core.h
@@ -0,0 +1,179 @@
+/*
+ * cyttsp5_core.h
+ * Parade TrueTouch(TM) Standard Product V5 Core Module.
+ * For use with Parade touchscreen controllers.
+ * Supported parts include:
+ * CYTMA5XX
+ * CYTMA448
+ * CYTMA445A
+ * CYTT21XXX
+ * CYTT31XXX
+ *
+ * Copyright (C) 2015 Parade Semiconductor
+ * Copyright (C) 2012-2015 Cypress Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Contact Parade Semiconductor at www.parade.com <ttdrivers@paradetech.com>
+ *
+ */
+
+#ifndef _LINUX_CYTTSP5_CORE_H
+#define _LINUX_CYTTSP5_CORE_H
+
+#include <linux/stringify.h>
+
+#define CYTTSP5_I2C_NAME "cyttsp5_i2c_adapter"
+#define CYTTSP5_SPI_NAME "cyttsp5_spi_adapter"
+
+#define CYTTSP5_CORE_NAME "cyttsp5_core"
+#define CYTTSP5_MT_NAME "cyttsp5_mt"
+#define CYTTSP5_BTN_NAME "cyttsp5_btn"
+#define CYTTSP5_PROXIMITY_NAME "cyttsp5_proximity"
+
+#define CY_DRIVER_NAME TTDA
+#define CY_DRIVER_MAJOR 03
+#define CY_DRIVER_MINOR 08
+
+#define CY_DRIVER_REVCTRL 874312
+
+#define CY_DRIVER_VERSION		    \
+__stringify(CY_DRIVER_NAME)		    \
+"." __stringify(CY_DRIVER_MAJOR)	    \
+"." __stringify(CY_DRIVER_MINOR)	    \
+"." __stringify(CY_DRIVER_REVCTRL)
+
+#define CY_DRIVER_DATE "20170125"
+
+/* abs settings */
+#define CY_IGNORE_VALUE             -1
+
+enum cyttsp5_core_platform_flags {
+	CY_CORE_FLAG_NONE,
+	CY_CORE_FLAG_POWEROFF_ON_SLEEP = 0x02,
+	CY_CORE_FLAG_RESTORE_PARAMETERS = 0x04,
+};
+
+enum cyttsp5_core_platform_easy_wakeup_gesture {
+	CY_CORE_EWG_NONE,
+	CY_CORE_EWG_TAP_TAP,
+	CY_CORE_EWG_TWO_FINGER_SLIDE,
+	CY_CORE_EWG_RESERVED,
+	CY_CORE_EWG_WAKE_ON_INT_FROM_HOST = 0xFF,
+};
+
+enum cyttsp5_loader_platform_flags {
+	CY_LOADER_FLAG_NONE,
+	CY_LOADER_FLAG_CALIBRATE_AFTER_FW_UPGRADE,
+	/* Use CONFIG_VER field in TT_CFG to decide TT_CFG update */
+	CY_LOADER_FLAG_CHECK_TTCONFIG_VERSION,
+	CY_LOADER_FLAG_CALIBRATE_AFTER_TTCONFIG_UPGRADE,
+};
+
+struct touch_settings {
+	const uint8_t   *data;
+	uint32_t         size;
+	uint8_t         tag;
+};
+
+struct cyttsp5_touch_firmware {
+	const uint8_t *img;
+	uint32_t size;
+	const uint8_t *ver;
+	uint8_t vsize;
+	uint8_t panel_id;
+};
+
+struct cyttsp5_touch_config {
+	struct touch_settings *param_regs;
+	struct touch_settings *param_size;
+	const uint8_t *fw_ver;
+	uint8_t fw_vsize;
+	uint8_t panel_id;
+};
+
+struct cyttsp5_loader_platform_data {
+	struct cyttsp5_touch_firmware *fw;
+	struct cyttsp5_touch_config *ttconfig;
+	struct cyttsp5_touch_firmware **fws;
+	struct cyttsp5_touch_config **ttconfigs;
+	u32 flags;
+};
+
+typedef int (*cyttsp5_platform_read) (struct device *dev, void *buf, int size);
+
+#define CY_TOUCH_SETTINGS_MAX 32
+
+struct cyttsp5_core_platform_data {
+	int irq_gpio;
+	int rst_gpio;
+	int level_irq_udelay;
+	u16 hid_desc_register;
+	u16 vendor_id;
+	u16 product_id;
+
+	int (*xres)(struct cyttsp5_core_platform_data *pdata,
+		struct device *dev);
+	int (*init)(struct cyttsp5_core_platform_data *pdata,
+		int on, struct device *dev);
+	int (*power)(struct cyttsp5_core_platform_data *pdata,
+		int on, struct device *dev, atomic_t *ignore_irq);
+	int (*detect)(struct cyttsp5_core_platform_data *pdata,
+		struct device *dev, cyttsp5_platform_read read);
+	int (*irq_stat)(struct cyttsp5_core_platform_data *pdata,
+		struct device *dev);
+	struct touch_settings *sett[CY_TOUCH_SETTINGS_MAX];
+	u32 flags;
+	u8 easy_wakeup_gesture;
+};
+
+struct touch_framework {
+	const int16_t  *abs;
+	uint8_t         size;
+	uint8_t         enable_vkeys;
+} __packed;
+
+enum cyttsp5_mt_platform_flags {
+	CY_MT_FLAG_NONE,
+	CY_MT_FLAG_HOVER = 0x04,
+	CY_MT_FLAG_FLIP = 0x08,
+	CY_MT_FLAG_INV_X = 0x10,
+	CY_MT_FLAG_INV_Y = 0x20,
+	CY_MT_FLAG_VKEYS = 0x40,
+	CY_MT_FLAG_NO_TOUCH_ON_LO = 0x80,
+};
+
+struct cyttsp5_mt_platform_data {
+	struct touch_framework *frmwrk;
+	unsigned short flags;
+	char const *inp_dev_name;
+	int vkeys_x;
+	int vkeys_y;
+};
+
+struct cyttsp5_btn_platform_data {
+	char const *inp_dev_name;
+};
+
+struct cyttsp5_proximity_platform_data {
+	struct touch_framework *frmwrk;
+	char const *inp_dev_name;
+};
+
+struct cyttsp5_platform_data {
+	struct cyttsp5_core_platform_data *core_pdata;
+	struct cyttsp5_mt_platform_data *mt_pdata;
+	struct cyttsp5_btn_platform_data *btn_pdata;
+	struct cyttsp5_proximity_platform_data *prox_pdata;
+	struct cyttsp5_loader_platform_data *loader_pdata;
+};
+
+#endif /* _LINUX_CYTTSP5_CORE_H */
diff --git a/tp/cyttsp5/cyttsp5_debug.c b/tp/cyttsp5/cyttsp5_debug.c
new file mode 100644
index 0000000..f4ebba7
--- /dev/null
+++ b/tp/cyttsp5/cyttsp5_debug.c
@@ -0,0 +1,393 @@
+/*
+ * cyttsp5_debug.c
+ * Parade TrueTouch(TM) Standard Product V5 Debug Module.
+ * For use with Parade touchscreen controllers.
+ * Supported parts include:
+ * CYTMA5XX
+ * CYTMA448
+ * CYTMA445A
+ * CYTT21XXX
+ * CYTT31XXX
+ *
+ * Copyright (C) 2015 Parade Technologies
+ * Copyright (C) 2012-2015 Cypress Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
+ *
+ */
+
+#include "cyttsp5_regs.h"
+
+#define CYTTSP5_DEBUG_NAME "cyttsp5_debug"
+
+struct cyttsp5_debug_data {
+	struct device *dev;
+	struct cyttsp5_sysinfo *si;
+	uint32_t interrupt_count;
+	uint32_t formated_output;
+	struct mutex sysfs_lock;
+	u8 pr_buf[CY_MAX_PRBUF_SIZE];
+};
+
+static struct cyttsp5_core_commands *cmd;
+
+static struct cyttsp5_module debug_module;
+
+static inline struct cyttsp5_debug_data *cyttsp5_get_debug_data(
+		struct device *dev)
+{
+	return cyttsp5_get_module_data(dev, &debug_module);
+}
+
+/*
+ * This function provide output of combined xy_mode and xy_data.
+ * Required by TTHE.
+ */
+static void cyttsp5_pr_buf_op_mode(struct cyttsp5_debug_data *dd, u8 *pr_buf,
+		struct cyttsp5_sysinfo *si, u8 cur_touch)
+{
+	const char fmt[] = "%02X ";
+	int max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED);
+	u8 report_id = si->xy_mode[2];
+	int header_size = 0;
+	int report_size = 0;
+	int total_size = 0;
+	int i, k;
+
+	if (report_id == si->desc.tch_report_id) {
+		header_size = si->desc.tch_header_size;
+		report_size = cur_touch * si->desc.tch_record_size;
+	} else if (report_id == si->desc.btn_report_id) {
+		header_size = BTN_INPUT_HEADER_SIZE;
+		report_size = BTN_REPORT_SIZE;
+	}
+	total_size = header_size + report_size;
+
+	pr_buf[0] = 0;
+	for (i = k = 0; i < header_size && i < max; i++, k += 3)
+		scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, si->xy_mode[i]);
+
+	for (i = 0; i < report_size && i < max; i++, k += 3)
+		scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, si->xy_data[i]);
+
+	pr_info("%s=%s%s\n", "cyttsp5_OpModeData", pr_buf,
+			total_size <= max ? "" : CY_PR_TRUNCATED);
+}
+
+static void cyttsp5_debug_print(struct device *dev, u8 *pr_buf, u8 *sptr,
+		int size, const char *data_name)
+{
+	int i, j;
+	int elem_size = sizeof("XX ") - 1;
+	int max = (CY_MAX_PRBUF_SIZE - 1) / elem_size;
+	int limit = size < max ? size : max;
+
+	if (limit < 0)
+		limit = 0;
+
+	pr_buf[0] = 0;
+	for (i = j = 0; i < limit; i++, j += elem_size)
+		scnprintf(pr_buf + j, CY_MAX_PRBUF_SIZE - j, "%02X ", sptr[i]);
+
+	if (size)
+		pr_info("%s[0..%d]=%s%s\n", data_name, size - 1, pr_buf,
+			size <= max ? "" : CY_PR_TRUNCATED);
+	else
+		pr_info("%s[]\n", data_name);
+}
+
+static void cyttsp5_debug_formated(struct device *dev, u8 *pr_buf,
+		struct cyttsp5_sysinfo *si, u8 num_cur_tch)
+{
+	u8 report_id = si->xy_mode[2];
+	int header_size = 0;
+	int report_size = 0;
+	u8 data_name[] = "touch[99]";
+	int max_print_length = 20;
+	int i;
+
+	if (report_id == si->desc.tch_report_id) {
+		header_size = si->desc.tch_header_size;
+		report_size = num_cur_tch * si->desc.tch_record_size;
+	} else if (report_id == si->desc.btn_report_id) {
+		header_size = BTN_INPUT_HEADER_SIZE;
+		report_size = BTN_REPORT_SIZE;
+	}
+
+	/* xy_mode */
+	cyttsp5_debug_print(dev, pr_buf, si->xy_mode, header_size, "xy_mode");
+
+	/* xy_data */
+	if (report_size > max_print_length) {
+		pr_info("xy_data[0..%d]:\n", report_size);
+		for (i = 0; i < report_size - max_print_length;
+				i += max_print_length) {
+			cyttsp5_debug_print(dev, pr_buf, si->xy_data + i,
+					max_print_length, " ");
+		}
+		if (report_size - i)
+			cyttsp5_debug_print(dev, pr_buf, si->xy_data + i,
+					report_size - i, " ");
+	} else {
+		cyttsp5_debug_print(dev, pr_buf, si->xy_data, report_size,
+				"xy_data");
+	}
+
+	/* touches */
+	if (report_id == si->desc.tch_report_id) {
+		for (i = 0; i < num_cur_tch; i++) {
+			scnprintf(data_name, sizeof(data_name) - 1,
+					"touch[%u]", i);
+			cyttsp5_debug_print(dev, pr_buf,
+				si->xy_data + (i * si->desc.tch_record_size),
+				si->desc.tch_record_size, data_name);
+		}
+	}
+
+	/* buttons */
+	if (report_id == si->desc.btn_report_id)
+		cyttsp5_debug_print(dev, pr_buf, si->xy_data, report_size,
+				"button");
+}
+
+/* read xy_data for all touches for debug */
+static int cyttsp5_xy_worker(struct cyttsp5_debug_data *dd)
+{
+	struct device *dev = dd->dev;
+	struct cyttsp5_sysinfo *si = dd->si;
+	u8 report_reg = si->xy_mode[TOUCH_COUNT_BYTE_OFFSET];
+	u8 num_cur_tch = GET_NUM_TOUCHES(report_reg);
+	uint32_t formated_output;
+
+	mutex_lock(&dd->sysfs_lock);
+	dd->interrupt_count++;
+	formated_output = dd->formated_output;
+	mutex_unlock(&dd->sysfs_lock);
+
+	/* Interrupt */
+	pr_info("Interrupt(%u)\n", dd->interrupt_count);
+
+	if (formated_output)
+		cyttsp5_debug_formated(dev, dd->pr_buf, si, num_cur_tch);
+	else
+		/* print data for TTHE */
+		cyttsp5_pr_buf_op_mode(dd, dd->pr_buf, si, num_cur_tch);
+
+	pr_info("\n");
+
+	return 0;
+}
+
+static int cyttsp5_debug_attention(struct device *dev)
+{
+	struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
+	struct cyttsp5_sysinfo *si = dd->si;
+	u8 report_id = si->xy_mode[2];
+	int rc = 0;
+
+	if (report_id != si->desc.tch_report_id
+			&& report_id != si->desc.btn_report_id)
+		return 0;
+
+	/* core handles handshake */
+	rc = cyttsp5_xy_worker(dd);
+	if (rc < 0)
+		dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
+
+	return rc;
+}
+
+static ssize_t cyttsp5_interrupt_count_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
+	int val;
+
+	mutex_lock(&dd->sysfs_lock);
+	val = dd->interrupt_count;
+	mutex_unlock(&dd->sysfs_lock);
+
+	return scnprintf(buf, CY_MAX_PRBUF_SIZE, "Interrupt Count: %d\n", val);
+}
+
+static ssize_t cyttsp5_interrupt_count_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
+
+	mutex_lock(&dd->sysfs_lock);
+	dd->interrupt_count = 0;
+	mutex_unlock(&dd->sysfs_lock);
+	return size;
+}
+
+static DEVICE_ATTR(int_count, S_IRUSR | S_IWUSR,
+	cyttsp5_interrupt_count_show, cyttsp5_interrupt_count_store);
+
+static ssize_t cyttsp5_formated_output_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
+	int val;
+
+	mutex_lock(&dd->sysfs_lock);
+	val = dd->formated_output;
+	mutex_unlock(&dd->sysfs_lock);
+
+	return scnprintf(buf, CY_MAX_PRBUF_SIZE,
+			"Formated debug output: %x\n", val);
+}
+
+static ssize_t cyttsp5_formated_output_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
+	unsigned long value;
+	int rc;
+
+	rc = kstrtoul(buf, 10, &value);
+	if (rc < 0) {
+		dev_err(dev, "%s: Invalid value\n", __func__);
+		return size;
+	}
+
+	/* Expecting only 0 or 1 */
+	if (value != 0 && value != 1) {
+		dev_err(dev, "%s: Invalid value %lu\n", __func__, value);
+		return size;
+	}
+
+	mutex_lock(&dd->sysfs_lock);
+	dd->formated_output = value;
+	mutex_unlock(&dd->sysfs_lock);
+	return size;
+}
+
+static DEVICE_ATTR(formated_output, S_IRUSR | S_IWUSR,
+	cyttsp5_formated_output_show, cyttsp5_formated_output_store);
+
+static int cyttsp5_debug_probe(struct device *dev, void **data)
+{
+	struct cyttsp5_debug_data *dd;
+	int rc;
+
+	/* get context and debug print buffers */
+	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+	if (!dd) {
+		rc = -ENOMEM;
+		goto cyttsp5_debug_probe_alloc_failed;
+	}
+
+	rc = device_create_file(dev, &dev_attr_int_count);
+	if (rc) {
+		dev_err(dev, "%s: Error, could not create int_count\n",
+				__func__);
+		goto cyttsp5_debug_probe_create_int_count_failed;
+	}
+
+	rc = device_create_file(dev, &dev_attr_formated_output);
+	if (rc) {
+		dev_err(dev, "%s: Error, could not create formated_output\n",
+				__func__);
+		goto cyttsp5_debug_probe_create_formated_failed;
+	}
+
+	mutex_init(&dd->sysfs_lock);
+	dd->dev = dev;
+	*data = dd;
+
+	dd->si = cmd->request_sysinfo(dev);
+	if (!dd->si) {
+		dev_err(dev, "%s: Fail get sysinfo pointer from core\n",
+				__func__);
+		rc = -ENODEV;
+		goto cyttsp5_debug_probe_sysinfo_failed;
+	}
+
+	rc = cmd->subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_DEBUG_NAME,
+		cyttsp5_debug_attention, CY_MODE_OPERATIONAL);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error, could not subscribe attention cb\n",
+				__func__);
+		goto cyttsp5_debug_probe_subscribe_failed;
+	}
+
+	return 0;
+
+cyttsp5_debug_probe_subscribe_failed:
+cyttsp5_debug_probe_sysinfo_failed:
+	device_remove_file(dev, &dev_attr_formated_output);
+cyttsp5_debug_probe_create_formated_failed:
+	device_remove_file(dev, &dev_attr_int_count);
+cyttsp5_debug_probe_create_int_count_failed:
+	kfree(dd);
+cyttsp5_debug_probe_alloc_failed:
+	dev_err(dev, "%s failed.\n", __func__);
+	return rc;
+}
+
+static void cyttsp5_debug_release(struct device *dev, void *data)
+{
+	struct cyttsp5_debug_data *dd = data;
+	int rc;
+
+	rc = cmd->unsubscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_DEBUG_NAME,
+		cyttsp5_debug_attention, CY_MODE_OPERATIONAL);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error, could not un-subscribe attention\n",
+				__func__);
+		goto cyttsp5_debug_release_exit;
+	}
+
+cyttsp5_debug_release_exit:
+	device_remove_file(dev, &dev_attr_formated_output);
+	device_remove_file(dev, &dev_attr_int_count);
+	kfree(dd);
+}
+
+static struct cyttsp5_module debug_module = {
+	.name = CYTTSP5_DEBUG_NAME,
+	.probe = cyttsp5_debug_probe,
+	.release = cyttsp5_debug_release,
+};
+
+static int __init cyttsp5_debug_init(void)
+{
+	int rc;
+
+	cmd = cyttsp5_get_commands();
+	if (!cmd)
+		return -EINVAL;
+
+	rc = cyttsp5_register_module(&debug_module);
+	if (rc < 0) {
+		pr_err("%s: Error, failed registering module\n",
+			__func__);
+			return rc;
+	}
+
+	pr_info("%s: Parade TTSP Debug Driver (Built %s) rc=%d\n",
+		 __func__, CY_DRIVER_VERSION, rc);
+	return 0;
+}
+module_init(cyttsp5_debug_init);
+
+static void __exit cyttsp5_debug_exit(void)
+{
+	cyttsp5_unregister_module(&debug_module);
+}
+module_exit(cyttsp5_debug_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Debug Driver");
+MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");
diff --git a/tp/cyttsp5/cyttsp5_device_access-api.h b/tp/cyttsp5/cyttsp5_device_access-api.h
new file mode 100644
index 0000000..c071e52
--- /dev/null
+++ b/tp/cyttsp5/cyttsp5_device_access-api.h
@@ -0,0 +1,44 @@
+/*
+ * cyttsp5_device_access-api.h
+ * Parade TrueTouch(TM) Standard Product V5 Device Access API module.
+ * For use with Parade touchscreen controllers.
+ * Supported parts include:
+ * CYTMA5XX
+ * CYTMA448
+ * CYTMA445A
+ * CYTT21XXX
+ * CYTT31XXX
+ *
+ * Copyright (C) 2015 Parade Semiconductor
+ * Copyright (C) 2012-2015 Cypress Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Contact Parade Semiconductor at www.parade.com <ttdrivers@paradetech.com>
+ *
+ */
+
+#ifndef _LINUX_CYTTSP5_DEVICE_ACCESS_API_H
+#define _LINUX_CYTTSP5_DEVICE_ACCESS_API_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+int cyttsp5_device_access_user_command(const char *core_name, u16 read_len,
+		u8 *read_buf, u16 write_len, u8 *write_buf,
+		u16 *actual_read_len);
+
+int cyttsp5_device_access_user_command_async(const char *core_name,
+		u16 read_len, u8 *read_buf, u16 write_len, u8 *write_buf,
+		void (*cont)(const char *core_name, u16 read_len, u8 *read_buf,
+			u16 write_len, u8 *write_buf, u16 actual_read_length,
+			int rc));
+#endif /* _LINUX_CYTTSP5_DEVICE_ACCESS_API_H */
diff --git a/tp/cyttsp5/cyttsp5_device_access.c b/tp/cyttsp5/cyttsp5_device_access.c
new file mode 100644
index 0000000..287c531
--- /dev/null
+++ b/tp/cyttsp5/cyttsp5_device_access.c
@@ -0,0 +1,5201 @@
+/*
+ * cyttsp5_device_access.c
+ * Parade TrueTouch(TM) Standard Product V5 Device Access Module.
+ * Configuration and Test command/status user interface.
+ * For use with Parade touchscreen controllers.
+ * Supported parts include:
+ * CYTMA5XX
+ * CYTMA448
+ * CYTMA445A
+ * CYTT21XXX
+ * CYTT31XXX
+ *
+ * Copyright (C) 2015 Parade Technologies
+ * Copyright (C) 2012-2015 Cypress Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
+ *
+ */
+
+#include "cyttsp5_regs.h"
+#include <linux/firmware.h>
+
+#include <linux/timer.h>
+#include <linux/timex.h>
+#include <linux/rtc.h>
+
+#define CY_CMCP_THRESHOLD_FILE_NAME "cyttsp5_thresholdfile.csv"
+#define CMCP_THRESHOLD_FILE_NAME "ttdl_cmcp_thresholdfile.csv"
+
+/* Max test case number */
+#define MAX_CASE_NUM            (22)
+
+/* ASCII */
+#define ASCII_LF                (0x0A)
+#define ASCII_CR                (0x0D)
+#define ASCII_COMMA             (0x2C)
+#define ASCII_ZERO              (0x30)
+#define ASCII_NINE              (0x39)
+
+/* Max characters of test case name */
+#define NAME_SIZE_MAX           (50)
+
+/* Max sensor and button number */
+#define MAX_BUTTONS             (HID_SYSINFO_MAX_BTN)
+#define MAX_SENSORS             (1024)
+#define MAX_TX_SENSORS          (128)
+#define MAX_RX_SENSORS          (128)
+
+/* Multiply by 2 for double (min, max) values */
+#define TABLE_BUTTON_MAX_SIZE   (MAX_BUTTONS * 2)
+#define TABLE_SENSOR_MAX_SIZE   (MAX_SENSORS * 2)
+#define TABLE_TX_MAX_SIZE       (MAX_TX_SENSORS*2)
+#define TABLE_RX_MAX_SIZE       (MAX_RX_SENSORS*2)
+
+#define CM_PANEL_DATA_OFFSET    (6)
+#define CM_BTN_DATA_OFFSET      (6)
+#define CP_PANEL_DATA_OFFSET    (6)
+#define CP_BTN_DATA_OFFSET      (6)
+#define MAX_BUF_LEN             (50000)
+
+/* cmcp csv file information */
+struct configuration {
+	u32 cm_range_limit_row;
+	u32 cm_range_limit_col;
+	u32 cm_min_limit_cal;
+	u32 cm_max_limit_cal;
+	u32 cm_max_delta_sensor_percent;
+	u32 cm_max_delta_button_percent;
+	u32 min_sensor_rx;
+	u32 max_sensor_rx;
+	u32 min_sensor_tx;
+	u32 max_sensor_tx;
+	u32 min_button;
+	u32 max_button;
+	u32 max_delta_sensor;
+	u32 cp_max_delta_sensor_rx_percent;
+	u32 cp_max_delta_sensor_tx_percent;
+	u32 cm_min_max_table_button[TABLE_BUTTON_MAX_SIZE];
+	u32 cp_min_max_table_button[TABLE_BUTTON_MAX_SIZE];
+	u32 cm_min_max_table_sensor[TABLE_SENSOR_MAX_SIZE];
+	u32 cp_min_max_table_rx[TABLE_RX_MAX_SIZE];
+	u32 cp_min_max_table_tx[TABLE_TX_MAX_SIZE];
+	u32 cm_min_max_table_button_size;
+	u32 cp_min_max_table_button_size;
+	u32 cm_min_max_table_sensor_size;
+	u32 cp_min_max_table_rx_size;
+	u32 cp_min_max_table_tx_size;
+	u32 cp_max_delta_button_percent;
+	u32 cm_max_table_gradient_cols_percent[TABLE_TX_MAX_SIZE];
+	u32 cm_max_table_gradient_cols_percent_size;
+	u32 cm_max_table_gradient_rows_percent[TABLE_RX_MAX_SIZE];
+	u32 cm_max_table_gradient_rows_percent_size;
+	u32 cm_excluding_row_edge;
+	u32 cm_excluding_col_edge;
+	u32 rx_num;
+	u32 tx_num;
+	u32 btn_num;
+	u32 cm_enabled;
+	u32 cp_enabled;
+	u32 is_valid_or_not;
+};
+
+/* Test case search definition */
+struct test_case_search {
+	char name[NAME_SIZE_MAX]; /* Test case name */
+	u32 name_size;            /* Test case name size */
+	u32 offset;               /* Test case offset */
+};
+
+/* Test case field definition */
+struct test_case_field {
+	char *name;     /* Test case name */
+	u32 name_size;  /* Test case name size */
+	u32 type;       /* Test case type */
+	u32 *bufptr;    /* Buffer to store value information */
+	u32 exist_or_not;/* Test case exist or not */
+	u32 data_num;   /* Buffer data number */
+	u32 line_num;   /* Buffer line number */
+};
+
+/* Test case type */
+enum test_case_type {
+	TEST_CASE_TYPE_NO,
+	TEST_CASE_TYPE_ONE,
+	TEST_CASE_TYPE_MUL,
+	TEST_CASE_TYPE_MUL_LINES,
+};
+
+/* Test case order in test_case_field_array */
+enum case_order {
+	CM_TEST_INPUTS,
+	CM_EXCLUDING_COL_EDGE,
+	CM_EXCLUDING_ROW_EDGE,
+	CM_GRADIENT_CHECK_COL,
+	CM_GRADIENT_CHECK_ROW,
+	CM_RANGE_LIMIT_ROW,
+	CM_RANGE_LIMIT_COL,
+	CM_MIN_LIMIT_CAL,
+	CM_MAX_LIMIT_CAL,
+	CM_MAX_DELTA_SENSOR_PERCENT,
+	CM_MAX_DELTA_BUTTON_PERCENT,
+	PER_ELEMENT_MIN_MAX_TABLE_BUTTON,
+	PER_ELEMENT_MIN_MAX_TABLE_SENSOR,
+	CP_TEST_INPUTS,
+	CP_MAX_DELTA_SENSOR_RX_PERCENT,
+	CP_MAX_DELTA_SENSOR_TX_PERCENT,
+	CP_MAX_DELTA_BUTTON_PERCENT,
+	CP_PER_ELEMENT_MIN_MAX_BUTTON,
+	MIN_BUTTON,
+	MAX_BUTTON,
+	PER_ELEMENT_MIN_MAX_RX,
+	PER_ELEMENT_MIN_MAX_TX,
+	CASE_ORDER_MAX,
+};
+
+enum cmcp_test_item {
+	CMCP_FULL = 0,
+	CMCP_CM_PANEL,
+	CMCP_CP_PANEL,
+	CMCP_CM_BTN,
+	CMCP_CP_BTN,
+};
+
+#define CM_ENABLED 0x10
+#define CP_ENABLED 0x20
+#define CM_PANEL (0x01 | CM_ENABLED)
+#define CP_PANEL (0x02 | CP_ENABLED)
+#define CM_BTN (0x04 | CM_ENABLED)
+#define CP_BTN (0x08 | CP_ENABLED)
+#define CMCP_FULL_CASE\
+	(CM_PANEL | CP_PANEL | CM_BTN | CP_BTN | CM_ENABLED | CP_ENABLED)
+
+#define CYTTSP5_DEVICE_ACCESS_NAME "cyttsp5_device_access"
+#define CYTTSP5_INPUT_ELEM_SZ (sizeof("0xHH") + 1)
+
+#define STATUS_SUCCESS	0
+#define STATUS_FAIL	-1
+#define PIP_CMD_MAX_LENGTH ((1 << 16) - 1)
+
+#ifdef TTHE_TUNER_SUPPORT
+struct heatmap_param {
+	bool scan_start;
+	enum scan_data_type_list data_type; /* raw, base, diff */
+	int num_element;
+};
+#endif
+#define ABS(x)			(((x) < 0) ? -(x) : (x))
+
+#define CY_MAX_CONFIG_BYTES    256
+#define CYTTSP5_TTHE_TUNER_GET_PANEL_DATA_FILE_NAME "get_panel_data"
+#define TTHE_TUNER_MAX_BUF	(CY_MAX_PRBUF_SIZE * 3)
+
+struct cyttsp5_device_access_data {
+	struct device *dev;
+	struct cyttsp5_sysinfo *si;
+	struct mutex sysfs_lock;
+	u8 status;
+	u16 response_length;
+	bool sysfs_nodes_created;
+	struct kobject mfg_test;
+	u8 panel_scan_data_id;
+	u8 get_idac_data_id;
+	u8 calibrate_sensing_mode;
+	u8 calibrate_initialize_baselines;
+	u8 baseline_sensing_mode;
+#ifdef TTHE_TUNER_SUPPORT
+	struct heatmap_param heatmap;
+	struct dentry *tthe_get_panel_data_debugfs;
+	struct mutex debugfs_lock;
+	u8 tthe_get_panel_data_buf[TTHE_TUNER_MAX_BUF];
+	u8 tthe_get_panel_data_is_open;
+#endif
+	struct dentry *cmcp_results_debugfs;
+
+	struct dentry *base_dentry;
+	struct dentry *mfg_test_dentry;
+	u8 ic_buf[CY_MAX_PRBUF_SIZE];
+	u8 response_buf[CY_MAX_PRBUF_SIZE];
+	struct mutex cmcp_threshold_lock;
+	u8 *cmcp_threshold_data;
+	int cmcp_threshold_size;
+	bool cmcp_threshold_loading;
+	struct work_struct cmcp_threshold_update;
+	struct completion builtin_cmcp_threshold_complete;
+	int builtin_cmcp_threshold_status;
+	bool is_manual_upgrade_enabled;
+	struct configuration *configs;
+	struct cmcp_data *cmcp_info;
+	struct result *result;
+	struct test_case_search *test_search_array;
+	struct test_case_field *test_field_array;
+	int cmcp_test_items;
+	int test_executed;
+	int cmcp_range_check;
+	int cmcp_force_calibrate;
+	int cmcp_test_in_progress;
+};
+
+struct cmcp_data {
+	struct gd_sensor *gd_sensor_col;
+	struct gd_sensor *gd_sensor_row;
+	int32_t *cm_data_panel;
+	int32_t *cp_tx_data_panel;
+	int32_t *cp_rx_data_panel;
+	int32_t *cp_tx_cal_data_panel;
+	int32_t *cp_rx_cal_data_panel;
+	int32_t cp_sensor_rx_delta;
+	int32_t cp_sensor_tx_delta;
+	int32_t cp_button_delta;
+	int32_t *cm_btn_data;
+	int32_t *cp_btn_data;
+	int32_t *cm_sensor_column_delta;
+	int32_t *cm_sensor_row_delta;
+	int32_t cp_btn_cal;
+	int32_t cm_btn_cal;
+	int32_t cp_button_ave;
+	int32_t cm_ave_data_panel;
+	int32_t cp_tx_ave_data_panel;
+	int32_t cp_rx_ave_data_panel;
+	int32_t cm_cal_data_panel;
+	int32_t cm_ave_data_btn;
+	int32_t cm_cal_data_btn;
+	int32_t cm_delta_data_btn;
+	int32_t cm_sensor_delta;
+
+	int32_t tx_num;
+	int32_t rx_num;
+	int32_t btn_num;
+};
+
+struct result {
+	int32_t sensor_assignment;
+	int32_t config_ver;
+	int32_t revision_ctrl;
+	int32_t device_id_high;
+	int32_t device_id_low;
+	bool cm_test_run;
+	bool cp_test_run;
+	/* Sensor Cm validation */
+	bool cm_test_pass;
+	bool cm_sensor_validation_pass;
+	bool cm_sensor_row_delta_pass;
+	bool cm_sensor_col_delta_pass;
+	bool cm_sensor_gd_row_pass;
+	bool cm_sensor_gd_col_pass;
+	bool cm_sensor_calibration_pass;
+	bool cm_sensor_delta_pass;
+	bool cm_button_validation_pass;
+	bool cm_button_delta_pass;
+
+	int32_t *cm_sensor_raw_data;
+	int32_t cm_sensor_calibration;
+	int32_t cm_sensor_delta;
+	int32_t *cm_button_raw_data;
+	int32_t cm_button_delta;
+
+	/* Sensor Cp validation */
+	bool cp_test_pass;
+	bool cp_sensor_delta_pass;
+	bool cp_sensor_rx_delta_pass;
+	bool cp_sensor_tx_delta_pass;
+	bool cp_sensor_average_pass;
+	bool cp_button_delta_pass;
+	bool cp_button_average_pass;
+	bool cp_rx_validation_pass;
+	bool cp_tx_validation_pass;
+	bool cp_button_validation_pass;
+
+	int32_t *cp_sensor_rx_raw_data;
+	int32_t *cp_sensor_tx_raw_data;
+	int32_t cp_sensor_rx_delta;
+	int32_t cp_sensor_tx_delta;
+	int32_t cp_sensor_rx_calibration;
+	int32_t cp_sensor_tx_calibration;
+	int32_t *cp_button_raw_data;
+	int32_t cp_button_delta;
+
+	/*other validation*/
+	bool short_test_pass;
+	bool test_summary;
+	uint8_t *cm_open_pwc;
+};
+
+static struct cyttsp5_core_commands *cmd;
+
+static struct cyttsp5_module device_access_module;
+
+static ssize_t cyttsp5_run_and_get_selftest_result_noprint(struct device *dev,
+		char *buf, size_t buf_len, u8 test_id, u16 read_length,
+		bool get_result_on_pass);
+
+static int _cyttsp5_calibrate_idacs_cmd(struct device *dev,
+		u8 sensing_mode, u8 *status);
+
+static inline struct cyttsp5_device_access_data *cyttsp5_get_device_access_data(
+		struct device *dev)
+{
+	return cyttsp5_get_module_data(dev, &device_access_module);
+}
+
+static ssize_t cyttsp5_status_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	u8 val;
+
+	mutex_lock(&dad->sysfs_lock);
+	val = dad->status;
+	mutex_unlock(&dad->sysfs_lock);
+
+	return scnprintf(buf, CY_MAX_PRBUF_SIZE, "%d\n", val);
+}
+
+static DEVICE_ATTR(status, S_IRUSR, cyttsp5_status_show, NULL);
+
+static ssize_t cyttsp5_response_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	int i;
+	ssize_t num_read;
+	int index;
+
+	mutex_lock(&dad->sysfs_lock);
+	index = scnprintf(buf, CY_MAX_PRBUF_SIZE,
+			"Status %d\n", dad->status);
+	if (!dad->status)
+		goto error;
+
+	num_read = dad->response_length;
+
+	for (i = 0; i < num_read; i++)
+		index += scnprintf(buf + index, CY_MAX_PRBUF_SIZE - index,
+				"0x%02X\n", dad->response_buf[i]);
+
+	index += scnprintf(buf + index, CY_MAX_PRBUF_SIZE - index,
+			"(%zd bytes)\n", num_read);
+
+error:
+	mutex_unlock(&dad->sysfs_lock);
+	return index;
+}
+
+static DEVICE_ATTR(response, S_IRUSR, cyttsp5_response_show, NULL);
+
+/*
+ * Gets user input from sysfs and parse it
+ * return size of parsed output buffer
+ */
+static int cyttsp5_ic_parse_input(struct device *dev, const char *buf,
+		size_t buf_size, u8 *ic_buf, size_t ic_buf_size)
+{
+	const char *pbuf = buf;
+	unsigned long value;
+	char scan_buf[CYTTSP5_INPUT_ELEM_SZ];
+	u32 i = 0;
+	u32 j;
+	int last = 0;
+	int ret;
+
+	parade_debug(dev, DEBUG_LEVEL_1,
+		"%s: pbuf=%p buf=%p size=%zu %s=%zu buf=%s\n",
+		__func__, pbuf, buf, buf_size, "scan buf size",
+		CYTTSP5_INPUT_ELEM_SZ, buf);
+
+	while (pbuf <= (buf + buf_size)) {
+		if (i >= CY_MAX_CONFIG_BYTES) {
+			dev_err(dev, "%s: %s size=%d max=%d\n", __func__,
+					"Max cmd size exceeded", i,
+					CY_MAX_CONFIG_BYTES);
+			return -EINVAL;
+		}
+		if (i >= ic_buf_size) {
+			dev_err(dev, "%s: %s size=%d buf_size=%zu\n", __func__,
+					"Buffer size exceeded", i, ic_buf_size);
+			return -EINVAL;
+		}
+		while (((*pbuf == ' ') || (*pbuf == ','))
+				&& (pbuf < (buf + buf_size))) {
+			last = *pbuf;
+			pbuf++;
+		}
+
+		if (pbuf >= (buf + buf_size))
+			break;
+
+		memset(scan_buf, 0, CYTTSP5_INPUT_ELEM_SZ);
+		if ((last == ',') && (*pbuf == ',')) {
+			dev_err(dev, "%s: %s \",,\" not allowed.\n", __func__,
+					"Invalid data format.");
+			return -EINVAL;
+		}
+		for (j = 0; j < (CYTTSP5_INPUT_ELEM_SZ - 1)
+				&& (pbuf < (buf + buf_size))
+				&& (*pbuf != ' ')
+				&& (*pbuf != ','); j++) {
+			last = *pbuf;
+			scan_buf[j] = *pbuf++;
+		}
+
+		ret = kstrtoul(scan_buf, 16, &value);
+		if (ret < 0) {
+			dev_err(dev, "%s: %s '%s' %s%s i=%d r=%d\n", __func__,
+					"Invalid data format. ", scan_buf,
+					"Use \"0xHH,...,0xHH\"", " instead.",
+					i, ret);
+			return ret;
+		}
+
+		ic_buf[i] = value;
+		i++;
+	}
+
+	return i;
+}
+
+static ssize_t cyttsp5_command_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	ssize_t length;
+	int rc;
+
+	mutex_lock(&dad->sysfs_lock);
+	dad->status = 0;
+	dad->response_length = 0;
+	length = cyttsp5_ic_parse_input(dev, buf, size, dad->ic_buf,
+			CY_MAX_PRBUF_SIZE);
+	if (length <= 0) {
+		dev_err(dev, "%s: %s Group Data store\n", __func__,
+				"Malformed input for");
+		goto exit;
+	}
+
+	/* write ic_buf to log */
+	cyttsp5_pr_buf(dev, dad->ic_buf, length, "ic_buf");
+
+	pm_runtime_get_sync(dev);
+	rc = cmd->nonhid_cmd->user_cmd(dev, 1, CY_MAX_PRBUF_SIZE,
+			dad->response_buf, length, dad->ic_buf,
+			&dad->response_length);
+	pm_runtime_put(dev);
+	if (rc) {
+		dad->response_length = 0;
+		dev_err(dev, "%s: Failed to store command\n", __func__);
+	} else {
+		dad->status = 1;
+	}
+
+exit:
+	mutex_unlock(&dad->sysfs_lock);
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: return size=%zu\n",
+		__func__, size);
+	return size;
+}
+
+static DEVICE_ATTR(command, S_IWUSR, NULL, cyttsp5_command_store);
+
+static int cmcp_check_config_fw_match(struct device *dev,
+	struct configuration *configuration)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	int32_t tx_num = dad->configs->tx_num;
+	int32_t rx_num = dad->configs->rx_num;
+	int32_t button_num = dad->configs->btn_num;
+	int ret = 0;
+
+	if (tx_num != dad->si->sensing_conf_data.tx_num) {
+		dev_err(dev, "%s: TX number mismatch!\n", __func__);
+		ret = -EINVAL;
+	}
+
+	if (rx_num != dad->si->sensing_conf_data.rx_num) {
+		dev_err(dev, "%s: RX number mismatch!\n", __func__);
+		ret = -EINVAL;
+	}
+
+	if (button_num != dad->si->num_btns) {
+		dev_err(dev, "%s: Button number mismatch!\n", __func__);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int validate_cm_test_results(struct device *dev,
+	struct configuration *configuration, struct cmcp_data *cmcp_info,
+	struct result *result, bool *pass, int test_item)
+{
+	int32_t tx_num = cmcp_info->tx_num;
+	int32_t rx_num = cmcp_info->rx_num;
+	int32_t button_num =  cmcp_info->btn_num;
+	uint32_t sensor_num = tx_num * rx_num;
+	int32_t *cm_sensor_data = cmcp_info->cm_data_panel;
+	int32_t cm_button_delta;
+	int32_t cm_sensor_calibration;
+	int32_t *cm_button_data = cmcp_info->cm_btn_data;
+	struct gd_sensor *gd_sensor_col = cmcp_info->gd_sensor_col;
+	struct gd_sensor *gd_sensor_row = cmcp_info->gd_sensor_row;
+	int32_t *cm_sensor_column_delta = cmcp_info->cm_sensor_column_delta;
+	int32_t *cm_sensor_row_delta = cmcp_info->cm_sensor_row_delta;
+	int ret = 0;
+	int i, j;
+
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: start\n", __func__);
+
+	if ((test_item & CM_PANEL) == CM_PANEL) {
+		parade_debug(dev, DEBUG_LEVEL_2, "Check each sensor Cm data for min max value\n ");
+
+		/* Check each sensor Cm data for min/max values */
+		result->cm_sensor_validation_pass = true;
+
+	for (i = 0; i < sensor_num; i++) {
+		int row = i % rx_num;
+		int col = i / rx_num;
+		int32_t cm_sensor_min =
+		configuration->cm_min_max_table_sensor[(row*tx_num+col)*2];
+		int32_t cm_sensor_max =
+		configuration->cm_min_max_table_sensor[(row*tx_num+col)*2+1];
+		if ((cm_sensor_data[i] < cm_sensor_min)
+		|| (cm_sensor_data[i] > cm_sensor_max)) {
+			dev_err(dev, "%s: Sensor[%d,%d]:%d (%d,%d)\n",
+					"Cm sensor min/max test",
+					row, col,
+					cm_sensor_data[i],
+					cm_sensor_min, cm_sensor_max);
+			result->cm_sensor_validation_pass = false;
+		}
+	}
+
+	/*check cm gradient column data*/
+	result->cm_sensor_gd_col_pass = true;
+	for (i = 0;
+	i < configuration->cm_max_table_gradient_cols_percent_size;
+	i++) {
+		if ((gd_sensor_col + i)->gradient_val >
+		10 * configuration->cm_max_table_gradient_cols_percent[i]){
+			dev_err(dev,
+		"%s: cm_max_table_gradient_cols_percent[%d]:%d, gradient_val:%d\n",
+		__func__,
+		i,
+		configuration->cm_max_table_gradient_cols_percent[i],
+		(gd_sensor_col + i)->gradient_val);
+			result->cm_sensor_gd_col_pass = false;
+		}
+	}
+
+	/*check cm gradient row data*/
+	result->cm_sensor_gd_row_pass = true;
+	for (j = 0;
+	j < configuration->cm_max_table_gradient_rows_percent_size;
+	j++) {
+		if ((gd_sensor_row + j)->gradient_val >
+		10 * configuration->cm_max_table_gradient_rows_percent[j]) {
+			dev_err(dev,
+		"%s: cm_max_table_gradient_rows_percent[%d]:%d, gradient_val:%d\n",
+		__func__,
+		j, configuration->cm_max_table_gradient_rows_percent[j],
+		(gd_sensor_row + j)->gradient_val);
+			result->cm_sensor_gd_row_pass = false;
+		}
+	}
+
+	result->cm_sensor_row_delta_pass = true;
+	result->cm_sensor_col_delta_pass = true;
+	result->cm_sensor_calibration_pass = true;
+	result->cm_sensor_delta_pass = true;
+
+
+	/*
+	 * Check each row Cm data
+	 * with neighbor for difference
+	 */
+	for (i = 0; i < tx_num; i++) {
+		for (j = 1; j < rx_num; j++) {
+			int32_t cm_sensor_row_diff =
+			ABS(cm_sensor_data[i * rx_num + j] -
+			cm_sensor_data[i * rx_num + j - 1]);
+		cm_sensor_row_delta[i * rx_num + j - 1] =
+			cm_sensor_row_diff;
+			if (cm_sensor_row_diff
+			> configuration->cm_range_limit_row) {
+				dev_err(dev,
+				"%s: Sensor[%d,%d]:%d (%d)\n",
+				"Cm sensor row range limit test",
+				j, i,
+				cm_sensor_row_diff,
+			configuration->cm_range_limit_row);
+		result->cm_sensor_row_delta_pass = false;
+			}
+		}
+	}
+
+	/*
+	 * Check each column Cm data
+	 * with neighbor for difference
+	 */
+	for (i = 1; i < tx_num; i++) {
+		for (j = 0; j < rx_num; j++) {
+			int32_t cm_sensor_col_diff =
+		ABS((int)cm_sensor_data[i * rx_num + j] -
+		(int)cm_sensor_data[(i - 1) * rx_num + j]);
+		cm_sensor_column_delta[(i - 1) * rx_num + j] =
+			cm_sensor_col_diff;
+		if (cm_sensor_col_diff >
+			configuration->cm_range_limit_col) {
+			dev_err(dev,
+			"%s: Sensor[%d,%d]:%d (%d)\n",
+			"Cm sensor column range limit test",
+			j, i,
+			cm_sensor_col_diff,
+			configuration->cm_range_limit_col);
+		result->cm_sensor_col_delta_pass = false;
+			}
+		}
+	}
+
+	/* Check sensor calculated Cm for min/max values */
+	cm_sensor_calibration = cmcp_info->cm_cal_data_panel;
+	if (cm_sensor_calibration <
+		configuration->cm_min_limit_cal
+		|| cm_sensor_calibration >
+		configuration->cm_max_limit_cal) {
+		dev_err(dev, "%s: Cm_cal:%d (%d,%d)\n",
+			"Cm sensor Cm_cal min/max test",
+			cm_sensor_calibration,
+			configuration->cm_min_limit_cal,
+			configuration->cm_max_limit_cal);
+		result->cm_sensor_calibration_pass = false;
+	}
+
+	/* Check sensor Cm delta for range limit */
+	if (cmcp_info->cm_sensor_delta
+		 > 10 * configuration->cm_max_delta_sensor_percent) {
+		dev_err(dev,
+			"%s: Cm_sensor_delta:%d (%d)\n",
+			"Cm sensor delta range limit test",
+			cmcp_info->cm_sensor_delta,
+		configuration->cm_max_delta_sensor_percent);
+		result->cm_sensor_delta_pass = false;
+	}
+
+	result->cm_test_pass = result->cm_sensor_gd_col_pass
+			&& result->cm_sensor_gd_row_pass
+			&& result->cm_sensor_validation_pass
+			&& result->cm_sensor_row_delta_pass
+			&& result->cm_sensor_col_delta_pass
+			&& result->cm_sensor_calibration_pass
+			&& result->cm_sensor_delta_pass;
+	}
+
+	if (((test_item & CM_BTN) == CM_BTN) && (cmcp_info->btn_num)) {
+		/* Check each button Cm data for min/max values */
+		result->cm_button_validation_pass = true;
+		for (i = 0; i < button_num; i++) {
+			int32_t  cm_button_min =
+			configuration->cm_min_max_table_button[i * 2];
+			int32_t  cm_button_max =
+			configuration->cm_min_max_table_button[i * 2 + 1];
+			if ((cm_button_data[i] <= cm_button_min)
+				|| (cm_button_data[i] >= cm_button_max)) {
+				dev_err(dev,
+					"%s: Button[%d]:%d (%d,%d)\n",
+					"Cm button min/max test",
+					i,
+					cm_button_data[i],
+					cm_button_min, cm_button_max);
+				result->cm_button_validation_pass = false;
+			}
+		}
+
+		/* Check button Cm delta for range limit */
+		result->cm_button_delta_pass = true;
+
+		cm_button_delta = ABS((cmcp_info->cm_ave_data_btn -
+			cmcp_info->cm_cal_data_btn) * 100 /
+			cmcp_info->cm_ave_data_btn);
+		if (cm_button_delta >
+		configuration->cm_max_delta_button_percent) {
+			dev_err(dev,
+				"%s: Cm_button_delta:%d (%d)\n",
+				"Cm button delta range limit test",
+				cm_button_delta,
+			configuration->cm_max_delta_button_percent);
+			result->cm_button_delta_pass = false;
+		}
+
+		result->cm_test_pass = result->cm_test_pass
+				&& result->cm_button_validation_pass
+				&& result->cm_button_delta_pass;
+	}
+
+	if (pass)
+		*pass = result->cm_test_pass;
+
+	return ret;
+}
+static int validate_cp_test_results(struct device *dev,
+	struct configuration *configuration, struct cmcp_data *cmcp_info,
+	struct result *result, bool *pass, int test_item)
+{
+	int i = 0;
+	uint32_t configuration_rx_num;
+	uint32_t configuration_tx_num;
+	int32_t *cp_sensor_tx_data = cmcp_info->cp_tx_data_panel;
+	int32_t *cp_sensor_rx_data = cmcp_info->cp_rx_data_panel;
+	int32_t cp_button_delta;
+	int32_t cp_button_average;
+
+	result->cp_test_pass = true;
+	configuration_rx_num = configuration->cp_min_max_table_rx_size/2;
+	configuration_tx_num = configuration->cp_min_max_table_tx_size/2;
+
+	parade_debug(dev, DEBUG_LEVEL_2, "%s start\n", __func__);
+
+	if ((test_item & CP_PANEL) == CP_PANEL) {
+		int32_t cp_sensor_tx_delta;
+		int32_t cp_sensor_rx_delta;
+
+		/* Check Sensor Cp delta for range limit */
+		result->cp_sensor_delta_pass = true;
+		/*check cp_sensor_tx_delta */
+		for (i = 0; i < configuration_tx_num; i++) {
+			cp_sensor_tx_delta =
+			ABS((cmcp_info->cp_tx_cal_data_panel[i]-
+			cmcp_info->cp_tx_data_panel[i]) * 100 /
+			cmcp_info->cp_tx_data_panel[i]);
+
+			if (cp_sensor_tx_delta >
+			configuration->cp_max_delta_sensor_tx_percent) {
+				dev_err(dev,
+				"%s: Cp_sensor_tx_delta:%d (%d)\n",
+				"Cp sensor delta range limit test",
+				cp_sensor_tx_delta,
+			configuration->cp_max_delta_sensor_tx_percent);
+				result->cp_sensor_delta_pass = false;
+			}
+		}
+
+		/*check cp_sensor_rx_delta */
+		for (i = 0; i < configuration_rx_num; i++) {
+			cp_sensor_rx_delta =
+			ABS((cmcp_info->cp_rx_cal_data_panel[i] -
+			cmcp_info->cp_rx_data_panel[i]) * 100 /
+			cmcp_info->cp_rx_data_panel[i]);
+			if (cp_sensor_rx_delta >
+			configuration->cp_max_delta_sensor_rx_percent) {
+				dev_err(dev,
+				"%s: Cp_sensor_rx_delta:%d(%d)\n",
+				"Cp sensor delta range limit test",
+				cp_sensor_rx_delta,
+			configuration->cp_max_delta_sensor_rx_percent);
+				result->cp_sensor_delta_pass = false;
+			}
+		}
+
+		/* Check sensor Cp rx for min/max values */
+		result->cp_rx_validation_pass = true;
+		for (i = 0; i < configuration_rx_num; i++) {
+			int32_t cp_rx_min =
+				configuration->cp_min_max_table_rx[i * 2];
+			int32_t cp_rx_max =
+				configuration->cp_min_max_table_rx[i * 2 + 1];
+			if ((cp_sensor_rx_data[i] <= cp_rx_min)
+				|| (cp_sensor_rx_data[i] >= cp_rx_max)) {
+				dev_err(dev,
+				"%s: Cp Rx[%d]:%d (%d,%d)\n",
+				"Cp Rx min/max test",
+				i,
+				(int)cp_sensor_rx_data[i],
+				cp_rx_min, cp_rx_max);
+				result->cp_rx_validation_pass = false;
+			}
+		}
+
+		/* Check sensor Cp tx for min/max values */
+		result->cp_tx_validation_pass = true;
+		for (i = 0; i < configuration_tx_num; i++) {
+			int32_t cp_tx_min =
+				configuration->cp_min_max_table_tx[i * 2];
+			int32_t cp_tx_max =
+				configuration->cp_min_max_table_tx[i * 2 + 1];
+			if ((cp_sensor_tx_data[i] <= cp_tx_min)
+				|| (cp_sensor_tx_data[i] >= cp_tx_max)) {
+				dev_err(dev,
+				"%s: Cp Tx[%d]:%d(%d,%d)\n",
+				"Cp Tx min/max test",
+				i,
+				cp_sensor_tx_data[i],
+				cp_tx_min, cp_tx_max);
+				result->cp_tx_validation_pass = false;
+			}
+		}
+
+		result->cp_test_pass = result->cp_test_pass
+				&& result->cp_sensor_delta_pass
+				&& result->cp_rx_validation_pass
+				&& result->cp_tx_validation_pass;
+	}
+
+	if (((test_item & CP_BTN) == CP_BTN) && (cmcp_info->btn_num)) {
+		result->cp_button_delta_pass = true;
+
+		/* Check button Cp delta for range limit */
+		cp_button_delta = ABS((cmcp_info->cp_btn_cal
+		- cmcp_info->cp_button_ave) * 100 /
+		cmcp_info->cp_button_ave);
+		if (cp_button_delta >
+		configuration->cp_max_delta_button_percent) {
+			dev_err(dev,
+			"%s: Cp_button_delta:%d (%d)\n",
+			"Cp button delta range limit test",
+			cp_button_delta,
+			configuration->cp_max_delta_button_percent);
+			result->cp_button_delta_pass = false;
+		}
+
+		/* Check button Cp average for min/max values */
+		result->cp_button_average_pass = true;
+		cp_button_average = cmcp_info->cp_button_ave;
+		if (cp_button_average < configuration->min_button
+				|| cp_button_average >
+					configuration->max_button) {
+			dev_err(dev,
+				"%s: Button Cp average fails min/max test\n",
+				__func__);
+			dev_err(dev,
+				"%s: Cp_button_average:%d (%d,%d)\n",
+				"Cp button average min/max test",
+				cp_button_average,
+				configuration->min_button,
+				configuration->max_button);
+			result->cp_button_average_pass = false;
+		}
+
+		/* Check each button Cp data for min/max values */
+		result->cp_button_validation_pass = true;
+		for (i = 0; i < cmcp_info->btn_num; i++) {
+			int32_t  cp_button_min =
+			configuration->cp_min_max_table_button[i * 2];
+			int32_t  cp_button_max =
+			configuration->cp_min_max_table_button[i * 2 + 1];
+			if ((cmcp_info->cp_btn_data[i] <= cp_button_min)
+			|| (cmcp_info->cp_btn_data[i] >= cp_button_max)) {
+				dev_err(dev,
+					"%s: Button[%d]:%d (%d,%d)\n",
+					"Cp button min/max test",
+					i,
+					cmcp_info->cp_btn_data[i],
+					cp_button_min, cp_button_max);
+				result->cp_button_validation_pass = false;
+			}
+		}
+
+		result->cp_test_pass = result->cp_test_pass
+				&& result->cp_button_delta_pass
+				&& result->cp_button_average_pass
+				&& result->cp_button_validation_pass;
+	}
+
+	if (pass)
+		*pass = result->cp_test_pass;
+
+	return 0;
+}
+
+static void calculate_gradient_row(struct gd_sensor *gd_sensor_row_head,
+		 uint16_t row_num, int exclude_row_edge, int exclude_col_edge)
+{
+	int i = 0;
+	uint16_t cm_min_cur = 0;
+	uint16_t cm_max_cur = 0;
+	uint16_t cm_ave_cur = 0;
+	uint16_t cm_ave_next = 0;
+	uint16_t cm_ave_prev = 0;
+	struct gd_sensor *p = gd_sensor_row_head;
+
+	if (exclude_row_edge) {
+		for (i = 0; i < row_num; i++) {
+			if (!exclude_col_edge) {
+				cm_ave_cur = (p + i)->cm_ave;
+				cm_min_cur = (p + i)->cm_min;
+				cm_max_cur = (p + i)->cm_max;
+				if (i < (row_num-1))
+					cm_ave_next = (p + i+1)->cm_ave;
+				if (i > 0)
+					cm_ave_prev = (p + i-1)->cm_ave;
+			} else {
+				cm_ave_cur = (p + i)->cm_ave_exclude_edge;
+				cm_min_cur = (p + i)->cm_min_exclude_edge;
+				cm_max_cur = (p + i)->cm_max_exclude_edge;
+				if (i < (row_num-1))
+					cm_ave_next =
+					(p + i+1)->cm_ave_exclude_edge;
+				if (i > 0)
+					cm_ave_prev =
+					(p + i-1)->cm_ave_exclude_edge;
+			}
+
+			if (cm_ave_cur == 0)
+				cm_ave_cur = 1;
+
+			/*multiple 1000 to increate accuracy*/
+			if ((i == 0) || (i == (row_num-1))) {
+				(p + i)->gradient_val =
+				(cm_max_cur - cm_min_cur) * 1000 /
+				cm_ave_cur;
+			} else if (i == 1) {
+				(p + i)->gradient_val = (cm_max_cur - cm_min_cur
+				+ ABS(cm_ave_cur - cm_ave_next)) * 1000 /
+				cm_ave_cur;
+			} else {
+				(p + i)->gradient_val = (cm_max_cur - cm_min_cur
+				+ ABS(cm_ave_cur - cm_ave_prev)) * 1000 /
+				cm_ave_cur;
+			}
+		}
+	} else if (!exclude_row_edge) {
+		for (i = 0; i < row_num; i++) {
+			if (!exclude_col_edge) {
+				cm_ave_cur = (p + i)->cm_ave;
+				cm_min_cur = (p + i)->cm_min;
+				cm_max_cur = (p + i)->cm_max;
+				if (i < (row_num-1))
+					cm_ave_next = (p + i+1)->cm_ave;
+				if (i > 0)
+					cm_ave_prev = (p + i-1)->cm_ave;
+			} else {
+				cm_ave_cur = (p + i)->cm_ave_exclude_edge;
+				cm_min_cur = (p + i)->cm_min_exclude_edge;
+				cm_max_cur = (p + i)->cm_max_exclude_edge;
+				if (i < (row_num-1))
+					cm_ave_next =
+					(p + i+1)->cm_ave_exclude_edge;
+				if (i > 0)
+					cm_ave_prev =
+					(p + i-1)->cm_ave_exclude_edge;
+			}
+
+			if (cm_ave_cur == 0)
+				cm_ave_cur = 1;
+			/*multiple 1000 to increate accuracy*/
+			if (i <= 1)
+				(p + i)->gradient_val = (cm_max_cur - cm_min_cur
+				+ ABS(cm_ave_cur - cm_ave_next)) * 1000 /
+				cm_ave_cur;
+			else
+				(p + i)->gradient_val = (cm_max_cur - cm_min_cur
+				+ ABS(cm_ave_cur - cm_ave_prev)) * 1000 /
+				cm_ave_cur;
+		}
+	}
+}
+
+static void calculate_gradient_col(struct gd_sensor *gd_sensor_row_head,
+	uint16_t col_num, int exclude_row_edge, int exclude_col_edge)
+{
+	int i = 0;
+	int32_t cm_min_cur = 0;
+	int32_t cm_max_cur = 0;
+	int32_t cm_ave_cur = 0;
+	int32_t cm_ave_next = 0;
+	int32_t cm_ave_prev = 0;
+	struct gd_sensor *p = gd_sensor_row_head;
+
+	if (!exclude_col_edge) {
+		for (i = 0; i < col_num; i++) {
+			if (!exclude_row_edge) {
+				cm_ave_cur = (p + i)->cm_ave;
+				cm_min_cur = (p + i)->cm_min;
+				cm_max_cur = (p + i)->cm_max;
+				if (i < (col_num-1))
+					cm_ave_next = (p + i+1)->cm_ave;
+				if (i > 0)
+					cm_ave_prev = (p + i-1)->cm_ave;
+			} else {
+				cm_ave_cur = (p + i)->cm_ave_exclude_edge;
+				cm_min_cur = (p + i)->cm_min_exclude_edge;
+				cm_max_cur = (p + i)->cm_max_exclude_edge;
+				if (i < (col_num-1))
+					cm_ave_next =
+					(p + i+1)->cm_ave_exclude_edge;
+				if (i > 0)
+					cm_ave_prev =
+					(p + i-1)->cm_ave_exclude_edge;
+			}
+			if (cm_ave_cur == 0)
+				cm_ave_cur = 1;
+			/*multiple 1000 to increate accuracy*/
+			if (i <= 1)
+				(p + i)->gradient_val = (cm_max_cur - cm_min_cur
+				+ ABS(cm_ave_cur - cm_ave_next)) * 1000 /
+				cm_ave_cur;
+			else
+				(p + i)->gradient_val = (cm_max_cur - cm_min_cur
+				+ ABS(cm_ave_cur - cm_ave_prev)) * 1000 /
+				cm_ave_cur;
+		}
+	} else if (exclude_col_edge) {
+		for (i = 0; i < col_num; i++) {
+			if (!exclude_row_edge) {
+				cm_ave_cur = (p + i)->cm_ave;
+				cm_min_cur = (p + i)->cm_min;
+				cm_max_cur = (p + i)->cm_max;
+				if (i < (col_num-1))
+					cm_ave_next = (p + i+1)->cm_ave;
+				if (i > 0)
+					cm_ave_prev = (p + i-1)->cm_ave;
+			} else {
+				cm_ave_cur = (p + i)->cm_ave_exclude_edge;
+				cm_min_cur = (p + i)->cm_min_exclude_edge;
+				cm_max_cur = (p + i)->cm_max_exclude_edge;
+				if (i < (col_num-1))
+					cm_ave_next =
+					(p + i+1)->cm_ave_exclude_edge;
+				if (i > 0)
+					cm_ave_prev =
+					(p + i-1)->cm_ave_exclude_edge;
+			}
+
+			if (cm_ave_cur == 0)
+				cm_ave_cur = 1;
+			/*multiple 1000 to increate accuracy*/
+			if ((i == 0) || (i == (col_num - 1)))
+				(p + i)->gradient_val =
+					 (cm_max_cur - cm_min_cur) * 1000 /
+					 cm_ave_cur;
+			else if (i == 1)
+				(p + i)->gradient_val =
+					(cm_max_cur - cm_min_cur +
+					ABS(cm_ave_cur - cm_ave_next))
+					 * 1000 / cm_ave_cur;
+			else
+				(p + i)->gradient_val =
+					(cm_max_cur - cm_min_cur +
+					ABS(cm_ave_cur - cm_ave_prev))
+					* 1000 / cm_ave_cur;
+			}
+	}
+}
+
+static void fill_gd_sensor_table(struct gd_sensor *head, int32_t index,
+	int32_t cm_max, int32_t cm_min,	int32_t cm_ave,
+	int32_t cm_max_exclude_edge, int32_t cm_min_exclude_edge,
+	int32_t cm_ave_exclude_edge)
+{
+	(head + index)->cm_max = cm_max;
+	(head + index)->cm_min = cm_min;
+	(head + index)->cm_ave = cm_ave;
+	(head + index)->cm_ave_exclude_edge = cm_ave_exclude_edge;
+	(head + index)->cm_max_exclude_edge = cm_max_exclude_edge;
+	(head + index)->cm_min_exclude_edge = cm_min_exclude_edge;
+}
+
+static void calculate_gd_info(struct gd_sensor *gd_sensor_col,
+	struct gd_sensor *gd_sensor_row, int tx_num, int rx_num,
+	int32_t *cm_sensor_data, int cm_excluding_row_edge,
+	int cm_excluding_col_edge)
+{
+	int32_t cm_max;
+	int32_t cm_min;
+	int32_t cm_ave;
+	int32_t cm_max_exclude_edge;
+	int32_t cm_min_exclude_edge;
+	int32_t cm_ave_exclude_edge;
+	int32_t cm_data;
+	int i;
+	int j;
+
+	/*calculate all the gradient related info for column*/
+	for (i = 0; i < tx_num; i++) {
+		/*re-initialize for a new col*/
+		cm_max = cm_sensor_data[i * rx_num];
+		cm_min = cm_max;
+		cm_ave = 0;
+		cm_max_exclude_edge = cm_sensor_data[i * rx_num + 1];
+		cm_min_exclude_edge = cm_max_exclude_edge;
+		cm_ave_exclude_edge = 0;
+
+		for (j = 0; j < rx_num; j++) {
+			cm_data = cm_sensor_data[i * rx_num + j];
+			if (cm_data > cm_max)
+				cm_max = cm_data;
+			if (cm_data < cm_min)
+				cm_min = cm_data;
+			cm_ave += cm_data;
+			/*calculate exclude edge data*/
+			if ((j > 0) && (j < (rx_num-1))) {
+				if (cm_data > cm_max_exclude_edge)
+					cm_max_exclude_edge = cm_data;
+				if (cm_data < cm_min_exclude_edge)
+					cm_min_exclude_edge = cm_data;
+				cm_ave_exclude_edge += cm_data;
+			}
+		}
+		cm_ave /= rx_num;
+		cm_ave_exclude_edge /= (rx_num-2);
+		fill_gd_sensor_table(gd_sensor_col, i, cm_max, cm_min, cm_ave,
+		cm_max_exclude_edge, cm_min_exclude_edge, cm_ave_exclude_edge);
+	}
+
+	calculate_gradient_col(gd_sensor_col, tx_num, cm_excluding_row_edge,
+		 cm_excluding_col_edge);
+
+	/*calculate all the gradient related info for row*/
+	for (j = 0; j < rx_num; j++) {
+		/*re-initialize for a new row*/
+		cm_max = cm_sensor_data[j];
+		cm_min = cm_max;
+		cm_ave = 0;
+		cm_max_exclude_edge = cm_sensor_data[rx_num + j];
+		cm_min_exclude_edge = cm_max_exclude_edge;
+		cm_ave_exclude_edge = 0;
+		for (i = 0; i < tx_num; i++) {
+			cm_data = cm_sensor_data[i * rx_num + j];
+			if (cm_data > cm_max)
+				cm_max = cm_data;
+			if (cm_data < cm_min)
+				cm_min = cm_data;
+			cm_ave += cm_data;
+			/*calculate exclude edge data*/
+			if ((i >  0) && (i < (tx_num-1))) {
+				if (cm_data > cm_max_exclude_edge)
+					cm_max_exclude_edge = cm_data;
+				if (cm_data < cm_min_exclude_edge)
+					cm_min_exclude_edge = cm_data;
+				cm_ave_exclude_edge += cm_data;
+			}
+		}
+		cm_ave /= tx_num;
+		cm_ave_exclude_edge /= (tx_num-2);
+		fill_gd_sensor_table(gd_sensor_row, j, cm_max, cm_min, cm_ave,
+		cm_max_exclude_edge, cm_min_exclude_edge, cm_ave_exclude_edge);
+	}
+	calculate_gradient_row(gd_sensor_row, rx_num, cm_excluding_row_edge,
+		 cm_excluding_col_edge);
+}
+
+static int  cyttsp5_get_cmcp_info(struct cyttsp5_device_access_data *dad,
+	struct cmcp_data *cmcp_info)
+{
+	struct device *dev;
+	int32_t *cm_data_panel = cmcp_info->cm_data_panel;
+	int32_t *cp_tx_data_panel = cmcp_info->cp_tx_data_panel;
+	int32_t *cp_rx_data_panel = cmcp_info->cp_rx_data_panel;
+	int32_t *cp_tx_cal_data_panel = cmcp_info->cp_tx_cal_data_panel;
+	int32_t *cp_rx_cal_data_panel = cmcp_info->cp_rx_cal_data_panel;
+	int32_t *cm_btn_data = cmcp_info->cm_btn_data;
+	int32_t *cp_btn_data = cmcp_info->cp_btn_data;
+	struct gd_sensor *gd_sensor_col = cmcp_info->gd_sensor_col;
+	struct gd_sensor *gd_sensor_row = cmcp_info->gd_sensor_row;
+	struct result *result = dad->result;
+	int32_t cp_btn_cal = 0;
+	int32_t cm_btn_cal = 0;
+	int32_t cp_btn_ave = 0;
+	int32_t cm_ave_data_panel = 0;
+	int32_t cm_ave_data_btn = 0;
+	int32_t cm_delta_data_btn = 0;
+	int32_t cp_tx_ave_data_panel = 0;
+	int32_t cp_rx_ave_data_panel = 0;
+	u8 tmp_buf[3];
+	int tx_num;
+	int rx_num;
+	int btn_num;
+	int rc = 0;
+	int i;
+
+	dev = dad->dev;
+	cmcp_info->tx_num = dad->si->sensing_conf_data.tx_num;
+	cmcp_info->rx_num = dad->si->sensing_conf_data.rx_num;
+	cmcp_info->btn_num = dad->si->num_btns;
+
+	tx_num = cmcp_info->tx_num;
+	rx_num = cmcp_info->rx_num;
+	btn_num = cmcp_info->btn_num;
+	parade_debug(dev, DEBUG_LEVEL_2, "%s tx_num=%d", __func__, tx_num);
+	parade_debug(dev, DEBUG_LEVEL_2, "%s rx_num=%d", __func__, rx_num);
+	parade_debug(dev, DEBUG_LEVEL_2, "%s btn_num=%d", __func__, btn_num);
+
+	/*short test*/
+	result->short_test_pass = true;
+	rc = cyttsp5_run_and_get_selftest_result_noprint(
+		dev, tmp_buf, sizeof(tmp_buf),
+		CY_ST_ID_AUTOSHORTS, PIP_CMD_MAX_LENGTH, false);
+	if (rc) {
+		dev_err(dev, "short test not supported");
+		goto exit;
+	}
+	if (dad->ic_buf[1] != 0)
+		result->short_test_pass = false;
+
+	/*Get cm_panel data*/
+	rc = cyttsp5_run_and_get_selftest_result_noprint(
+		dev, tmp_buf, sizeof(tmp_buf),
+		CY_ST_ID_CM_PANEL, PIP_CMD_MAX_LENGTH, true);
+	if (rc) {
+		dev_err(dev, "Get CM Panel not supported");
+		goto exit;
+	}
+	if (cm_data_panel != NULL) {
+		for (i = 0; i < tx_num * rx_num;  i++) {
+			cm_data_panel[i] =
+			10*(dad->ic_buf[CM_PANEL_DATA_OFFSET+i*2] + 256
+			* dad->ic_buf[CM_PANEL_DATA_OFFSET+i*2+1]);
+			parade_debug(dev, DEBUG_LEVEL_2,
+				"cm_data_panel[%d]=%d\n",
+				i, cm_data_panel[i]);
+			cm_ave_data_panel += cm_data_panel[i];
+		}
+		cm_ave_data_panel /= (tx_num * rx_num);
+		cmcp_info->cm_ave_data_panel = cm_ave_data_panel;
+		cmcp_info->cm_cal_data_panel =
+		10*(dad->ic_buf[CM_PANEL_DATA_OFFSET+i*2]
+		+256 * dad->ic_buf[CM_PANEL_DATA_OFFSET+i*2+1]);
+		/*multiple 1000 to increate accuracy*/
+		cmcp_info->cm_sensor_delta = ABS((cmcp_info->cm_ave_data_panel -
+			cmcp_info->cm_cal_data_panel) * 1000 /
+			cmcp_info->cm_ave_data_panel);
+	}
+
+	/*calculate gradient panel sensor column/row here*/
+	calculate_gd_info(gd_sensor_col, gd_sensor_row, tx_num, rx_num,
+		 cm_data_panel, 1, 1);
+	for (i = 0; i < tx_num; i++) {
+		parade_debug(dev, DEBUG_LEVEL_2,
+			"i=%d max=%d,min=%d,ave=%d, gradient=%d",
+			i, gd_sensor_col[i].cm_max, gd_sensor_col[i].cm_min,
+			gd_sensor_col[i].cm_ave, gd_sensor_col[i].gradient_val);
+	}
+
+	for (i = 0; i < rx_num; i++) {
+		parade_debug(dev, DEBUG_LEVEL_2,
+			"i=%d max=%d,min=%d,ave=%d, gradient=%d",
+			i, gd_sensor_row[i].cm_max, gd_sensor_row[i].cm_min,
+			gd_sensor_row[i].cm_ave, gd_sensor_row[i].gradient_val);
+	}
+
+	/*Get cp data*/
+	rc = cyttsp5_run_and_get_selftest_result_noprint(
+		dev, tmp_buf, sizeof(tmp_buf),
+		CY_ST_ID_CP_PANEL, PIP_CMD_MAX_LENGTH, true);
+	if (rc) {
+		dev_err(dev, "Get CP Panel not supported");
+		goto exit;
+	}
+	/*Get cp_tx_data_panel*/
+	if (cp_tx_data_panel != NULL) {
+		for (i = 0; i < tx_num; i++) {
+			cp_tx_data_panel[i] =
+			10*(dad->ic_buf[CP_PANEL_DATA_OFFSET+i*2]
+			+ 256 * dad->ic_buf[CP_PANEL_DATA_OFFSET+i*2+1]);
+			parade_debug(dev, DEBUG_LEVEL_2,
+				"cp_tx_data_panel[%d]=%d\n",
+				i, cp_tx_data_panel[i]);
+			cp_tx_ave_data_panel += cp_tx_data_panel[i];
+		}
+		cp_tx_ave_data_panel /= tx_num;
+		cmcp_info->cp_tx_ave_data_panel = cp_tx_ave_data_panel;
+	}
+
+	/*Get cp_tx_cal_data_panel*/
+	if (cp_tx_cal_data_panel != NULL) {
+		for (i = 0; i < tx_num; i++) {
+			cp_tx_cal_data_panel[i] =
+			10*(dad->ic_buf[CP_PANEL_DATA_OFFSET+tx_num*2+i*2]
+		+ 256 * dad->ic_buf[CP_PANEL_DATA_OFFSET+tx_num*2+i*2+1]);
+			parade_debug(dev, DEBUG_LEVEL_2, " cp_tx_cal_data_panel[%d]=%d\n",
+				i, cp_tx_cal_data_panel[i]);
+		}
+	}
+
+	/*get cp_sensor_tx_delta,using the first sensor cal value for temp */
+	/*multiple 1000 to increase accuracy*/
+	cmcp_info->cp_sensor_tx_delta = ABS((cp_tx_cal_data_panel[0]
+		- cp_tx_ave_data_panel) * 1000 / cp_tx_ave_data_panel);
+
+	/*Get cp_rx_data_panel*/
+	if (cp_rx_data_panel != NULL) {
+		for (i = 0; i < rx_num;  i++) {
+			cp_rx_data_panel[i] =
+			10*(dad->ic_buf[CP_PANEL_DATA_OFFSET+tx_num*4+i*2] +
+			256 * dad->ic_buf[CP_PANEL_DATA_OFFSET+tx_num*4+i*2+1]);
+			parade_debug(dev, DEBUG_LEVEL_2,
+				"cp_rx_data_panel[%d]=%d\n", i,
+				cp_rx_data_panel[i]);
+			cp_rx_ave_data_panel += cp_rx_data_panel[i];
+		}
+		cp_rx_ave_data_panel /= rx_num;
+		cmcp_info->cp_rx_ave_data_panel = cp_rx_ave_data_panel;
+	}
+
+	/*Get cp_rx_cal_data_panel*/
+	if (cp_rx_cal_data_panel != NULL) {
+		for (i = 0; i < rx_num; i++) {
+			cp_rx_cal_data_panel[i] =
+		10 * (dad->ic_buf[CP_PANEL_DATA_OFFSET+tx_num*4+rx_num*2+i*2] +
+		256 *
+		dad->ic_buf[CP_PANEL_DATA_OFFSET+tx_num*4+rx_num*2+i*2+1]);
+			parade_debug(dev, DEBUG_LEVEL_2,
+				"cp_rx_cal_data_panel[%d]=%d\n", i,
+				cp_rx_cal_data_panel[i]);
+		}
+	}
+
+	/*get cp_sensor_rx_delta,using the first sensor cal value for temp */
+	/*multiple 1000 to increase accuracy*/
+	cmcp_info->cp_sensor_rx_delta = ABS((cp_rx_cal_data_panel[0]
+		- cp_rx_ave_data_panel) * 1000 / cp_rx_ave_data_panel);
+
+	if (btn_num == 0)
+		goto skip_button_test;
+
+	/*get cm btn data*/
+	rc = cyttsp5_run_and_get_selftest_result_noprint(
+		dev, tmp_buf, sizeof(tmp_buf),
+		CY_ST_ID_CM_BUTTON, PIP_CMD_MAX_LENGTH, true);
+	if (rc) {
+		dev_err(dev, "Get CM BTN not supported");
+		goto exit;
+	}
+	if (cm_btn_data != NULL) {
+		for (i = 0; i < btn_num; i++) {
+			cm_btn_data[i] =
+			10 * (dad->ic_buf[CM_BTN_DATA_OFFSET+i*2] +
+			256 * dad->ic_buf[CM_BTN_DATA_OFFSET+i*2+1]);
+			parade_debug(dev, DEBUG_LEVEL_2,
+				" cm_btn_data[%d]=%d\n",
+				i, cm_btn_data[i]);
+			cm_ave_data_btn += cm_btn_data[i];
+		}
+		cm_ave_data_btn /= btn_num;
+		cm_btn_cal = 10*(dad->ic_buf[CM_BTN_DATA_OFFSET+i*2]
+			 + 256 * dad->ic_buf[CM_BTN_DATA_OFFSET+i*2+1]);
+		/*multiple 1000 to increase accuracy*/
+		cm_delta_data_btn = ABS((cm_ave_data_btn-cm_btn_cal)
+			 * 1000 / cm_ave_data_btn);
+		parade_debug(dev, DEBUG_LEVEL_2, " cm_btn_cal=%d\n",
+			cm_btn_cal);
+
+		cmcp_info->cm_ave_data_btn = cm_ave_data_btn;
+		cmcp_info->cm_cal_data_btn = cm_btn_cal;
+		cmcp_info->cm_delta_data_btn = cm_delta_data_btn;
+	}
+
+	/*get cp btn data*/
+	rc = cyttsp5_run_and_get_selftest_result_noprint(
+		dev, tmp_buf, sizeof(tmp_buf),
+		CY_ST_ID_CP_BUTTON, PIP_CMD_MAX_LENGTH, true);
+	if (rc) {
+		dev_err(dev, "Get CP BTN not supported");
+		goto exit;
+	}
+	if (cp_btn_data != NULL) {
+		for (i = 0; i < btn_num; i++) {
+			cp_btn_data[i] =
+			10 * (dad->ic_buf[CP_BTN_DATA_OFFSET+i*2] +
+			256 * dad->ic_buf[CP_BTN_DATA_OFFSET+i*2+1]);
+			cp_btn_ave += cp_btn_data[i];
+			parade_debug(dev, DEBUG_LEVEL_2,
+				"cp_btn_data[%d]=%d\n",
+				i, cp_btn_data[i]);
+		}
+		cp_btn_ave /= btn_num;
+		cp_btn_cal = 10*(dad->ic_buf[CP_BTN_DATA_OFFSET+i*2]
+			 + 256 * dad->ic_buf[CP_BTN_DATA_OFFSET+i*2+1]);
+		cmcp_info->cp_button_ave = cp_btn_ave;
+		cmcp_info->cp_btn_cal = cp_btn_cal;
+		/*multiple 1000 to increase accuracy*/
+		cmcp_info->cp_button_delta = ABS((cp_btn_cal
+		- cp_btn_ave) * 1000 / cp_btn_ave);
+		parade_debug(dev, DEBUG_LEVEL_2, " cp_btn_cal=%d\n",
+			cp_btn_cal);
+		parade_debug(dev, DEBUG_LEVEL_2, " cp_btn_ave=%d\n",
+			cp_btn_ave);
+	}
+skip_button_test:
+exit:
+	return rc;
+}
+
+static void cyttsp5_free_cmcp_buf(struct cmcp_data *cmcp_info)
+{
+	if (cmcp_info->gd_sensor_col != NULL)
+		kfree(cmcp_info->gd_sensor_col);
+	if (cmcp_info->gd_sensor_row != NULL)
+		kfree(cmcp_info->gd_sensor_row);
+	if (cmcp_info->cm_data_panel != NULL)
+		kfree(cmcp_info->cm_data_panel);
+	if (cmcp_info->cp_tx_data_panel != NULL)
+		kfree(cmcp_info->cp_tx_data_panel);
+	if (cmcp_info->cp_rx_data_panel != NULL)
+		kfree(cmcp_info->cp_rx_data_panel);
+	if (cmcp_info->cp_tx_cal_data_panel != NULL)
+		kfree(cmcp_info->cp_tx_cal_data_panel);
+	if (cmcp_info->cp_rx_cal_data_panel != NULL)
+		kfree(cmcp_info->cp_rx_cal_data_panel);
+	if (cmcp_info->cm_btn_data != NULL)
+		kfree(cmcp_info->cm_btn_data);
+	if (cmcp_info->cp_btn_data != NULL)
+		kfree(cmcp_info->cp_btn_data);
+	if (cmcp_info->cm_sensor_column_delta != NULL)
+		kfree(cmcp_info->cm_sensor_column_delta);
+	if (cmcp_info->cm_sensor_row_delta != NULL)
+		kfree(cmcp_info->cm_sensor_row_delta);
+}
+
+static int cyttsp5_cmcp_get_test_item(int item_input)
+{
+	int test_item = 0;
+
+	switch (item_input) {
+	case CMCP_FULL:
+		test_item = CMCP_FULL_CASE;
+		break;
+	case CMCP_CM_PANEL:
+		test_item = CM_PANEL;
+		break;
+	case CMCP_CP_PANEL:
+		test_item = CP_PANEL;
+		break;
+	case CMCP_CM_BTN:
+		test_item = CM_BTN;
+		break;
+	case CMCP_CP_BTN:
+		test_item = CP_BTN;
+		break;
+	}
+	return test_item;
+}
+
+static ssize_t cyttsp5_cmcp_test_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	struct cmcp_data *cmcp_info = dad->cmcp_info;
+	struct result *result = dad->result;
+	struct configuration *configuration = dad->configs;
+	bool final_pass = true;
+	static const char * const cmcp_test_case_array[] = {"Full Cm/Cp test",
+		"Cm panel test", "Cp panel test",
+		"Cm button test", "Cp button test"};
+	int index = 0;
+	int test_item = 0;
+	int no_builtin_file = 0;
+	int rc;
+	u8 status;
+	int self_test_id_supported = 0;
+
+	dev = dad->dev;
+	if ((configuration == NULL) || (cmcp_info == NULL))
+		goto exit;
+
+	mutex_lock(&dad->sysfs_lock);
+
+	if (dad->cmcp_test_in_progress) {
+		mutex_unlock(&dad->sysfs_lock);
+		goto cmcp_not_ready;
+	}
+	dad->cmcp_test_in_progress = 1;
+
+	dad->test_executed = 0;
+	test_item = cyttsp5_cmcp_get_test_item(dad->cmcp_test_items);
+
+	if (dad->builtin_cmcp_threshold_status < 0) {
+		dev_err(dev, "%s: No cmcp threshold file.\n", __func__);
+		no_builtin_file = 1;
+		mutex_unlock(&dad->sysfs_lock);
+		goto start_testing;
+	}
+
+	if (dad->cmcp_test_items < 0) {
+		parade_debug(dev, DEBUG_LEVEL_2,
+			"%s: Invalid test item! Should be 0~4!\n", __func__);
+		mutex_unlock(&dad->sysfs_lock);
+		goto invalid_item;
+	}
+
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: Test item is %s, %d\n",
+		__func__, cmcp_test_case_array[dad->cmcp_test_items],
+		test_item);
+
+	if ((dad->si->num_btns == 0)
+		&& ((dad->cmcp_test_items == CMCP_CM_BTN)
+			|| (dad->cmcp_test_items == CMCP_CP_BTN))) {
+		parade_debug(dev, DEBUG_LEVEL_2,
+			"%s: FW doesn't support button!\n", __func__);
+		mutex_unlock(&dad->sysfs_lock);
+		goto invalid_item_btn;
+	}
+
+	mutex_unlock(&dad->sysfs_lock);
+
+	if (cmcp_check_config_fw_match(dev, configuration))
+		goto mismatch;
+
+start_testing:
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: Start Cm/Cp test!\n", __func__);
+	result->cm_test_pass = true;
+	result->cp_test_pass = true;
+	/*stop watchdog*/
+	rc = cmd->request_stop_wd(dev);
+	if (rc)
+		dev_err(dev, "stop watchdog failed");
+	/*force single tx*/
+	rc = cmd->nonhid_cmd->set_param(dev, 0, 0x1F, 1, 1);
+	if (rc)
+		dev_err(dev, "force single tx failed");
+	/*suspend_scanning */
+	rc = cmd->nonhid_cmd->suspend_scanning(dev, 0);
+	if (rc)
+		dev_err(dev, "suspend_scanning failed");
+	/*do calibration*/
+	if (!dad->cmcp_force_calibrate) {
+		parade_debug(dev, DEBUG_LEVEL_2, "do calibration in single tx mode");
+		rc = _cyttsp5_calibrate_idacs_cmd(dev, 0, &status);
+		if (rc < 0) {
+			dev_err(dev, "%s: Error on calibrate idacs for mutual r=%d\n",
+					__func__, rc);
+		}
+		rc = _cyttsp5_calibrate_idacs_cmd(dev, 1, &status);
+		if (rc < 0) {
+			dev_err(dev, "%s: Error on calibrate idacs for buttons r=%d\n",
+					__func__, rc);
+		}
+		rc = _cyttsp5_calibrate_idacs_cmd(dev, 2, &status);
+		if (rc < 0) {
+			dev_err(dev, "%s: Error on calibrate idacs  for self r=%d\n",
+					__func__, rc);
+		}
+	}
+	/*resume_scanning */
+	rc = cmd->nonhid_cmd->resume_scanning(dev, 0);
+	if (rc)
+		dev_err(dev, "resume_scanning failed");
+
+	/*get all cmcp data from FW*/
+	self_test_id_supported =
+		cyttsp5_get_cmcp_info(dad, cmcp_info);
+	if (self_test_id_supported)
+		dev_err(dev, "cyttsp5_get_cmcp_info failed");
+
+	/*restore to multi tx*/
+	rc = cmd->nonhid_cmd->set_param(dev, 0, 0x1F, 0, 1);
+	if (rc)
+		dev_err(dev, "restore multi tx failed");
+
+	/*suspend_scanning */
+	rc = cmd->nonhid_cmd->suspend_scanning(dev, 0);
+	if (rc)
+		dev_err(dev, "suspend_scanning failed");
+	/*do calibration*/
+	if (!dad->cmcp_force_calibrate) {
+		parade_debug(dev, DEBUG_LEVEL_2, "do calibration in multi tx mode");
+		rc = _cyttsp5_calibrate_idacs_cmd(dev, 0, &status);
+		if (rc < 0) {
+			dev_err(dev, "%s: Error on calibrate idacs for mutual r=%d\n",
+					__func__, rc);
+		}
+		rc = _cyttsp5_calibrate_idacs_cmd(dev, 1, &status);
+		if (rc < 0) {
+			dev_err(dev, "%s: Error on calibrate idacs for buttons r=%d\n",
+					__func__, rc);
+		}
+		rc = _cyttsp5_calibrate_idacs_cmd(dev, 2, &status);
+		if (rc < 0) {
+			dev_err(dev, "%s: Error on calibrate idacs  for self r=%d\n",
+					__func__, rc);
+		}
+
+	}
+	/*resume_scanning */
+	rc = cmd->nonhid_cmd->resume_scanning(dev, 0);
+	if (rc)
+		dev_err(dev, "resume_scanning failed");
+
+	/*start  watchdog*/
+	rc = cmd->request_start_wd(dev);
+	if (rc)
+		dev_err(dev, "start watchdog failed");
+
+	if (self_test_id_supported)
+		goto self_test_id_failed;
+
+	if (no_builtin_file)
+		goto no_builtin;
+
+	if (test_item && CM_ENABLED)
+		validate_cm_test_results(dev, configuration, cmcp_info,
+		result, &final_pass, test_item);
+
+	if (test_item && CP_ENABLED)
+		validate_cp_test_results(dev, configuration, cmcp_info,
+		result, &final_pass, test_item);
+no_builtin:
+	if ((dad->cmcp_test_items == CMCP_FULL)
+	&& (dad->cmcp_range_check == 0)) {
+		/*full test and full check*/
+		result->test_summary =
+			result->cm_test_pass
+			&& result->cp_test_pass
+			&& result->short_test_pass;
+	} else if ((dad->cmcp_test_items == CMCP_FULL)
+		&& (dad->cmcp_range_check == 1)) {
+		/*full test and basic check*/
+		result->test_summary =
+			result->cm_sensor_gd_col_pass
+			&& result->cm_sensor_gd_row_pass
+			&& result->cm_sensor_validation_pass
+			&& result->cp_rx_validation_pass
+			&& result->cp_tx_validation_pass
+			&& result->short_test_pass;
+	} else if (dad->cmcp_test_items == CMCP_CM_PANEL) {
+		/*cm panel test result only*/
+		result->test_summary =
+			result->cm_sensor_gd_col_pass
+			&& result->cm_sensor_gd_row_pass
+			&& result->cm_sensor_validation_pass
+			&& result->cm_sensor_row_delta_pass
+			&& result->cm_sensor_col_delta_pass
+			&& result->cm_sensor_calibration_pass
+			&& result->cm_sensor_delta_pass;
+	} else if (dad->cmcp_test_items == CMCP_CP_PANEL) {
+		/*cp panel test result only*/
+		result->test_summary =
+			result->cp_sensor_delta_pass
+			&& result->cp_rx_validation_pass
+			&& result->cp_tx_validation_pass;
+	} else if (dad->cmcp_test_items == CMCP_CM_BTN) {
+		/*cm button test result only*/
+		result->test_summary =
+			result->cm_button_validation_pass
+			&& result->cm_button_delta_pass;
+	} else if (dad->cmcp_test_items == CMCP_CP_BTN) {
+		/*cp button test result only*/
+		result->test_summary =
+			result->cp_button_delta_pass
+			&& result->cp_button_average_pass
+			&& result->cp_button_validation_pass;
+	}
+	mutex_lock(&dad->sysfs_lock);
+	dad->test_executed = 1;
+	mutex_unlock(&dad->sysfs_lock);
+
+	if (result->test_summary) {
+		dev_vdbg(dev, "%s: Finish Cm/Cp test! All Test Passed\n",
+				__func__);
+		index = snprintf(buf, CY_MAX_PRBUF_SIZE,
+				"Status 1\n");
+	} else {
+		dev_vdbg(dev, "%s: Finish Cm/Cp test! Range Check Failure\n",
+				__func__);
+		index = snprintf(buf, CY_MAX_PRBUF_SIZE,
+				"Status 6\n");
+	}
+
+	goto cmcp_ready;
+mismatch:
+	index = snprintf(buf, CY_MAX_PRBUF_SIZE,
+		 "Status 2\nInput cmcp threshold file mismatches with FW\n");
+	goto cmcp_ready;
+invalid_item_btn:
+	index = snprintf(buf, CY_MAX_PRBUF_SIZE,
+		"Status 3\nFW doesn't support button!\n");
+	goto cmcp_ready;
+invalid_item:
+	index = snprintf(buf, CY_MAX_PRBUF_SIZE,
+		"Status 4\nWrong test item or range check input!\nOnly support below items:\n0 - Cm/Cp Panel & Button with Gradient (Typical)\n1 - Cm Panel with Gradient\n2 - Cp Panel\n3 - Cm Button\n4 - Cp Button\nOnly support below range check:\n0 - Full Range Checking (default)\n1 - Basic Range Checking(TSG5 style)\n");
+	goto cmcp_ready;
+self_test_id_failed:
+	index = snprintf(buf, CY_MAX_PRBUF_SIZE,
+		"Status 5\nget self test ID not supported!");
+	goto cmcp_ready;
+cmcp_not_ready:
+	index = snprintf(buf, CY_MAX_PRBUF_SIZE,
+			"Status 0\n");
+	goto cmcp_ready;
+cmcp_ready:
+	mutex_lock(&dad->sysfs_lock);
+	dad->cmcp_test_in_progress = 0;
+	mutex_unlock(&dad->sysfs_lock);
+exit:
+	return index;
+}
+
+static ssize_t cyttsp5_cmcp_test_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	u8 test_item = 0;
+	u8 range_check = 0;
+	u8 force_calibrate = 0;
+	int ret;
+	static const char * const cmcp_test_case_array[] = {"Full Cm/Cp test",
+		"Cm panel test", "Cp panel test",
+		"Cm button test", "Cp button test"};
+	static const char * const cmcp_test_range_check_array[] = {
+		"Full (default)", "Basic"};
+	static const char * const cmcp_test_force_cal_array[] =	{
+		"Calibrate When Testing (default)", "No Calibration"};
+	ssize_t length = 0;
+
+	pm_runtime_get_sync(dev);
+	mutex_lock(&dad->sysfs_lock);
+
+	length = cyttsp5_ic_parse_input(dev, buf, size, dad->ic_buf,
+			CY_MAX_PRBUF_SIZE);
+	if (length <= 0 || length > 3) {
+		dev_err(dev, "%s: Input format error!\n", __func__);
+		dad->cmcp_test_items = -EINVAL;
+		ret = -EINVAL;
+		goto error;
+	}
+
+	/* Get test item  */
+	test_item = dad->ic_buf[0];
+	/* Get range check */
+	if (length >= 2)
+		range_check = dad->ic_buf[1];
+	/* Get force calibration */
+	if (length == 3)
+		force_calibrate = dad->ic_buf[2];
+
+	/*
+	 * Test item limitation:
+	 *	 0: Perform all Tests
+	 *	 1: CM Panel with Gradient
+	 *	 2: CP Panel
+	 *	 3: CM Button
+	 *	 4: CP Button
+	 * Ranage check limitation:
+	 *	 0: full check
+	 *	 1: basic check
+	 * Force calibrate limitation:
+	 *	 0: do calibration
+	 *	 1: don't do calibration
+	 */
+	if ((test_item < 0) || (test_item > 4) || (range_check > 1)
+		|| (force_calibrate > 1)) {
+		dev_err(dev,
+		"%s: Test item should be 0~4; Range check should be 0~1; Force calibrate should be 0~1\n",
+		__func__);
+		dad->cmcp_test_items = -EINVAL;
+		ret = -EINVAL;
+		goto error;
+	}
+	/*
+	 * If it is not all Test, then range_check should be 0
+	 * because other test does not has concept of basic check
+	 */
+	if (test_item > 0 && test_item < 5)
+		range_check = 0;
+		dad->cmcp_test_items = test_item;
+		dad->cmcp_range_check = range_check;
+		dad->cmcp_force_calibrate = force_calibrate;
+		parade_debug(dev, DEBUG_LEVEL_2,
+			"%s: Test item is %s; Range check is %s; Force calibrate is %s.\n",
+			__func__,
+			cmcp_test_case_array[test_item],
+			cmcp_test_range_check_array[range_check],
+			cmcp_test_force_cal_array[force_calibrate]);
+
+error:
+	mutex_unlock(&dad->sysfs_lock);
+	pm_runtime_put(dev);
+
+	if (ret)
+		return ret;
+
+	return size;
+}
+
+static DEVICE_ATTR(cmcp_test, S_IRUSR | S_IWUSR,
+	cyttsp5_cmcp_test_show, cyttsp5_cmcp_test_store);
+
+int prepare_print_string(char *out_buf, char *in_buf, int index)
+{
+	if ((out_buf == NULL) || (in_buf == NULL))
+		return index;
+	index += scnprintf(&out_buf[index], MAX_BUF_LEN - index,
+			"%s", in_buf);
+	return index;
+}
+
+int prepare_print_data(char *out_buf, int32_t *in_buf, int index, int data_num)
+{
+	int i;
+
+	if ((out_buf == NULL) || (in_buf == NULL))
+		return index;
+	for (i = 0; i < data_num; i++)
+		index += scnprintf(&out_buf[index], MAX_BUF_LEN - index,
+				"%d,", in_buf[i]);
+	return index;
+}
+
+int save_header(char *out_buf, int index, struct result *result)
+{
+	struct timex txc;
+	struct rtc_time tm;
+	char time_buf[100] = {0};
+
+	do_gettimeofday(&(txc.time));
+	rtc_time_to_tm(txc.time.tv_sec, &tm);
+	scnprintf(time_buf, 100, "%d/%d/%d,TIME,%d:%d:%d,", tm.tm_year+1900,
+		 tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+	index = prepare_print_string(out_buf, ",.header,\n", index);
+	index = prepare_print_string(out_buf, ",DATE,", index);
+	index = prepare_print_string(out_buf, &time_buf[0], index);
+	index = prepare_print_string(out_buf, ",\n", index);
+	index = prepare_print_string(out_buf, ",SW_VERSION,", index);
+	index = prepare_print_string(out_buf, CY_DRIVER_VERSION, index);
+	index = prepare_print_string(out_buf, ",\n", index);
+	index = prepare_print_string(out_buf, ",.end,\n", index);
+	index = prepare_print_string(out_buf, ",.engineering data,\n", index);
+
+	return index;
+}
+
+static int print_silicon_id(char *out_buf, char *in_buf, int index)
+{
+	index = prepare_print_string(out_buf, ",1,", index);
+	index = prepare_print_string(out_buf, &in_buf[0], index);
+	return index;
+}
+
+int save_engineering_data(struct device *dev, char *out_buf, int index,
+	struct cmcp_data *cmcp_info, struct configuration *configuration,
+	struct result *result, int test_item, int no_builtin_file)
+{
+	int i;
+	int j;
+	int tx_num = cmcp_info->tx_num;
+	int rx_num = cmcp_info->rx_num;
+	int btn_num = cmcp_info->btn_num;
+	int tmp = 0;
+	uint32_t fw_revision_control;
+	uint32_t fw_config_ver;
+	char device_id[20] = {0};
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+
+	fw_revision_control = dad->si->cydata.revctrl;
+	fw_config_ver = dad->si->cydata.fw_ver_conf;
+	/*calculate silicon id*/
+	result->device_id_low = 0;
+	result->device_id_high = 0;
+
+	for (i = 0; i < 4; i++)
+		result->device_id_low =
+		(result->device_id_low << 8) + dad->si->cydata.mfg_id[i];
+
+	for (i = 4; i < 8; i++)
+		result->device_id_high =
+		(result->device_id_high << 8) + dad->si->cydata.mfg_id[i];
+
+	scnprintf(device_id, 20, "%x%x",
+		result->device_id_high, result->device_id_low);
+
+	/*print test summary*/
+	index = print_silicon_id(out_buf, &device_id[0], index);
+	if (result->test_summary)
+		index = prepare_print_string(out_buf, ",PASS,\n", index);
+	else
+		index = prepare_print_string(out_buf, ",FAIL,\n", index);
+
+	/*revision ctrl number*/
+	index = print_silicon_id(out_buf, &device_id[0], index);
+	index = prepare_print_string(out_buf, ",FW revision Control,", index);
+	index = prepare_print_data(out_buf, &fw_revision_control, index, 1);
+	index = prepare_print_string(out_buf, "\n", index);
+
+	/*config version*/
+	index = print_silicon_id(out_buf, &device_id[0], index);
+	index = prepare_print_string(out_buf, ",CONFIG_VER,", index);
+	index = prepare_print_data(out_buf, &fw_config_ver, index, 1);
+	index = prepare_print_string(out_buf, "\n", index);
+
+	/*short test*/
+	index = print_silicon_id(out_buf, &device_id[0], index);
+	if (result->short_test_pass)
+		index = prepare_print_string(out_buf, ",Shorts,PASS,\n", index);
+	else
+		index = prepare_print_string(out_buf, ",Shorts,FAIL,\n", index);
+
+	if ((test_item & CM_ENABLED) == CM_ENABLED) {
+		/*print BUTNS_CM_DATA_ROW00*/
+		if (((test_item & CM_BTN) == CM_BTN) && (btn_num > 0)) {
+			index = print_silicon_id(out_buf, &device_id[0], index);
+			index = prepare_print_string(out_buf,
+				",Sensor Cm Validation,BUTNS_CM_DATA_ROW00,",
+				index);
+			index = prepare_print_data(out_buf,
+				&cmcp_info->cm_btn_data[0],
+				index,
+				btn_num);
+			index = prepare_print_string(out_buf, "\n", index);
+		}
+
+		if ((test_item & CM_PANEL) == CM_PANEL) {
+			/*print CM_DATA_ROW*/
+			for (i = 0; i < rx_num; i++) {
+				index = print_silicon_id(out_buf, &device_id[0],
+							index);
+				index = prepare_print_string(out_buf,
+							",Sensor Cm Validation,CM_DATA_ROW",
+							index);
+				index = prepare_print_data(out_buf, &i,
+							index, 1);
+				for (j = 0; j < tx_num; j++)
+					index = prepare_print_data(out_buf,
+					&cmcp_info->cm_data_panel[j*rx_num+i],
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+			}
+
+			if (!no_builtin_file) {
+				/*print CM_MAX_GRADIENT_COLS_PERCENT*/
+				index = print_silicon_id(out_buf,
+							&device_id[0], index);
+				index = prepare_print_string(out_buf,
+					 ",Sensor Cm Validation,CM_MAX_GRADIENT_COLS_PERCENT,",
+					index);
+				for (i = 0; i < tx_num; i++) {
+					char tmp_buf[10] = {0};
+
+					scnprintf(tmp_buf, 10, "%d.%d,",
+				cmcp_info->gd_sensor_col[i].gradient_val / 10,
+				cmcp_info->gd_sensor_col[i].gradient_val % 10);
+					index = prepare_print_string(out_buf,
+						&tmp_buf[0], index);
+				}
+				index = prepare_print_string(out_buf,
+								"\n", index);
+
+				/*print CM_MAX_GRADIENT_ROWS_PERCENT*/
+				index = print_silicon_id(out_buf,
+							&device_id[0], index);
+				index = prepare_print_string(out_buf,
+			",Sensor Cm Validation,CM_MAX_GRADIENT_ROWS_PERCENT,",
+					index);
+				for (i = 0; i < rx_num; i++) {
+					char tmp_buf[10] = {0};
+
+					scnprintf(tmp_buf, 10, "%d.%d,",
+				cmcp_info->gd_sensor_row[i].gradient_val / 10,
+				cmcp_info->gd_sensor_row[i].gradient_val % 10);
+					index = prepare_print_string(out_buf,
+						&tmp_buf[0], index);
+				}
+				index = prepare_print_string(out_buf,
+								"\n", index);
+
+				if (!dad->cmcp_range_check) {
+					/*print CM_DELTA_COLUMN*/
+					for (i = 0; i < rx_num; i++) {
+						index = print_silicon_id(
+							out_buf,
+							&device_id[0], index);
+						index = prepare_print_string(
+							out_buf,
+							",Sensor Cm Validation,DELTA_COLUMNS_ROW",
+							index);
+						index = prepare_print_data(
+							out_buf,
+							&i, index, 1);
+						index = prepare_print_data(
+							out_buf,
+							&tmp, index, 1);
+					for (j = 1; j < tx_num; j++)
+						index = prepare_print_data(
+						out_buf,
+			&cmcp_info->cm_sensor_column_delta[(j-1)*rx_num+i],
+						index, 1);
+						index = prepare_print_string(
+								out_buf,
+								"\n", index);
+					}
+
+					/*print CM_DELTA_ROW*/
+					index = print_silicon_id(out_buf,
+								&device_id[0],
+								index);
+					index = prepare_print_string(out_buf,
+						 ",Sensor Cm Validation,DELTA_ROWS_ROW",
+								index);
+					index = prepare_print_data(out_buf,
+								&tmp, index, 1);
+					for (j = 0; j < tx_num; j++)
+						index = prepare_print_data(
+								out_buf,
+								&tmp, index, 1);
+					index = prepare_print_string(out_buf,
+								"\n", index);
+
+					for (i = 1; i < rx_num; i++) {
+						index = print_silicon_id(
+								out_buf,
+								&device_id[0],
+								index);
+						index = prepare_print_string(
+								out_buf,
+						",Sensor Cm Validation,DELTA_ROWS_ROW",
+								index);
+						index = prepare_print_data(
+								out_buf, &i,
+								index, 1);
+					for (j = 0; j < tx_num; j++)
+						index = prepare_print_data(
+							out_buf,
+				&cmcp_info->cm_sensor_row_delta[j*rx_num+i-1],
+							index, 1);
+						index = prepare_print_string(
+							out_buf,
+							"\n", index);
+					}
+
+				/*print pass/fail Sensor Cm Validation*/
+				index = print_silicon_id(out_buf, &device_id[0],
+							index);
+				if (result->cm_test_pass)
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation,PASS,\n",
+						index);
+				else
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation,FAIL,\n",
+						index);
+			}
+			}
+		}
+
+		if (!no_builtin_file) {
+			if (((test_item & CM_BTN) == CM_BTN) && (btn_num > 0)
+				&& (!dad->cmcp_range_check)) {
+				char tmp_buf[10] = {0};
+				/*print Button Element by Element */
+				index = print_silicon_id(out_buf, &device_id[0],
+					index);
+				if (result->cm_button_validation_pass)
+					index = prepare_print_string(out_buf,
+					",Sensor Cm Validation - Button Element by Element,PASS\n",
+					index);
+				else
+					index = prepare_print_string(out_buf,
+					",Sensor Cm Validation - Button Element by Element,FAIL\n",
+					index);
+
+				/*
+				*print  Sensor Cm Validation
+				*- Buttons Range Buttons Range
+				*/
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+					 ",Sensor Cm Validation - Buttons Range,Buttons Range,",
+					 index);
+				scnprintf(tmp_buf, 10, "%d.%d,",
+					 cmcp_info->cm_delta_data_btn / 10,
+					 cmcp_info->cm_delta_data_btn % 10);
+				index = prepare_print_string(out_buf,
+					&tmp_buf[0], index);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print  Sensor Cm Validation
+				 *-Buttons Range Cm_button_avg
+				 */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+					 ",Sensor Cm Validation - Buttons Range,Cm_button_avg,",
+					 index);
+				index = prepare_print_data(out_buf,
+					&cmcp_info->cm_ave_data_btn,
+					 index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print  Sensor Cm Validation
+				 * -Buttons Range Cm_button_avg
+				 */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+					",Sensor Cm Validation - Buttons Range,Cm_button_cal,",
+					index);
+				index = prepare_print_data(out_buf,
+					&cmcp_info->cm_cal_data_btn,
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print  Sensor Cm Validation
+				 *-Buttons Range pass/fail
+				 */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				if (result->cm_button_delta_pass)
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Buttons Range,PASS,LIMITS,",
+						index);
+				else
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Buttons Range,FAIL,LIMITS,",
+						index);
+				index = prepare_print_data(out_buf,
+				&configuration->cm_max_delta_button_percent,
+				index, 1);
+				index = prepare_print_string(out_buf,
+				"\n", index);
+			}
+
+			if ((test_item & CM_PANEL) == CM_PANEL &&
+				!dad->cmcp_range_check) {
+				char tmp_buf[10] = {0};
+				/*print Cm_sensor_cal */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+					",Sensor Cm Validation - Calibration,Cm_sensor_cal,",
+					index);
+				index = prepare_print_data(out_buf,
+					&cmcp_info->cm_cal_data_panel,
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print Cm_sensor_cal limit*/
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				if (result->cm_sensor_calibration_pass)
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Calibration,PASS,LIMITS,",
+						index);
+				else
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Calibration,FAIL,LIMITS,",
+						index);
+				index = prepare_print_data(out_buf,
+					&configuration->cm_min_limit_cal,
+					index, 1);
+				index = prepare_print_data(out_buf,
+					&configuration->cm_max_limit_cal,
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print Columns Delta Matrix*/
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				if (result->cm_sensor_col_delta_pass)
+					index = prepare_print_string(out_buf,
+					",Sensor Cm Validation - Columns Delta Matrix,PASS,LIMITS,",
+					index);
+				else
+					index = prepare_print_string(out_buf,
+					",Sensor Cm Validation - Columns Delta Matrix,FAIL,LIMITS,",
+					index);
+				index = prepare_print_data(out_buf,
+					&configuration->cm_range_limit_col,
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print Cm Validation - Element by Element*/
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				if (result->cm_sensor_validation_pass)
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Element by Element,PASS,",
+						index);
+				else
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Element by Element,FAIL,",
+						index);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print Cm Validation -Gradient Cols*/
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				if (result->cm_sensor_gd_col_pass)
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Gradient Cols,PASS,",
+						index);
+				else
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Gradient Cols,FAIL,",
+						index);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print Cm Validation -Gradient Rows*/
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				if (result->cm_sensor_gd_row_pass)
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Gradient Rows,PASS,",
+						index);
+				else
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Gradient Rows,FAIL,",
+						index);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+
+				/*
+				 * Print Sensor Cm Validation
+				 * -Rows Delta Matrix
+				 */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				if (result->cm_sensor_row_delta_pass)
+					index = prepare_print_string(out_buf,
+					",Sensor Cm Validation - Rows Delta Matrix,PASS,LIMITS,",
+					index);
+				else
+					index = prepare_print_string(out_buf,
+					",Sensor Cm Validation - Rows Delta Matrix,FAIL,LIMITS,",
+					index);
+				index = prepare_print_data(out_buf,
+					&configuration->cm_range_limit_row,
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print Cm_sensor_avg */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+					",Sensor Cm Validation - Sensor Range,Cm_sensor_avg,",
+					index);
+				index = prepare_print_data(out_buf,
+					&cmcp_info->cm_ave_data_panel,
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*printSensor Cm Validation -
+				* Sensor Range,   Sensor Range
+				*/
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+					",Sensor Cm Validation - Sensor Range,Sensor Range,",
+					index);
+				scnprintf(tmp_buf, 10, "%d.%d,",
+					cmcp_info->cm_sensor_delta / 10,
+					cmcp_info->cm_sensor_delta % 10);
+				index = prepare_print_string(out_buf,
+					&tmp_buf[0], index);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print Sensor Cm Validation - Sensor Range*/
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				if (result->cm_sensor_delta_pass)
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Sensor Range,PASS,LIMITS,",
+						index);
+				else
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation - Sensor Range,FAIL,LIMITS,",
+						index);
+				index = prepare_print_data(out_buf,
+				&configuration->cm_max_delta_sensor_percent,
+						index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+			}
+		}
+	}
+
+	if ((test_item & CP_ENABLED) == CP_ENABLED) {
+		if (((test_item & CP_BTN) == CP_BTN) && (btn_num > 0)) {
+			/*print   BUTNS_CP_DATA_ROW00  */
+			index = print_silicon_id(out_buf, &device_id[0], index);
+			index = prepare_print_string(out_buf,
+			",Self-cap Calibration Check,BUTNS_CP_DATA_ROW00,",
+				index);
+			index = prepare_print_data(out_buf,
+				&cmcp_info->cp_btn_data[0],
+				index, btn_num);
+			index = prepare_print_string(out_buf,
+				"\n", index);
+
+			if (!no_builtin_file && !dad->cmcp_range_check) {
+				/*print Cp Button Element by Element */
+				index = print_silicon_id(out_buf, &device_id[0],
+					index);
+				if (result->cp_button_validation_pass)
+					index = prepare_print_string(out_buf,
+					",Self-cap Calibration Check - Button Element by Element,PASS\n",
+					index);
+				else
+					index = prepare_print_string(out_buf,
+					",Self-cap Calibration Check - Button Element by Element,FAIL\n",
+					index);
+
+				/*print   cp_button_ave  */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,Cp_button_avg,",
+					index);
+				index = prepare_print_data(out_buf,
+					&cmcp_info->cp_button_ave,
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print   Cp_button_cal  */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,Cp_button_cal,",
+					index);
+				index = prepare_print_data(out_buf,
+					&cmcp_info->cp_btn_cal,
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+			}
+		}
+
+		if ((test_item & CP_PANEL) == CP_PANEL) {
+			/*print CP_DATA_RX */
+			index = print_silicon_id(out_buf, &device_id[0], index);
+			index = prepare_print_string(out_buf,
+			",Self-cap Calibration Check,CP_DATA_RX,", index);
+			index = prepare_print_data(out_buf,
+				&cmcp_info->cp_rx_data_panel[0], index, rx_num);
+			index = prepare_print_string(out_buf, "\n", index);
+
+			/*print CP_DATA_TX */
+			index = print_silicon_id(out_buf, &device_id[0], index);
+			index = prepare_print_string(out_buf,
+			",Self-cap Calibration Check,CP_DATA_TX,", index);
+			index = prepare_print_data(out_buf,
+				&cmcp_info->cp_tx_data_panel[0], index, tx_num);
+			index = prepare_print_string(out_buf, "\n", index);
+		}
+		if (((test_item & CP_BTN) == CP_BTN) && (btn_num > 0)
+			&& !dad->cmcp_range_check) {
+			if (!no_builtin_file) {
+				char tmp_buf[10] = {0};
+				/*print  Cp_delta_button */
+				index = print_silicon_id(out_buf, &device_id[0],
+					index);
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,Cp_delta_button,",
+				index);
+				scnprintf(tmp_buf, 10, "%d.%d,",
+				cmcp_info->cp_button_delta / 10,
+				cmcp_info->cp_button_delta % 10);
+				index = prepare_print_string(out_buf,
+						&tmp_buf[0], index);
+				index = prepare_print_string(out_buf, "\n",
+					index);
+			}
+		}
+		if ((test_item & CP_PANEL) == CP_PANEL &&
+			!dad->cmcp_range_check) {
+			if (!no_builtin_file) {
+				char tmp_buf[10] = {0};
+				/*print Cp_delta_rx */
+				index = print_silicon_id(out_buf, &device_id[0],
+					index);
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,Cp_delta_rx,",
+				index);
+				scnprintf(tmp_buf, 10, "%d.%d,",
+				cmcp_info->cp_sensor_rx_delta / 10,
+				cmcp_info->cp_sensor_rx_delta % 10);
+				index = prepare_print_string(out_buf,
+						&tmp_buf[0], index);
+				index = prepare_print_string(out_buf, "\n",
+					index);
+
+				/*print Cp_delta_tx */
+				index = print_silicon_id(out_buf, &device_id[0],
+					index);
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,Cp_delta_tx,",
+					index);
+				scnprintf(tmp_buf, 10, "%d.%d,",
+				cmcp_info->cp_sensor_tx_delta / 10,
+				cmcp_info->cp_sensor_tx_delta % 10);
+				index = prepare_print_string(out_buf,
+						&tmp_buf[0], index);
+				index = prepare_print_string(out_buf, "\n",
+					index);
+
+				/*print Cp_sensor_avg_rx */
+				index = print_silicon_id(out_buf, &device_id[0],
+					index);
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,Cp_sensor_avg_rx,",
+					index);
+				index = prepare_print_data(out_buf,
+					&cmcp_info->cp_rx_ave_data_panel,
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print Cp_sensor_avg_tx */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,Cp_sensor_avg_tx,",
+					index);
+				index = prepare_print_data(out_buf,
+					&cmcp_info->cp_tx_ave_data_panel,
+					index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print Cp_sensor_cal_rx */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,Cp_sensor_cal_rx,",
+					index);
+				index = prepare_print_data(out_buf,
+					&cmcp_info->cp_rx_cal_data_panel[0],
+					index, rx_num);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print Cp_sensor_cal_tx */
+				index = print_silicon_id(out_buf,
+					&device_id[0], index);
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,Cp_sensor_cal_tx,",
+					index);
+				index = prepare_print_data(out_buf,
+					&cmcp_info->cp_tx_cal_data_panel[0],
+					index, tx_num);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+			}
+		}
+
+		if (!no_builtin_file && !dad->cmcp_range_check) {
+			/*print  cp test limits  */
+			index = print_silicon_id(out_buf, &device_id[0], index);
+			if (result->cp_test_pass)
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,PASS, LIMITS,",
+				index);
+			else
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,FAIL, LIMITS,",
+				index);
+
+			index = prepare_print_string(out_buf,
+				"CP_MAX_DELTA_SENSOR_RX_PERCENT,", index);
+			index = prepare_print_data(out_buf,
+				&configuration->cp_max_delta_sensor_rx_percent,
+				index, 1);
+			index = prepare_print_string(out_buf,
+				"CP_MAX_DELTA_SENSOR_TX_PERCENT,", index);
+			index = prepare_print_data(out_buf,
+				&configuration->cp_max_delta_sensor_tx_percent,
+				index, 1);
+			index = prepare_print_string(out_buf,
+				"CP_MAX_DELTA_BUTTON_PERCENT,", index);
+			index = prepare_print_data(out_buf,
+				&configuration->cp_max_delta_button_percent,
+				index, 1);
+			index = prepare_print_string(out_buf, "\n", index);
+		}
+	}
+
+	if (!no_builtin_file) {
+		if ((test_item & CM_ENABLED) == CM_ENABLED) {
+			if ((test_item & CM_PANEL) == CM_PANEL) {
+				/*print columns gradient limit*/
+				index = prepare_print_string(out_buf,
+			",Sensor Cm Validation,MAX_LIMITS,CM_MAX_GRADIENT_COLS_PERCENT,",
+					index);
+				index = prepare_print_data(out_buf,
+			&configuration->cm_max_table_gradient_cols_percent[0],
+					index,
+			configuration->cm_max_table_gradient_cols_percent_size);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+				/*print rows gradient limit*/
+				index = prepare_print_string(out_buf,
+			",Sensor Cm Validation,MAX_LIMITS,CM_MAX_GRADIENT_ROWS_PERCENT,",
+					index);
+				index = prepare_print_data(out_buf,
+			&configuration->cm_max_table_gradient_rows_percent[0],
+					index,
+			configuration->cm_max_table_gradient_rows_percent_size);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print cm max limit*/
+				for (i = 0; i < rx_num; i++) {
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation,MAX_LIMITS,CM_DATA_ROW",
+						index);
+					index = prepare_print_data(out_buf,
+						&i, index, 1);
+					for (j = 0; j < tx_num; j++)
+						index = prepare_print_data(
+							out_buf,
+		&configuration->cm_min_max_table_sensor[i*tx_num*2+j*2+1],
+							index, 1);
+					index = prepare_print_string(out_buf,
+						"\n", index);
+				}
+			}
+
+			if (((test_item & CM_BTN) == CM_BTN) && (btn_num > 0)) {
+				index = prepare_print_string(out_buf,
+					",Sensor Cm Validation,MAX LIMITS,M_BUTNS,",
+					index);
+				for (j = 0; j < btn_num; j++) {
+					index = prepare_print_data(out_buf,
+				&configuration->cm_min_max_table_button[2*j+1],
+						index, 1);
+				}
+				index = prepare_print_string(out_buf,
+					"\n", index);
+			}
+
+			index = prepare_print_string(out_buf,
+				 ",Sensor Cm Validation MAX LIMITS\n", index);
+
+			if ((test_item & CM_PANEL) == CM_PANEL) {
+				/*print cm min limit*/
+				for (i = 0; i < rx_num; i++) {
+					index = prepare_print_string(out_buf,
+						",Sensor Cm Validation,MIN_LIMITS,CM_DATA_ROW",
+						index);
+					index = prepare_print_data(out_buf, &i,
+						index, 1);
+					for (j = 0; j < tx_num; j++)
+						index = prepare_print_data(
+							out_buf,
+		&configuration->cm_min_max_table_sensor[i*tx_num*2 + j*2],
+							index, 1);
+					index = prepare_print_string(out_buf,
+						"\n", index);
+				}
+			}
+
+			if (((test_item & CM_BTN) == CM_BTN) && (btn_num > 0)) {
+				index = prepare_print_string(out_buf,
+					",Sensor Cm Validation,MIN LIMITS,M_BUTNS,",
+					index);
+				for (j = 0; j < btn_num; j++) {
+					index = prepare_print_data(out_buf,
+				&configuration->cm_min_max_table_button[2*j],
+						 index, 1);
+				}
+				index = prepare_print_string(out_buf,
+					"\n", index);
+			}
+			index = prepare_print_string(out_buf,
+				",Sensor Cm Validation MIN LIMITS\n", index);
+		}
+
+		if ((test_item & CP_ENABLED) == CP_ENABLED) {
+			if ((test_item & CP_PANEL) == CP_PANEL) {
+				/*print cp tx max limit*/
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,MAX_LIMITS,TX,",
+					index);
+				for (i = 0; i < tx_num; i++)
+					index = prepare_print_data(out_buf,
+				&configuration->cp_min_max_table_tx[i*2+1],
+						index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print cp rx max limit*/
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,MAX_LIMITS,RX,",
+					index);
+				for (i = 0; i < rx_num; i++)
+					index = prepare_print_data(out_buf,
+				&configuration->cp_min_max_table_rx[i*2+1],
+						index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+			}
+
+			/*print cp btn max limit*/
+			if (((test_item & CP_BTN) == CP_BTN) && (btn_num > 0)) {
+				index = prepare_print_string(out_buf,
+			",Self-cap Calibration Check,MAX_LIMITS,S_BUTNS,",
+					index);
+				for (i = 0; i < btn_num; i++)
+					index = prepare_print_data(out_buf,
+				&configuration->cp_min_max_table_button[i*2+1],
+						index, 1);
+				index = prepare_print_string(out_buf,
+						"\n", index);
+			}
+
+			if ((test_item & CP_PANEL) == CP_PANEL) {
+				/*print cp tx min limit*/
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,MIN_LIMITS,TX,",
+					index);
+				for (i = 0; i < tx_num; i++)
+					index = prepare_print_data(out_buf,
+				&configuration->cp_min_max_table_tx[i*2],
+						index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+
+				/*print cp rx min limit*/
+				index = prepare_print_string(out_buf,
+				",Self-cap Calibration Check,MIN_LIMITS,RX,",
+					index);
+				for (i = 0; i < rx_num; i++)
+					index = prepare_print_data(out_buf,
+				&configuration->cp_min_max_table_rx[i*2],
+						index, 1);
+				index = prepare_print_string(out_buf,
+					"\n", index);
+			}
+
+			/*print cp btn min limit*/
+			if (((test_item & CP_BTN) == CP_BTN) && (btn_num > 0)) {
+				index = prepare_print_string(out_buf,
+			",Self-cap Calibration Check,MIN_LIMITS,S_BUTNS,",
+					index);
+				for (i = 0; i < btn_num; i++)
+					index = prepare_print_data(out_buf,
+				&configuration->cp_min_max_table_button[i*2],
+						index, 1);
+				index = prepare_print_string(out_buf,
+						"\n", index);
+			}
+		}
+	}
+	return index;
+}
+
+int result_save(struct device *dev, char *buf,
+	struct configuration *configuration, struct result *result,
+	struct cmcp_data *cmcp_info, loff_t *ppos, size_t count, int test_item,
+	int no_builtin_file)
+{
+	u8 *out_buf = NULL;
+	int index = 0;
+	int byte_left;
+
+	out_buf = kzalloc(MAX_BUF_LEN, GFP_KERNEL);
+	if (configuration == NULL)
+		dev_err(dev, "config is NULL");
+	if (result == NULL)
+		dev_err(dev, "result is NULL");
+	if (cmcp_info == NULL)
+		dev_err(dev, "cmcp_info is NULL");
+
+	index = save_header(out_buf, index, result);
+	index = save_engineering_data(dev, out_buf, index,
+		cmcp_info, configuration, result,
+		test_item, no_builtin_file);
+	byte_left = simple_read_from_buffer(buf, count, ppos, out_buf, index);
+
+	kfree(out_buf);
+	return byte_left;
+}
+
+static int cmcp_results_debugfs_open(struct inode *inode,
+		struct file *filp)
+{
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+static int cmcp_results_debugfs_close(struct inode *inode,
+		struct file *filp)
+{
+	filp->private_data = NULL;
+	return 0;
+}
+
+static ssize_t cmcp_results_debugfs_read(struct file *filp,
+		char __user *buf, size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_data *dad = filp->private_data;
+	struct device *dev;
+	struct cmcp_data *cmcp_info = dad->cmcp_info;
+	struct result *result = dad->result;
+	struct configuration *configuration = dad->configs;
+	int ret = 0;
+	int test_item;
+	int no_builtin_file = 0;
+	int test_executed = 0;
+
+	dev = dad->dev;
+
+	mutex_lock(&dad->sysfs_lock);
+	test_executed = dad->test_executed;
+	test_item = cyttsp5_cmcp_get_test_item(dad->cmcp_test_items);
+	if (dad->builtin_cmcp_threshold_status < 0) {
+		dev_err(dev, "%s: No cmcp threshold file.\n", __func__);
+		no_builtin_file = 1;
+	}
+	mutex_unlock(&dad->sysfs_lock);
+
+	if (test_executed)
+		/*save result to buf*/
+		ret = result_save(dev, buf, configuration, result, cmcp_info,
+			ppos, count, test_item, no_builtin_file);
+	else {
+		char warning_info[] =
+		"No test result available!\n";
+		dev_err(dev, "%s: No test result available!\n", __func__);
+
+		return simple_read_from_buffer(buf, count, ppos, warning_info,
+			strlen(warning_info));
+	}
+
+	return ret;
+}
+
+static const struct file_operations cmcp_results_debugfs_fops = {
+	.open = cmcp_results_debugfs_open,
+	.release = cmcp_results_debugfs_close,
+	.read = cmcp_results_debugfs_read,
+	.write = NULL,
+};
+
+static ssize_t cyttsp5_cmcp_threshold_loading_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	bool cmcp_threshold_loading;
+
+	mutex_lock(&dad->cmcp_threshold_lock);
+	cmcp_threshold_loading = dad->cmcp_threshold_loading;
+	mutex_unlock(&dad->cmcp_threshold_lock);
+
+	return sprintf(buf, "%d\n", cmcp_threshold_loading);
+}
+
+/* Return the buffer offset of new test case */
+u32 cmcp_return_offset_of_new_case(const char *bufPtr, u32 first_time)
+{
+	static u32 offset, first_search;
+
+	if (first_time == 0) {
+		first_search = 0;
+		offset = 0;
+	}
+
+	if (first_search != 0) {
+		/* Search one case */
+		for (;;) {
+			/* Search ASCII_LF */
+			while (*bufPtr++ != ASCII_LF)
+				offset++;
+
+			offset++;
+			/*
+			 * Single line: end loop
+			 * Multiple lines: continue loop
+			 */
+			if (*bufPtr != ASCII_COMMA)
+				break;
+		}
+	} else
+		first_search = 1;
+
+	return offset;
+}
+
+/* Get test case information from cmcp threshold file */
+u32 cmcp_get_case_info_from_threshold_file(struct device *dev, const char *buf,
+		struct test_case_search *search_array, u32 file_size)
+{
+	u32 case_num = 0, buffer_offset = 0, name_count = 0, first_search = 0;
+
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: Search cmcp threshold file\n",
+		__func__);
+
+	/* Get all the test cases */
+	for (case_num = 0; case_num < MAX_CASE_NUM; case_num++) {
+		buffer_offset =
+			cmcp_return_offset_of_new_case(&buf[buffer_offset],
+			first_search);
+		first_search = 1;
+
+		if (buf[buffer_offset] == 0)
+			break;
+
+		for (name_count = 0; name_count < NAME_SIZE_MAX; name_count++) {
+			/* File end */
+			if (buf[buffer_offset + name_count] == ASCII_COMMA)
+				break;
+
+			search_array[case_num].name[name_count] =
+					buf[buffer_offset + name_count];
+		}
+
+		/* Exit when buffer offset is larger than file size */
+		if (buffer_offset >= file_size)
+			break;
+
+		search_array[case_num].name_size = name_count;
+		search_array[case_num].offset = buffer_offset;
+		/*
+		 *  parade_debug(dev, DEBUG_LEVEL_2, "Find case %d: Name is %s;
+		 *  Name size is %d; Case offset is %d\n",
+		 *	case_num,
+		 *	search_array[case_num].name,
+		 *	search_array[case_num].name_size,
+		 *	search_array[case_num].offset);
+		 */
+	}
+
+	return case_num;
+}
+
+/* Compose one value based on data of each bit */
+int cmcp_compose_data(char *buf, u32 count)
+{
+	u32 base_array[] = {1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9};
+	int value = 0;
+	u32 index = 0;
+
+	for (index = 0; index < count; index++)
+		value += buf[index] * base_array[count - 1 - index];
+
+	return value;
+}
+
+/* Return one value */
+int cmcp_return_one_value(struct device *dev,
+		const char *buf, u32 *offset, u32 *line_num)
+{
+	int value = -1;
+	char tmp_buffer[10];
+	u32 count = 0;
+	u32 tmp_offset = *offset;
+	static u32 line_count = 1;
+
+	/* Bypass extra commas */
+	while (buf[tmp_offset] == ASCII_COMMA
+			&& buf[tmp_offset + 1] == ASCII_COMMA)
+		tmp_offset++;
+
+	/* Windows and Linux difference at the end of one line */
+	if (buf[tmp_offset] == ASCII_COMMA
+			&& buf[tmp_offset + 1] == ASCII_CR
+			&& buf[tmp_offset + 2] == ASCII_LF)
+		tmp_offset += 2;
+	else if (buf[tmp_offset] == ASCII_COMMA
+			&& buf[tmp_offset + 1] == ASCII_LF)
+		tmp_offset += 1;
+	else if (buf[tmp_offset] == ASCII_COMMA
+			&& buf[tmp_offset + 1] == ASCII_CR)
+		tmp_offset += 1;
+
+	/* New line for multiple lines */
+	if (buf[tmp_offset] == ASCII_LF && buf[tmp_offset + 1] == ASCII_COMMA) {
+		tmp_offset++;
+		line_count++;
+		/*parade_debug(dev, DEBUG_LEVEL_2, "\n");*/
+	}
+
+	/* Beginning */
+	if (buf[tmp_offset] == ASCII_COMMA) {
+		tmp_offset++;
+		for (;;) {
+			if ((buf[tmp_offset] >= ASCII_ZERO)
+			&& (buf[tmp_offset] <= ASCII_NINE)) {
+				tmp_buffer[count++] =
+				buf[tmp_offset] - ASCII_ZERO;
+				tmp_offset++;
+			} else {
+				if (count != 0) {
+					value = cmcp_compose_data(tmp_buffer,
+					count);
+					/*parade_debug(dev, DEBUG_LEVEL_2, */
+					/* ",%d", value);*/
+				} else {
+					/* 0 indicates no data available */
+					value = -1;
+				}
+				break;
+			}
+		}
+	} else {
+		/* Multiple line: line count */
+		*line_num = line_count;
+		/* Reset for next case */
+		line_count = 1;
+	}
+
+	*offset = tmp_offset;
+
+	return value;
+}
+
+/* Get configuration information */
+void cmcp_get_configuration_info(struct device *dev,
+		const char *buf, struct test_case_search *search_array,
+		u32 case_count, struct test_case_field *field_array,
+		struct configuration *config)
+{
+	u32 count = 0, sub_count = 0;
+	u32 exist_or_not = 0;
+	u32 value_offset = 0;
+	int retval = 0;
+	u32 data_num = 0;
+	u32 line_num = 1;
+
+	parade_debug(dev, DEBUG_LEVEL_2,
+		"%s: Fill configuration struct per cmcp threshold file\n",
+		__func__);
+
+	/* Search cases */
+	for (count = 0; count < MAX_CASE_NUM; count++) {
+		exist_or_not = 0;
+		for (sub_count = 0; sub_count < case_count; sub_count++) {
+			if (!strncmp(field_array[count].name,
+					search_array[sub_count].name,
+					field_array[count].name_size)) {
+				exist_or_not = 1;
+				break;
+			}
+		}
+
+		field_array[count].exist_or_not = exist_or_not;
+
+		/* Clear data number */
+		data_num = 0;
+
+		if (exist_or_not == 1) {
+			switch (field_array[count].type) {
+			case TEST_CASE_TYPE_NO:
+				field_array[count].data_num = 0;
+				field_array[count].line_num = 1;
+				break;
+			case TEST_CASE_TYPE_ONE:
+				value_offset = search_array[sub_count].offset
+					+ search_array[sub_count].name_size;
+				*field_array[count].bufptr =
+						cmcp_return_one_value(dev, buf,
+						&value_offset, 0);
+				field_array[count].data_num = 1;
+				field_array[count].line_num = 1;
+				break;
+			case TEST_CASE_TYPE_MUL:
+			case TEST_CASE_TYPE_MUL_LINES:
+				line_num = 1;
+				value_offset = search_array[sub_count].offset
+					+ search_array[sub_count].name_size;
+				for (;;) {
+					retval = cmcp_return_one_value(dev,
+						buf, &value_offset, &line_num);
+					if (retval >= 0) {
+						*field_array[count].bufptr++ =
+						retval;
+						data_num++;
+					} else
+						break;
+				}
+
+				field_array[count].data_num = data_num;
+				field_array[count].line_num = line_num;
+				break;
+			default:
+				break;
+			}
+			parade_debug(dev, DEBUG_LEVEL_2,
+				"%s: %s: Data number is %d, line number is %d\n",
+				__func__,
+				field_array[count].name,
+				field_array[count].data_num,
+				field_array[count].line_num);
+		} else
+			parade_debug(dev, DEBUG_LEVEL_2, "%s: !!! %s doesn't exist\n",
+				__func__, field_array[count].name);
+	}
+}
+
+/* Get basic information, like tx, rx, button number */
+void cmcp_get_basic_info(struct device *dev,
+	struct test_case_field *field_array, struct configuration *config)
+{
+#define CMCP_DEBUG 0
+	u32 tx_num = 0;
+#if CMCP_DEBUG
+	u32 index = 0;
+#endif
+
+	config->is_valid_or_not = 1; /* Set to valid by default */
+	config->cm_enabled = 0;
+	config->cp_enabled = 0;
+
+	if (field_array[CM_TEST_INPUTS].exist_or_not)
+		config->cm_enabled = 1;
+	if (field_array[CP_TEST_INPUTS].exist_or_not)
+		config->cp_enabled = 1;
+
+	/* Get basic information only when CM and CP are enabled */
+	if (config->cm_enabled && config->cp_enabled) {
+		parade_debug(dev, DEBUG_LEVEL_2,
+			"%s: Find CM and CP thresholds\n", __func__);
+
+		config->rx_num =
+			field_array[PER_ELEMENT_MIN_MAX_TABLE_SENSOR].line_num;
+		tx_num =
+		(field_array[PER_ELEMENT_MIN_MAX_TABLE_SENSOR].data_num >> 1)
+			/field_array[PER_ELEMENT_MIN_MAX_TABLE_SENSOR].line_num;
+		config->tx_num = tx_num;
+
+		config->btn_num =
+		field_array[PER_ELEMENT_MIN_MAX_TABLE_BUTTON].data_num >> 1;
+
+		config->cm_min_max_table_button_size =
+			field_array[PER_ELEMENT_MIN_MAX_TABLE_BUTTON].data_num;
+		config->cm_min_max_table_sensor_size =
+			field_array[PER_ELEMENT_MIN_MAX_TABLE_SENSOR].data_num;
+		config->cp_min_max_table_rx_size =
+			field_array[PER_ELEMENT_MIN_MAX_RX].data_num;
+		config->cp_min_max_table_tx_size =
+			field_array[PER_ELEMENT_MIN_MAX_TX].data_num;
+		config->cm_max_table_gradient_cols_percent_size =
+			field_array[CM_GRADIENT_CHECK_COL].data_num;
+		config->cm_max_table_gradient_rows_percent_size =
+			field_array[CM_GRADIENT_CHECK_ROW].data_num;
+		config->cp_min_max_table_button_size =
+			field_array[CP_PER_ELEMENT_MIN_MAX_BUTTON].data_num;
+
+#if CMCP_DEBUG
+		parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+					config->cm_excluding_col_edge);
+		parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+					config->cm_excluding_row_edge);
+		for (index = 0;
+		index < config->cm_max_table_gradient_cols_percent_size;
+		index++)
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+			config->cm_max_table_gradient_cols_percent[index]);
+		for (index = 0;
+		index < config->cm_max_table_gradient_rows_percent_size;
+		index++)
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+			config->cm_max_table_gradient_rows_percent[index]);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cm_range_limit_row);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cm_range_limit_col);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cm_min_limit_cal);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cm_max_limit_cal);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cm_max_delta_sensor_percent);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cm_max_delta_button_percent);
+		for (index = 0;
+		index < config->cm_min_max_table_button_size; index++)
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cm_min_max_table_button[index]);
+		for (index = 0;
+			index < config->cm_min_max_table_sensor_size; index++)
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cm_min_max_table_sensor[index]);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cp_max_delta_sensor_rx_percent);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cp_max_delta_sensor_tx_percent);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cp_max_delta_button_percent);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->min_button);
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->max_button);
+
+		for (index = 0;
+		index < config->cp_min_max_table_button_size; index++)
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cp_min_max_table_button[index]);
+		for (index = 0;
+		index < config->cp_min_max_table_rx_size; index++)
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cp_min_max_table_rx[index]);
+		for (index = 0;
+		index < config->cp_min_max_table_tx_size; index++)
+			parade_debug(dev, DEBUG_LEVEL_2, "%d\n",
+				config->cp_min_max_table_tx[index]);
+#endif
+		/* Invalid mutual data length */
+		if ((field_array[PER_ELEMENT_MIN_MAX_TABLE_SENSOR].data_num >>
+		1) % field_array[PER_ELEMENT_MIN_MAX_TABLE_SENSOR].line_num) {
+			config->is_valid_or_not = 0;
+			parade_debug(dev, DEBUG_LEVEL_2, "Invalid mutual data length\n");
+		}
+	} else {
+		if (!config->cm_enabled)
+			parade_debug(dev, DEBUG_LEVEL_2,
+				"%s: Miss CM thresholds or CM data format is wrong!\n",
+				__func__);
+
+		if (!config->cp_enabled)
+			parade_debug(dev, DEBUG_LEVEL_2,
+				"%s: Miss CP thresholds or CP data format is wrong!\n",
+				__func__);
+
+		config->rx_num = 0;
+		config->tx_num = 0;
+		config->btn_num = 0;
+		config->is_valid_or_not = 0;
+	}
+
+	parade_debug(dev, DEBUG_LEVEL_2,
+		"%s:\n"
+		"Input file is %s!\n"
+		"CM test: %s\n"
+		"CP test: %s\n"
+		"rx_num is %d\n"
+		"tx_num is %d\n"
+		"btn_num is %d\n",
+		__func__,
+		config->is_valid_or_not == 1 ? "VALID" : "!!! INVALID !!!",
+		config->cm_enabled == 1 ? "Found" : "Not found",
+		config->cp_enabled == 1 ? "Found" : "Not found",
+		config->rx_num,
+		config->tx_num,
+		config->btn_num);
+}
+
+void cmcp_test_case_field_init(struct test_case_field *test_field_array,
+	struct configuration *configs)
+{
+	struct test_case_field test_case_field_array[MAX_CASE_NUM] = {
+		{"CM TEST INPUTS", 14, TEST_CASE_TYPE_NO,
+				NULL, 0, 0, 0},
+		{"CM_EXCLUDING_COL_EDGE", 21, TEST_CASE_TYPE_ONE,
+				&configs->cm_excluding_col_edge, 0, 0, 0},
+		{"CM_EXCLUDING_ROW_EDGE", 21, TEST_CASE_TYPE_ONE,
+				&configs->cm_excluding_row_edge, 0, 0, 0},
+		{"CM_GRADIENT_CHECK_COL", 21, TEST_CASE_TYPE_MUL,
+				&configs->cm_max_table_gradient_cols_percent[0],
+				0, 0, 0},
+		{"CM_GRADIENT_CHECK_ROW", 21, TEST_CASE_TYPE_MUL,
+				&configs->cm_max_table_gradient_rows_percent[0],
+				0, 0, 0},
+		{"CM_RANGE_LIMIT_ROW", 18, TEST_CASE_TYPE_ONE,
+				&configs->cm_range_limit_row, 0, 0, 0},
+		{"CM_RANGE_LIMIT_COL", 18, TEST_CASE_TYPE_ONE,
+				&configs->cm_range_limit_col, 0, 0, 0},
+		{"CM_MIN_LIMIT_CAL", 16, TEST_CASE_TYPE_ONE,
+				&configs->cm_min_limit_cal, 0, 0, 0},
+		{"CM_MAX_LIMIT_CAL", 16, TEST_CASE_TYPE_ONE,
+				&configs->cm_max_limit_cal, 0, 0, 0},
+		{"CM_MAX_DELTA_SENSOR_PERCENT", 27, TEST_CASE_TYPE_ONE,
+				&configs->cm_max_delta_sensor_percent, 0, 0, 0},
+		{"CM_MAX_DELTA_BUTTON_PERCENT", 27, TEST_CASE_TYPE_ONE,
+				&configs->cm_max_delta_button_percent, 0, 0, 0},
+		{"PER_ELEMENT_MIN_MAX_TABLE_BUTTON", 32, TEST_CASE_TYPE_MUL,
+				&configs->cm_min_max_table_button[0], 0, 0, 0},
+		{"PER_ELEMENT_MIN_MAX_TABLE_SENSOR", 32,
+				TEST_CASE_TYPE_MUL_LINES,
+				&configs->cm_min_max_table_sensor[0], 0, 0, 0},
+		{"CP TEST INPUTS", 14, TEST_CASE_TYPE_NO,
+				NULL, 0, 0, 0},
+		{"CP_PER_ELEMENT_MIN_MAX_BUTTON", 29, TEST_CASE_TYPE_MUL,
+				&configs->cp_min_max_table_button[0], 0, 0, 0},
+		{"CP_MAX_DELTA_SENSOR_RX_PERCENT", 30, TEST_CASE_TYPE_ONE,
+				&configs->cp_max_delta_sensor_rx_percent,
+				0, 0, 0},
+		{"CP_MAX_DELTA_SENSOR_TX_PERCENT", 30, TEST_CASE_TYPE_ONE,
+				&configs->cp_max_delta_sensor_tx_percent,
+				0, 0, 0},
+		{"CP_MAX_DELTA_BUTTON_PERCENT", 27, TEST_CASE_TYPE_ONE,
+				&configs->cp_max_delta_button_percent, 0, 0, 0},
+		{"MIN_BUTTON", 10, TEST_CASE_TYPE_ONE,
+				&configs->min_button, 0, 0, 0},
+		{"MAX_BUTTON", 10, TEST_CASE_TYPE_ONE,
+				&configs->max_button, 0, 0, 0},
+		{"PER_ELEMENT_MIN_MAX_RX", 22, TEST_CASE_TYPE_MUL,
+				&configs->cp_min_max_table_rx[0], 0, 0, 0},
+		{"PER_ELEMENT_MIN_MAX_TX", 22, TEST_CASE_TYPE_MUL,
+				&configs->cp_min_max_table_tx[0], 0, 0, 0},
+	};
+
+	memcpy(test_field_array, test_case_field_array,
+		sizeof(struct test_case_field) * MAX_CASE_NUM);
+}
+
+static ssize_t cyttsp5_parse_cmcp_threshold_file_common(
+	struct device *dev, const char *buf, u32 file_size)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	ssize_t rc = 0;
+	u32 case_count = 0;
+
+	parade_debug(dev, DEBUG_LEVEL_2,
+		"%s: Start parsing cmcp threshold file. File size is %d\n",
+		__func__, file_size);
+
+	cmcp_test_case_field_init(dad->test_field_array, dad->configs);
+
+	/* Get all the cases from .csv file */
+	case_count = cmcp_get_case_info_from_threshold_file(dev,
+		buf, dad->test_search_array, file_size);
+
+	/* Search cases */
+	cmcp_get_configuration_info(dev,
+		buf,
+		dad->test_search_array, case_count, dad->test_field_array,
+		dad->configs);
+
+	/* Get basic information */
+	cmcp_get_basic_info(dev, dad->test_field_array, dad->configs);
+
+	return rc;
+}
+
+static ssize_t cyttsp5_cmcp_threshold_loading_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	long value;
+	int rc;
+
+	rc = kstrtol(buf, 10, &value);
+	if (rc < 0 || value < -1 || value > 1) {
+		dev_err(dev, "%s: Invalid value\n", __func__);
+		return size;
+	}
+
+	mutex_lock(&dad->cmcp_threshold_lock);
+
+	if (value == 1)
+		dad->cmcp_threshold_loading = true;
+	else if (value == -1)
+		dad->cmcp_threshold_loading = false;
+	else if (value == 0 && dad->cmcp_threshold_loading) {
+		dad->cmcp_threshold_loading = false;
+
+		if (dad->cmcp_threshold_size == 0) {
+			dev_err(dev, "%s: No cmcp threshold data\n", __func__);
+			goto exit_free;
+		}
+
+		/* Clear test executed flag */
+		dad->test_executed = 0;
+
+		cyttsp5_parse_cmcp_threshold_file_common(dev,
+			&dad->cmcp_threshold_data[0], dad->cmcp_threshold_size);
+
+		/* Mark valid */
+		dad->builtin_cmcp_threshold_status = 0;
+		/* Restore test item to default value when new file input */
+		dad->cmcp_test_items = 0;
+	}
+
+exit_free:
+	kfree(dad->cmcp_threshold_data);
+	dad->cmcp_threshold_data = NULL;
+	dad->cmcp_threshold_size = 0;
+
+	mutex_unlock(&dad->cmcp_threshold_lock);
+
+	if (rc)
+		return rc;
+
+	return size;
+}
+
+static DEVICE_ATTR(cmcp_threshold_loading, S_IRUSR | S_IWUSR,
+	cyttsp5_cmcp_threshold_loading_show,
+	cyttsp5_cmcp_threshold_loading_store);
+
+/*
+* cmcp threshold data write
+*/
+static ssize_t cyttsp5_cmcp_threshold_data_write(struct file *filp,
+		struct kobject *kobj, struct bin_attribute *bin_attr,
+		char *buf, loff_t offset, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	u8 *p;
+
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: offset:%lld count:%zu\n",
+		__func__, offset, count);
+
+	mutex_lock(&dad->cmcp_threshold_lock);
+
+	if (!dad->cmcp_threshold_loading) {
+		mutex_unlock(&dad->cmcp_threshold_lock);
+		return -ENODEV;
+	}
+
+	p = krealloc(dad->cmcp_threshold_data, offset + count, GFP_KERNEL);
+	if (!p) {
+		kfree(dad->cmcp_threshold_data);
+		dad->cmcp_threshold_data = NULL;
+		mutex_unlock(&dad->cmcp_threshold_lock);
+		return -ENOMEM;
+	}
+	dad->cmcp_threshold_data = p;
+
+	memcpy(&dad->cmcp_threshold_data[offset], buf, count);
+	dad->cmcp_threshold_size += count;
+
+	mutex_unlock(&dad->cmcp_threshold_lock);
+
+	return count;
+}
+
+static struct bin_attribute bin_attr_cmcp_threshold_data = {
+	.attr = {
+		.name = "cmcp_threshold_data",
+		.mode = S_IWUSR,
+	},
+	.size = 0,
+	.write = cyttsp5_cmcp_threshold_data_write,
+};
+
+/*
+ * Suspend scan command
+ */
+static int cyttsp5_suspend_scan_cmd_(struct device *dev)
+{
+	int rc;
+
+	rc = cmd->nonhid_cmd->suspend_scanning(dev, 0);
+	if (rc < 0)
+		dev_err(dev, "%s: Suspend scan failed r=%d\n",
+			__func__, rc);
+	return rc;
+}
+
+/*
+ * Resume scan command
+ */
+static int cyttsp5_resume_scan_cmd_(struct device *dev)
+{
+	int rc;
+
+	rc = cmd->nonhid_cmd->resume_scanning(dev, 0);
+	if (rc < 0)
+		dev_err(dev, "%s: Resume scan failed r=%d\n",
+			__func__, rc);
+	return rc;
+}
+
+/*
+ * Execute scan command
+ */
+static int cyttsp5_exec_scan_cmd_(struct device *dev)
+{
+	int rc;
+
+	rc = cmd->nonhid_cmd->exec_panel_scan(dev, 0);
+	if (rc < 0)
+		dev_err(dev, "%s: Heatmap start scan failed r=%d\n",
+			__func__, rc);
+	return rc;
+}
+
+/*
+ * Retrieve panel data command
+ */
+static int cyttsp5_ret_scan_data_cmd_(struct device *dev, u16 read_offset,
+		u16 read_count, u8 data_id, u8 *response, u8 *config,
+		u16 *actual_read_len, u8 *return_buf)
+{
+	int rc;
+
+	rc = cmd->nonhid_cmd->retrieve_panel_scan(dev, 0, read_offset,
+			read_count, data_id, response, config, actual_read_len,
+			return_buf);
+	if (rc < 0)
+		dev_err(dev, "%s: Retrieve scan data failed r=%d\n",
+				__func__, rc);
+	return rc;
+}
+
+/*
+ * Get data structure command
+ */
+static int cyttsp5_get_data_structure_cmd_(struct device *dev, u16 read_offset,
+		u16 read_length, u8 data_id, u8 *status, u8 *data_format,
+		u16 *actual_read_len, u8 *data)
+{
+	int rc;
+
+	rc = cmd->nonhid_cmd->get_data_structure(dev, 0, read_offset,
+			read_length, data_id, status, data_format,
+			actual_read_len, data);
+	if (rc < 0)
+		dev_err(dev, "%s: Get data structure failed r=%d\n",
+				__func__, rc);
+	return rc;
+}
+
+/*
+ * Run self test command
+ */
+static int cyttsp5_run_selftest_cmd_(struct device *dev, u8 test_id,
+		u8 write_idacs_to_flash, u8 *status, u8 *summary_result,
+		u8 *results_available)
+{
+	int rc;
+
+	rc = cmd->nonhid_cmd->run_selftest(dev, 0, test_id,
+			write_idacs_to_flash, status, summary_result,
+			results_available);
+	if (rc < 0)
+		dev_err(dev, "%s: Run self test failed r=%d\n",
+				__func__, rc);
+	return rc;
+}
+
+/*
+ * Get self test result command
+ */
+static int cyttsp5_get_selftest_result_cmd_(struct device *dev,
+		u16 read_offset, u16 read_length, u8 test_id, u8 *status,
+		u16 *actual_read_len, u8 *data)
+{
+	int rc;
+
+	rc = cmd->nonhid_cmd->get_selftest_result(dev, 0, read_offset,
+			read_length, test_id, status, actual_read_len, data);
+	if (rc < 0)
+		dev_err(dev, "%s: Get self test result failed r=%d\n",
+				__func__, rc);
+	return rc;
+}
+
+/*
+ * Calibrate IDACs command
+ */
+static int _cyttsp5_calibrate_idacs_cmd(struct device *dev,
+		u8 sensing_mode, u8 *status)
+{
+	int rc;
+
+	rc = cmd->nonhid_cmd->calibrate_idacs(dev, 0, sensing_mode, status);
+	return rc;
+}
+
+/*
+ * Initialize Baselines command
+ */
+static int _cyttsp5_initialize_baselines_cmd(struct device *dev,
+		u8 sensing_mode, u8 *status)
+{
+	int rc;
+
+	rc = cmd->nonhid_cmd->initialize_baselines(dev, 0, sensing_mode,
+			status);
+	return rc;
+}
+
+static int prepare_print_buffer(int status, u8 *in_buf, int length,
+		u8 *out_buf, size_t out_buf_size)
+{
+	int index = 0;
+	int i;
+
+	index += scnprintf(out_buf, out_buf_size, "status %d\n", status);
+
+	for (i = 0; i < length; i++) {
+		index += scnprintf(&out_buf[index], out_buf_size - index,
+				"%02X\n", in_buf[i]);
+	}
+
+	return index;
+}
+static ssize_t cyttsp5_run_and_get_selftest_result_noprint(struct device *dev,
+		char *buf, size_t buf_len, u8 test_id, u16 read_length,
+		bool get_result_on_pass)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	int status = STATUS_FAIL;
+	u8 cmd_status = 0;
+	u8 summary_result = 0;
+	u16 act_length = 0;
+	int length = 0;
+	int rc;
+
+	mutex_lock(&dad->sysfs_lock);
+
+	pm_runtime_get_sync(dev);
+
+	rc = cmd->request_exclusive(dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on request exclusive r=%d\n",
+				__func__, rc);
+		goto put_pm_runtime;
+	}
+
+	rc = cyttsp5_suspend_scan_cmd_(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on suspend scan r=%d\n",
+				__func__, rc);
+		goto release_exclusive;
+	}
+
+	rc = cyttsp5_run_selftest_cmd_(dev, test_id, 0,
+			&cmd_status, &summary_result, NULL);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on run self test for test_id:%d r=%d\n",
+				__func__, test_id, rc);
+		goto resume_scan;
+	}
+
+	/* Form response buffer */
+	dad->ic_buf[0] = cmd_status;
+	dad->ic_buf[1] = summary_result;
+
+	length = 2;
+
+	/* Get data if command status is success */
+	if (cmd_status != CY_CMD_STATUS_SUCCESS)
+		goto status_success;
+
+	/* Get data unless test result is pass */
+	if (summary_result == CY_ST_RESULT_PASS && !get_result_on_pass)
+		goto status_success;
+
+	rc = cyttsp5_get_selftest_result_cmd_(dev, 0, read_length,
+			test_id, &cmd_status, &act_length, &dad->ic_buf[6]);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on get self test result r=%d\n",
+				__func__, rc);
+		goto resume_scan;
+	}
+
+	dad->ic_buf[2] = cmd_status;
+	dad->ic_buf[3] = test_id;
+	dad->ic_buf[4] = LOW_BYTE(act_length);
+	dad->ic_buf[5] = HI_BYTE(act_length);
+
+	length = 6 + act_length;
+
+status_success:
+	status = STATUS_SUCCESS;
+
+resume_scan:
+	cyttsp5_resume_scan_cmd_(dev);
+
+release_exclusive:
+	cmd->release_exclusive(dev);
+
+put_pm_runtime:
+	pm_runtime_put(dev);
+	mutex_unlock(&dad->sysfs_lock);
+
+	return status;
+}
+
+static ssize_t cyttsp5_run_and_get_selftest_result(struct device *dev,
+		char *buf, size_t buf_len, u8 test_id, u16 read_length,
+		bool get_result_on_pass)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	int status = STATUS_FAIL;
+	u8 cmd_status = 0;
+	u8 summary_result = 0;
+	u16 act_length = 0;
+	int length = 0;
+	int size;
+	int rc;
+
+	mutex_lock(&dad->sysfs_lock);
+
+	pm_runtime_get_sync(dev);
+
+	rc = cmd->request_exclusive(dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on request exclusive r=%d\n",
+				__func__, rc);
+		goto put_pm_runtime;
+	}
+
+	rc = cyttsp5_suspend_scan_cmd_(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on suspend scan r=%d\n",
+				__func__, rc);
+		goto release_exclusive;
+	}
+
+	rc = cyttsp5_run_selftest_cmd_(dev, test_id, 0,
+			&cmd_status, &summary_result, NULL);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on run self test for test_id:%d r=%d\n",
+				__func__, test_id, rc);
+		goto resume_scan;
+	}
+
+	/* Form response buffer */
+	dad->ic_buf[0] = cmd_status;
+	dad->ic_buf[1] = summary_result;
+
+	length = 2;
+
+	/* Get data if command status is success */
+	if (cmd_status != CY_CMD_STATUS_SUCCESS)
+		goto status_success;
+
+	/* Get data unless test result is pass */
+	if (summary_result == CY_ST_RESULT_PASS && !get_result_on_pass)
+		goto status_success;
+
+	rc = cyttsp5_get_selftest_result_cmd_(dev, 0, read_length,
+			test_id, &cmd_status, &act_length, &dad->ic_buf[6]);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on get self test result r=%d\n",
+				__func__, rc);
+		goto resume_scan;
+	}
+
+	dad->ic_buf[2] = cmd_status;
+	dad->ic_buf[3] = test_id;
+	dad->ic_buf[4] = LOW_BYTE(act_length);
+	dad->ic_buf[5] = HI_BYTE(act_length);
+
+	length = 6 + act_length;
+
+status_success:
+	status = STATUS_SUCCESS;
+
+resume_scan:
+	cyttsp5_resume_scan_cmd_(dev);
+
+release_exclusive:
+	cmd->release_exclusive(dev);
+
+put_pm_runtime:
+	pm_runtime_put(dev);
+
+	if (status == STATUS_FAIL)
+		length = 0;
+
+	size = prepare_print_buffer(status, dad->ic_buf, length, buf, buf_len);
+
+	mutex_unlock(&dad->sysfs_lock);
+
+	return size;
+}
+
+struct cyttsp5_device_access_debugfs_data {
+	struct cyttsp5_device_access_data *dad;
+	ssize_t pr_buf_len;
+	u8 pr_buf[3 * CY_MAX_PRBUF_SIZE];
+};
+
+static int cyttsp5_device_access_debugfs_open(struct inode *inode,
+		struct file *filp)
+{
+	struct cyttsp5_device_access_data *dad = inode->i_private;
+	struct cyttsp5_device_access_debugfs_data *data;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->dad = dad;
+
+	filp->private_data = data;
+
+	return nonseekable_open(inode, filp);
+}
+
+static int cyttsp5_device_access_debugfs_release(struct inode *inode,
+		struct file *filp)
+{
+	kfree(filp->private_data);
+
+	return 0;
+}
+
+#define CY_DEBUGFS_FOPS(_name, _read, _write) \
+static const struct file_operations _name##_debugfs_fops = { \
+	.open = cyttsp5_device_access_debugfs_open, \
+	.release = cyttsp5_device_access_debugfs_release, \
+	.read = _read, \
+	.write = _write, \
+}
+
+static ssize_t panel_scan_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+	struct cyttsp5_device_access_data *dad = data->dad;
+	struct device *dev = dad->dev;
+	struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
+	int status = STATUS_FAIL;
+	u8 config;
+	u16 actual_read_len;
+	int length = 0;
+	u8 element_size = 0;
+	u8 *buf_offset;
+	int elem_offset = 0;
+	int rc;
+
+	if (*ppos)
+		goto exit;
+
+
+	mutex_lock(&dad->sysfs_lock);
+
+	pm_runtime_get_sync(dev);
+
+	rc = cmd->request_exclusive(dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on request exclusive r=%d\n",
+				__func__, rc);
+		goto put_pm_runtime;
+	}
+
+	rc = cyttsp5_suspend_scan_cmd_(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on suspend scan r=%d\n",
+				__func__, rc);
+		goto release_exclusive;
+	}
+
+	rc = cyttsp5_exec_scan_cmd_(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on execute panel scan r=%d\n",
+				__func__, rc);
+		goto resume_scan;
+	}
+
+	/* Set length to max to read all */
+	rc = cyttsp5_ret_scan_data_cmd_(dev, 0, 0xFFFF,
+			dad->panel_scan_data_id, dad->ic_buf, &config,
+			&actual_read_len, NULL);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on retrieve panel scan r=%d\n",
+				__func__, rc);
+		goto resume_scan;
+	}
+
+	length = get_unaligned_le16(&dad->ic_buf[0]);
+	buf_offset = dad->ic_buf + length;
+	element_size = config & 0x07;
+	elem_offset = actual_read_len;
+	while (actual_read_len > 0) {
+		rc = cyttsp5_ret_scan_data_cmd_(dev, elem_offset, 0xFFFF,
+				dad->panel_scan_data_id, NULL, &config,
+				&actual_read_len, buf_offset);
+		if (rc < 0)
+			goto resume_scan;
+
+		length += actual_read_len * element_size;
+		buf_offset = dad->ic_buf + length;
+		elem_offset += actual_read_len;
+	}
+	/* Reconstruct cmd header */
+	put_unaligned_le16(length, &dad->ic_buf[0]);
+	put_unaligned_le16(elem_offset, &dad->ic_buf[7]);
+
+	/* Do not print command header */
+	length -= 5;
+
+	status = STATUS_SUCCESS;
+
+resume_scan:
+	cyttsp5_resume_scan_cmd_(dev);
+
+release_exclusive:
+	cmd->release_exclusive(dev);
+
+put_pm_runtime:
+	pm_runtime_put(dev);
+
+	if (status == STATUS_FAIL)
+		length = 0;
+	if (cd->show_timestamp) {
+		int index = 0;
+
+		index += scnprintf(data->pr_buf, sizeof(data->pr_buf),
+			"[%u] ", jiffies_to_msecs(jiffies));
+		data->pr_buf_len = prepare_print_buffer(status,
+			&dad->ic_buf[5], length, &data->pr_buf[index],
+			sizeof(data->pr_buf)-index);
+	} else {
+		data->pr_buf_len = prepare_print_buffer(status,
+			&dad->ic_buf[5], length, data->pr_buf,
+			sizeof(data->pr_buf));
+	}
+
+	mutex_unlock(&dad->sysfs_lock);
+
+exit:
+	return simple_read_from_buffer(buf, count, ppos, data->pr_buf,
+			data->pr_buf_len);
+}
+
+static ssize_t panel_scan_debugfs_write(struct file *filp,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+	struct cyttsp5_device_access_data *dad = data->dad;
+	ssize_t length;
+	int rc = 0;
+
+	rc = simple_write_to_buffer(data->pr_buf, sizeof(data->pr_buf), ppos,
+			buf, count);
+	if (rc < 0)
+		return rc;
+
+	count = rc;
+
+	mutex_lock(&dad->sysfs_lock);
+
+	length = cyttsp5_ic_parse_input(dad->dev, data->pr_buf, count,
+			dad->ic_buf, CY_MAX_PRBUF_SIZE);
+
+	if (length != 1) {
+		dev_err(dad->dev, "%s: Malformed input\n", __func__);
+		rc = -EINVAL;
+		goto exit_unlock;
+	}
+
+	dad->panel_scan_data_id = dad->ic_buf[0];
+
+exit_unlock:
+	mutex_unlock(&dad->sysfs_lock);
+
+	if (rc)
+		return rc;
+
+	return count;
+}
+
+CY_DEBUGFS_FOPS(panel_scan, panel_scan_debugfs_read, panel_scan_debugfs_write);
+
+static ssize_t get_idac_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+	struct cyttsp5_device_access_data *dad = data->dad;
+	struct device *dev = dad->dev;
+	int status = STATUS_FAIL;
+	u8 cmd_status = 0;
+	u8 data_format = 0;
+	u16 act_length = 0;
+	int length = 0;
+	int rc;
+
+	if (*ppos)
+		goto exit;
+
+	mutex_lock(&dad->sysfs_lock);
+
+	pm_runtime_get_sync(dev);
+
+	rc = cmd->request_exclusive(dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on request exclusive r=%d\n",
+				__func__, rc);
+		goto put_pm_runtime;
+	}
+
+	rc = cyttsp5_suspend_scan_cmd_(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on suspend scan r=%d\n",
+				__func__, rc);
+		goto release_exclusive;
+	}
+
+	rc = cyttsp5_get_data_structure_cmd_(dev, 0, PIP_CMD_MAX_LENGTH,
+			dad->get_idac_data_id, &cmd_status, &data_format,
+			&act_length, &dad->ic_buf[5]);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on get data structure r=%d\n",
+				__func__, rc);
+		goto resume_scan;
+	}
+
+	dad->ic_buf[0] = cmd_status;
+	dad->ic_buf[1] = dad->get_idac_data_id;
+	dad->ic_buf[2] = LOW_BYTE(act_length);
+	dad->ic_buf[3] = HI_BYTE(act_length);
+	dad->ic_buf[4] = data_format;
+
+	length = 5 + act_length;
+
+	status = STATUS_SUCCESS;
+
+resume_scan:
+	cyttsp5_resume_scan_cmd_(dev);
+
+release_exclusive:
+	cmd->release_exclusive(dev);
+
+put_pm_runtime:
+	pm_runtime_put(dev);
+
+	if (status == STATUS_FAIL)
+		length = 0;
+
+	data->pr_buf_len = prepare_print_buffer(status, dad->ic_buf, length,
+			data->pr_buf, sizeof(data->pr_buf));
+
+	mutex_unlock(&dad->sysfs_lock);
+
+exit:
+	return simple_read_from_buffer(buf, count, ppos, data->pr_buf,
+			data->pr_buf_len);
+}
+
+static ssize_t get_idac_debugfs_write(struct file *filp,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+	struct cyttsp5_device_access_data *dad = data->dad;
+	ssize_t length;
+	int rc = 0;
+
+	rc = simple_write_to_buffer(data->pr_buf, sizeof(data->pr_buf), ppos,
+			buf, count);
+	if (rc < 0)
+		return rc;
+
+	count = rc;
+
+	mutex_lock(&dad->sysfs_lock);
+
+	length = cyttsp5_ic_parse_input(dad->dev, data->pr_buf, count,
+			dad->ic_buf, CY_MAX_PRBUF_SIZE);
+	if (length != 1) {
+		dev_err(dad->dev, "%s: Malformed input\n", __func__);
+		rc = -EINVAL;
+		goto exit_unlock;
+	}
+
+	dad->get_idac_data_id = dad->ic_buf[0];
+
+exit_unlock:
+	mutex_unlock(&dad->sysfs_lock);
+
+	if (rc)
+		return rc;
+
+	return count;
+}
+
+CY_DEBUGFS_FOPS(get_idac, get_idac_debugfs_read, get_idac_debugfs_write);
+
+static ssize_t calibrate_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+	struct cyttsp5_device_access_data *dad = data->dad;
+	struct device *dev = dad->dev;
+	int status = STATUS_FAIL;
+	int length = 0;
+	int rc;
+
+	if (*ppos)
+		goto exit;
+
+	mutex_lock(&dad->sysfs_lock);
+
+	pm_runtime_get_sync(dev);
+
+	rc = cmd->request_exclusive(dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on request exclusive r=%d\n",
+				__func__, rc);
+		goto put_pm_runtime;
+	}
+
+	rc = cyttsp5_suspend_scan_cmd_(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on suspend scan r=%d\n",
+				__func__, rc);
+		goto release_exclusive;
+	}
+
+	rc = _cyttsp5_calibrate_idacs_cmd(dev, dad->calibrate_sensing_mode,
+			&dad->ic_buf[0]);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on calibrate idacs r=%d\n",
+				__func__, rc);
+		goto resume_scan;
+	}
+
+	length = 1;
+
+	/* Check if baseline initialization is requested */
+	if (dad->calibrate_initialize_baselines) {
+		/* Perform baseline initialization for all modes */
+		rc = _cyttsp5_initialize_baselines_cmd(dev, CY_IB_SM_MUTCAP |
+				CY_IB_SM_SELFCAP | CY_IB_SM_BUTTON,
+				&dad->ic_buf[length]);
+		if (rc < 0) {
+			dev_err(dev, "%s: Error on initialize baselines r=%d\n",
+					__func__, rc);
+			goto resume_scan;
+		}
+
+		length++;
+	}
+
+	status = STATUS_SUCCESS;
+
+resume_scan:
+	cyttsp5_resume_scan_cmd_(dev);
+
+release_exclusive:
+	cmd->release_exclusive(dev);
+
+put_pm_runtime:
+	pm_runtime_put(dev);
+
+	if (status == STATUS_FAIL)
+		length = 0;
+
+	data->pr_buf_len = prepare_print_buffer(status, dad->ic_buf, length,
+			data->pr_buf, sizeof(data->pr_buf));
+
+	mutex_unlock(&dad->sysfs_lock);
+
+exit:
+	return simple_read_from_buffer(buf, count, ppos, data->pr_buf,
+			data->pr_buf_len);
+}
+
+static ssize_t calibrate_debugfs_write(struct file *filp,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+	struct cyttsp5_device_access_data *dad = data->dad;
+	ssize_t length;
+	int rc = 0;
+
+	rc = simple_write_to_buffer(data->pr_buf, sizeof(data->pr_buf), ppos,
+			buf, count);
+	if (rc < 0)
+		return rc;
+
+	count = rc;
+
+	mutex_lock(&dad->sysfs_lock);
+
+	length = cyttsp5_ic_parse_input(dad->dev, data->pr_buf, count,
+			dad->ic_buf, CY_MAX_PRBUF_SIZE);
+	if (length != 2) {
+		dev_err(dad->dev, "%s: Malformed input\n", __func__);
+		rc = -EINVAL;
+		goto exit_unlock;
+	}
+
+	dad->calibrate_sensing_mode = dad->ic_buf[0];
+	dad->calibrate_initialize_baselines = dad->ic_buf[1];
+
+exit_unlock:
+	mutex_unlock(&dad->sysfs_lock);
+
+	if (rc)
+		return rc;
+
+	return count;
+}
+
+CY_DEBUGFS_FOPS(calibrate, calibrate_debugfs_read, calibrate_debugfs_write);
+
+static ssize_t baseline_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+	struct cyttsp5_device_access_data *dad = data->dad;
+	struct device *dev = dad->dev;
+	int status = STATUS_FAIL;
+	int length = 0;
+	int rc;
+
+	if (*ppos)
+		goto exit;
+
+	mutex_lock(&dad->sysfs_lock);
+
+	pm_runtime_get_sync(dev);
+
+	rc = cmd->request_exclusive(dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on request exclusive r=%d\n",
+				__func__, rc);
+		goto put_pm_runtime;
+	}
+
+	rc = cyttsp5_suspend_scan_cmd_(dev);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on suspend scan r=%d\n",
+				__func__, rc);
+		goto release_exclusive;
+	}
+
+	rc = _cyttsp5_initialize_baselines_cmd(dev, dad->baseline_sensing_mode,
+			&dad->ic_buf[0]);
+	if (rc < 0) {
+		dev_err(dev, "%s: Error on initialize baselines r=%d\n",
+				__func__, rc);
+		goto resume_scan;
+	}
+
+	length = 1;
+
+	status = STATUS_SUCCESS;
+
+resume_scan:
+	cyttsp5_resume_scan_cmd_(dev);
+
+release_exclusive:
+	cmd->release_exclusive(dev);
+
+put_pm_runtime:
+	pm_runtime_put(dev);
+
+	if (status == STATUS_FAIL)
+		length = 0;
+
+	data->pr_buf_len = prepare_print_buffer(status, dad->ic_buf, length,
+			data->pr_buf, sizeof(data->pr_buf));
+
+	mutex_unlock(&dad->sysfs_lock);
+
+exit:
+	return simple_read_from_buffer(buf, count, ppos, data->pr_buf,
+			data->pr_buf_len);
+}
+
+static ssize_t baseline_debugfs_write(struct file *filp,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+	struct cyttsp5_device_access_data *dad = data->dad;
+	ssize_t length;
+	int rc = 0;
+
+	rc = simple_write_to_buffer(data->pr_buf, sizeof(data->pr_buf), ppos,
+			buf, count);
+	if (rc < 0)
+		return rc;
+
+	count = rc;
+
+	mutex_lock(&dad->sysfs_lock);
+
+	length = cyttsp5_ic_parse_input(dad->dev, buf, count, dad->ic_buf,
+			CY_MAX_PRBUF_SIZE);
+	if (length != 1) {
+		dev_err(dad->dev, "%s: Malformed input\n", __func__);
+		rc = -EINVAL;
+		goto exit_unlock;
+	}
+
+	dad->baseline_sensing_mode = dad->ic_buf[0];
+
+exit_unlock:
+	mutex_unlock(&dad->sysfs_lock);
+
+	if (rc)
+		return rc;
+
+	return count;
+}
+
+CY_DEBUGFS_FOPS(baseline, baseline_debugfs_read, baseline_debugfs_write);
+
+static ssize_t auto_shorts_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+
+	if (!*ppos)
+		/* Set length to PIP_CMD_MAX_LENGTH to read all */
+		data->pr_buf_len = cyttsp5_run_and_get_selftest_result(
+			data->dad->dev, data->pr_buf, sizeof(data->pr_buf),
+			CY_ST_ID_AUTOSHORTS, PIP_CMD_MAX_LENGTH, false);
+
+	return simple_read_from_buffer(buf, count, ppos, data->pr_buf,
+			data->pr_buf_len);
+}
+
+CY_DEBUGFS_FOPS(auto_shorts, auto_shorts_debugfs_read, NULL);
+
+static ssize_t opens_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+
+	if (!*ppos)
+		/* Set length to PIP_CMD_MAX_LENGTH to read all */
+		data->pr_buf_len = cyttsp5_run_and_get_selftest_result(
+			data->dad->dev, data->pr_buf, sizeof(data->pr_buf),
+			CY_ST_ID_OPENS, PIP_CMD_MAX_LENGTH, false);
+
+	return simple_read_from_buffer(buf, count, ppos, data->pr_buf,
+			data->pr_buf_len);
+}
+
+CY_DEBUGFS_FOPS(opens, opens_debugfs_read, NULL);
+
+static ssize_t cm_panel_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+
+	if (!*ppos)
+		/* Set length to PIP_CMD_MAX_LENGTH to read all */
+		data->pr_buf_len = cyttsp5_run_and_get_selftest_result(
+			data->dad->dev, data->pr_buf, sizeof(data->pr_buf),
+			CY_ST_ID_CM_PANEL, PIP_CMD_MAX_LENGTH, true);
+
+	return simple_read_from_buffer(buf, count, ppos, data->pr_buf,
+			data->pr_buf_len);
+}
+
+CY_DEBUGFS_FOPS(cm_panel, cm_panel_debugfs_read, NULL);
+
+static ssize_t cp_panel_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+
+	if (!*ppos)
+		/* Set length to PIP_CMD_MAX_LENGTH to read all */
+		data->pr_buf_len = cyttsp5_run_and_get_selftest_result(
+			data->dad->dev, data->pr_buf, sizeof(data->pr_buf),
+			CY_ST_ID_CP_PANEL, PIP_CMD_MAX_LENGTH, true);
+
+	return simple_read_from_buffer(buf, count, ppos, data->pr_buf,
+			data->pr_buf_len);
+}
+
+CY_DEBUGFS_FOPS(cp_panel, cp_panel_debugfs_read, NULL);
+
+static ssize_t cm_button_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+
+	if (!*ppos)
+		/* Set length to PIP_CMD_MAX_LENGTH to read all */
+		data->pr_buf_len = cyttsp5_run_and_get_selftest_result(
+			data->dad->dev, data->pr_buf, sizeof(data->pr_buf),
+			CY_ST_ID_CM_BUTTON, PIP_CMD_MAX_LENGTH, true);
+
+	return simple_read_from_buffer(buf, count, ppos, data->pr_buf,
+			data->pr_buf_len);
+}
+
+CY_DEBUGFS_FOPS(cm_button, cm_button_debugfs_read, NULL);
+
+static ssize_t cp_button_debugfs_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_debugfs_data *data = filp->private_data;
+
+	if (!*ppos)
+		/* Set length to PIP_CMD_MAX_LENGTH to read all */
+		data->pr_buf_len = cyttsp5_run_and_get_selftest_result(
+			data->dad->dev, data->pr_buf, sizeof(data->pr_buf),
+			CY_ST_ID_CP_BUTTON, PIP_CMD_MAX_LENGTH, true);
+
+	return simple_read_from_buffer(buf, count, ppos, data->pr_buf,
+			data->pr_buf_len);
+}
+
+CY_DEBUGFS_FOPS(cp_button, cp_button_debugfs_read, NULL);
+
+#ifdef TTHE_TUNER_SUPPORT
+static ssize_t tthe_get_panel_data_debugfs_read(struct file *filp,
+		char __user *buf, size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_data *dad = filp->private_data;
+	struct device *dev;
+	struct cyttsp5_core_data *cd;
+	u8 config;
+	u16 actual_read_len;
+	u16 length = 0;
+	u8 element_size = 0;
+	u8 *buf_offset;
+	u8 *buf_out;
+	int elem;
+	int elem_offset = 0;
+	int print_idx = 0;
+	int rc;
+	int rc1;
+	int i;
+
+	mutex_lock(&dad->debugfs_lock);
+	dev = dad->dev;
+	cd = dev_get_drvdata(dev);
+	buf_out = dad->tthe_get_panel_data_buf;
+	if (!buf_out)
+		goto release_mutex;
+
+	pm_runtime_get_sync(dev);
+
+	rc = cmd->request_exclusive(dev, CY_REQUEST_EXCLUSIVE_TIMEOUT);
+	if (rc < 0)
+		goto put_runtime;
+
+	if (dad->heatmap.scan_start) {
+		/*
+		 * To fix CDT206291: avoid multiple scans when
+		 * return data is larger than 4096 bytes in one cycle
+		 */
+		dad->heatmap.scan_start = 0;
+
+		/* Start scan */
+		rc = cyttsp5_exec_scan_cmd_(dev);
+		if (rc < 0)
+			goto release_exclusive;
+	}
+
+	elem = dad->heatmap.num_element;
+
+#if defined(CY_ENABLE_MAX_ELEN)
+	if (elem > CY_MAX_ELEN) {
+		rc = cyttsp5_ret_scan_data_cmd_(dev, elem_offset,
+		CY_MAX_ELEN, dad->heatmap.data_type, dad->ic_buf,
+		&config, &actual_read_len, NULL);
+	} else{
+		rc = cyttsp5_ret_scan_data_cmd_(dev, elem_offset, elem,
+			dad->heatmap.data_type, dad->ic_buf, &config,
+			&actual_read_len, NULL);
+	}
+#else
+	rc = cyttsp5_ret_scan_data_cmd_(dev, elem_offset, elem,
+			dad->heatmap.data_type, dad->ic_buf, &config,
+			&actual_read_len, NULL);
+#endif
+	if (rc < 0)
+		goto release_exclusive;
+
+	length = get_unaligned_le16(&dad->ic_buf[0]);
+	buf_offset = dad->ic_buf + length;
+
+	element_size = config & CY_CMD_RET_PANEL_ELMNT_SZ_MASK;
+
+	elem -= actual_read_len;
+	elem_offset = actual_read_len;
+	while (elem > 0) {
+#ifdef CY_ENABLE_MAX_ELEN
+		if (elem > CY_MAX_ELEN) {
+			rc = cyttsp5_ret_scan_data_cmd_(dev, elem_offset,
+			CY_MAX_ELEN, dad->heatmap.data_type, NULL, &config,
+			&actual_read_len, buf_offset);
+		} else{
+			rc = cyttsp5_ret_scan_data_cmd_(dev, elem_offset, elem,
+				dad->heatmap.data_type, NULL, &config,
+				&actual_read_len, buf_offset);
+		}
+#else
+
+		rc = cyttsp5_ret_scan_data_cmd_(dev, elem_offset, elem,
+				dad->heatmap.data_type, NULL, &config,
+				&actual_read_len, buf_offset);
+#endif
+		if (rc < 0)
+			goto release_exclusive;
+
+		if (!actual_read_len)
+			break;
+
+		length += actual_read_len * element_size;
+		buf_offset = dad->ic_buf + length;
+		elem -= actual_read_len;
+		elem_offset += actual_read_len;
+	}
+
+	/* Reconstruct cmd header */
+	put_unaligned_le16(length, &dad->ic_buf[0]);
+	put_unaligned_le16(elem_offset, &dad->ic_buf[7]);
+
+release_exclusive:
+	rc1 = cmd->release_exclusive(dev);
+put_runtime:
+	pm_runtime_put(dev);
+
+	if (rc < 0)
+		goto release_mutex;
+	if (cd->show_timestamp)
+		print_idx += scnprintf(buf_out, TTHE_TUNER_MAX_BUF,
+			"[%u] CY_DATA:", jiffies_to_msecs(jiffies));
+	else
+		print_idx += scnprintf(buf_out, TTHE_TUNER_MAX_BUF,
+			"CY_DATA:");
+	for (i = 0; i < length; i++)
+		print_idx += scnprintf(buf_out + print_idx,
+				TTHE_TUNER_MAX_BUF - print_idx,
+				"%02X ", dad->ic_buf[i]);
+	print_idx += scnprintf(buf_out + print_idx,
+			TTHE_TUNER_MAX_BUF - print_idx,
+			":(%d bytes)\n", length);
+	rc = simple_read_from_buffer(buf, count, ppos, buf_out, print_idx);
+	print_idx = rc;
+
+release_mutex:
+	mutex_unlock(&dad->debugfs_lock);
+	return print_idx;
+}
+
+static ssize_t tthe_get_panel_data_debugfs_write(struct file *filp,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct cyttsp5_device_access_data *dad = filp->private_data;
+	struct device *dev = dad->dev;
+	ssize_t length;
+	int max_read;
+	u8 *buf_in = dad->tthe_get_panel_data_buf;
+	int ret;
+
+	mutex_lock(&dad->debugfs_lock);
+	ret = copy_from_user(buf_in + (*ppos), buf, count);
+	if (ret)
+		goto exit;
+	buf_in[count] = 0;
+
+	length = cyttsp5_ic_parse_input(dev, buf_in, count, dad->ic_buf,
+			CY_MAX_PRBUF_SIZE);
+	if (length <= 0) {
+		dev_err(dev, "%s: %s Group Data store\n", __func__,
+				"Malformed input for");
+		goto exit;
+	}
+
+	/* update parameter value */
+	dad->heatmap.num_element = get_unaligned_le16(&dad->ic_buf[3]);
+	dad->heatmap.data_type = dad->ic_buf[5];
+
+	if (dad->ic_buf[6] > 0)
+		dad->heatmap.scan_start = true;
+	else
+		dad->heatmap.scan_start = false;
+
+	/* elem can not be bigger then buffer size */
+	max_read = CY_CMD_RET_PANEL_HDR;
+	max_read += dad->heatmap.num_element * CY_CMD_RET_PANEL_ELMNT_SZ_MAX;
+
+	if (max_read >= CY_MAX_PRBUF_SIZE) {
+		dad->heatmap.num_element =
+			(CY_MAX_PRBUF_SIZE - CY_CMD_RET_PANEL_HDR)
+			/ CY_CMD_RET_PANEL_ELMNT_SZ_MAX;
+		parade_debug(dev, DEBUG_LEVEL_2, "%s: Will get %d element\n",
+			__func__, dad->heatmap.num_element);
+	}
+
+exit:
+	mutex_unlock(&dad->debugfs_lock);
+	parade_debug(dev, DEBUG_LEVEL_2, "%s: return count=%zu\n",
+		__func__, count);
+	return count;
+}
+
+static int tthe_get_panel_data_debugfs_open(struct inode *inode,
+		struct file *filp)
+{
+	struct cyttsp5_device_access_data *dad = inode->i_private;
+
+	mutex_lock(&dad->debugfs_lock);
+
+	if (dad->tthe_get_panel_data_is_open) {
+		mutex_unlock(&dad->debugfs_lock);
+		return -EBUSY;
+	}
+
+	filp->private_data = inode->i_private;
+
+	dad->tthe_get_panel_data_is_open = 1;
+	mutex_unlock(&dad->debugfs_lock);
+	return 0;
+}
+
+static int tthe_get_panel_data_debugfs_close(struct inode *inode,
+		struct file *filp)
+{
+	struct cyttsp5_device_access_data *dad = filp->private_data;
+
+	mutex_lock(&dad->debugfs_lock);
+	filp->private_data = NULL;
+	dad->tthe_get_panel_data_is_open = 0;
+	mutex_unlock(&dad->debugfs_lock);
+
+	return 0;
+}
+
+static const struct file_operations tthe_get_panel_data_fops = {
+	.open = tthe_get_panel_data_debugfs_open,
+	.release = tthe_get_panel_data_debugfs_close,
+	.read = tthe_get_panel_data_debugfs_read,
+	.write = tthe_get_panel_data_debugfs_write,
+};
+#endif
+
+static int cyttsp5_setup_sysfs(struct device *dev)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	int rc;
+
+	rc = device_create_file(dev, &dev_attr_command);
+	if (rc) {
+		dev_err(dev, "%s: Error, could not create command\n",
+				__func__);
+		goto exit;
+	}
+
+	rc = device_create_file(dev, &dev_attr_status);
+	if (rc) {
+		dev_err(dev, "%s: Error, could not create status\n",
+				__func__);
+		goto unregister_command;
+	}
+
+	rc = device_create_file(dev, &dev_attr_response);
+	if (rc) {
+		dev_err(dev, "%s: Error, could not create response\n",
+				__func__);
+		goto unregister_status;
+	}
+
+	dad->base_dentry = debugfs_create_dir(dev_name(dev), NULL);
+	if (IS_ERR_OR_NULL(dad->base_dentry)) {
+		dev_err(dev, "%s: Error, could not create base directory\n",
+				__func__);
+		goto unregister_response;
+	}
+
+	dad->mfg_test_dentry = debugfs_create_dir("mfg_test",
+			dad->base_dentry);
+	if (IS_ERR_OR_NULL(dad->mfg_test_dentry)) {
+		dev_err(dev, "%s: Error, could not create mfg_test directory\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("panel_scan", 0600,
+			dad->mfg_test_dentry, dad,
+			&panel_scan_debugfs_fops))) {
+		dev_err(dev, "%s: Error, could not create panel_scan\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("get_idac", 0600,
+			dad->mfg_test_dentry, dad, &get_idac_debugfs_fops))) {
+		dev_err(dev, "%s: Error, could not create get_idac\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("auto_shorts", 0444,
+			dad->mfg_test_dentry, dad,
+			&auto_shorts_debugfs_fops))) {
+		dev_err(dev, "%s: Error, could not create auto_shorts\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("opens", 0444,
+			dad->mfg_test_dentry, dad, &opens_debugfs_fops))) {
+		dev_err(dev, "%s: Error, could not create opens\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("calibrate", 0600,
+			dad->mfg_test_dentry, dad, &calibrate_debugfs_fops))) {
+		dev_err(dev, "%s: Error, could not create calibrate\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("baseline", 0600,
+			dad->mfg_test_dentry, dad, &baseline_debugfs_fops))) {
+		dev_err(dev, "%s: Error, could not create baseline\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("cm_panel", 0400,
+			dad->mfg_test_dentry, dad, &cm_panel_debugfs_fops))) {
+		dev_err(dev, "%s: Error, could not create cm_panel\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("cp_panel", 0400,
+			dad->mfg_test_dentry, dad, &cp_panel_debugfs_fops))) {
+		dev_err(dev, "%s: Error, could not create cp_panel\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("cm_button", 0400,
+			dad->mfg_test_dentry, dad, &cm_button_debugfs_fops))) {
+		dev_err(dev, "%s: Error, could not create cm_button\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("cp_button", 0400,
+			dad->mfg_test_dentry, dad, &cp_button_debugfs_fops))) {
+		dev_err(dev, "%s: Error, could not create cp_button\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	dad->cmcp_results_debugfs = debugfs_create_file("cmcp_results", 0644,
+		dad->mfg_test_dentry, dad, &cmcp_results_debugfs_fops);
+	if (IS_ERR_OR_NULL(dad->cmcp_results_debugfs)) {
+		dev_err(dev, "%s: Error, could not create cmcp_results\n",
+				__func__);
+		dad->cmcp_results_debugfs = NULL;
+		goto unregister_base_dir;
+	}
+
+#ifdef TTHE_TUNER_SUPPORT
+	dad->tthe_get_panel_data_debugfs = debugfs_create_file(
+			CYTTSP5_TTHE_TUNER_GET_PANEL_DATA_FILE_NAME,
+			0644, NULL, dad, &tthe_get_panel_data_fops);
+	if (IS_ERR_OR_NULL(dad->tthe_get_panel_data_debugfs)) {
+		dev_err(dev, "%s: Error, could not create get_panel_data\n",
+				__func__);
+		dad->tthe_get_panel_data_debugfs = NULL;
+		goto unregister_base_dir;
+	}
+#endif
+
+	rc = device_create_file(dev, &dev_attr_cmcp_test);
+	if (rc) {
+		dev_err(dev, "%s: Error, could not create cmcp_test\n",
+				__func__);
+		goto unregister_base_dir;
+	}
+
+	rc = device_create_file(dev, &dev_attr_cmcp_threshold_loading);
+	if (rc) {
+		dev_err(dev, "%s: Error, could not create cmcp_thresold_loading\n",
+				__func__);
+		goto unregister_cmcp_test;
+	}
+
+	rc = device_create_bin_file(dev, &bin_attr_cmcp_threshold_data);
+	if (rc) {
+		dev_err(dev, "%s: Error, could not create cmcp_thresold_data\n",
+				__func__);
+		goto unregister_cmcp_thresold_loading;
+	}
+
+	dad->sysfs_nodes_created = true;
+	return rc;
+
+unregister_cmcp_thresold_loading:
+	device_remove_file(dev, &dev_attr_cmcp_threshold_loading);
+unregister_cmcp_test:
+	device_remove_file(dev, &dev_attr_cmcp_test);
+unregister_base_dir:
+	debugfs_remove_recursive(dad->base_dentry);
+unregister_response:
+	device_remove_file(dev, &dev_attr_response);
+unregister_status:
+	device_remove_file(dev, &dev_attr_status);
+unregister_command:
+	device_remove_file(dev, &dev_attr_command);
+exit:
+	return rc;
+}
+
+static int cyttsp5_setup_sysfs_attention(struct device *dev)
+{
+	struct cyttsp5_device_access_data *dad
+		= cyttsp5_get_device_access_data(dev);
+	int rc = 0;
+
+	dad->si = cmd->request_sysinfo(dev);
+	if (!dad->si)
+		return -EINVAL;
+
+	rc = cyttsp5_setup_sysfs(dev);
+
+	cmd->unsubscribe_attention(dev, CY_ATTEN_STARTUP,
+		CYTTSP5_DEVICE_ACCESS_NAME, cyttsp5_setup_sysfs_attention,
+		0);
+
+	return rc;
+}
+
+#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS_API
+int cyttsp5_device_access_user_command(const char *core_name, u16 read_len,
+		u8 *read_buf, u16 write_len, u8 *write_buf,
+		u16 *actual_read_len)
+{
+	struct cyttsp5_core_data *cd;
+	int rc;
+
+	might_sleep();
+
+	/* Check parameters */
+	if (!read_buf || !write_buf || !actual_read_len)
+		return -EINVAL;
+
+	if (!core_name)
+		core_name = CY_DEFAULT_CORE_ID;
+
+	/* Find device */
+	cd = cyttsp5_get_core_data((char *)core_name);
+	if (!cd) {
+		pr_err("%s: No device.\n", __func__);
+		return -ENODEV;
+	}
+
+	pm_runtime_get_sync(cd->dev);
+	rc = cmd->nonhid_cmd->user_cmd(cd->dev, 1, read_len, read_buf,
+			write_len, write_buf, actual_read_len);
+	pm_runtime_put(cd->dev);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(cyttsp5_device_access_user_command);
+
+struct command_work {
+	struct work_struct work;
+	const char *core_name;
+	u16 read_len;
+	u8 *read_buf;
+	u16 write_len;
+	u8 *write_buf;
+
+	void (*cont)(const char *core_name, u16 read_len, u8 *read_buf,
+		u16 write_len, u8 *write_buf, u16 actual_read_length,
+		int rc);
+};
+
+static void cyttsp5_device_access_user_command_work_func(
+		struct work_struct *work)
+{
+	struct command_work *cmd_work =
+			container_of(work, struct command_work, work);
+	u16 actual_read_length;
+	int rc;
+
+	rc = cyttsp5_device_access_user_command(cmd_work->core_name,
+			cmd_work->read_len, cmd_work->read_buf,
+			cmd_work->write_len, cmd_work->write_buf,
+			&actual_read_length);
+
+	if (cmd_work->cont)
+		cmd_work->cont(cmd_work->core_name,
+			cmd_work->read_len, cmd_work->read_buf,
+			cmd_work->write_len, cmd_work->write_buf,
+			actual_read_length, rc);
+
+	kfree(cmd_work);
+}
+
+int cyttsp5_device_access_user_command_async(const char *core_name,
+		u16 read_len, u8 *read_buf, u16 write_len, u8 *write_buf,
+		void (*cont)(const char *core_name, u16 read_len, u8 *read_buf,
+			u16 write_len, u8 *write_buf, u16 actual_read_length,
+			int rc))
+{
+	struct command_work *cmd_work;
+
+	cmd_work = kzalloc(sizeof(*cmd_work), GFP_ATOMIC);
+	if (!cmd_work)
+		return -ENOMEM;
+
+	cmd_work->core_name = core_name;
+	cmd_work->read_len = read_len;
+	cmd_work->read_buf = read_buf;
+	cmd_work->write_len = write_len;
+	cmd_work->write_buf = write_buf;
+	cmd_work->cont = cont;
+
+	INIT_WORK(&cmd_work->work,
+			cyttsp5_device_access_user_command_work_func);
+	schedule_work(&cmd_work->work);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cyttsp5_device_access_user_command_async);
+#endif
+
+static void cyttsp5_cmcp_parse_threshold_file(const struct firmware *fw,
+		void *context)
+{
+	struct device *dev = context;
+	struct cyttsp5_device_access_data *dad =
+		cyttsp5_get_device_access_data(dev);
+
+	if (!fw) {
+		dev_info(dev, "%s: No builtin cmcp threshold file\n", __func__);
+		goto exit;
+	}
+
+	if (!fw->data || !fw->size) {
+		dev_err(dev, "%s: Invalid builtin cmcp threshold file\n",
+		__func__);
+		goto exit;
+	}
+
+	parade_debug(dev, DEBUG_LEVEL_1, "%s: Found cmcp threshold file.\n",
+		__func__);
+
+	cyttsp5_parse_cmcp_threshold_file_common(dev, &fw->data[0], fw->size);
+
+	dad->builtin_cmcp_threshold_status = 0;
+	complete(&dad->builtin_cmcp_threshold_complete);
+	return;
+
+exit:
+	release_firmware(fw);
+
+	dad->builtin_cmcp_threshold_status = -EINVAL;
+	complete(&dad->builtin_cmcp_threshold_complete);
+}
+
+static void cyttsp5_parse_cmcp_threshold_builtin(
+	struct work_struct *cmcp_threshold_update)
+{
+	struct cyttsp5_device_access_data *dad =
+		container_of(cmcp_threshold_update,
+		struct cyttsp5_device_access_data,
+		cmcp_threshold_update);
+	struct device *dev = dad->dev;
+	int retval;
+
+	dad->si = cmd->request_sysinfo(dev);
+	if (!dad->si) {
+		dev_err(dev, "%s: Fail get sysinfo pointer from core\n",
+			__func__);
+		return;
+	}
+
+	parade_debug(dev, DEBUG_LEVEL_2,
+		"%s: Enabling cmcp threshold class loader built-in\n",
+		__func__);
+
+	/* Open threshold file */
+	retval = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+			CMCP_THRESHOLD_FILE_NAME, dev, GFP_KERNEL, dev,
+			cyttsp5_cmcp_parse_threshold_file);
+	if (retval < 0) {
+		dev_err(dev, "%s: Failed loading cmcp threshold file, attempting legacy file\n",
+			__func__);
+		/* Try legacy file name */
+		retval = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+				CY_CMCP_THRESHOLD_FILE_NAME, dev, GFP_KERNEL,
+				dev, cyttsp5_cmcp_parse_threshold_file);
+		if (retval < 0) {
+			dev_err(dev, "%s: Fail request cmcp threshold class file load\n",
+				__func__);
+			goto exit;
+		}
+	}
+
+	/* wait until cmcp threshold upgrade finishes */
+	wait_for_completion(&dad->builtin_cmcp_threshold_complete);
+
+	retval = dad->builtin_cmcp_threshold_status;
+
+exit:
+	return;
+}
+
+static int cyttsp5_device_access_probe(struct device *dev, void **data)
+{
+	struct cyttsp5_device_access_data *dad;
+	struct configuration *configurations;
+	struct cmcp_data *cmcp_info;
+	struct result *result;
+
+	int tx_num = MAX_TX_SENSORS;
+	int rx_num = MAX_RX_SENSORS;
+	int btn_num = MAX_BUTTONS;
+
+	struct test_case_field *test_case_field_array;
+	struct test_case_search *test_case_search_array;
+	int rc = 0;
+
+	dad = kzalloc(sizeof(*dad), GFP_KERNEL);
+	if (!dad) {
+		rc = -ENOMEM;
+		goto cyttsp5_device_access_probe_data_failed;
+	}
+
+	configurations =
+		kzalloc(sizeof(*configurations), GFP_KERNEL);
+	if (!configurations) {
+		rc = -ENOMEM;
+		goto cyttsp5_device_access_probe_configs_failed;
+	}
+	dad->configs = configurations;
+
+	cmcp_info = kzalloc(sizeof(*cmcp_info), GFP_KERNEL);
+	if (!cmcp_info) {
+		rc = -ENOMEM;
+		goto cyttsp5_device_access_probe_cmcp_info_failed;
+	}
+	dad->cmcp_info = cmcp_info;
+
+	cmcp_info->tx_num = tx_num;
+	cmcp_info->rx_num = rx_num;
+	cmcp_info->btn_num = btn_num;
+
+	result = kzalloc(sizeof(*result), GFP_KERNEL);
+	if (!result) {
+		rc = -ENOMEM;
+		goto cyttsp5_device_access_probe_result_failed;
+	}
+	dad->result = result;
+
+	test_case_field_array =
+		kzalloc(sizeof(*test_case_field_array) * MAX_CASE_NUM,
+		GFP_KERNEL);
+	if (!test_case_field_array) {
+		rc = -ENOMEM;
+		goto cyttsp5_device_access_probe_field_array_failed;
+	}
+
+	test_case_search_array =
+		kzalloc(sizeof(*test_case_search_array) * MAX_CASE_NUM,
+		GFP_KERNEL);
+	if (!test_case_search_array) {
+		rc = -ENOMEM;
+		goto cyttsp5_device_access_probe_search_array_failed;
+	}
+
+	cmcp_info->gd_sensor_col = (struct gd_sensor *)
+		 kzalloc(tx_num * sizeof(struct gd_sensor), GFP_KERNEL);
+	if (cmcp_info->gd_sensor_col == NULL)
+		goto cyttsp5_device_access_probe_gd_sensor_col_failed;
+
+	cmcp_info->gd_sensor_row = (struct gd_sensor *)
+		 kzalloc(rx_num * sizeof(struct gd_sensor), GFP_KERNEL);
+	if (cmcp_info->gd_sensor_row == NULL)
+		goto cyttsp5_device_access_probe_gd_sensor_row_failed;
+
+	cmcp_info->cm_data_panel =
+		 kzalloc((tx_num * rx_num + 1) * sizeof(int32_t), GFP_KERNEL);
+	if (cmcp_info->cm_data_panel == NULL)
+		goto cyttsp5_device_access_probe_cm_data_panel_failed;
+
+	cmcp_info->cp_tx_data_panel =
+		kzalloc(tx_num * sizeof(int32_t), GFP_KERNEL);
+	if (cmcp_info->cp_tx_data_panel == NULL)
+		goto cyttsp5_device_access_probe_cp_tx_data_panel_failed;
+
+	cmcp_info->cp_tx_cal_data_panel =
+		kzalloc(tx_num * sizeof(int32_t), GFP_KERNEL);
+	if (cmcp_info->cp_tx_cal_data_panel == NULL)
+		goto cyttsp5_device_access_probe_cp_tx_cal_data_panel_failed;
+
+	cmcp_info->cp_rx_data_panel =
+		 kzalloc(rx_num * sizeof(int32_t), GFP_KERNEL);
+	if (cmcp_info->cp_rx_data_panel == NULL)
+		goto cyttsp5_device_access_probe_cp_rx_data_panel_failed;
+
+	cmcp_info->cp_rx_cal_data_panel =
+		 kzalloc(rx_num * sizeof(int32_t), GFP_KERNEL);
+	if (cmcp_info->cp_rx_cal_data_panel == NULL)
+		goto cyttsp5_device_access_probe_cp_rx_cal_data_panel_failed;
+
+	cmcp_info->cm_btn_data = kcalloc(btn_num, sizeof(int32_t), GFP_KERNEL);
+	if (cmcp_info->cm_btn_data == NULL)
+		goto cyttsp5_device_access_probe_cm_btn_data_failed;
+
+	cmcp_info->cp_btn_data = kcalloc(btn_num, sizeof(int32_t), GFP_KERNEL);
+	if (cmcp_info->cp_btn_data == NULL)
+		goto cyttsp5_device_access_probe_cp_btn_data_failed;
+
+	cmcp_info->cm_sensor_column_delta =
+		 kzalloc(rx_num * tx_num * sizeof(int32_t), GFP_KERNEL);
+	if (cmcp_info->cm_sensor_column_delta == NULL)
+		goto cyttsp5_device_access_probe_cm_sensor_column_delta_failed;
+
+	cmcp_info->cm_sensor_row_delta =
+		 kzalloc(tx_num * rx_num  * sizeof(int32_t), GFP_KERNEL);
+	if (cmcp_info->cm_sensor_row_delta == NULL)
+		goto cyttsp5_device_access_probe_cm_sensor_row_delta_failed;
+
+	mutex_init(&dad->sysfs_lock);
+	mutex_init(&dad->cmcp_threshold_lock);
+	dad->dev = dev;
+#ifdef TTHE_TUNER_SUPPORT
+	mutex_init(&dad->debugfs_lock);
+	dad->heatmap.num_element = 200;
+#endif
+	*data = dad;
+
+	dad->test_field_array = test_case_field_array;
+	dad->test_search_array = test_case_search_array;
+	dad->test_executed = 0;
+
+	init_completion(&dad->builtin_cmcp_threshold_complete);
+
+	/* get sysinfo */
+	dad->si = cmd->request_sysinfo(dev);
+	if (dad->si) {
+		rc = cyttsp5_setup_sysfs(dev);
+		if (rc)
+			goto cyttsp5_device_access_setup_sysfs_failed;
+	} else {
+		dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
+				__func__, dad->si);
+		cmd->subscribe_attention(dev, CY_ATTEN_STARTUP,
+			CYTTSP5_DEVICE_ACCESS_NAME,
+			cyttsp5_setup_sysfs_attention, 0);
+	}
+
+	INIT_WORK(&dad->cmcp_threshold_update,
+		cyttsp5_parse_cmcp_threshold_builtin);
+	schedule_work(&dad->cmcp_threshold_update);
+
+	return 0;
+
+cyttsp5_device_access_setup_sysfs_failed:
+	kfree(cmcp_info->cm_sensor_row_delta);
+cyttsp5_device_access_probe_cm_sensor_row_delta_failed:
+	kfree(cmcp_info->cm_sensor_column_delta);
+cyttsp5_device_access_probe_cm_sensor_column_delta_failed:
+	kfree(cmcp_info->cp_btn_data);
+cyttsp5_device_access_probe_cp_btn_data_failed:
+	kfree(cmcp_info->cm_btn_data);
+cyttsp5_device_access_probe_cm_btn_data_failed:
+	kfree(cmcp_info->cp_rx_cal_data_panel);
+cyttsp5_device_access_probe_cp_rx_cal_data_panel_failed:
+	kfree(cmcp_info->cp_rx_data_panel);
+cyttsp5_device_access_probe_cp_rx_data_panel_failed:
+	kfree(cmcp_info->cp_tx_cal_data_panel);
+cyttsp5_device_access_probe_cp_tx_cal_data_panel_failed:
+	kfree(cmcp_info->cp_tx_data_panel);
+cyttsp5_device_access_probe_cp_tx_data_panel_failed:
+	kfree(cmcp_info->cm_data_panel);
+cyttsp5_device_access_probe_cm_data_panel_failed:
+	kfree(cmcp_info->gd_sensor_row);
+cyttsp5_device_access_probe_gd_sensor_row_failed:
+	kfree(cmcp_info->gd_sensor_col);
+cyttsp5_device_access_probe_gd_sensor_col_failed:
+	kfree(test_case_search_array);
+cyttsp5_device_access_probe_search_array_failed:
+	kfree(test_case_field_array);
+cyttsp5_device_access_probe_field_array_failed:
+	kfree(result);
+cyttsp5_device_access_probe_result_failed:
+	kfree(cmcp_info);
+cyttsp5_device_access_probe_cmcp_info_failed:
+	kfree(configurations);
+cyttsp5_device_access_probe_configs_failed:
+	kfree(dad);
+cyttsp5_device_access_probe_data_failed:
+	dev_err(dev, "%s failed.\n", __func__);
+	return rc;
+}
+
+static void cyttsp5_device_access_release(struct device *dev, void *data)
+{
+	struct cyttsp5_device_access_data *dad = data;
+
+	if (dad->sysfs_nodes_created) {
+		device_remove_file(dev, &dev_attr_command);
+		device_remove_file(dev, &dev_attr_status);
+		device_remove_file(dev, &dev_attr_response);
+		debugfs_remove(dad->cmcp_results_debugfs);
+		debugfs_remove_recursive(dad->base_dentry);
+#ifdef TTHE_TUNER_SUPPORT
+		debugfs_remove(dad->tthe_get_panel_data_debugfs);
+#endif
+		device_remove_file(dev, &dev_attr_cmcp_test);
+		device_remove_file(dev, &dev_attr_cmcp_threshold_loading);
+		device_remove_bin_file(dev, &bin_attr_cmcp_threshold_data);
+		kfree(dad->cmcp_threshold_data);
+	} else {
+		cmd->unsubscribe_attention(dev, CY_ATTEN_STARTUP,
+			CYTTSP5_DEVICE_ACCESS_NAME,
+			cyttsp5_setup_sysfs_attention, 0);
+	}
+
+	kfree(dad->test_search_array);
+	kfree(dad->test_field_array);
+	kfree(dad->configs);
+	cyttsp5_free_cmcp_buf(dad->cmcp_info);
+	kfree(dad->cmcp_info);
+	kfree(dad->result);
+	kfree(dad);
+}
+
+static struct cyttsp5_module device_access_module = {
+	.name = CYTTSP5_DEVICE_ACCESS_NAME,
+	.probe = cyttsp5_device_access_probe,
+	.release = cyttsp5_device_access_release,
+};
+
+static int __init cyttsp5_device_access_init(void)
+{
+	int rc;
+
+	cmd = cyttsp5_get_commands();
+	if (!cmd)
+		return -EINVAL;
+
+	rc = cyttsp5_register_module(&device_access_module);
+	if (rc < 0) {
+		pr_err("%s: Error, failed registering module\n",
+			__func__);
+			return rc;
+	}
+
+	pr_info("%s: Parade TTSP Device Access Driver (Built %s) rc=%d\n",
+		 __func__, CY_DRIVER_VERSION, rc);
+	return 0;
+}
+module_init(cyttsp5_device_access_init);
+
+static void __exit cyttsp5_device_access_exit(void)
+{
+	cyttsp5_unregister_module(&device_access_module);
+}
+module_exit(cyttsp5_device_access_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Device Access Driver");
+MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");
+
diff --git a/tp/cyttsp5/cyttsp5_devtree.c b/tp/cyttsp5/cyttsp5_devtree.c
new file mode 100644
index 0000000..afb0d08
--- /dev/null
+++ b/tp/cyttsp5/cyttsp5_devtree.c
@@ -0,0 +1,747 @@
+/*
+ * cyttsp5_devtree.c
+ * Parade TrueTouch(TM) Standard Product V5 Device Tree Support Module.
+ * For use with Parade touchscreen controllers.
+ * Supported parts include:
+ * CYTMA5XX
+ * CYTMA448
+ * CYTMA445A
+ * CYTT21XXX
+ * CYTT31XXX
+ *
+ * Copyright (C) 2015 Parade Technologies
+ * Copyright (C) 2013-2015 Cypress Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+
+/* cyttsp */
+#include "cyttsp5_regs.h"
+#include "cyttsp5_platform.h"
+
+#define ENABLE_VIRTUAL_KEYS
+
+#define MAX_NAME_LENGTH		64
+
+enum cyttsp5_device_type {
+	DEVICE_MT,
+	DEVICE_BTN,
+	DEVICE_PROXIMITY,
+	DEVICE_TYPE_MAX,
+};
+
+struct cyttsp5_device_pdata_func {
+	void * (*create_and_get_pdata)(struct device_node *);
+	void (*free_pdata)(void *);
+};
+
+struct cyttsp5_pdata_ptr {
+	void **pdata;
+};
+
+#ifdef ENABLE_VIRTUAL_KEYS
+static struct kobject *board_properties_kobj;
+
+struct cyttsp5_virtual_keys {
+	struct kobj_attribute kobj_attr;
+	u16 *data;
+	int size;
+};
+#endif
+
+struct cyttsp5_extended_mt_platform_data {
+	struct cyttsp5_mt_platform_data pdata;
+#ifdef ENABLE_VIRTUAL_KEYS
+	struct cyttsp5_virtual_keys vkeys;
+#endif
+};
+
+static inline int get_inp_dev_name(struct device_node *dev_node,
+		const char **inp_dev_name)
+{
+	return of_property_read_string(dev_node, "cy,inp_dev_name",
+			inp_dev_name);
+}
+
+static s16 *create_and_get_u16_array(struct device_node *dev_node,
+		const char *name, int *size)
+{
+	const __be32 *values;
+	s16 *val_array;
+	int len;
+	int sz;
+	int rc;
+	int i;
+
+	values = of_get_property(dev_node, name, &len);
+	if (values == NULL)
+		return NULL;
+
+	sz = len / sizeof(u32);
+	pr_debug("%s: %s size:%d\n", __func__, name, sz);
+
+	val_array = kcalloc(sz, sizeof(s16), GFP_KERNEL);
+	if (!val_array) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	for (i = 0; i < sz; i++)
+		val_array[i] = (s16)be32_to_cpup(values++);
+
+	*size = sz;
+
+	return val_array;
+
+fail:
+	return ERR_PTR(rc);
+}
+
+static struct touch_framework *create_and_get_touch_framework(
+		struct device_node *dev_node)
+{
+	struct touch_framework *frmwrk;
+	s16 *abs;
+	int size;
+	int rc;
+
+	abs = create_and_get_u16_array(dev_node, "cy,abs", &size);
+	if (IS_ERR_OR_NULL(abs))
+		return (void *)abs;
+
+	/* Check for valid abs size */
+	if (size % CY_NUM_ABS_SET) {
+		rc = -EINVAL;
+		goto fail_free_abs;
+	}
+
+	frmwrk = kzalloc(sizeof(*frmwrk), GFP_KERNEL);
+	if (!frmwrk) {
+		rc = -ENOMEM;
+		goto fail_free_abs;
+	}
+
+	frmwrk->abs = abs;
+	frmwrk->size = size;
+
+	return frmwrk;
+
+fail_free_abs:
+	kfree(abs);
+
+	return ERR_PTR(rc);
+}
+
+static void free_touch_framework(struct touch_framework *frmwrk)
+{
+	kfree(frmwrk->abs);
+	kfree(frmwrk);
+}
+
+#ifdef ENABLE_VIRTUAL_KEYS
+#define VIRTUAL_KEY_ELEMENT_SIZE	5
+static ssize_t virtual_keys_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	struct cyttsp5_virtual_keys *vkeys = container_of(attr,
+		struct cyttsp5_virtual_keys, kobj_attr);
+	u16 *data = vkeys->data;
+	int size = vkeys->size;
+	int index;
+	int i;
+
+	index = 0;
+	for (i = 0; i < size; i += VIRTUAL_KEY_ELEMENT_SIZE)
+		index += scnprintf(buf + index, CY_MAX_PRBUF_SIZE - index,
+			"0x01:%d:%d:%d:%d:%d\n",
+			data[i], data[i+1], data[i+2], data[i+3], data[i+4]);
+
+	return index;
+}
+
+static int setup_virtual_keys(struct device_node *dev_node,
+		const char *inp_dev_name, struct cyttsp5_virtual_keys *vkeys)
+{
+	char *name;
+	u16 *data;
+	int size;
+	int rc;
+
+	data = create_and_get_u16_array(dev_node, "cy,virtual_keys", &size);
+	if (data == NULL)
+		return 0;
+	else if (IS_ERR(data)) {
+		rc = PTR_ERR(data);
+		goto fail;
+	}
+
+	/* Check for valid virtual keys size */
+	if (size % VIRTUAL_KEY_ELEMENT_SIZE) {
+		rc = -EINVAL;
+		goto fail_free_data;
+	}
+
+	name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL);
+	if (!name) {
+		rc = -ENOMEM;
+		goto fail_free_data;
+	}
+
+	snprintf(name, MAX_NAME_LENGTH, "virtualkeys.%s", inp_dev_name);
+
+	vkeys->data = data;
+	vkeys->size = size;
+
+	/* TODO: Instantiate in board file and export it */
+	if (board_properties_kobj == NULL)
+		board_properties_kobj =
+			kobject_create_and_add("board_properties", NULL);
+	if (board_properties_kobj == NULL) {
+		pr_err("%s: Cannot get board_properties kobject!\n", __func__);
+		rc = -EINVAL;
+		goto fail_free_name;
+	}
+
+	/* Initialize dynamic SysFs attribute */
+	sysfs_attr_init(&vkeys->kobj_attr.attr);
+	vkeys->kobj_attr.attr.name = name;
+	vkeys->kobj_attr.attr.mode = S_IRUGO;
+	vkeys->kobj_attr.show = virtual_keys_show;
+
+	rc = sysfs_create_file(board_properties_kobj, &vkeys->kobj_attr.attr);
+	if (rc)
+		goto fail_del_kobj;
+
+	return 0;
+
+fail_del_kobj:
+	kobject_del(board_properties_kobj);
+fail_free_name:
+	kfree(name);
+	vkeys->kobj_attr.attr.name = NULL;
+fail_free_data:
+	kfree(data);
+	vkeys->data = NULL;
+fail:
+	return rc;
+}
+
+static void free_virtual_keys(struct cyttsp5_virtual_keys *vkeys)
+{
+	if (board_properties_kobj)
+		sysfs_remove_file(board_properties_kobj,
+			&vkeys->kobj_attr.attr);
+
+
+	kobject_del(board_properties_kobj);
+	board_properties_kobj = NULL;
+
+	kfree(vkeys->data);
+	kfree(vkeys->kobj_attr.attr.name);
+}
+#endif
+
+static void *create_and_get_mt_pdata(struct device_node *dev_node)
+{
+	struct cyttsp5_extended_mt_platform_data *ext_pdata;
+	struct cyttsp5_mt_platform_data *pdata;
+	u32 value;
+	int rc;
+
+	ext_pdata = kzalloc(sizeof(*ext_pdata), GFP_KERNEL);
+	if (!ext_pdata) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	pdata = &ext_pdata->pdata;
+
+	rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
+	if (rc)
+		goto fail_free_pdata;
+
+	/* Optional fields */
+	rc = of_property_read_u32(dev_node, "cy,flags", &value);
+	if (!rc)
+		pdata->flags = value;
+
+	rc = of_property_read_u32(dev_node, "cy,vkeys_x", &value);
+	if (!rc)
+		pdata->vkeys_x = value;
+
+	rc = of_property_read_u32(dev_node, "cy,vkeys_y", &value);
+	if (!rc)
+		pdata->vkeys_y = value;
+
+	/* Required fields */
+	pdata->frmwrk = create_and_get_touch_framework(dev_node);
+	if (pdata->frmwrk == NULL) {
+		rc = -EINVAL;
+		goto fail_free_pdata;
+	} else if (IS_ERR(pdata->frmwrk)) {
+		rc = PTR_ERR(pdata->frmwrk);
+		goto fail_free_pdata;
+	}
+#ifdef ENABLE_VIRTUAL_KEYS
+	rc = setup_virtual_keys(dev_node, pdata->inp_dev_name,
+			&ext_pdata->vkeys);
+	if (rc) {
+		pr_err("%s: Cannot setup virtual keys!\n", __func__);
+		goto fail_free_pdata;
+	}
+#endif
+	return pdata;
+
+fail_free_pdata:
+	kfree(ext_pdata);
+fail:
+	return ERR_PTR(rc);
+}
+
+static void free_mt_pdata(void *pdata)
+{
+	struct cyttsp5_mt_platform_data *mt_pdata =
+		(struct cyttsp5_mt_platform_data *)pdata;
+	struct cyttsp5_extended_mt_platform_data *ext_mt_pdata =
+		container_of(mt_pdata,
+			struct cyttsp5_extended_mt_platform_data, pdata);
+
+	free_touch_framework(mt_pdata->frmwrk);
+#ifdef ENABLE_VIRTUAL_KEYS
+	free_virtual_keys(&ext_mt_pdata->vkeys);
+#endif
+	kfree(ext_mt_pdata);
+}
+
+static void *create_and_get_btn_pdata(struct device_node *dev_node)
+{
+	struct cyttsp5_btn_platform_data *pdata;
+	int rc;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
+	if (rc)
+		goto fail_free_pdata;
+
+	return pdata;
+
+fail_free_pdata:
+	kfree(pdata);
+fail:
+	return ERR_PTR(rc);
+}
+
+static void free_btn_pdata(void *pdata)
+{
+	struct cyttsp5_btn_platform_data *btn_pdata =
+		(struct cyttsp5_btn_platform_data *)pdata;
+
+	kfree(btn_pdata);
+}
+
+static void *create_and_get_proximity_pdata(struct device_node *dev_node)
+{
+	struct cyttsp5_proximity_platform_data *pdata;
+	int rc;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
+	if (rc)
+		goto fail_free_pdata;
+
+	pdata->frmwrk = create_and_get_touch_framework(dev_node);
+	if (pdata->frmwrk == NULL) {
+		rc = -EINVAL;
+		goto fail_free_pdata;
+	} else if (IS_ERR(pdata->frmwrk)) {
+		rc = PTR_ERR(pdata->frmwrk);
+		goto fail_free_pdata;
+	}
+
+	return pdata;
+
+fail_free_pdata:
+	kfree(pdata);
+fail:
+	return ERR_PTR(rc);
+}
+
+static void free_proximity_pdata(void *pdata)
+{
+	struct cyttsp5_proximity_platform_data *proximity_pdata =
+		(struct cyttsp5_proximity_platform_data *)pdata;
+
+	free_touch_framework(proximity_pdata->frmwrk);
+
+	kfree(proximity_pdata);
+}
+
+static struct cyttsp5_device_pdata_func device_pdata_funcs[DEVICE_TYPE_MAX] = {
+	[DEVICE_MT] = {
+		.create_and_get_pdata = create_and_get_mt_pdata,
+		.free_pdata = free_mt_pdata,
+	},
+	[DEVICE_BTN] = {
+		.create_and_get_pdata = create_and_get_btn_pdata,
+		.free_pdata = free_btn_pdata,
+	},
+	[DEVICE_PROXIMITY] = {
+		.create_and_get_pdata = create_and_get_proximity_pdata,
+		.free_pdata = free_proximity_pdata,
+	},
+};
+
+static struct cyttsp5_pdata_ptr pdata_ptr[DEVICE_TYPE_MAX];
+
+static const char *device_names[DEVICE_TYPE_MAX] = {
+	[DEVICE_MT] = "cy,mt",
+	[DEVICE_BTN] = "cy,btn",
+	[DEVICE_PROXIMITY] = "cy,proximity",
+};
+
+static void set_pdata_ptr(struct cyttsp5_platform_data *pdata)
+{
+	pdata_ptr[DEVICE_MT].pdata = (void **)&pdata->mt_pdata;
+	pdata_ptr[DEVICE_BTN].pdata = (void **)&pdata->btn_pdata;
+	pdata_ptr[DEVICE_PROXIMITY].pdata = (void **)&pdata->prox_pdata;
+}
+
+static int get_device_type(struct device_node *dev_node,
+		enum cyttsp5_device_type *type)
+{
+	const char *name;
+	enum cyttsp5_device_type t;
+	int rc;
+
+	rc = of_property_read_string(dev_node, "name", &name);
+	if (rc)
+		return rc;
+
+	for (t = 0; t < DEVICE_TYPE_MAX; t++)
+		if (!strncmp(name, device_names[t], MAX_NAME_LENGTH)) {
+			*type = t;
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+static inline void *create_and_get_device_pdata(struct device_node *dev_node,
+		enum cyttsp5_device_type type)
+{
+	return device_pdata_funcs[type].create_and_get_pdata(dev_node);
+}
+
+static inline void free_device_pdata(enum cyttsp5_device_type type)
+{
+	device_pdata_funcs[type].free_pdata(*pdata_ptr[type].pdata);
+}
+
+static struct touch_settings *create_and_get_touch_setting(
+		struct device_node *core_node, const char *name)
+{
+	struct touch_settings *setting;
+	char *tag_name;
+	u32 tag_value;
+	u16 *data;
+	int size;
+	int rc;
+
+	data = create_and_get_u16_array(core_node, name, &size);
+	if (IS_ERR_OR_NULL(data))
+		return (void *)data;
+
+	pr_debug("%s: Touch setting:'%s' size:%d\n", __func__, name, size);
+
+	setting = kzalloc(sizeof(*setting), GFP_KERNEL);
+	if (!setting) {
+		rc = -ENOMEM;
+		goto fail_free_data;
+	}
+
+	setting->data = (u8 *)data;
+	setting->size = size;
+
+	tag_name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL);
+	if (!tag_name) {
+		rc = -ENOMEM;
+		goto fail_free_setting;
+	}
+
+	snprintf(tag_name, MAX_NAME_LENGTH, "%s-tag", name);
+
+	rc = of_property_read_u32(core_node, tag_name, &tag_value);
+	if (!rc)
+		setting->tag = tag_value;
+
+	kfree(tag_name);
+
+	return setting;
+
+fail_free_setting:
+	kfree(setting);
+fail_free_data:
+	kfree(data);
+
+	return ERR_PTR(rc);
+}
+
+static void free_touch_setting(struct touch_settings *setting)
+{
+	if (setting) {
+		kfree(setting->data);
+		kfree(setting);
+	}
+}
+
+static char *touch_setting_names[CY_IC_GRPNUM_NUM] = {
+	NULL,			/* CY_IC_GRPNUM_RESERVED */
+	"cy,cmd_regs",		/* CY_IC_GRPNUM_CMD_REGS */
+	"cy,tch_rep",		/* CY_IC_GRPNUM_TCH_REP */
+	"cy,data_rec",		/* CY_IC_GRPNUM_DATA_REC */
+	"cy,test_rec",		/* CY_IC_GRPNUM_TEST_REC */
+	"cy,pcfg_rec",		/* CY_IC_GRPNUM_PCFG_REC */
+	"cy,tch_parm_val",	/* CY_IC_GRPNUM_TCH_PARM_VAL */
+	"cy,tch_parm_size",	/* CY_IC_GRPNUM_TCH_PARM_SIZE */
+	NULL,			/* CY_IC_GRPNUM_RESERVED1 */
+	NULL,			/* CY_IC_GRPNUM_RESERVED2 */
+	"cy,opcfg_rec",		/* CY_IC_GRPNUM_OPCFG_REC */
+	"cy,ddata_rec",		/* CY_IC_GRPNUM_DDATA_REC */
+	"cy,mdata_rec",		/* CY_IC_GRPNUM_MDATA_REC */
+	"cy,test_regs",		/* CY_IC_GRPNUM_TEST_REGS */
+	"cy,btn_keys",		/* CY_IC_GRPNUM_BTN_KEYS */
+	NULL,			/* CY_IC_GRPNUM_TTHE_REGS */
+};
+
+static struct cyttsp5_core_platform_data *create_and_get_core_pdata(
+		struct device_node *core_node)
+{
+	struct cyttsp5_core_platform_data *pdata;
+	u32 value;
+	int rc;
+	int i;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	/* Required fields */
+	rc = of_property_read_u32(core_node, "cy,irq_gpio", &value);
+	if (rc)
+		goto fail_free;
+	pdata->irq_gpio = value;
+
+	rc = of_property_read_u32(core_node, "cy,hid_desc_register", &value);
+	if (rc)
+		goto fail_free;
+	pdata->hid_desc_register = value;
+
+	/* Optional fields */
+	/* rst_gpio is optional since a platform may use
+	 * power cycling instead of using the XRES pin
+	 */
+	rc = of_property_read_u32(core_node, "cy,rst_gpio", &value);
+	if (!rc)
+		pdata->rst_gpio = value;
+
+	rc = of_property_read_u32(core_node, "cy,level_irq_udelay", &value);
+	if (!rc)
+		pdata->level_irq_udelay = value;
+
+	rc = of_property_read_u32(core_node, "cy,vendor_id", &value);
+	if (!rc)
+		pdata->vendor_id = value;
+
+	rc = of_property_read_u32(core_node, "cy,product_id", &value);
+	if (!rc)
+		pdata->product_id = value;
+
+	rc = of_property_read_u32(core_node, "cy,flags", &value);
+	if (!rc)
+		pdata->flags = value;
+
+	rc = of_property_read_u32(core_node, "cy,easy_wakeup_gesture", &value);
+	if (!rc)
+		pdata->easy_wakeup_gesture = (u8)value;
+
+	for (i = 0; (unsigned int)i < ARRAY_SIZE(touch_setting_names); i++) {
+		if (touch_setting_names[i] == NULL)
+			continue;
+
+		pdata->sett[i] = create_and_get_touch_setting(core_node,
+				touch_setting_names[i]);
+		if (IS_ERR(pdata->sett[i])) {
+			rc = PTR_ERR(pdata->sett[i]);
+			goto fail_free_sett;
+		} else if (pdata->sett[i] == NULL)
+			pr_debug("%s: No data for setting '%s'\n", __func__,
+				touch_setting_names[i]);
+	}
+
+	pr_debug("%s: irq_gpio:%d rst_gpio:%d\n"
+		"hid_desc_register:%d level_irq_udelay:%d vendor_id:%d product_id:%d\n"
+		"flags:%d easy_wakeup_gesture:%d\n", __func__,
+		pdata->irq_gpio, pdata->rst_gpio,
+		pdata->hid_desc_register,
+		pdata->level_irq_udelay, pdata->vendor_id, pdata->product_id,
+		pdata->flags, pdata->easy_wakeup_gesture);
+
+	pdata->xres = cyttsp5_xres;
+	pdata->init = cyttsp5_init;
+	pdata->power = cyttsp5_power;
+	pdata->detect = cyttsp5_detect;
+	pdata->irq_stat = cyttsp5_irq_stat;
+
+	return pdata;
+
+fail_free_sett:
+	for (i--; i >= 0; i--)
+		free_touch_setting(pdata->sett[i]);
+fail_free:
+	kfree(pdata);
+fail:
+	return ERR_PTR(rc);
+}
+
+static void free_core_pdata(void *pdata)
+{
+	struct cyttsp5_core_platform_data *core_pdata = pdata;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(touch_setting_names); i++)
+		free_touch_setting(core_pdata->sett[i]);
+	kfree(core_pdata);
+}
+
+int cyttsp5_devtree_create_and_get_pdata(struct device *adap_dev)
+{
+	struct cyttsp5_platform_data *pdata;
+	struct device_node *core_node, *dev_node, *dev_node_fail;
+	enum cyttsp5_device_type type;
+	int count = 0;
+	int rc = 0;
+
+	if (!adap_dev->of_node)
+		return 0;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	adap_dev->platform_data = pdata;
+	set_pdata_ptr(pdata);
+
+	/* There should be only one core node */
+	for_each_child_of_node(adap_dev->of_node, core_node) {
+		const char *name;
+
+		rc = of_property_read_string(core_node, "name", &name);
+		if (!rc)
+			pr_debug("%s: name:%s\n", __func__, name);
+
+		pdata->core_pdata = create_and_get_core_pdata(core_node);
+		if (IS_ERR(pdata->core_pdata)) {
+			rc = PTR_ERR(pdata->core_pdata);
+			break;
+		}
+
+		/* Increment reference count */
+		of_node_get(core_node);
+
+		for_each_child_of_node(core_node, dev_node) {
+			count++;
+			rc = get_device_type(dev_node, &type);
+			if (rc)
+				break;
+			*pdata_ptr[type].pdata
+				= create_and_get_device_pdata(dev_node, type);
+			if (IS_ERR(*pdata_ptr[type].pdata))
+				rc = PTR_ERR(*pdata_ptr[type].pdata);
+			if (rc)
+				break;
+			/* Increment reference count */
+			of_node_get(dev_node);
+		}
+
+		if (rc) {
+			free_core_pdata(pdata->core_pdata);
+			of_node_put(core_node);
+			for_each_child_of_node(core_node, dev_node_fail) {
+				if (dev_node == dev_node_fail)
+					break;
+				rc = get_device_type(dev_node, &type);
+				if (rc)
+					break;
+				free_device_pdata(type);
+				of_node_put(dev_node);
+			}
+			break;
+		}
+		pdata->loader_pdata = NULL; /*change &_cyttsp5_loader_platform_data; lihongshuai*/
+	}
+
+	pr_debug("%s: %d child node(s) found\n", __func__, count);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(cyttsp5_devtree_create_and_get_pdata);
+
+int cyttsp5_devtree_clean_pdata(struct device *adap_dev)
+{
+	struct cyttsp5_platform_data *pdata;
+	struct device_node *core_node, *dev_node;
+	enum cyttsp5_device_type type;
+	int rc = 0;
+
+	if (!adap_dev->of_node)
+		return 0;
+
+	pdata = dev_get_platdata(adap_dev);
+	set_pdata_ptr(pdata);
+	for_each_child_of_node(adap_dev->of_node, core_node) {
+		free_core_pdata(pdata->core_pdata);
+		of_node_put(core_node);
+		for_each_child_of_node(core_node, dev_node) {
+			rc = get_device_type(dev_node, &type);
+			if (rc)
+				break;
+			free_device_pdata(type);
+			of_node_put(dev_node);
+		}
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(cyttsp5_devtree_clean_pdata);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product DeviceTree Driver");
+MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");
diff --git a/tp/cyttsp5/cyttsp5_i2c.c b/tp/cyttsp5/cyttsp5_i2c.c
new file mode 100644
index 0000000..7f12671
--- /dev/null
+++ b/tp/cyttsp5/cyttsp5_i2c.c
@@ -0,0 +1,223 @@
+/*
+ * cyttsp5_i2c.c
+ * Parade TrueTouch(TM) Standard Product V5 I2C Module.
+ * For use with Parade touchscreen controllers.
+ * Supported parts include:
+ * CYTMA5XX
+ * CYTMA448
+ * CYTMA445A
+ * CYTT21XXX
+ * CYTT31XXX
+ *
+ * Copyright (C) 2015 Parade Technologies
+ * Copyright (C) 2012-2015 Cypress Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
+ *
+ */
+
+#include "cyttsp5_regs.h"
+
+#include <linux/i2c.h>
+#include <linux/version.h>
+
+#define CY_I2C_DATA_SIZE  (2 * 256)
+
+static int cyttsp5_i2c_read_default(struct device *dev, void *buf, int size)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int rc;
+
+	if (!buf || !size || size > CY_I2C_DATA_SIZE)
+		return -EINVAL;
+
+	rc = i2c_master_recv(client, buf, size);
+
+	return (rc < 0) ? rc : rc != size ? -EIO : 0;
+}
+
+static int cyttsp5_i2c_read_default_nosize(struct device *dev, u8 *buf, u32 max)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct i2c_msg msgs[2];
+	u8 msg_count = 1;
+	int rc;
+	u32 size;
+
+	if (!buf)
+		return -EINVAL;
+
+	msgs[0].addr = client->addr;
+	msgs[0].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
+	msgs[0].len = 2;
+	msgs[0].buf = buf;
+	rc = i2c_transfer(client->adapter, msgs, msg_count);
+	if (rc < 0 || rc != msg_count)
+		return (rc < 0) ? rc : -EIO;
+
+	size = get_unaligned_le16(&buf[0]);
+	if (!size || size == 2 || size >= CY_PIP_1P7_EMPTY_BUF)
+		/*
+		 * Before PIP 1.7, empty buffer is 0x0002;
+		 * From PIP 1.7, empty buffer is 0xFFXX
+		 */
+		return 0;
+
+	if (size > max)
+		return -EINVAL;
+
+	rc = i2c_master_recv(client, buf, size);
+
+	return (rc < 0) ? rc : rc != (int)size ? -EIO : 0;
+}
+
+static int cyttsp5_i2c_write_read_specific(struct device *dev, u8 write_len,
+		u8 *write_buf, u8 *read_buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct i2c_msg msgs[2];
+	u8 msg_count = 1;
+	int rc;
+
+	if (!write_buf || !write_len)
+		return -EINVAL;
+
+	msgs[0].addr = client->addr;
+	msgs[0].flags = client->flags & I2C_M_TEN;
+	msgs[0].len = write_len;
+	msgs[0].buf = write_buf;
+	rc = i2c_transfer(client->adapter, msgs, msg_count);
+
+	if (rc < 0 || rc != msg_count)
+		return (rc < 0) ? rc : -EIO;
+
+	rc = 0;
+
+	if (read_buf)
+		rc = cyttsp5_i2c_read_default_nosize(dev, read_buf,
+				CY_I2C_DATA_SIZE);
+
+	return rc;
+}
+
+static struct cyttsp5_bus_ops cyttsp5_i2c_bus_ops = {
+	.bustype = BUS_I2C,
+	.read_default = cyttsp5_i2c_read_default,
+	.read_default_nosize = cyttsp5_i2c_read_default_nosize,
+	.write_read_specific = cyttsp5_i2c_write_read_specific,
+};
+
+#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
+static const struct of_device_id cyttsp5_i2c_of_match[] = {
+	{ .compatible = "cy,cyttsp5_i2c_adapter", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cyttsp5_i2c_of_match);
+#endif
+
+static int cyttsp5_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *i2c_id)
+{
+	struct device *dev = &client->dev;
+#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
+	const struct of_device_id *match;
+#endif
+	int rc;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(dev, "I2C functionality not Supported\n");
+		return -EIO;
+	}
+
+#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
+	match = of_match_device(of_match_ptr(cyttsp5_i2c_of_match), dev);
+	if (match) {
+		rc = cyttsp5_devtree_create_and_get_pdata(dev);
+		if (rc < 0)
+			return rc;
+	}
+#endif
+
+	rc = cyttsp5_probe(&cyttsp5_i2c_bus_ops, &client->dev, client->irq,
+			  CY_I2C_DATA_SIZE);
+
+#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
+	if (rc && match)
+		cyttsp5_devtree_clean_pdata(dev);
+#endif
+
+	return rc;
+}
+
+static int cyttsp5_i2c_remove(struct i2c_client *client)
+{
+#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
+	struct device *dev = &client->dev;
+	const struct of_device_id *match;
+#endif
+	struct cyttsp5_core_data *cd = i2c_get_clientdata(client);
+
+	cyttsp5_release(cd);
+
+#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
+	match = of_match_device(of_match_ptr(cyttsp5_i2c_of_match), dev);
+	if (match)
+		cyttsp5_devtree_clean_pdata(dev);
+#endif
+
+	return 0;
+}
+
+static const struct i2c_device_id cyttsp5_i2c_id[] = {
+	{ CYTTSP5_I2C_NAME, 0, },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id);
+
+static struct i2c_driver cyttsp5_i2c_driver = {
+	.driver = {
+		.name = CYTTSP5_I2C_NAME,
+		.owner = THIS_MODULE,
+		.pm = &cyttsp5_pm_ops,
+#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
+		.of_match_table = cyttsp5_i2c_of_match,
+#endif
+	},
+	.probe = cyttsp5_i2c_probe,
+	.remove = cyttsp5_i2c_remove,
+	.id_table = cyttsp5_i2c_id,
+};
+
+#if (KERNEL_VERSION(3, 3, 0) <= LINUX_VERSION_CODE)
+module_i2c_driver(cyttsp5_i2c_driver);
+#else
+static int __init cyttsp5_i2c_init(void)
+{
+	int rc = i2c_add_driver(&cyttsp5_i2c_driver);
+
+	pr_info("%s: Parade TTSP I2C Driver (Built %s) rc=%d\n",
+			__func__, CY_DRIVER_VERSION, rc);
+	return rc;
+}
+module_init(cyttsp5_i2c_init);
+
+static void __exit cyttsp5_i2c_exit(void)
+{
+	i2c_del_driver(&cyttsp5_i2c_driver);
+}
+module_exit(cyttsp5_i2c_exit);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product I2C driver");
+MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");
diff --git a/tp/cyttsp5/cyttsp5_img_1.h b/tp/cyttsp5/cyttsp5_img_1.h
new file mode 100644
index 0000000..b5e0f15
--- /dev/null
+++ b/tp/cyttsp5/cyttsp5_img_1.h
@@ -0,0 +1,4067 @@
+/* Touchscreen contents */

+static u8 cyttsp4_ver_1[] = {

+	0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x65, 0xE9, 0x0B, 0x21, 0x12, 0x9B, 0x00, 0x70

+};

+

+static u8 cyttsp4_img_1[] = {

+	0x00, 0x00, 0x32, 0x00, 0x80, 0x00, 0x30, 0x00, 0x20, 0xB9, 0x19, 0x00, 0x00, 0x15, 0xDC, 0x00, 

+	0x00, 0x15, 0xDC, 0x00, 0x00, 0x00, 0xF0, 0x02, 0xF8, 0x00, 0xF0, 0x40, 0xF8, 0x0C, 0xA0, 0x30, 

+	0xC8, 0x08, 0x38, 0x24, 0x18, 0x2D, 0x18, 0xA2, 0x46, 0x67, 0x1E, 0xAB, 0x46, 0x54, 0x46, 0x5D, 

+	0x46, 0xAC, 0x42, 0x01, 0xD1, 0x00, 0xF0, 0x32, 0xF8, 0x7E, 0x46, 0x0F, 0x3E, 0x0F, 0xCC, 0xB6, 

+	0x46, 0x01, 0x26, 0x33, 0x42, 0x00, 0xD0, 0xFB, 0x1A, 0xA2, 0x46, 0xAB, 0x46, 0x33, 0x43, 0x18, 

+	0x47, 0x50, 0xD0, 0x00, 0x00, 0x80, 0xD0, 0x00, 0x00, 0x10, 0x3A, 0x02, 0xD3, 0x78, 0xC8, 0x78, 

+	0xC1, 0xFA, 0xD8, 0x52, 0x07, 0x01, 0xD3, 0x30, 0xC8, 0x30, 0xC1, 0x01, 0xD5, 0x04, 0x68, 0x0C, 

+	0x60, 0x70, 0x47, 0x00, 0x00, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x10, 0x3A, 0x01, 

+	0xD3, 0x78, 0xC1, 0xFB, 0xD8, 

+	0x00, 0x00, 0x33, 0x00, 0x80, 0x52, 0x07, 0x00, 0xD3, 0x30, 0xC1, 0x00, 0xD5, 0x0B, 0x60, 0x70, 

+	0x47, 0x1F, 0xB5, 0xC0, 0x46, 0xC0, 0x46, 0x1F, 0xBD, 0x10, 0xB5, 0x10, 0xBD, 0x03, 0x48, 0x85, 

+	0x46, 0xFF, 0xF7, 0xF6, 0xFF, 0x0C, 0xF0, 0x39, 0xF9, 0x0C, 0xF0, 0x1F, 0xFD, 0x00, 0x30, 0x00, 

+	0x20, 0x03, 0xB4, 0xFF, 0xF7, 0xF1, 0xFF, 0x03, 0xBC, 0x0C, 0xF0, 0x1E, 0xFD, 0x01, 0x4B, 0x9D, 

+	0x46, 0x01, 0x48, 0x00, 0x47, 0x00, 0x30, 0x00, 0x20, 0x11, 0x19, 0x00, 0x00, 0x70, 0xB5, 0x05, 

+	0x46, 0x0C, 0x46, 0x16, 0x46, 0x02, 0xE0, 0x0F, 0xCC, 0x0F, 0xC5, 0x10, 0x3E, 0x10, 0x2E, 0xFA, 

+	0xD2, 0x08, 0x2E, 0x02, 0xD3, 0x03, 0xCC, 0x03, 0xC5, 0x08, 0x3E, 0x04, 0x2E, 0x07, 0xD3, 0x01, 

+	0xCC, 0x01, 0xC5, 0x36, 0x1F, 0x03, 0xE0, 0x21, 0x78, 0x29, 0x70, 0x64, 0x1C, 0x6D, 0x1C, 0x76, 

+	0x1E, 0xF9, 0xD2, 0x70, 0xBD, 

+	0x00, 0x00, 0x34, 0x00, 0x80, 0x02, 0x48, 0x09, 0xF0, 0x9A, 0xFF, 0x09, 0xF0, 0x3A, 0xFE, 0xFC, 

+	0xE7, 0x68, 0xE5, 0x00, 0x00, 0xC0, 0x20, 0x80, 0x7B, 0x81, 0x07, 0x07, 0xD0, 0x80, 0x07, 0x80, 

+	0x0F, 0x01, 0x28, 0x05, 0xD0, 0x02, 0x28, 0x00, 0xD0, 0x03, 0x20, 0x70, 0x47, 0x04, 0x20, 0x70, 

+	0x47, 0x05, 0x20, 0x70, 0x47, 0x07, 0x49, 0x0A, 0x88, 0x02, 0x42, 0x03, 0xD0, 0x48, 0x68, 0x00, 

+	0x28, 0x00, 0xD0, 0x00, 0x47, 0x70, 0x47, 0x03, 0x49, 0x08, 0x80, 0x70, 0x47, 0x01, 0x49, 0x48, 

+	0x60, 0x70, 0x47, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x20, 0xBC, 0x49, 0x00, 0x20, 0xC8, 0x70, 0x70, 

+	0x47, 0xBA, 0x49, 0x48, 0x61, 0x70, 0x47, 0xF8, 0xB5, 0x0D, 0x46, 0xB9, 0x49, 0x02, 0x46, 0x48, 

+	0x7B, 0xB8, 0x4B, 0x40, 0x00, 0xB5, 0x4C, 0xC3, 0x18, 0xE3, 0x61, 0xB6, 0x4B, 0xE2, 0x60, 0x48, 

+	0x33, 0x65, 0x61, 0xC0, 0x18, 

+	0x00, 0x00, 0x35, 0x00, 0x80, 0x22, 0x61, 0x20, 0x62, 0x18, 0x46, 0xAC, 0x38, 0x4A, 0x7B, 0x02, 

+	0x73, 0x0A, 0x7B, 0x06, 0x46, 0x42, 0x73, 0x00, 0x27, 0x60, 0x36, 0xF7, 0x70, 0x09, 0x7B, 0x81, 

+	0x73, 0x00, 0xF0, 0x22, 0xFA, 0x03, 0xF0, 0x24, 0xFC, 0x02, 0xF0, 0x26, 0xFE, 0x04, 0xF0, 0x86, 

+	0xF8, 0x60, 0x79, 0x00, 0x28, 0x10, 0xD1, 0x01, 0xF0, 0xEE, 0xFD, 0x00, 0x28, 0x04, 0xD0, 0x04, 

+	0xF0, 0x2E, 0xFB, 0x00, 0x28, 0x03, 0xD0, 0x05, 0xE0, 0x5F, 0x20, 0x02, 0xF0, 0x0A, 0xF9, 0x28, 

+	0x46, 0x04, 0xF0, 0xEC, 0xFA, 0x01, 0x20, 0x60, 0x71, 0x5F, 0x20, 0x02, 0xF0, 0x45, 0xFE, 0x01, 

+	0x20, 0xE0, 0x71, 0x27, 0x71, 0x0B, 0xF0, 0xD4, 0xFE, 0x65, 0x61, 0xA0, 0x61, 0xB7, 0x70, 0x04, 

+	0xF0, 0x9D, 0xFA, 0x01, 0x20, 0xA0, 0x71, 0xE7, 0x70, 0xF8, 0xBD, 0xF8, 0xB5, 0x05, 0x46, 0x96, 

+	0x48, 0x16, 0x46, 0x0F, 0x46, 

+	0x00, 0x00, 0x36, 0x00, 0x80, 0x04, 0x78, 0x0B, 0xF0, 0xC3, 0xFE, 0x92, 0x49, 0x32, 0x46, 0x64, 

+	0x39, 0x8E, 0x4E, 0x08, 0x60, 0xF2, 0x60, 0xB0, 0x79, 0x00, 0x28, 0x02, 0xD0, 0x03, 0xF0, 0x8D, 

+	0xF9, 0x05, 0x43, 0xF8, 0xB2, 0x30, 0x70, 0x00, 0x2C, 0x02, 0xD0, 0xA0, 0x42, 0x00, 0xD0, 0x34, 

+	0x70, 0x30, 0x78, 0x86, 0x49, 0x40, 0x00, 0x24, 0x31, 0x09, 0x5C, 0x28, 0x46, 0x01, 0xF0, 0x20, 

+	0xF9, 0x01, 0x20, 0xB0, 0x70, 0xF8, 0xBD, 0x10, 0xB5, 0x84, 0x49, 0x00, 0x20, 0x08, 0x56, 0x01, 

+	0x21, 0x48, 0x40, 0x0C, 0xD0, 0x01, 0xF0, 0x69, 0xFA, 0x00, 0x28, 0x08, 0xD0, 0x01, 0xF0, 0x83, 

+	0xF9, 0x00, 0x28, 0x05, 0xD0, 0x01, 0xF0, 0x3D, 0xF9, 0x00, 0x28, 0x06, 0xD1, 0x01, 0xE0, 0x01, 

+	0x20, 0x10, 0xBD, 0x01, 0xF0, 0x57, 0xF9, 0x00, 0x28, 0xFA, 0xD0, 0x02, 0x20, 0x10, 0xBD, 0x70, 

+	0xB5, 0x72, 0x4C, 0xA0, 0x78, 

+	0x00, 0x00, 0x37, 0x00, 0x80, 0x00, 0x28, 0x11, 0xD0, 0x00, 0x21, 0x75, 0x48, 0x0B, 0xF0, 0x9F, 

+	0xFF, 0x00, 0x26, 0xA6, 0x70, 0xE0, 0x68, 0x73, 0x4D, 0x20, 0x61, 0x28, 0x88, 0x60, 0x81, 0x20, 

+	0x78, 0x60, 0x70, 0xFF, 0xF7, 0xD0, 0xFF, 0x00, 0x28, 0x01, 0xD0, 0xE6, 0x70, 0x70, 0xBD, 0x01, 

+	0x20, 0xE0, 0x70, 0x6D, 0x48, 0x40, 0x78, 0x01, 0x28, 0xF8, 0xD1, 0x28, 0x78, 0x40, 0x07, 0xF5, 

+	0xD5, 0x20, 0x78, 0x04, 0xF0, 0x95, 0xF9, 0xE0, 0x70, 0x70, 0xBD, 0x60, 0x49, 0x03, 0x20, 0x08, 

+	0x56, 0x70, 0x47, 0x70, 0xB5, 0x5D, 0x4C, 0x04, 0x20, 0x02, 0x21, 0x20, 0x56, 0x61, 0x56, 0x88, 

+	0x43, 0x11, 0xD0, 0x5D, 0x48, 0x00, 0x78, 0x00, 0x28, 0x0D, 0xD1, 0x5A, 0x48, 0x00, 0x25, 0x25, 

+	0x71, 0x24, 0x38, 0x00, 0x7F, 0x01, 0x28, 0x07, 0xD0, 0x55, 0x48, 0x04, 0x21, 0x40, 0x7F, 0x08, 

+	0x43, 0x02, 0xF0, 0xB2, 0xFD, 

+	0x00, 0x00, 0x38, 0x00, 0x80, 0xE5, 0x70, 0x70, 0xBD, 0x07, 0x20, 0xF9, 0xE7, 0xF8, 0xB5, 0x4F, 

+	0x4C, 0x01, 0x78, 0x21, 0x72, 0x40, 0x78, 0x60, 0x72, 0x00, 0x25, 0xE5, 0x70, 0x60, 0x78, 0x26, 

+	0x46, 0x40, 0x00, 0x24, 0x36, 0x80, 0x19, 0x40, 0x78, 0x61, 0x89, 0x03, 0xF0, 0xE5, 0xFD, 0x03, 

+	0xF0, 0x2C, 0xF9, 0x07, 0x46, 0x60, 0x78, 0x61, 0x89, 0x40, 0x00, 0x80, 0x19, 0x40, 0x78, 0x03, 

+	0xF0, 0xB9, 0xF8, 0x21, 0x79, 0x07, 0x20, 0x20, 0x56, 0x39, 0x43, 0x01, 0x40, 0x21, 0x71, 0x00, 

+	0x28, 0x08, 0xD0, 0x0B, 0xF0, 0x1D, 0xFE, 0xA1, 0x69, 0x46, 0x1A, 0x03, 0xF0, 0x1A, 0xF9, 0x86, 

+	0x42, 0x00, 0xD9, 0xE5, 0x71, 0x60, 0x89, 0x41, 0x07, 0x01, 0xD5, 0x03, 0xF0, 0x3F, 0xFE, 0x39, 

+	0x48, 0x61, 0x78, 0x24, 0x38, 0x81, 0x80, 0x61, 0x89, 0xC1, 0x80, 0x40, 0x38, 0xF8, 0xBD, 0x10, 

+	0xB5, 0x0F, 0x22, 0x0A, 0x80, 

+	0x00, 0x00, 0x39, 0x00, 0x80, 0x01, 0xF0, 0xF6, 0xF8, 0x10, 0xBD, 0x10, 0xB5, 0x03, 0x29, 0x03, 

+	0xD8, 0x02, 0xF0, 0xDA, 0xFA, 0x01, 0x20, 0x10, 0xBD, 0x00, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x02, 

+	0xF0, 0x74, 0xF8, 0x10, 0xBD, 0x70, 0xB5, 0x29, 0x4C, 0x0D, 0x46, 0xE1, 0x60, 0x06, 0x46, 0x21, 

+	0x61, 0x02, 0xF0, 0x17, 0xF8, 0x70, 0x07, 0x0D, 0xD5, 0x03, 0xF0, 0x8E, 0xFF, 0x70, 0x06, 0x02, 

+	0xD5, 0x28, 0x46, 0x04, 0xF0, 0xF3, 0xF9, 0x01, 0x20, 0xE0, 0x71, 0x00, 0x20, 0x20, 0x71, 0x0B, 

+	0xF0, 0xDF, 0xFD, 0xA0, 0x61, 0x30, 0x46, 0x02, 0xF0, 0x47, 0xFD, 0x70, 0xBD, 0x70, 0xB5, 0x1B, 

+	0x4C, 0x05, 0x46, 0xE1, 0x60, 0x21, 0x61, 0x40, 0x07, 0x08, 0xD5, 0x03, 0xF0, 0x75, 0xFF, 0x01, 

+	0x20, 0xE0, 0x71, 0x00, 0x20, 0x20, 0x71, 0x0B, 0xF0, 0xCB, 0xFD, 0xA0, 0x61, 0x28, 0x46, 0x02, 

+	0xF0, 0x33, 0xFD, 0x70, 0xBD, 

+	0x00, 0x00, 0x3A, 0x00, 0x80, 0x10, 0xB5, 0x00, 0xF0, 0x01, 0xF9, 0x10, 0xBD, 0x0F, 0x48, 0xC1, 

+	0x68, 0x08, 0x46, 0xA8, 0xE6, 0x10, 0xB5, 0x0D, 0x4C, 0xE1, 0x68, 0x08, 0x46, 0xFF, 0xF7, 0xA3, 

+	0xFE, 0x00, 0x20, 0xA0, 0x71, 0x10, 0xBD, 0x09, 0x49, 0x01, 0x20, 0x88, 0x71, 0xC9, 0x68, 0x08, 

+	0x46, 0x99, 0xE6, 0x08, 0x48, 0x24, 0x38, 0x40, 0x7A, 0x07, 0x28, 0x01, 0xD0, 0x00, 0x20, 0x70, 

+	0x47, 0x01, 0x20, 0x70, 0x47, 0x03, 0x48, 0x64, 0x38, 0x70, 0x47, 0x70, 0x47, 0xD8, 0x00, 0x00, 

+	0x20, 0x84, 0xF4, 0x00, 0x00, 0x50, 0x04, 0x00, 0x20, 0xFB, 0x01, 0x00, 0x20, 0x33, 0x01, 0x00, 

+	0x20, 0xDD, 0x2D, 0x00, 0x00, 0x66, 0x01, 0x00, 0x20, 0x88, 0x00, 0x00, 0x20, 0xFE, 0x49, 0x08, 

+	0x56, 0xFE, 0x49, 0x40, 0x00, 0x40, 0x18, 0x60, 0x30, 0x40, 0x88, 0x70, 0x47, 0x10, 0xB5, 0xFC, 

+	0x48, 0x01, 0x6B, 0x82, 0x15, 

+	0x00, 0x00, 0x3B, 0x00, 0x80, 0x91, 0x43, 0x01, 0x63, 0x00, 0x20, 0xFA, 0x4C, 0xC0, 0x43, 0x20, 

+	0x60, 0x20, 0x61, 0x05, 0x20, 0x0B, 0xF0, 0xD2, 0xFF, 0x05, 0x20, 0x0B, 0xF0, 0xC8, 0xFF, 0xA0, 

+	0x68, 0x01, 0x21, 0x08, 0x43, 0xA0, 0x60, 0x06, 0x20, 0x0B, 0xF0, 0xC8, 0xFF, 0x06, 0x20, 0x0B, 

+	0xF0, 0xBE, 0xFF, 0x10, 0xBD, 0xF8, 0xB5, 0xED, 0x4E, 0x30, 0x7F, 0x0B, 0xF0, 0x51, 0xFD, 0xEC, 

+	0x48, 0xC0, 0x38, 0x01, 0x68, 0x49, 0x00, 0x49, 0x08, 0x01, 0x60, 0xE9, 0x49, 0x0A, 0x6B, 0x52, 

+	0x00, 0x52, 0x08, 0x0A, 0x63, 0x00, 0x25, 0x05, 0x62, 0x45, 0x62, 0xE3, 0x49, 0xE6, 0x4C, 0x90, 

+	0x22, 0x1A, 0x31, 0xE0, 0x6B, 0xFF, 0xF7, 0xF2, 0xFD, 0xE5, 0x48, 0xE4, 0x49, 0x01, 0x60, 0xE5, 

+	0x49, 0x41, 0x60, 0xDF, 0x49, 0x70, 0x69, 0x40, 0x39, 0x08, 0x63, 0xE3, 0x48, 0x31, 0x68, 0x01, 

+	0x60, 0x71, 0x68, 0x41, 0x60, 

+	0x00, 0x00, 0x3C, 0x00, 0x80, 0xB1, 0x68, 0x81, 0x60, 0xD9, 0x4F, 0x30, 0x68, 0x80, 0x3F, 0x00, 

+	0x28, 0x01, 0xDB, 0xDE, 0x48, 0x01, 0xE0, 0xDD, 0x48, 0x80, 0x1C, 0x38, 0x61, 0xD3, 0x4E, 0x20, 

+	0x36, 0x70, 0x7C, 0x01, 0x28, 0x06, 0xD0, 0x02, 0x28, 0x08, 0xD0, 0x03, 0x28, 0x16, 0xD0, 0x04, 

+	0x28, 0x0A, 0xD1, 0x17, 0xE0, 0x01, 0x23, 0x09, 0x22, 0x00, 0x21, 0x02, 0xE0, 0x01, 0x23, 0x09, 

+	0x22, 0x19, 0x46, 0x01, 0x20, 0x0B, 0xF0, 0xD2, 0xFF, 0xC8, 0x48, 0x80, 0x69, 0x38, 0x62, 0x30, 

+	0x7C, 0xE0, 0x76, 0x02, 0x28, 0x0A, 0xD0, 0x03, 0x28, 0x08, 0xD0, 0x09, 0xE0, 0x01, 0x23, 0x09, 

+	0x22, 0x02, 0x21, 0xEE, 0xE7, 0x01, 0x23, 0x09, 0x22, 0x03, 0x21, 0xEA, 0xE7, 0x04, 0x20, 0xE0, 

+	0x76, 0xC7, 0x49, 0x48, 0x68, 0x09, 0x68, 0x69, 0x18, 0x68, 0x41, 0x21, 0x67, 0x60, 0x67, 0xC5, 

+	0x48, 0xE1, 0x7E, 0x00, 0x7B, 

+	0x00, 0x00, 0x3D, 0x00, 0x80, 0x0F, 0x46, 0x40, 0x1E, 0x0C, 0xF0, 0x0C, 0xFA, 0x40, 0x1C, 0x78, 

+	0x43, 0xA0, 0x72, 0xE0, 0x72, 0x00, 0x21, 0x05, 0x20, 0x0B, 0xF0, 0x20, 0xFF, 0x03, 0x21, 0x06, 

+	0x20, 0x0B, 0xF0, 0x1C, 0xFF, 0xB0, 0x7C, 0x01, 0x28, 0x13, 0xD1, 0x00, 0x20, 0xFF, 0xF7, 0x5E, 

+	0xFF, 0x02, 0x46, 0x03, 0x23, 0x09, 0xE0, 0x9E, 0x1C, 0xF0, 0xB2, 0xFF, 0xF7, 0x57, 0xFF, 0x90, 

+	0x42, 0x03, 0xD8, 0xF0, 0xB2, 0xFF, 0xF7, 0x52, 0xFF, 0x02, 0x46, 0x5B, 0x1E, 0xF3, 0xD2, 0x0A, 

+	0x3A, 0xA2, 0x86, 0xA9, 0x48, 0xB0, 0x49, 0x20, 0x30, 0x05, 0x70, 0x45, 0x70, 0xA5, 0x71, 0xE5, 

+	0x71, 0x06, 0x20, 0x0B, 0xF0, 0x1F, 0xFF, 0xF8, 0xBD, 0x10, 0xB5, 0xA3, 0x4C, 0x20, 0x78, 0x00, 

+	0x28, 0x09, 0xD1, 0x01, 0xF0, 0x6B, 0xFB, 0xFF, 0xF7, 0x5D, 0xFF, 0x9C, 0x48, 0xA7, 0x49, 0x40, 

+	0x7F, 0x08, 0x70, 0x01, 0x20, 

+	0x00, 0x00, 0x3E, 0x00, 0x80, 0x20, 0x70, 0xFF, 0xF7, 0x39, 0xFF, 0x10, 0xBD, 0x10, 0xB5, 0x05, 

+	0x20, 0x0B, 0xF0, 0xF7, 0xFD, 0x06, 0x20, 0x0B, 0xF0, 0xF4, 0xFD, 0x95, 0x48, 0x01, 0x6A, 0x49, 

+	0x00, 0x49, 0x08, 0x01, 0x62, 0x92, 0x49, 0xC0, 0x39, 0x0A, 0x68, 0xD2, 0x00, 0xD2, 0x08, 0x0A, 

+	0x60, 0x8F, 0x49, 0x80, 0x39, 0x0A, 0x6A, 0x92, 0x00, 0x92, 0x08, 0x0A, 0x62, 0x8C, 0x49, 0x40, 

+	0x39, 0x0A, 0x68, 0x05, 0x23, 0x5B, 0x07, 0x9A, 0x43, 0x0A, 0x60, 0x01, 0x6B, 0x49, 0x00, 0x49, 

+	0x08, 0x01, 0x63, 0x01, 0x6B, 0x82, 0x15, 0x11, 0x43, 0x01, 0x63, 0x10, 0xBD, 0x84, 0x48, 0xC0, 

+	0x38, 0x01, 0x68, 0x49, 0x00, 0x49, 0x08, 0x01, 0x60, 0x81, 0x48, 0x01, 0x6B, 0x49, 0x00, 0x49, 

+	0x08, 0x01, 0x63, 0x70, 0x47, 0x01, 0x46, 0x00, 0x20, 0x8A, 0x1E, 0x03, 0x2A, 0x00, 0xD2, 0x48, 

+	0x1E, 0x70, 0x47, 0xF8, 0xB5, 

+	0x00, 0x00, 0x3F, 0x00, 0x80, 0x7A, 0x4A, 0x84, 0x46, 0x40, 0x3A, 0x11, 0x68, 0x77, 0x4E, 0x07, 

+	0x20, 0x00, 0x05, 0xF3, 0x68, 0x01, 0x40, 0x19, 0x43, 0x81, 0x4B, 0x0F, 0x27, 0x1B, 0x78, 0x55, 

+	0x05, 0x3F, 0x04, 0x00, 0x2B, 0x07, 0xD0, 0x11, 0x68, 0x7F, 0x23, 0x1B, 0x04, 0x19, 0x40, 0xF3, 

+	0x68, 0xBB, 0x43, 0x19, 0x43, 0x00, 0x25, 0x70, 0x4C, 0x00, 0x23, 0xA3, 0x70, 0x01, 0x23, 0x6C, 

+	0x4C, 0xDB, 0x07, 0x23, 0x63, 0x33, 0x69, 0xBB, 0x43, 0x07, 0x27, 0x7F, 0x04, 0x3B, 0x43, 0x0F, 

+	0x27, 0x3F, 0x05, 0xBB, 0x43, 0x07, 0x27, 0x7F, 0x05, 0x3B, 0x43, 0x23, 0x62, 0x63, 0x46, 0x00, 

+	0x2B, 0x15, 0xD0, 0xA0, 0x15, 0x01, 0x43, 0x11, 0x60, 0x0A, 0x20, 0x0B, 0xF0, 0x45, 0xFC, 0x20, 

+	0x6A, 0x28, 0x43, 0x20, 0x62, 0x5D, 0x48, 0x01, 0x21, 0x20, 0x30, 0x83, 0x7B, 0x49, 0x07, 0x8A, 

+	0x10, 0x01, 0x25, 0x00, 0x2B, 

+	0x00, 0x00, 0x40, 0x00, 0x80, 0x0C, 0xD0, 0x20, 0x6A, 0x88, 0x43, 0x10, 0x43, 0x21, 0xE0, 0x11, 

+	0x68, 0x01, 0x40, 0xF0, 0x68, 0x01, 0x43, 0x11, 0x60, 0x0A, 0x20, 0x0B, 0xF0, 0x2D, 0xFC, 0xE9, 

+	0xE7, 0x00, 0x7B, 0x01, 0x23, 0x9B, 0x02, 0x00, 0x28, 0x52, 0xD0, 0x01, 0x28, 0x4D, 0xD0, 0x02, 

+	0x28, 0x02, 0xD0, 0x03, 0x28, 0x0A, 0xD1, 0x02, 0xE0, 0x20, 0x6A, 0x98, 0x43, 0x01, 0xE0, 0x20, 

+	0x6A, 0x18, 0x43, 0x20, 0x62, 0xA0, 0x6B, 0x40, 0x08, 0x40, 0x00, 0xA0, 0x63, 0x20, 0x6A, 0x08, 

+	0x43, 0x90, 0x43, 0x20, 0x62, 0x21, 0x6A, 0x01, 0x20, 0x80, 0x06, 0x01, 0x43, 0x21, 0x62, 0x44, 

+	0x4F, 0x80, 0x3F, 0x38, 0x6A, 0x03, 0x21, 0x89, 0x07, 0x08, 0x43, 0x38, 0x62, 0x38, 0x6A, 0x79, 

+	0x04, 0x08, 0x43, 0x38, 0x62, 0x0C, 0x20, 0x0B, 0xF0, 0xFF, 0xFB, 0x20, 0x6A, 0x39, 0x05, 0x88, 

+	0x43, 0x20, 0x62, 0x12, 0x20, 

+	0x00, 0x00, 0x41, 0x00, 0x80, 0x0B, 0xF0, 0xF8, 0xFB, 0x39, 0x6A, 0x78, 0x04, 0x81, 0x43, 0x39, 

+	0x62, 0x0A, 0x20, 0x0B, 0xF0, 0xF1, 0xFB, 0x20, 0x6A, 0xFF, 0x21, 0x09, 0x04, 0x32, 0x69, 0x88, 

+	0x43, 0x0A, 0x40, 0x02, 0x43, 0x22, 0x62, 0x34, 0x4C, 0x31, 0x48, 0x61, 0x78, 0x00, 0x22, 0xD2, 

+	0x43, 0xC0, 0x38, 0x00, 0x29, 0x01, 0x68, 0x11, 0xD0, 0x53, 0x07, 0x19, 0x43, 0x01, 0x60, 0x2D, 

+	0x49, 0x0A, 0x61, 0x8A, 0x69, 0x02, 0x23, 0x1A, 0x43, 0x10, 0xE0, 0x20, 0x6A, 0x98, 0x43, 0x01, 

+	0xE0, 0x20, 0x6A, 0x18, 0x43, 0x20, 0x62, 0xA0, 0x6B, 0x28, 0x43, 0xB6, 0xE7, 0x03, 0x23, 0x9B, 

+	0x07, 0x19, 0x43, 0x01, 0x60, 0x23, 0x49, 0x0A, 0x61, 0x8A, 0x69, 0x2A, 0x43, 0x8A, 0x61, 0x79, 

+	0x6A, 0x00, 0x29, 0x02, 0xD0, 0xE1, 0x78, 0x00, 0x29, 0x0F, 0xD0, 0x78, 0x6A, 0x00, 0x28, 0x11, 

+	0xD0, 0xE0, 0x78, 0x00, 0x28, 

+	0x00, 0x00, 0x42, 0x00, 0x80, 0x0E, 0xD0, 0xFF, 0xF7, 0x01, 0xFF, 0x30, 0x7F, 0x0B, 0xF0, 0xA8, 

+	0xFB, 0xFF, 0xF7, 0x34, 0xFE, 0x00, 0x20, 0xE0, 0x70, 0x07, 0xE0, 0x31, 0x68, 0x00, 0x29, 0x00, 

+	0xDB, 0x85, 0x60, 0xF8, 0xBD, 0xFF, 0xF7, 0xF2, 0xFE, 0xE5, 0x70, 0xA5, 0x70, 0xF8, 0xBD, 0x70, 

+	0xB5, 0x03, 0x68, 0x42, 0x68, 0x23, 0x21, 0x08, 0x20, 0x1A, 0x4D, 0x04, 0x24, 0x16, 0x46, 0x06, 

+	0x42, 0x02, 0xD0, 0x8E, 0x00, 0x76, 0x19, 0x34, 0x60, 0x40, 0x08, 0x49, 0x1E, 0x00, 0x28, 0xF5, 

+	0xD1, 0x01, 0x20, 0xC0, 0x07, 0x1A, 0x46, 0x02, 0x42, 0x02, 0xD0, 0x8A, 0x00, 0x52, 0x19, 0x14, 

+	0x60, 0x40, 0x08, 0x49, 0x1E, 0x00, 0x28, 0x1F, 0xE0, 0xE2, 0xE5, 0x00, 0x00, 0xA4, 0xF4, 0x00, 

+	0x00, 0xC0, 0x00, 0x0A, 0x40, 0xC0, 0x0F, 0x0A, 0x40, 0x30, 0x01, 0x00, 0x20, 0x00, 0x01, 0x02, 

+	0x03, 0x00, 0x04, 0x0A, 0x40, 

+	0x00, 0x00, 0x43, 0x00, 0x80, 0x06, 0x11, 0x1C, 0x23, 0x00, 0x02, 0x0A, 0x40, 0x00, 0x01, 0x01, 

+	0x01, 0xD8, 0xF5, 0x00, 0x00, 0x84, 0xF4, 0x00, 0x00, 0x05, 0x35, 0x00, 0x00, 0x8C, 0x00, 0x00, 

+	0x20, 0xA8, 0x01, 0x00, 0x20, 0x00, 0x60, 0x0A, 0x40, 0xD4, 0xD1, 0x70, 0xBD, 0xFE, 0x49, 0x08, 

+	0x60, 0x70, 0x47, 0x70, 0xB5, 0xFD, 0x4D, 0xFE, 0x49, 0xEC, 0x7D, 0xFE, 0x4E, 0xCC, 0x73, 0x70, 

+	0x78, 0x28, 0x22, 0x50, 0x43, 0xFC, 0x4A, 0x80, 0x18, 0x88, 0x64, 0xF7, 0x4A, 0x01, 0x21, 0x11, 

+	0x60, 0xFF, 0xF7, 0xAD, 0xFF, 0xE8, 0x7E, 0xC0, 0x43, 0x80, 0x07, 0xC0, 0x17, 0x40, 0x1C, 0x0F, 

+	0xD0, 0xF0, 0x7B, 0x01, 0x28, 0x00, 0xD0, 0x01, 0x24, 0xF4, 0x49, 0x0A, 0x22, 0xF4, 0x4B, 0x05, 

+	0xE0, 0xA8, 0x7B, 0x00, 0x19, 0x08, 0x5C, 0x80, 0x00, 0xC0, 0x18, 0x02, 0x60, 0x64, 0x1E, 0xF7, 

+	0xD2, 0x01, 0x20, 0xFF, 0xF7, 

+	0x00, 0x00, 0x44, 0x00, 0x80, 0xBE, 0xFE, 0x70, 0xBD, 0xFF, 0xB5, 0xEA, 0x48, 0x81, 0xB0, 0x20, 

+	0x38, 0x00, 0x8B, 0x0A, 0x9F, 0x80, 0x04, 0x80, 0x0F, 0x0C, 0x9E, 0x01, 0x28, 0x00, 0xD1, 0x7F, 

+	0x08, 0xE8, 0x48, 0x80, 0x6A, 0x15, 0x1A, 0x28, 0x46, 0x58, 0x43, 0x01, 0x22, 0x40, 0x00, 0xD2, 

+	0x03, 0x90, 0x42, 0x01, 0xD2, 0x0E, 0x20, 0x00, 0xE0, 0x0F, 0x20, 0x02, 0x46, 0x0E, 0x3A, 0x01, 

+	0x24, 0x94, 0x40, 0x0E, 0x9A, 0x10, 0x70, 0xDA, 0x48, 0x40, 0x79, 0x00, 0x28, 0x07, 0xD0, 0x34, 

+	0x60, 0x0D, 0x99, 0x00, 0x20, 0x08, 0x80, 0x0F, 0x99, 0x08, 0x70, 0x05, 0xB0, 0xF0, 0xBD, 0x22, 

+	0x46, 0x64, 0x20, 0x6B, 0x43, 0x42, 0x43, 0x4B, 0x43, 0x58, 0x00, 0x11, 0x46, 0x0C, 0xF0, 0x10, 

+	0xF8, 0x0D, 0x99, 0x19, 0x22, 0x08, 0x80, 0xD4, 0x48, 0x0B, 0x99, 0x67, 0x43, 0x41, 0x5C, 0x01, 

+	0x98, 0x92, 0x03, 0x41, 0x43, 

+	0x00, 0x00, 0x45, 0x00, 0x80, 0x28, 0x46, 0x79, 0x43, 0x50, 0x43, 0x0C, 0xF0, 0x01, 0xF8, 0x02, 

+	0xF0, 0x0F, 0xFA, 0x0F, 0x99, 0x08, 0x70, 0xCD, 0x49, 0x09, 0x78, 0x00, 0x29, 0x02, 0xD0, 0x84, 

+	0x40, 0x34, 0x60, 0xDA, 0xE7, 0xC8, 0x49, 0x0B, 0x9A, 0x8A, 0x5C, 0x01, 0x99, 0x81, 0x40, 0x4A, 

+	0x43, 0x64, 0x20, 0x29, 0x46, 0x7A, 0x43, 0x41, 0x43, 0x10, 0x46, 0x0B, 0xF0, 0xE9, 0xFF, 0x30, 

+	0x60, 0xCB, 0xE7, 0x10, 0xB5, 0xC2, 0x49, 0xBF, 0x4B, 0x09, 0x78, 0x40, 0x33, 0x00, 0x29, 0x03, 

+	0xD0, 0x19, 0x6A, 0x2F, 0x22, 0x12, 0x06, 0x11, 0x40, 0xB6, 0x4A, 0x7F, 0x24, 0x20, 0x3A, 0x92, 

+	0x69, 0x24, 0x04, 0xA2, 0x43, 0x00, 0x04, 0x02, 0x43, 0x0A, 0x43, 0x1A, 0x62, 0x10, 0xBD, 0xF0, 

+	0xB5, 0xB8, 0x49, 0x0E, 0x22, 0x09, 0x5C, 0x01, 0x27, 0x51, 0x43, 0xB7, 0x4A, 0xB7, 0x4E, 0x12, 

+	0x68, 0x8D, 0x18, 0x9C, 0x35, 

+	0x00, 0x00, 0x46, 0x00, 0x80, 0x0E, 0x21, 0x3F, 0x04, 0x0C, 0xE0, 0x6A, 0x5C, 0x13, 0x02, 0x03, 

+	0x22, 0x92, 0x07, 0x9B, 0x18, 0x8A, 0x00, 0x92, 0x19, 0x14, 0x68, 0x3C, 0x40, 0x14, 0x60, 0x14, 

+	0x68, 0x1C, 0x43, 0x14, 0x60, 0x49, 0x1E, 0xF0, 0xD2, 0xA2, 0x49, 0x09, 0x7E, 0x01, 0x43, 0xA5, 

+	0x48, 0x80, 0x30, 0x01, 0x62, 0xF0, 0xBD, 0xF7, 0xB5, 0x00, 0x25, 0x84, 0xB0, 0x2E, 0x46, 0x2C, 

+	0x46, 0x00, 0x95, 0x01, 0x2A, 0x05, 0xD1, 0x03, 0x20, 0xC0, 0x06, 0x95, 0x02, 0xA4, 0x4C, 0x56, 

+	0x07, 0x00, 0x90, 0x01, 0x29, 0x19, 0xD0, 0x04, 0x98, 0x00, 0x29, 0x19, 0xD0, 0x80, 0x00, 0xC0, 

+	0x1C, 0x06, 0x21, 0x0B, 0xF0, 0x95, 0xFF, 0xC0, 0x1E, 0xFF, 0x22, 0x01, 0x32, 0xFF, 0x28, 0x00, 

+	0xD9, 0x10, 0x46, 0x04, 0x99, 0x09, 0x1A, 0x09, 0x39, 0xFF, 0x29, 0x00, 0xD9, 0x11, 0x46, 0x15, 

+	0x27, 0x15, 0x29, 0x07, 0xD9, 

+	0x00, 0x00, 0x47, 0x00, 0x80, 0x03, 0x46, 0xCA, 0x1B, 0x9F, 0xE0, 0x89, 0x48, 0x80, 0x8E, 0xEB, 

+	0xE7, 0x0A, 0x38, 0xE9, 0xE7, 0x15, 0x29, 0x7D, 0xD0, 0x43, 0x18, 0x01, 0x22, 0x16, 0x3B, 0x94, 

+	0x46, 0x7A, 0x1A, 0x40, 0x1E, 0x49, 0x1E, 0xBF, 0x1A, 0x8E, 0x46, 0x02, 0x90, 0x5B, 0x1E, 0x60, 

+	0x46, 0x85, 0x49, 0x40, 0x1E, 0x52, 0x1E, 0x7F, 0x1E, 0x01, 0x93, 0x09, 0x31, 0xCB, 0x68, 0x84, 

+	0x46, 0x7B, 0x48, 0x73, 0x40, 0xC0, 0x6B, 0xC3, 0x60, 0x0B, 0x69, 0x73, 0x40, 0x03, 0x61, 0x4B, 

+	0x69, 0x73, 0x40, 0x43, 0x61, 0x8E, 0x69, 0x00, 0x9B, 0x23, 0x43, 0x5E, 0x40, 0x00, 0x93, 0x86, 

+	0x61, 0xCB, 0x69, 0x63, 0x40, 0xC3, 0x61, 0x0B, 0x6A, 0x63, 0x40, 0x03, 0x62, 0x4B, 0x6A, 0x63, 

+	0x40, 0x43, 0x62, 0x8B, 0x6A, 0x63, 0x40, 0x83, 0x62, 0xCB, 0x6A, 0x1E, 0x0A, 0x01, 0x9B, 0x36, 

+	0x02, 0x1E, 0x43, 0x66, 0x40, 

+	0x00, 0x00, 0x48, 0x00, 0x80, 0xC6, 0x62, 0x8B, 0x6B, 0x1B, 0x0A, 0x1B, 0x02, 0x3B, 0x43, 0x63, 

+	0x40, 0x83, 0x63, 0xCB, 0x6B, 0x63, 0x40, 0xC3, 0x63, 0x0B, 0x6C, 0x63, 0x40, 0x03, 0x64, 0x4E, 

+	0x6C, 0x00, 0x9B, 0x5E, 0x40, 0x46, 0x64, 0x8B, 0x6C, 0x63, 0x40, 0x83, 0x64, 0xCB, 0x6C, 0x63, 

+	0x40, 0xC3, 0x64, 0x0B, 0x6D, 0x63, 0x40, 0x03, 0x65, 0x4B, 0x6D, 0x63, 0x40, 0x43, 0x65, 0x8B, 

+	0x6D, 0x1E, 0x0A, 0x01, 0x9B, 0x36, 0x02, 0x1E, 0x43, 0x66, 0x40, 0x86, 0x65, 0x4B, 0x6E, 0x1B, 

+	0x0A, 0x1B, 0x02, 0x3B, 0x43, 0x63, 0x40, 0x43, 0x66, 0x8B, 0x6E, 0x63, 0x40, 0x83, 0x66, 0xCB, 

+	0x6E, 0x63, 0x40, 0xC3, 0x66, 0x0B, 0x6F, 0x6B, 0x40, 0x03, 0x67, 0x4B, 0x6F, 0x6B, 0x40, 0x43, 

+	0x67, 0x8B, 0x6F, 0x1E, 0x0A, 0x02, 0x9B, 0x36, 0x02, 0x1E, 0x43, 0x6E, 0x40, 0x86, 0x67, 0xC9, 

+	0x6F, 0x0B, 0x0A, 0x1B, 0x02, 

+	0x00, 0x00, 0x49, 0x00, 0x80, 0x71, 0x46, 0x0B, 0x43, 0x6B, 0x40, 0xC3, 0x67, 0x4E, 0x4E, 0x89, 

+	0x36, 0x31, 0x68, 0x00, 0xE0, 0x17, 0xE0, 0x69, 0x40, 0x03, 0x46, 0x80, 0x33, 0x19, 0x60, 0x71, 

+	0x68, 0x69, 0x40, 0x59, 0x60, 0xB1, 0x68, 0x69, 0x40, 0x99, 0x60, 0x71, 0x46, 0x15, 0x29, 0x61, 

+	0x46, 0x0E, 0xD9, 0x4C, 0x4B, 0x19, 0x43, 0x61, 0x40, 0x01, 0x63, 0x4B, 0x4B, 0x61, 0x46, 0x19, 

+	0x43, 0x61, 0x40, 0xC1, 0x65, 0x17, 0xE0, 0x43, 0x1E, 0x01, 0x22, 0x94, 0x46, 0x01, 0x22, 0x68, 

+	0xE7, 0x46, 0x4B, 0x19, 0x43, 0x61, 0x40, 0x01, 0x63, 0x45, 0x4B, 0x61, 0x46, 0x19, 0x43, 0x61, 

+	0x40, 0xC1, 0x65, 0x71, 0x46, 0x15, 0x29, 0x06, 0xD2, 0x42, 0x4B, 0x11, 0x46, 0x19, 0x43, 0x61, 

+	0x40, 0x41, 0x63, 0x41, 0x49, 0x05, 0xE0, 0x41, 0x4B, 0x11, 0x46, 0x19, 0x43, 0x61, 0x40, 0x41, 

+	0x63, 0x3F, 0x49, 0x0A, 0x43, 

+	0x00, 0x00, 0x4A, 0x00, 0x80, 0x62, 0x40, 0x02, 0x66, 0x2A, 0x48, 0x18, 0x21, 0x40, 0x7B, 0x48, 

+	0x43, 0x04, 0x99, 0x0B, 0xF0, 0xBD, 0xFE, 0x2B, 0x49, 0x88, 0x62, 0x07, 0xB0, 0xF0, 0xBD, 0x25, 

+	0x49, 0x01, 0x22, 0xC9, 0x7C, 0x07, 0xE7, 0xF0, 0xB5, 0x21, 0x4C, 0x27, 0x4D, 0x60, 0x7A, 0x06, 

+	0x21, 0x48, 0x43, 0x47, 0x3D, 0x40, 0x19, 0x87, 0xB0, 0x00, 0x79, 0xFF, 0xF7, 0x17, 0xFC, 0xFF, 

+	0xF7, 0xEE, 0xFF, 0x25, 0x4E, 0x30, 0x68, 0x80, 0x7A, 0xFF, 0xF7, 0xD1, 0xFE, 0x30, 0x68, 0xC0, 

+	0x7A, 0xFF, 0xF7, 0xB7, 0xFE, 0x1B, 0x48, 0x80, 0x30, 0x01, 0x6B, 0xC2, 0x04, 0x11, 0x43, 0x01, 

+	0x63, 0x60, 0x7A, 0x06, 0x21, 0x48, 0x43, 0x40, 0x19, 0x04, 0x21, 0x41, 0x56, 0x11, 0x4F, 0x49, 

+	0x00, 0x20, 0x3F, 0xC9, 0x19, 0x60, 0x31, 0x89, 0x8A, 0x12, 0x4A, 0x49, 0x1E, 0x11, 0x60, 0x00, 

+	0x79, 0xFF, 0xF7, 0xF4, 0xFB, 

+	0x00, 0x00, 0x4B, 0x00, 0x80, 0x23, 0x46, 0x19, 0x33, 0x9A, 0x1E, 0x11, 0x46, 0x84, 0x46, 0x19, 

+	0x31, 0x08, 0x46, 0x05, 0x93, 0x2C, 0x30, 0x02, 0xAB, 0x07, 0xC3, 0x30, 0x68, 0x81, 0x7A, 0xC0, 

+	0x7A, 0x01, 0x91, 0x00, 0x90, 0x60, 0x7A, 0x2D, 0xE0, 0x00, 0x61, 0x0A, 0x40, 0x84, 0xF4, 0x00, 

+	0x00, 0x30, 0x01, 0x00, 0x20, 0xC4, 0xF4, 0x00, 0x00, 0x20, 0xF6, 0x00, 0x00, 0x6C, 0xF5, 0x00, 

+	0x00, 0x00, 0x60, 0x0A, 0x40, 0x00, 0x00, 0x0A, 0x40, 0xF3, 0xE5, 0x00, 0x00, 0xA9, 0x01, 0x00, 

+	0x20, 0xA8, 0x01, 0x00, 0x20, 0x93, 0xE6, 0x00, 0x00, 0xAC, 0x01, 0x00, 0x20, 0x00, 0x70, 0x0A, 

+	0x40, 0x00, 0x04, 0x00, 0x20, 0x00, 0xC2, 0x2A, 0x24, 0x00, 0xC6, 0x09, 0x00, 0x00, 0xC2, 0x3A, 

+	0x24, 0x00, 0xC6, 0x19, 0x00, 0x00, 0xC2, 0x3A, 0x04, 0x00, 0xC6, 0x19, 0x20, 0x00, 0xC2, 0x2A, 

+	0x04, 0x00, 0xC6, 0x09, 0x20, 

+	0x00, 0x00, 0x4C, 0x00, 0x80, 0x06, 0x21, 0x48, 0x43, 0x40, 0x19, 0x04, 0x21, 0x41, 0x56, 0x63, 

+	0x46, 0x48, 0x00, 0xC0, 0x19, 0x60, 0x30, 0x82, 0x8A, 0x38, 0x46, 0x40, 0x30, 0x41, 0x7A, 0x28, 

+	0x20, 0x38, 0x5E, 0xFF, 0xF7, 0xF1, 0xFD, 0xFE, 0x49, 0x05, 0x20, 0x0B, 0xF0, 0x7B, 0xFB, 0x74, 

+	0xE7, 0x10, 0xB5, 0xFC, 0x48, 0xFC, 0x49, 0x80, 0x7B, 0x28, 0x22, 0x0C, 0x5C, 0xFB, 0x49, 0x00, 

+	0x20, 0xC8, 0x73, 0xFB, 0x48, 0x40, 0x78, 0x50, 0x43, 0xFA, 0x4A, 0x80, 0x18, 0x88, 0x64, 0xFA, 

+	0x4A, 0x01, 0x21, 0x11, 0x60, 0xFF, 0xF7, 0x6B, 0xFD, 0xF8, 0x4A, 0x02, 0x20, 0xA1, 0x00, 0x89, 

+	0x18, 0x08, 0x60, 0x00, 0x20, 0xFF, 0xF7, 0x8D, 0xFC, 0x10, 0xBD, 0xF1, 0x49, 0x00, 0x22, 0x89, 

+	0x7C, 0x61, 0xE6, 0xF0, 0xB5, 0xED, 0x4C, 0x06, 0x21, 0x60, 0x7A, 0xF1, 0x4D, 0x48, 0x43, 0x40, 

+	0x19, 0x87, 0xB0, 0xC0, 0x78, 

+	0x00, 0x00, 0x4D, 0x00, 0x80, 0xFF, 0xF7, 0x72, 0xFB, 0xFF, 0xF7, 0xEF, 0xFF, 0xED, 0x4E, 0x30, 

+	0x68, 0x00, 0x7A, 0xFF, 0xF7, 0x2C, 0xFE, 0x30, 0x68, 0x40, 0x7A, 0xFF, 0xF7, 0x12, 0xFE, 0xEA, 

+	0x48, 0x01, 0x6B, 0xC2, 0x04, 0x91, 0x43, 0x01, 0x63, 0x60, 0x7A, 0x06, 0x21, 0x48, 0x43, 0x40, 

+	0x19, 0x03, 0x21, 0x41, 0x56, 0xDE, 0x4F, 0x49, 0x00, 0x20, 0x3F, 0xC9, 0x19, 0x60, 0x31, 0x89, 

+	0x8A, 0xE1, 0x4A, 0x49, 0x1E, 0x80, 0x3A, 0x11, 0x60, 0xC0, 0x78, 0xFF, 0xF7, 0x4F, 0xFB, 0x23, 

+	0x46, 0x18, 0x33, 0x9A, 0x1E, 0x11, 0x46, 0x84, 0x46, 0x18, 0x31, 0x08, 0x46, 0x05, 0x93, 0x2A, 

+	0x30, 0x02, 0xAB, 0x07, 0xC3, 0x30, 0x68, 0x63, 0x46, 0x01, 0x7A, 0x40, 0x7A, 0x01, 0x91, 0x00, 

+	0x90, 0x60, 0x7A, 0x06, 0x21, 0x48, 0x43, 0x40, 0x19, 0x03, 0x21, 0x41, 0x56, 0x48, 0x00, 0xC0, 

+	0x19, 0x60, 0x30, 0x82, 0x8A, 

+	0x00, 0x00, 0x4E, 0x00, 0x80, 0x38, 0x46, 0x40, 0x30, 0x01, 0x7A, 0x26, 0x20, 0x38, 0x5E, 0xFF, 

+	0xF7, 0x7B, 0xFD, 0xCE, 0x49, 0x05, 0x20, 0x0B, 0xF0, 0x05, 0xFB, 0xFE, 0xE6, 0x30, 0xB5, 0xC3, 

+	0x4C, 0x87, 0xB0, 0x00, 0x20, 0xE0, 0x73, 0xC2, 0x48, 0x28, 0x21, 0x00, 0x78, 0x20, 0x77, 0xC0, 

+	0x48, 0x23, 0x46, 0x20, 0x38, 0xC0, 0x7F, 0x20, 0x73, 0x48, 0x43, 0xBE, 0x49, 0x15, 0x33, 0x40, 

+	0x18, 0xDA, 0x1E, 0xA0, 0x64, 0x11, 0x46, 0x1A, 0x31, 0x08, 0x46, 0x05, 0x93, 0x28, 0x30, 0x02, 

+	0xAB, 0x07, 0xC3, 0xBC, 0x4D, 0x28, 0x68, 0x81, 0x79, 0xC0, 0x79, 0x00, 0x90, 0x01, 0x91, 0xB4, 

+	0x48, 0x63, 0x8E, 0x20, 0x30, 0xC1, 0x79, 0xE2, 0x7F, 0x20, 0x6E, 0xFF, 0xF7, 0x4D, 0xFD, 0x28, 

+	0x68, 0x80, 0x79, 0xFF, 0xF7, 0xBC, 0xFD, 0x28, 0x68, 0xC0, 0x79, 0xFF, 0xF7, 0xA2, 0xFD, 0xAE, 

+	0x49, 0x0A, 0x20, 0x08, 0x60, 

+	0x00, 0x00, 0x4F, 0x00, 0x80, 0xA0, 0x6C, 0xFF, 0xF7, 0xD2, 0xFC, 0x01, 0x20, 0xFF, 0xF7, 0xF9, 

+	0xFB, 0x07, 0xB0, 0x30, 0xBD, 0x10, 0xB5, 0x04, 0x46, 0x80, 0xB2, 0xFF, 0xF7, 0xC0, 0xFE, 0xA3, 

+	0x48, 0xA9, 0x49, 0x44, 0x86, 0x0A, 0x6B, 0xCB, 0x04, 0x1A, 0x43, 0x0A, 0x63, 0xC0, 0x7F, 0xA6, 

+	0x49, 0x40, 0x1E, 0x80, 0x39, 0x08, 0x60, 0xA6, 0x49, 0x05, 0x20, 0x0B, 0xF0, 0xB3, 0xFA, 0x10, 

+	0xBD, 0x70, 0xB5, 0x05, 0x46, 0x99, 0x4C, 0x86, 0xB0, 0x00, 0x20, 0xE0, 0x73, 0x20, 0x73, 0x99, 

+	0x48, 0xA0, 0x64, 0x20, 0x46, 0x15, 0x30, 0x0E, 0x46, 0x02, 0x46, 0x03, 0x46, 0xC1, 0x1E, 0x00, 

+	0x96, 0x05, 0x90, 0x17, 0x32, 0x3F, 0x33, 0x01, 0x95, 0x02, 0x93, 0x03, 0x92, 0x04, 0x91, 0x90, 

+	0x48, 0x63, 0x8E, 0x20, 0x30, 0xC1, 0x79, 0xE2, 0x7F, 0x20, 0x6E, 0xFF, 0xF7, 0x05, 0xFD, 0x30, 

+	0x46, 0xFF, 0xF7, 0x5F, 0xFD, 

+	0x00, 0x00, 0x50, 0x00, 0x80, 0x28, 0x46, 0xFF, 0xF7, 0x72, 0xFD, 0x92, 0x48, 0x8A, 0x49, 0x00, 

+	0x78, 0x00, 0x28, 0x04, 0xD0, 0x01, 0x20, 0x20, 0x77, 0x00, 0x20, 0x08, 0x60, 0x08, 0xE0, 0x84, 

+	0x48, 0x20, 0x38, 0xC0, 0x7F, 0x20, 0x77, 0x0A, 0x20, 0x08, 0x60, 0xA0, 0x6C, 0xFF, 0xF7, 0x7F, 

+	0xFC, 0x01, 0x20, 0xFF, 0xF7, 0xA6, 0xFB, 0x06, 0xB0, 0x70, 0xBD, 0xF0, 0xB5, 0x79, 0x48, 0x82, 

+	0xB0, 0x45, 0x7B, 0x01, 0x7B, 0x01, 0x91, 0x86, 0x7B, 0x78, 0x48, 0x01, 0x22, 0x01, 0x6F, 0xC4, 

+	0x7B, 0x8C, 0x46, 0x41, 0x7B, 0x00, 0x91, 0x87, 0x7E, 0x78, 0x4B, 0xC0, 0x7E, 0xBE, 0x46, 0x00, 

+	0x2C, 0x03, 0xD0, 0x71, 0x46, 0x00, 0x29, 0x0C, 0xD0, 0x27, 0xE0, 0x2C, 0x46, 0xB5, 0x42, 0x16, 

+	0xD2, 0x6D, 0x49, 0x0F, 0x5D, 0xBF, 0x00, 0xFF, 0x18, 0x3A, 0x60, 0x64, 0x1C, 0xB4, 0x42, 0xF8, 

+	0xD3, 0x0D, 0xE0, 0x00, 0x24, 

+	0x00, 0x00, 0x51, 0x00, 0x80, 0x00, 0x28, 0x0D, 0xD9, 0x00, 0x9E, 0x67, 0x49, 0xAE, 0x19, 0x37, 

+	0x19, 0xCF, 0x5D, 0xBF, 0x00, 0xFF, 0x18, 0x3A, 0x60, 0x64, 0x1C, 0x84, 0x42, 0xF7, 0xD3, 0x71, 

+	0x46, 0x00, 0x29, 0x0A, 0xD1, 0x00, 0x99, 0x61, 0x4E, 0x09, 0x18, 0xC9, 0xB2, 0x71, 0x73, 0x0C, 

+	0x18, 0x01, 0x99, 0x8C, 0x42, 0x01, 0xD9, 0x09, 0x1A, 0x71, 0x73, 0x5C, 0x49, 0x49, 0x7B, 0x6D, 

+	0x18, 0x01, 0x28, 0x0F, 0xD0, 0x74, 0x46, 0x11, 0x46, 0xA1, 0x40, 0x00, 0x24, 0x00, 0x28, 0x1E, 

+	0xD9, 0x46, 0x1E, 0xB2, 0x40, 0x54, 0x4E, 0x2F, 0x19, 0xF7, 0x5D, 0x66, 0x46, 0x0E, 0x42, 0x0A, 

+	0xD0, 0x02, 0x26, 0x09, 0xE0, 0x71, 0x46, 0x6A, 0x18, 0x4F, 0x49, 0x89, 0x5C, 0x02, 0x22, 0x89, 

+	0x00, 0xC9, 0x18, 0x0A, 0x60, 0x0B, 0xE0, 0x03, 0x26, 0x8A, 0x42, 0x01, 0xD1, 0x01, 0x21, 0x00, 

+	0xE0, 0x49, 0x00, 0xBF, 0x00, 

+	0x00, 0x00, 0x52, 0x00, 0x80, 0xFF, 0x18, 0x3E, 0x60, 0x64, 0x1C, 0x84, 0x42, 0xE2, 0xD3, 0x47, 

+	0x49, 0x40, 0x1E, 0x72, 0x46, 0x86, 0x45, 0x01, 0xDA, 0x50, 0x1C, 0x00, 0xE0, 0x00, 0x20, 0x88, 

+	0x76, 0x02, 0xB0, 0xF0, 0xBD, 0xF8, 0xB5, 0x41, 0x4C, 0x07, 0x46, 0xA0, 0x64, 0x61, 0x77, 0xA2, 

+	0x77, 0xE5, 0x7E, 0x1E, 0x46, 0x48, 0x1B, 0x60, 0x73, 0x50, 0x1A, 0x29, 0x46, 0x0B, 0xF0, 0xA8, 

+	0xFC, 0x40, 0x1C, 0x68, 0x43, 0x20, 0x77, 0x00, 0x20, 0xA0, 0x76, 0xE0, 0x73, 0x41, 0x48, 0xA6, 

+	0x73, 0x00, 0x78, 0x39, 0x49, 0x00, 0x28, 0x02, 0xD0, 0x00, 0x20, 0x08, 0x60, 0x06, 0xE0, 0x01, 

+	0x20, 0x08, 0x60, 0x38, 0x46, 0xFF, 0xF7, 0xE3, 0xFB, 0xFF, 0xF7, 0x67, 0xFF, 0x00, 0x20, 0xFF, 

+	0xF7, 0x08, 0xFB, 0xF8, 0xBD, 0x2B, 0x48, 0x28, 0x21, 0x02, 0x7B, 0x2D, 0x48, 0x52, 0x1E, 0x20, 

+	0x38, 0x83, 0x7F, 0x80, 0x7F, 

+	0x00, 0x00, 0x53, 0x00, 0x80, 0x5B, 0x1E, 0x48, 0x43, 0x2A, 0x49, 0x40, 0x18, 0x28, 0x38, 0x00, 

+	0x21, 0xC8, 0xE7, 0xF0, 0xB5, 0xD2, 0x1A, 0x00, 0x24, 0x52, 0x1C, 0x05, 0x9E, 0xD5, 0x07, 0x03, 

+	0xD0, 0x52, 0x1E, 0x01, 0xE0, 0x01, 0x24, 0x92, 0x1E, 0xD5, 0x18, 0x6D, 0x1E, 0x0F, 0x46, 0x45, 

+	0x43, 0x57, 0x43, 0xBD, 0x42, 0xF6, 0xDD, 0x01, 0x2C, 0x00, 0xD1, 0x92, 0x1C, 0x32, 0x60, 0x00, 

+	0x2C, 0x01, 0xD0, 0x01, 0x20, 0xF0, 0xBD, 0x00, 0x20, 0xF0, 0xBD, 0xFE, 0xB5, 0x0C, 0x46, 0x05, 

+	0x46, 0x0B, 0xF0, 0x78, 0xF8, 0xAF, 0x21, 0xC9, 0x00, 0x48, 0x43, 0x40, 0x08, 0x29, 0x46, 0x0B, 

+	0xF0, 0x57, 0xFC, 0x06, 0x46, 0x18, 0x48, 0x80, 0x38, 0x85, 0x6A, 0xFF, 0x20, 0x67, 0x1B, 0x40, 

+	0x1B, 0xB0, 0x42, 0x00, 0xDA, 0x06, 0x46, 0x03, 0xF0, 0x22, 0xFC, 0x04, 0x46, 0x09, 0x48, 0x41, 

+	0x7B, 0xFF, 0x20, 0x71, 0x30, 

+	0x00, 0x00, 0x54, 0x00, 0x80, 0x0B, 0xF0, 0x44, 0xFC, 0x42, 0x1E, 0x02, 0x90, 0x01, 0xA8, 0x00, 

+	0x90, 0x23, 0x46, 0x31, 0x46, 0x38, 0x46, 0xFF, 0xF7, 0xBC, 0xFF, 0x04, 0x4C, 0x20, 0x34, 0x1B, 

+	0xE0, 0x51, 0x34, 0x00, 0x00, 0x84, 0xF4, 0x00, 0x00, 0x6C, 0xF5, 0x00, 0x00, 0x30, 0x01, 0x00, 

+	0x20, 0xC4, 0xF4, 0x00, 0x00, 0x20, 0xF6, 0x00, 0x00, 0x00, 0x61, 0x0A, 0x40, 0x00, 0x60, 0x0A, 

+	0x40, 0xAC, 0xE5, 0x00, 0x00, 0xAC, 0x01, 0x00, 0x20, 0x80, 0x00, 0x0A, 0x40, 0xC1, 0x33, 0x00, 

+	0x00, 0x41, 0x33, 0x00, 0x00, 0xA8, 0x01, 0x00, 0x20, 0x00, 0x28, 0x09, 0xD0, 0x38, 0x46, 0x01, 

+	0x99, 0x0B, 0xF0, 0x20, 0xFC, 0x06, 0x46, 0x01, 0x20, 0xA0, 0x71, 0x03, 0xF0, 0xE8, 0xFB, 0x1A, 

+	0xE0, 0x03, 0xF0, 0xE5, 0xFB, 0x43, 0x08, 0x02, 0x98, 0x31, 0x46, 0x42, 0x1E, 0x01, 0xA8, 0x00, 

+	0x90, 0x38, 0x46, 0xFF, 0xF7, 

+	0x00, 0x00, 0x55, 0x00, 0x80, 0x86, 0xFF, 0x00, 0x28, 0x02, 0xD0, 0x38, 0x46, 0x01, 0x99, 0x02, 

+	0xE0, 0x02, 0x98, 0x41, 0x1E, 0x30, 0x46, 0x0B, 0xF0, 0x05, 0xFC, 0x06, 0x46, 0x02, 0x20, 0xA0, 

+	0x71, 0x03, 0xF0, 0xCD, 0xFB, 0x40, 0x08, 0xE0, 0x71, 0xE1, 0x79, 0x01, 0x98, 0x7A, 0x19, 0x41, 

+	0x18, 0x49, 0x1E, 0x71, 0x43, 0x49, 0x19, 0xA1, 0x70, 0xC0, 0xB2, 0xE0, 0x70, 0xF1, 0xB2, 0x21, 

+	0x71, 0x48, 0x43, 0x11, 0x1A, 0xFA, 0x48, 0x65, 0x71, 0x81, 0x62, 0xFE, 0xBD, 0xF3, 0xB5, 0xF9, 

+	0x4C, 0x06, 0x21, 0x60, 0x7A, 0xF8, 0x4D, 0x48, 0x43, 0x87, 0xB0, 0x28, 0x5C, 0xFF, 0xF7, 0x46, 

+	0xF9, 0x06, 0x46, 0xF6, 0x48, 0x00, 0x78, 0x00, 0x28, 0x01, 0xD0, 0xFF, 0x26, 0x57, 0x36, 0x30, 

+	0x46, 0xFF, 0xF7, 0xBB, 0xFD, 0xF2, 0x48, 0xF3, 0x4F, 0x40, 0x78, 0x01, 0x28, 0x0A, 0xD1, 0x60, 

+	0x7A, 0x06, 0x21, 0x48, 0x43, 

+	0x00, 0x00, 0x56, 0x00, 0x80, 0x28, 0x56, 0x40, 0x00, 0xC0, 0x19, 0x60, 0x30, 0x81, 0x8A, 0x30, 

+	0x46, 0xFF, 0xF7, 0x5B, 0xFF, 0xEC, 0x48, 0x00, 0x78, 0x00, 0x28, 0x04, 0xD0, 0x01, 0x20, 0xE0, 

+	0x76, 0xEA, 0x48, 0x00, 0x7B, 0x0A, 0xE0, 0xE7, 0x48, 0x20, 0x30, 0x00, 0x7C, 0xE0, 0x76, 0x02, 

+	0x28, 0x01, 0xD0, 0x03, 0x28, 0x01, 0xD1, 0x04, 0x20, 0xE0, 0x76, 0xA0, 0x7A, 0xE0, 0x72, 0xDC, 

+	0x48, 0x80, 0x30, 0x01, 0x6B, 0xC2, 0x04, 0x91, 0x43, 0x01, 0x63, 0xDA, 0x4B, 0x13, 0x33, 0x9A, 

+	0x1E, 0x11, 0x46, 0x19, 0x31, 0x08, 0x46, 0x05, 0x93, 0x22, 0x30, 0x02, 0xAB, 0x07, 0xC3, 0x08, 

+	0x99, 0x07, 0x98, 0x00, 0x91, 0x01, 0x90, 0x60, 0x7A, 0x06, 0x21, 0x48, 0x43, 0x28, 0x56, 0x33, 

+	0x46, 0x40, 0x00, 0xC0, 0x19, 0x60, 0x30, 0x82, 0x8A, 0xD2, 0x48, 0x40, 0x30, 0x81, 0x79, 0x22, 

+	0x20, 0x38, 0x5E, 0xFF, 0xF7, 

+	0x00, 0x00, 0x57, 0x00, 0x80, 0x41, 0xFB, 0x07, 0x98, 0xFF, 0xF7, 0xB1, 0xFB, 0x08, 0x98, 0xFF, 

+	0xF7, 0x98, 0xFB, 0x60, 0x7A, 0x06, 0x21, 0x48, 0x43, 0x28, 0x56, 0xC5, 0x49, 0x40, 0x00, 0xC0, 

+	0x19, 0x60, 0x30, 0x80, 0x8A, 0x40, 0x1E, 0x08, 0x60, 0xC9, 0x49, 0x05, 0x20, 0x0B, 0xF0, 0xBA, 

+	0xF8, 0x09, 0xB0, 0xF0, 0xBD, 0xFE, 0xB5, 0xC5, 0x48, 0xC6, 0x4F, 0xC0, 0x7E, 0xBE, 0x4D, 0xBD, 

+	0x4C, 0xC6, 0x43, 0x20, 0x8D, 0x01, 0x90, 0xE1, 0x8E, 0x00, 0x91, 0x00, 0x21, 0x21, 0x71, 0x42, 

+	0x07, 0x1A, 0xD5, 0x04, 0x21, 0x88, 0x43, 0x20, 0x85, 0x60, 0x7A, 0x06, 0x21, 0x48, 0x43, 0x28, 

+	0x56, 0x00, 0x28, 0x7D, 0xDB, 0xFF, 0xF7, 0xC6, 0xF9, 0xC0, 0xB2, 0x20, 0x71, 0x0A, 0x21, 0x48, 

+	0x43, 0xB9, 0x49, 0x09, 0x68, 0x40, 0x18, 0xC1, 0x78, 0x80, 0x78, 0xFF, 0xF7, 0x67, 0xFF, 0xFF, 

+	0xF7, 0xB9, 0xFE, 0xE0, 0x8E, 

+	0x00, 0x00, 0x58, 0x00, 0x80, 0x04, 0x21, 0xA5, 0xE0, 0xC2, 0x07, 0x26, 0xD0, 0x40, 0x08, 0x40, 

+	0x00, 0x20, 0x85, 0x60, 0x7A, 0x06, 0x21, 0x48, 0x43, 0x41, 0x19, 0x02, 0x20, 0x08, 0x56, 0x00, 

+	0x28, 0xDF, 0xDB, 0x17, 0x21, 0x3A, 0x68, 0x49, 0x01, 0x51, 0x18, 0x61, 0x66, 0x41, 0x00, 0xA5, 

+	0x4A, 0xC0, 0xB2, 0x89, 0x18, 0x60, 0x31, 0x09, 0x7D, 0xE1, 0x77, 0x24, 0x21, 0x51, 0x5E, 0x21, 

+	0x66, 0xFF, 0xF7, 0x94, 0xF8, 0xFF, 0xF7, 0xA6, 0xFD, 0xA3, 0x48, 0x00, 0x68, 0x41, 0x79, 0x00, 

+	0x79, 0xFF, 0xF7, 0xB6, 0xFD, 0xE0, 0x8E, 0x01, 0x21, 0x7C, 0xE0, 0x82, 0x07, 0x22, 0xD5, 0x02, 

+	0x21, 0x88, 0x43, 0x20, 0x85, 0x60, 0x7A, 0x06, 0x21, 0x48, 0x43, 0x41, 0x19, 0x01, 0x20, 0x08, 

+	0x56, 0x00, 0x28, 0x77, 0xDB, 0x17, 0x21, 0x3A, 0x68, 0x49, 0x01, 0x51, 0x18, 0x61, 0x66, 0x42, 

+	0x00, 0x90, 0x49, 0xC0, 0xB2, 

+	0x00, 0x00, 0x59, 0x00, 0x80, 0x52, 0x18, 0x60, 0x32, 0x12, 0x7D, 0xE2, 0x77, 0x24, 0x22, 0x8A, 

+	0x5E, 0x22, 0x66, 0xFF, 0xF7, 0x6B, 0xF8, 0xFF, 0xF7, 0x7D, 0xFD, 0xFF, 0xF7, 0x3F, 0xFD, 0xE0, 

+	0x8E, 0x02, 0x21, 0x57, 0xE0, 0x02, 0x07, 0x23, 0xD5, 0x08, 0x21, 0x88, 0x43, 0x20, 0x85, 0x60, 

+	0x7A, 0x06, 0x21, 0x48, 0x43, 0x41, 0x19, 0x03, 0x20, 0x08, 0x56, 0x00, 0x28, 0x52, 0xDB, 0x83, 

+	0x49, 0xC9, 0x7D, 0x00, 0x29, 0x4E, 0xD0, 0xB1, 0x07, 0xC9, 0x17, 0x49, 0x1C, 0x4A, 0xD0, 0x65, 

+	0x22, 0x39, 0x68, 0xD2, 0x00, 0x89, 0x18, 0xA1, 0x66, 0xFF, 0xF7, 0x4C, 0xF9, 0x20, 0x71, 0x00, 

+	0xE0, 0x3A, 0xE0, 0xFF, 0xF7, 0xC6, 0xFC, 0xFF, 0xF7, 0xA3, 0xFC, 0xE0, 0x8E, 0x08, 0x21, 0x31, 

+	0xE0, 0xC2, 0x06, 0x1E, 0xD5, 0x10, 0x21, 0x88, 0x43, 0x20, 0x85, 0x60, 0x7A, 0x06, 0x21, 0x48, 

+	0x43, 0x41, 0x19, 0x04, 0x20, 

+	0x00, 0x00, 0x5A, 0x00, 0x80, 0x08, 0x56, 0x00, 0x28, 0x2C, 0xDB, 0x70, 0x48, 0xC0, 0x7D, 0x00, 

+	0x28, 0x28, 0xD0, 0xF0, 0x07, 0xC0, 0x17, 0x40, 0x1C, 0x24, 0xD0, 0x33, 0x21, 0x38, 0x68, 0x09, 

+	0x01, 0x40, 0x18, 0xA0, 0x66, 0xFF, 0xF7, 0xFF, 0xFB, 0xFF, 0xF7, 0x43, 0xFA, 0xE0, 0x8E, 0x10, 

+	0x21, 0x10, 0xE0, 0x02, 0x06, 0x11, 0xD5, 0x80, 0x21, 0x88, 0x43, 0x20, 0x85, 0x60, 0x7A, 0x06, 

+	0x21, 0x48, 0x43, 0x28, 0x56, 0xFF, 0xF7, 0x16, 0xF9, 0xC0, 0xB2, 0x20, 0x71, 0x01, 0xF0, 0x00, 

+	0xF9, 0xE0, 0x8E, 0x80, 0x21, 0x08, 0x43, 0xE0, 0x86, 0x04, 0xE0, 0x00, 0x28, 0x0B, 0xD0, 0x21, 

+	0x85, 0x01, 0x20, 0xA0, 0x70, 0xE1, 0x8E, 0x00, 0x98, 0x88, 0x42, 0x03, 0xD1, 0x01, 0x98, 0x00, 

+	0x28, 0x00, 0xD0, 0x26, 0xE7, 0xFE, 0xBD, 0x01, 0x20, 0xA0, 0x70, 0x4D, 0x48, 0x01, 0x62, 0xF1, 

+	0xE7, 0x4C, 0x4A, 0x00, 0x23, 

+	0x00, 0x00, 0x5B, 0x00, 0x80, 0x93, 0x70, 0xD3, 0x86, 0x10, 0x85, 0x51, 0x72, 0x13, 0x87, 0x53, 

+	0x87, 0x10, 0xE7, 0x48, 0x4B, 0x98, 0x78, 0x00, 0x28, 0x21, 0xD0, 0xD8, 0x8E, 0x40, 0x07, 0x03, 

+	0xD5, 0xD8, 0x6C, 0x18, 0x65, 0xD8, 0x7C, 0x18, 0x75, 0x46, 0x49, 0x1A, 0x8F, 0x40, 0x31, 0x48, 

+	0x8B, 0x90, 0x42, 0x01, 0xD2, 0x01, 0x22, 0x00, 0xE0, 0x00, 0x22, 0x3E, 0x48, 0x20, 0x30, 0x02, 

+	0x70, 0x89, 0x8B, 0x5A, 0x8F, 0x91, 0x42, 0x01, 0xD2, 0x01, 0x21, 0x00, 0xE0, 0x00, 0x21, 0x41, 

+	0x70, 0x19, 0x8F, 0x42, 0x48, 0xC1, 0x83, 0x59, 0x8F, 0x20, 0x30, 0x01, 0x80, 0x01, 0x20, 0x70, 

+	0x47, 0xD7, 0xE7, 0x70, 0xB5, 0x37, 0x48, 0x33, 0x49, 0x40, 0x30, 0xC4, 0x8B, 0x20, 0x31, 0x00, 

+	0x20, 0x08, 0x56, 0x00, 0x2C, 0x13, 0xD0, 0x2F, 0x4D, 0x00, 0x28, 0x05, 0xD0, 0x0A, 0xF0, 0x48, 

+	0xFD, 0x28, 0x64, 0x01, 0x20, 

+	0x00, 0x00, 0x5C, 0x00, 0x80, 0xA8, 0x71, 0x0B, 0xE0, 0xA8, 0x79, 0x00, 0x28, 0x07, 0xD0, 0x0A, 

+	0xF0, 0x3F, 0xFD, 0x29, 0x6C, 0x40, 0x1A, 0xA0, 0x42, 0x02, 0xD9, 0x00, 0x20, 0xA8, 0x71, 0x70, 

+	0xBD, 0x01, 0x20, 0x70, 0xBD, 0x70, 0xB5, 0x27, 0x48, 0x22, 0x49, 0x60, 0x30, 0x04, 0x88, 0x20, 

+	0x31, 0x01, 0x20, 0x08, 0x56, 0x00, 0x2C, 0x13, 0xD0, 0x1E, 0x4D, 0x00, 0x28, 0x05, 0xD0, 0x0A, 

+	0xF0, 0x27, 0xFD, 0x68, 0x64, 0x01, 0x20, 0xE8, 0x71, 0x0B, 0xE0, 0xE8, 0x79, 0x00, 0x28, 0x07, 

+	0xD0, 0x0A, 0xF0, 0x1E, 0xFD, 0x69, 0x6C, 0x40, 0x1A, 0xA0, 0x42, 0x02, 0xD9, 0x00, 0x20, 0xE8, 

+	0x71, 0x70, 0xBD, 0x01, 0x20, 0x70, 0xBD, 0x17, 0x48, 0x40, 0x30, 0x80, 0x7D, 0x00, 0x28, 0x00, 

+	0xD0, 0x01, 0x20, 0x70, 0x47, 0x7C, 0xB5, 0x04, 0x46, 0x69, 0x46, 0x00, 0x20, 0x01, 0xF0, 0x11, 

+	0xF9, 0x05, 0x46, 0x05, 0x22, 

+	0x00, 0x00, 0x5D, 0x00, 0x80, 0x69, 0x46, 0x60, 0x1D, 0x0B, 0xF0, 0xA1, 0xF9, 0x69, 0x46, 0x01, 

+	0x20, 0x01, 0xF0, 0x07, 0xF9, 0x05, 0x40, 0x20, 0x46, 0x05, 0x22, 0x69, 0x46, 0x0A, 0x30, 0x0B, 

+	0xF0, 0x96, 0xF9, 0x05, 0x22, 0x0E, 0x49, 0x20, 0x46, 0x0B, 0xF0, 0x91, 0xF9, 0x28, 0x46, 0x7C, 

+	0xBD, 0x00, 0x00, 0x0A, 0x40, 0x30, 0x01, 0x00, 0x20, 0xAC, 0xE5, 0x00, 0x00, 0xA8, 0x01, 0x00, 

+	0x20, 0x88, 0x00, 0x00, 0x20, 0xA4, 0xF4, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x20, 0x84, 0xF4, 0x00, 

+	0x00, 0x3D, 0x32, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x20, 0xAC, 0x01, 0x00, 0x20, 0x2C, 0x04, 0x00, 

+	0x20, 0x5C, 0xF5, 0x00, 0x00, 0xBA, 0x49, 0x88, 0x42, 0x02, 0xDB, 0x49, 0x0C, 0x88, 0x42, 0x00, 

+	0xDD, 0x08, 0x46, 0x00, 0xB2, 0x70, 0x47, 0xF0, 0xB5, 0x0F, 0x46, 0x06, 0x46, 0x0E, 0x24, 0x0B, 

+	0xE0, 0x38, 0x19, 0x1A, 0x25, 

+	0x00, 0x00, 0x5E, 0x00, 0x80, 0x45, 0x57, 0x00, 0x2D, 0x06, 0xDB, 0x6D, 0x00, 0x70, 0x5F, 0x50, 

+	0x43, 0x18, 0x41, 0xFF, 0xF7, 0xE7, 0xFF, 0x70, 0x53, 0x64, 0x1E, 0xF1, 0xD2, 0xF0, 0xBD, 0xF0, 

+	0xB5, 0xAC, 0x49, 0x9D, 0xB0, 0x48, 0x7B, 0xAC, 0x4E, 0x19, 0x90, 0xF0, 0x7A, 0x1B, 0x90, 0xAB, 

+	0x48, 0xAB, 0x4D, 0x00, 0x68, 0x1A, 0x90, 0xF0, 0x7E, 0x01, 0x28, 0x66, 0xD0, 0x42, 0x00, 0xA9, 

+	0x49, 0x68, 0x46, 0x0B, 0xF0, 0x44, 0xF9, 0xF0, 0x7E, 0x6C, 0x46, 0x42, 0x00, 0x10, 0x19, 0xA5, 

+	0x49, 0x0B, 0xF0, 0x3D, 0xF9, 0x00, 0x20, 0x18, 0x90, 0x1B, 0x98, 0x00, 0x28, 0x53, 0xD9, 0x19, 

+	0x98, 0x40, 0x1E, 0x86, 0x46, 0x40, 0x1C, 0x46, 0xD0, 0x19, 0x99, 0x18, 0x98, 0x48, 0x43, 0x1C, 

+	0x90, 0x99, 0x49, 0x70, 0x44, 0xCA, 0x7E, 0x84, 0x46, 0x50, 0x1E, 0x00, 0x2A, 0x09, 0xD0, 0x19, 

+	0x9A, 0x42, 0x43, 0x62, 0x44, 

+	0x00, 0x00, 0x5F, 0x00, 0x80, 0x53, 0x00, 0x1A, 0x9A, 0xD2, 0x5A, 0x43, 0x00, 0xEA, 0x52, 0x40, 

+	0x1E, 0xF5, 0xD2, 0xC8, 0x7E, 0x43, 0x1E, 0x00, 0x28, 0x26, 0xD0, 0x8F, 0x48, 0x00, 0x22, 0xC6, 

+	0x7E, 0x99, 0x19, 0x49, 0x1E, 0x70, 0x1E, 0x00, 0x2E, 0x08, 0xD0, 0x46, 0x00, 0x4F, 0x00, 0xAE, 

+	0x5F, 0xE7, 0x5F, 0x49, 0x1E, 0x7E, 0x43, 0xB2, 0x18, 0x40, 0x1E, 0xF6, 0xD2, 0x86, 0x49, 0x50, 

+	0x13, 0x0A, 0x6D, 0x09, 0x7D, 0x50, 0x43, 0x89, 0x1C, 0x08, 0x41, 0x81, 0x49, 0x88, 0x42, 0x02, 

+	0xDB, 0x49, 0x0C, 0x88, 0x42, 0x00, 0xDD, 0x08, 0x46, 0x19, 0x99, 0x59, 0x43, 0x61, 0x44, 0x4A, 

+	0x00, 0x1A, 0x99, 0x5B, 0x1E, 0x88, 0x52, 0xD8, 0xD2, 0x70, 0x46, 0x40, 0x1E, 0x86, 0x46, 0x40, 

+	0x1C, 0x01, 0xD0, 0x1C, 0x98, 0xBC, 0xE7, 0x78, 0x49, 0x18, 0x98, 0xC9, 0x7E, 0x40, 0x18, 0x1B, 

+	0x99, 0x18, 0x90, 0x88, 0x42, 

+	0x00, 0x00, 0x60, 0x00, 0x80, 0xAB, 0xD3, 0x1D, 0xB0, 0xF0, 0xBD, 0x35, 0x6D, 0x4A, 0x89, 0x1A, 

+	0x9C, 0x36, 0x7D, 0x06, 0xE0, 0x53, 0x00, 0xE0, 0x5E, 0x68, 0x43, 0x30, 0x41, 0xFF, 0xF7, 0x62, 

+	0xFF, 0xE0, 0x52, 0x52, 0x1E, 0xF6, 0xD2, 0x1D, 0xB0, 0xF0, 0xBD, 0x00, 0xB5, 0x01, 0x21, 0x6E, 

+	0x48, 0xC9, 0x07, 0x01, 0x63, 0x6C, 0x48, 0xC0, 0x38, 0x02, 0x68, 0x0A, 0x43, 0x02, 0x60, 0x6A, 

+	0x48, 0x80, 0x38, 0x40, 0x6A, 0x00, 0x28, 0x01, 0xD0, 0x01, 0x22, 0x00, 0xE0, 0x00, 0x22, 0xFE, 

+	0xF7, 0x85, 0xFF, 0x10, 0x46, 0x00, 0xBD, 0x10, 0xB5, 0x01, 0x46, 0x04, 0x20, 0xFF, 0xF7, 0x90, 

+	0xFE, 0x00, 0x21, 0x62, 0x48, 0x0A, 0xF0, 0x33, 0xFD, 0x04, 0x21, 0x08, 0x46, 0x02, 0xF0, 0xC4, 

+	0xFB, 0x10, 0xBD, 0x10, 0xB5, 0x00, 0x21, 0x01, 0x20, 0xFF, 0xF7, 0x82, 0xFE, 0x00, 0x21, 0x5B, 

+	0x48, 0x0A, 0xF0, 0x25, 0xFD, 

+	0x00, 0x00, 0x61, 0x00, 0x80, 0x01, 0x21, 0x04, 0x20, 0x02, 0xF0, 0xB6, 0xFB, 0x10, 0xBD, 0x10, 

+	0xB5, 0x00, 0x21, 0x02, 0x20, 0xFF, 0xF7, 0x74, 0xFE, 0x00, 0x21, 0x54, 0x48, 0x0A, 0xF0, 0x17, 

+	0xFD, 0x02, 0x21, 0x04, 0x20, 0x02, 0xF0, 0xA8, 0xFB, 0x10, 0xBD, 0x10, 0xB5, 0x01, 0x46, 0x08, 

+	0x20, 0xFF, 0xF7, 0x66, 0xFE, 0x00, 0x21, 0x4D, 0x48, 0x0A, 0xF0, 0x09, 0xFD, 0x08, 0x21, 0x04, 

+	0x20, 0x02, 0xF0, 0x9A, 0xFB, 0x10, 0xBD, 0x10, 0xB5, 0x00, 0x21, 0x10, 0x20, 0xFF, 0xF7, 0x58, 

+	0xFE, 0x00, 0x21, 0x46, 0x48, 0x0A, 0xF0, 0xFB, 0xFC, 0x10, 0x21, 0x04, 0x20, 0x02, 0xF0, 0x8C, 

+	0xFB, 0x10, 0xBD, 0xF3, 0xB5, 0x42, 0x48, 0x8F, 0xB0, 0x05, 0x68, 0x3A, 0x48, 0x40, 0x7B, 0x40, 

+	0x00, 0x46, 0x19, 0x01, 0x46, 0x0C, 0x90, 0x0D, 0x96, 0x28, 0x46, 0x0B, 0xF0, 0xC5, 0xF8, 0x36, 

+	0x4F, 0x00, 0x24, 0x20, 0x37, 

+	0x00, 0x00, 0x62, 0x00, 0x80, 0x41, 0xE0, 0x34, 0x49, 0x09, 0x7C, 0xA1, 0x42, 0xFB, 0xDD, 0x84, 

+	0x42, 0x30, 0x48, 0x40, 0x7B, 0x05, 0xDB, 0x0F, 0xE0, 0x41, 0x00, 0x6A, 0x5A, 0x73, 0x5A, 0xD2, 

+	0x18, 0x6A, 0x52, 0x40, 0x1E, 0xF8, 0xD5, 0x0D, 0xE0, 0x41, 0x00, 0x0D, 0x9A, 0x73, 0x5A, 0x52, 

+	0x5A, 0x9A, 0x1A, 0x6B, 0x5A, 0xD2, 0x18, 0x6A, 0x52, 0x40, 0x1E, 0xF5, 0xD5, 0x0D, 0x99, 0x0C, 

+	0x98, 0x40, 0x18, 0x0D, 0x90, 0x0C, 0x98, 0x86, 0x19, 0xF8, 0x78, 0x40, 0x1E, 0x84, 0x42, 0x1B, 

+	0xDB, 0x29, 0x46, 0x68, 0x46, 0x0C, 0x9A, 0x0B, 0xF0, 0x3A, 0xF8, 0x1F, 0x48, 0xC0, 0x7E, 0x08, 

+	0x28, 0x1D, 0x48, 0xC3, 0x7C, 0x00, 0xD9, 0x5B, 0x1C, 0xC2, 0x6C, 0x81, 0x6C, 0x68, 0x46, 0xFF, 

+	0xF7, 0xC2, 0xFE, 0x19, 0x48, 0x00, 0x7A, 0x00, 0x28, 0x06, 0xD1, 0xF8, 0x78, 0x0F, 0x99, 0x22, 

+	0x1A, 0x52, 0x1C, 0x68, 0x46, 

+	0x00, 0x00, 0x63, 0x00, 0x80, 0x03, 0xF0, 0x0F, 0xF8, 0x64, 0x1C, 0xF9, 0x79, 0xF8, 0x78, 0x09, 

+	0x18, 0x49, 0x1E, 0xA1, 0x42, 0xB7, 0xDC, 0x10, 0x48, 0x00, 0x7A, 0x00, 0x28, 0x15, 0xD0, 0x10, 

+	0x98, 0x00, 0x28, 0x12, 0xD0, 0x13, 0x48, 0x28, 0x21, 0x00, 0x78, 0x6B, 0x46, 0x48, 0x43, 0x12, 

+	0x49, 0x42, 0x18, 0x1A, 0x32, 0x0E, 0x20, 0x06, 0xE0, 0x11, 0x56, 0x00, 0x29, 0x03, 0xDB, 0x49, 

+	0x00, 0x10, 0x9C, 0x5D, 0x5A, 0x65, 0x52, 0x40, 0x1E, 0xF6, 0xD2, 0x11, 0xB0, 0xF0, 0xBD, 0x00, 

+	0x00, 0x00, 0x80, 0xFF, 0xFF, 0x84, 0xF4, 0x00, 0x00, 0x30, 0x01, 0x00, 0x20, 0xE8, 0x00, 0x00, 

+	0x20, 0xE8, 0x09, 0x00, 0x20, 0xE0, 0xF5, 0x00, 0x00, 0xC0, 0x00, 0x0A, 0x40, 0xDD, 0x2D, 0x00, 

+	0x00, 0xEC, 0x00, 0x00, 0x20, 0xB0, 0x01, 0x00, 0x20, 0x20, 0xF6, 0x00, 0x00, 0xFF, 0xB5, 0x96, 

+	0x46, 0x8C, 0x46, 0x0E, 0x23, 

+	0x00, 0x00, 0x64, 0x00, 0x80, 0x09, 0x9E, 0x18, 0xE0, 0xC7, 0x49, 0x1A, 0x25, 0x09, 0x68, 0xC9, 

+	0x18, 0x4D, 0x57, 0x00, 0x2D, 0x11, 0xDB, 0x9C, 0x00, 0x37, 0x5F, 0x01, 0x5B, 0xA2, 0x19, 0x4F, 

+	0x43, 0x02, 0x21, 0x24, 0x18, 0x51, 0x5E, 0x64, 0x88, 0x03, 0x9A, 0x61, 0x43, 0x79, 0x18, 0x11, 

+	0x41, 0x72, 0x46, 0x51, 0x1A, 0x6C, 0x00, 0x62, 0x46, 0x11, 0x53, 0x5B, 0x1E, 0xE4, 0xD2, 0xFF, 

+	0xBD, 0xF0, 0xB5, 0xBA, 0x48, 0x8F, 0xB0, 0x01, 0x21, 0x01, 0x61, 0x38, 0x22, 0xB8, 0x49, 0x01, 

+	0xA8, 0xFE, 0xF7, 0xBC, 0xFB, 0xB7, 0x4A, 0xB8, 0x4D, 0x14, 0x78, 0x29, 0x6B, 0xB7, 0x48, 0x03, 

+	0x88, 0xC9, 0x18, 0x01, 0x80, 0x60, 0x1C, 0xC0, 0xB2, 0xB5, 0x49, 0x10, 0x70, 0x09, 0x78, 0x6E, 

+	0x03, 0x49, 0x1E, 0x01, 0xAF, 0x88, 0x42, 0x02, 0xDA, 0xFF, 0xF7, 0xDF, 0xFA, 0x07, 0xE0, 0x88, 

+	0x42, 0x20, 0xD1, 0xFF, 0xF7, 

+	0x00, 0x00, 0x65, 0x00, 0x80, 0xDA, 0xFA, 0xAF, 0x48, 0x00, 0x78, 0x00, 0x28, 0x02, 0xD0, 0x28, 

+	0x68, 0x30, 0x43, 0x03, 0xE0, 0x28, 0x68, 0x03, 0x21, 0x49, 0x07, 0x08, 0x43, 0x28, 0x60, 0xAA, 

+	0x48, 0x40, 0x7B, 0x60, 0x43, 0x41, 0x00, 0xA9, 0x48, 0x00, 0x68, 0x00, 0x97, 0x09, 0x18, 0xA8, 

+	0x48, 0x03, 0x78, 0xA8, 0x48, 0x02, 0x88, 0xA8, 0x48, 0x00, 0x68, 0x2C, 0x30, 0xFF, 0xF7, 0x9E, 

+	0xFF, 0x0F, 0xB0, 0xF0, 0xBD, 0xA0, 0x48, 0x40, 0x7B, 0x60, 0x43, 0x41, 0x00, 0x9F, 0x48, 0x00, 

+	0x68, 0x00, 0x97, 0x09, 0x18, 0x9E, 0x48, 0x03, 0x78, 0x9E, 0x48, 0x02, 0x88, 0x9E, 0x48, 0x00, 

+	0x68, 0x2C, 0x30, 0xFF, 0xF7, 0x8B, 0xFF, 0x97, 0x49, 0x08, 0x78, 0x00, 0x28, 0x20, 0xD0, 0x40, 

+	0x1E, 0xC0, 0xB2, 0x08, 0x70, 0x28, 0x21, 0x48, 0x43, 0x98, 0x49, 0x8B, 0x4C, 0x40, 0x18, 0x20, 

+	0x60, 0x97, 0x48, 0x98, 0x49, 

+	0x00, 0x00, 0x66, 0x00, 0x80, 0x00, 0x78, 0x09, 0x78, 0x40, 0x1A, 0x97, 0x49, 0x08, 0x70, 0x97, 

+	0x48, 0x00, 0x21, 0x01, 0x70, 0x87, 0x48, 0x01, 0x70, 0x01, 0x20, 0xFE, 0xF7, 0x47, 0xFF, 0x20, 

+	0x68, 0xFE, 0xF7, 0x05, 0xFF, 0xFF, 0xF7, 0x89, 0xFA, 0x28, 0x68, 0x30, 0x43, 0x28, 0x60, 0xC7, 

+	0xE7, 0x7E, 0x48, 0x81, 0x69, 0x49, 0x08, 0x49, 0x00, 0x81, 0x61, 0xFE, 0xF7, 0x0F, 0xFE, 0xFF, 

+	0xF7, 0x39, 0xFC, 0xBD, 0xE7, 0x70, 0xB5, 0x79, 0x49, 0x01, 0x20, 0x08, 0x61, 0x88, 0x48, 0x8A, 

+	0x4D, 0x03, 0x78, 0x88, 0x48, 0x29, 0x68, 0x02, 0x88, 0x7F, 0x48, 0x00, 0x68, 0x64, 0x30, 0x01, 

+	0xF0, 0x83, 0xF9, 0x86, 0x48, 0x70, 0x4C, 0x03, 0x78, 0x85, 0x48, 0x21, 0x68, 0x02, 0x68, 0x28, 

+	0x68, 0xFF, 0xF7, 0xC1, 0xFD, 0x70, 0x48, 0x01, 0x6B, 0x70, 0x48, 0x02, 0x88, 0x89, 0x18, 0x01, 

+	0x80, 0x6C, 0x49, 0x08, 0x78, 

+	0x00, 0x00, 0x67, 0x00, 0x80, 0x40, 0x1C, 0xC0, 0xB2, 0x08, 0x70, 0x6D, 0x49, 0x09, 0x78, 0x88, 

+	0x42, 0x04, 0xD1, 0xFE, 0xF7, 0xE3, 0xFD, 0xFF, 0xF7, 0x0D, 0xFC, 0x70, 0xBD, 0x79, 0x49, 0x08, 

+	0x78, 0x40, 0x1C, 0xC0, 0xB2, 0x08, 0x70, 0x28, 0x21, 0x48, 0x43, 0x6C, 0x49, 0x40, 0x18, 0x20, 

+	0x60, 0x0A, 0x20, 0xFE, 0xF7, 0xFB, 0xFE, 0x20, 0x68, 0xFE, 0xF7, 0xB9, 0xFE, 0x01, 0x20, 0xFE, 

+	0xF7, 0xE0, 0xFD, 0x70, 0xBD, 0xF8, 0xB5, 0x5B, 0x4D, 0x6F, 0x49, 0x28, 0x78, 0x09, 0x68, 0x40, 

+	0x00, 0x5D, 0x4E, 0x47, 0x18, 0x55, 0x49, 0xF4, 0x7D, 0x01, 0x20, 0x08, 0x61, 0x6B, 0x48, 0x39, 

+	0x46, 0x03, 0x78, 0x6B, 0x48, 0x02, 0x88, 0x5C, 0x48, 0x00, 0x68, 0x2C, 0x30, 0x01, 0xF0, 0x1E, 

+	0xF9, 0x68, 0x48, 0x03, 0x78, 0x68, 0x48, 0x02, 0x68, 0x4B, 0x48, 0x01, 0x68, 0x38, 0x46, 0xFF, 

+	0xF7, 0x7A, 0xFD, 0x4D, 0x48, 

+	0x00, 0x00, 0x68, 0x00, 0x80, 0x02, 0x6B, 0x65, 0x48, 0x01, 0x88, 0x51, 0x18, 0x01, 0x80, 0x64, 

+	0x48, 0xC0, 0x7B, 0x01, 0x28, 0x19, 0xD1, 0x29, 0x78, 0x48, 0x1C, 0xC0, 0xB2, 0xA0, 0x42, 0x14, 

+	0xD2, 0xB2, 0x7B, 0x01, 0x23, 0x51, 0x18, 0x5F, 0x4A, 0x51, 0x5C, 0x8C, 0x00, 0x5E, 0x49, 0x64, 

+	0x18, 0x23, 0x60, 0x28, 0x70, 0xB3, 0x7B, 0x18, 0x18, 0x10, 0x5C, 0x02, 0x22, 0x80, 0x00, 0x40, 

+	0x18, 0x02, 0x60, 0x00, 0x20, 0xFE, 0xF7, 0x9D, 0xFD, 0xF8, 0xBD, 0xFE, 0xF7, 0x87, 0xFD, 0xFF, 

+	0xF7, 0xB1, 0xFB, 0xF8, 0xBD, 0x10, 0xB5, 0x35, 0x49, 0x01, 0x20, 0x08, 0x61, 0x53, 0x48, 0x4A, 

+	0x4C, 0x03, 0x78, 0x53, 0x48, 0x21, 0x68, 0x02, 0x88, 0x3B, 0x48, 0x00, 0x68, 0x64, 0x30, 0x01, 

+	0xF0, 0xFB, 0xF8, 0x50, 0x48, 0x03, 0x78, 0x50, 0x48, 0x02, 0x68, 0x2B, 0x48, 0x01, 0x68, 0x20, 

+	0x68, 0xFF, 0xF7, 0x39, 0xFD, 

+	0x00, 0x00, 0x69, 0x00, 0x80, 0x2C, 0x48, 0x01, 0x6B, 0x44, 0x48, 0x02, 0x88, 0x89, 0x18, 0x01, 

+	0x80, 0xFE, 0xF7, 0x64, 0xFD, 0xFF, 0xF7, 0x8E, 0xFB, 0x10, 0xBD, 0x30, 0xB5, 0x0E, 0x22, 0x22, 

+	0x4C, 0x0A, 0xE0, 0x23, 0x68, 0x9D, 0x18, 0x1A, 0x23, 0xEB, 0x56, 0x00, 0x2B, 0x04, 0xDB, 0x95, 

+	0x00, 0x6D, 0x18, 0x6D, 0x88, 0x5B, 0x00, 0xC5, 0x52, 0x52, 0x1E, 0xF2, 0xD2, 0x30, 0xBD, 0x70, 

+	0xB5, 0x1A, 0x4C, 0x02, 0x26, 0x26, 0x61, 0x20, 0x48, 0x3C, 0x4D, 0x40, 0x7B, 0x29, 0x78, 0x49, 

+	0x1C, 0x48, 0x43, 0x3B, 0x49, 0x40, 0x00, 0x09, 0x68, 0x40, 0x18, 0x15, 0x49, 0xFF, 0xF7, 0xDD, 

+	0xFF, 0x20, 0x69, 0xC0, 0x07, 0x0C, 0xD0, 0x01, 0x20, 0x20, 0x61, 0xA0, 0x69, 0x40, 0x08, 0x40, 

+	0x00, 0xA0, 0x61, 0xA0, 0x69, 0xB0, 0x43, 0xA0, 0x61, 0xFE, 0xF7, 0x30, 0xFD, 0xFF, 0xF7, 0x5A, 

+	0xFB, 0x28, 0x78, 0x40, 0x1C, 

+	0x00, 0x00, 0x6A, 0x00, 0x80, 0x28, 0x70, 0x70, 0xBD, 0x10, 0xB5, 0x08, 0x48, 0x01, 0x24, 0x04, 

+	0x60, 0x09, 0x48, 0x40, 0x30, 0x40, 0x6A, 0x00, 0x28, 0x05, 0xD1, 0xFE, 0xF7, 0xF7, 0xFC, 0x29, 

+	0x48, 0x04, 0x70, 0x29, 0x48, 0x04, 0x70, 0x10, 0xBD, 0x78, 0x01, 0x00, 0x20, 0xC0, 0x0F, 0x0A, 

+	0x40, 0x00, 0x40, 0x0A, 0x40, 0x3F, 0x01, 0x00, 0x20, 0x00, 0x00, 0x0A, 0x40, 0x68, 0x01, 0x00, 

+	0x20, 0x4C, 0x01, 0x00, 0x20, 0x3E, 0x01, 0x00, 0x20, 0x84, 0xF4, 0x00, 0x00, 0xE4, 0x00, 0x00, 

+	0x20, 0x41, 0x01, 0x00, 0x20, 0x5A, 0x01, 0x00, 0x20, 0xAC, 0x01, 0x00, 0x20, 0x20, 0xF6, 0x00, 

+	0x00, 0x4D, 0x01, 0x00, 0x20, 0x4B, 0x01, 0x00, 0x20, 0x3D, 0x01, 0x00, 0x20, 0x4A, 0x01, 0x00, 

+	0x20, 0x42, 0x01, 0x00, 0x20, 0x5C, 0x01, 0x00, 0x20, 0x94, 0x01, 0x00, 0x20, 0x45, 0x01, 0x00, 

+	0x20, 0x84, 0x01, 0x00, 0x20, 

+	0x00, 0x00, 0x6B, 0x00, 0x80, 0x3C, 0x01, 0x00, 0x20, 0x98, 0x01, 0x00, 0x20, 0x46, 0x01, 0x00, 

+	0x20, 0x5E, 0x01, 0x00, 0x20, 0x48, 0x01, 0x00, 0x20, 0x88, 0x01, 0x00, 0x20, 0x6A, 0x01, 0x00, 

+	0x20, 0xC4, 0xF4, 0x00, 0x00, 0x6C, 0xF5, 0x00, 0x00, 0x00, 0x60, 0x0A, 0x40, 0x47, 0x01, 0x00, 

+	0x20, 0x60, 0x01, 0x00, 0x20, 0x49, 0x01, 0x00, 0x20, 0x8C, 0x01, 0x00, 0x20, 0x40, 0x01, 0x00, 

+	0x20, 0xEC, 0x00, 0x00, 0x20, 0x33, 0x01, 0x00, 0x20, 0x32, 0x01, 0x00, 0x20, 0x70, 0x47, 0x70, 

+	0xB5, 0x0D, 0x46, 0x00, 0x24, 0x06, 0x46, 0x21, 0x46, 0xFF, 0xF7, 0xD2, 0xFB, 0xFF, 0xF7, 0xD9, 

+	0xFB, 0x00, 0x28, 0xFB, 0xD0, 0xFB, 0x49, 0xFC, 0x48, 0x04, 0x2E, 0x0C, 0xD0, 0x17, 0x22, 0x52, 

+	0x01, 0xFA, 0x4B, 0x01, 0x2E, 0x0E, 0xD0, 0x02, 0x2E, 0x10, 0xD0, 0x08, 0x2E, 0x16, 0xD0, 0x10, 

+	0x2E, 0x1B, 0xD0, 0x00, 0x20, 

+	0x00, 0x00, 0x6C, 0x00, 0x80, 0x70, 0xBD, 0x0A, 0x68, 0x41, 0x7B, 0xF5, 0x48, 0x00, 0x78, 0x41, 

+	0x43, 0xF4, 0x48, 0x18, 0xE0, 0x09, 0x68, 0x8A, 0x18, 0x41, 0x7B, 0x05, 0xE0, 0x46, 0x7B, 0x09, 

+	0x68, 0x76, 0x00, 0x71, 0x18, 0x8A, 0x18, 0x01, 0x7B, 0x18, 0x88, 0x0D, 0xE0, 0x09, 0x68, 0x65, 

+	0x22, 0xD2, 0x00, 0x8A, 0x18, 0xC1, 0x7D, 0xEC, 0x48, 0x05, 0xE0, 0x09, 0x68, 0x33, 0x22, 0x12, 

+	0x01, 0x8A, 0x18, 0xC1, 0x7D, 0xE9, 0x48, 0x00, 0x88, 0x28, 0x80, 0x0B, 0x46, 0x02, 0xE0, 0x58, 

+	0x00, 0x10, 0x5E, 0x04, 0x19, 0x5B, 0x1E, 0xFA, 0xD2, 0x20, 0x46, 0x0A, 0xF0, 0x23, 0xFE, 0x70, 

+	0xBD, 0xF8, 0xB5, 0x0D, 0x46, 0xE2, 0x4E, 0x01, 0x21, 0x71, 0x70, 0x69, 0x46, 0xFF, 0xF7, 0xAF, 

+	0xFF, 0x00, 0x28, 0x01, 0xDB, 0x04, 0x46, 0x00, 0xE0, 0x44, 0x42, 0x00, 0x20, 0x70, 0x70, 0x68, 

+	0x46, 0x00, 0x88, 0x64, 0x21, 

+	0x00, 0x00, 0x6D, 0x00, 0x80, 0x68, 0x43, 0x0A, 0xF0, 0x03, 0xFE, 0x84, 0x42, 0x01, 0xD9, 0x00, 

+	0x20, 0xF8, 0xBD, 0x01, 0x20, 0xF8, 0xBD, 0x70, 0xB5, 0xD6, 0x4C, 0xFE, 0x21, 0xA0, 0x1C, 0xD6, 

+	0x4A, 0x0A, 0xF0, 0xDC, 0xFE, 0x21, 0x88, 0x88, 0x42, 0x01, 0xD0, 0x00, 0x20, 0x70, 0xBD, 0xD3, 

+	0x4C, 0x04, 0x20, 0x61, 0x7E, 0xFF, 0xF7, 0xD4, 0xFF, 0x00, 0x28, 0xF7, 0xD0, 0xC6, 0x4E, 0x70, 

+	0x7F, 0xC5, 0x43, 0xE8, 0x07, 0xC0, 0x17, 0x40, 0x1C, 0x05, 0xD0, 0xA1, 0x7E, 0x01, 0x20, 0xFF, 

+	0xF7, 0xC7, 0xFF, 0x00, 0x28, 0xEA, 0xD0, 0xA8, 0x07, 0xC0, 0x17, 0x40, 0x1C, 0x05, 0xD0, 0xA1, 

+	0x7E, 0x02, 0x20, 0xFF, 0xF7, 0xBD, 0xFF, 0x00, 0x28, 0xE0, 0xD0, 0xF0, 0x7D, 0x00, 0x28, 0x15, 

+	0xD0, 0xF0, 0x7E, 0xC5, 0x43, 0xA8, 0x07, 0xC0, 0x17, 0x40, 0x1C, 0x05, 0xD0, 0xE1, 0x7E, 0x08, 

+	0x20, 0xFF, 0xF7, 0xAE, 0xFF, 

+	0x00, 0x00, 0x6E, 0x00, 0x80, 0x00, 0x28, 0xD1, 0xD0, 0xE8, 0x07, 0xC0, 0x17, 0x40, 0x1C, 0x05, 

+	0xD0, 0x21, 0x7F, 0x10, 0x20, 0xFF, 0xF7, 0xA4, 0xFF, 0x00, 0x28, 0xC7, 0xD0, 0x01, 0x20, 0x70, 

+	0xBD, 0xF7, 0xB5, 0x88, 0xB0, 0xB6, 0x4D, 0x04, 0x46, 0x00, 0x27, 0x6E, 0x46, 0xE8, 0x5D, 0x20, 

+	0x70, 0x07, 0xA9, 0x0A, 0x98, 0xFF, 0xF7, 0x4B, 0xFF, 0x00, 0x28, 0x00, 0xDA, 0x40, 0x42, 0xB9, 

+	0x00, 0x7F, 0x1C, 0x70, 0x50, 0x07, 0x2F, 0xF1, 0xD3, 0x00, 0x23, 0x00, 0x9A, 0x01, 0x21, 0x88, 

+	0x00, 0x30, 0x58, 0x90, 0x42, 0x04, 0xDC, 0x0B, 0x46, 0x49, 0x1C, 0x02, 0x46, 0x07, 0x29, 0xF6, 

+	0xD3, 0xE8, 0x5C, 0x20, 0x70, 0x07, 0xA9, 0x0A, 0x98, 0xFF, 0xF7, 0x31, 0xFF, 0x09, 0x99, 0x08, 

+	0x60, 0x0B, 0xB0, 0xF0, 0xBD, 0xFF, 0xB5, 0xA1, 0x49, 0x30, 0x26, 0x20, 0x39, 0x09, 0x8B, 0x81, 

+	0xB0, 0x89, 0x04, 0x8C, 0x0F, 

+	0x00, 0x00, 0x6F, 0x00, 0x80, 0xE6, 0x40, 0x45, 0x1C, 0x9E, 0x49, 0x50, 0x20, 0x1F, 0x46, 0x4D, 

+	0x43, 0x44, 0x43, 0x0A, 0xF0, 0x97, 0xF9, 0x02, 0x99, 0x7D, 0x43, 0x4C, 0x43, 0x03, 0x99, 0x68, 

+	0x43, 0x61, 0x43, 0x0A, 0xF0, 0x75, 0xFD, 0x40, 0x1D, 0x0A, 0x21, 0x0A, 0xF0, 0x71, 0xFD, 0x32, 

+	0x46, 0x7F, 0x21, 0x00, 0xF0, 0x41, 0xFB, 0x05, 0xB0, 0xF0, 0xBD, 0xF8, 0xB5, 0x04, 0x46, 0x8C, 

+	0x4D, 0x01, 0x20, 0x68, 0x70, 0x84, 0x48, 0xC0, 0x7D, 0x00, 0x28, 0x45, 0xD0, 0x8B, 0x48, 0x6C, 

+	0x60, 0x20, 0x38, 0x40, 0x69, 0x40, 0x03, 0x47, 0x0F, 0x08, 0x20, 0xFE, 0xF7, 0xC7, 0xFA, 0x87, 

+	0x4E, 0x01, 0x46, 0x20, 0x36, 0x73, 0x88, 0x32, 0x7A, 0x38, 0x46, 0xFF, 0xF7, 0xC3, 0xFF, 0x60, 

+	0x72, 0x08, 0x22, 0x69, 0x46, 0xA0, 0x18, 0xFF, 0xF7, 0x93, 0xFF, 0x7B, 0x48, 0x02, 0x88, 0x00, 

+	0x98, 0x11, 0x1A, 0x60, 0x7A, 

+	0x00, 0x00, 0x70, 0x00, 0x80, 0x00, 0xF0, 0x20, 0xFB, 0x60, 0x72, 0x09, 0x20, 0xFE, 0xF7, 0xAE, 

+	0xFA, 0x01, 0x46, 0xB3, 0x88, 0x72, 0x7A, 0x38, 0x46, 0xFF, 0xF7, 0xAC, 0xFF, 0xE0, 0x72, 0x20, 

+	0x46, 0x10, 0x22, 0x69, 0x46, 0x0A, 0x30, 0xFF, 0xF7, 0x7B, 0xFF, 0x70, 0x48, 0x02, 0x88, 0x00, 

+	0x98, 0x11, 0x18, 0xE0, 0x7A, 0x00, 0xF0, 0x08, 0xFB, 0xE0, 0x72, 0x01, 0x20, 0x0A, 0x21, 0x41, 

+	0x43, 0x09, 0x19, 0x22, 0x7A, 0x0A, 0x72, 0x62, 0x7A, 0x4A, 0x72, 0xA2, 0x7A, 0x8A, 0x72, 0xE2, 

+	0x7A, 0x40, 0x1C, 0xCA, 0x72, 0x04, 0x28, 0xF1, 0xD3, 0x00, 0x20, 0x68, 0x70, 0xF8, 0xBD, 0xF7, 

+	0xB5, 0x94, 0xB0, 0x6A, 0x48, 0x6A, 0xA1, 0x0E, 0x90, 0x03, 0xC9, 0x10, 0x91, 0x6A, 0x49, 0x0F, 

+	0x90, 0x08, 0x78, 0x12, 0x90, 0x5E, 0x4A, 0x01, 0x20, 0x10, 0x70, 0x08, 0x70, 0x5F, 0x48, 0x02, 

+	0x25, 0x20, 0x38, 0x00, 0x8B, 

+	0x00, 0x00, 0x71, 0x00, 0x80, 0x60, 0x4E, 0x80, 0x04, 0x81, 0x0F, 0x16, 0x98, 0x48, 0x43, 0x11, 

+	0x90, 0xD2, 0xE0, 0x0E, 0x24, 0x9A, 0xE0, 0x61, 0x49, 0x00, 0x20, 0x08, 0x70, 0x60, 0x49, 0x08, 

+	0x80, 0x60, 0x48, 0x07, 0x68, 0x15, 0x98, 0xC0, 0x1E, 0x05, 0x28, 0x29, 0xD8, 0x16, 0x99, 0x15, 

+	0x98, 0xFF, 0xF7, 0x0C, 0xF9, 0x5C, 0x48, 0xA1, 0x00, 0x08, 0x18, 0x01, 0x68, 0x01, 0x22, 0x12, 

+	0x04, 0x11, 0x43, 0x01, 0x60, 0x57, 0x48, 0x40, 0x38, 0x01, 0x6A, 0x0F, 0x22, 0x12, 0x06, 0x91, 

+	0x43, 0x01, 0x62, 0x02, 0x6A, 0x03, 0x23, 0x29, 0x46, 0x1B, 0x06, 0x59, 0x43, 0xC3, 0x05, 0x19, 

+	0x43, 0x0A, 0x43, 0x02, 0x62, 0x45, 0x48, 0x28, 0x21, 0x20, 0x38, 0x80, 0x7F, 0x00, 0x23, 0x48, 

+	0x43, 0x4E, 0x49, 0x1A, 0x46, 0x40, 0x18, 0x28, 0x38, 0x19, 0x46, 0xFF, 0xF7, 0x13, 0xF8, 0x42, 

+	0xE0, 0x11, 0x98, 0x24, 0x28, 

+	0x00, 0x00, 0x72, 0x00, 0x80, 0x02, 0xD2, 0xFF, 0x20, 0x57, 0x30, 0x04, 0xE0, 0x32, 0x28, 0x01, 

+	0xD2, 0xE4, 0x20, 0x00, 0xE0, 0xAB, 0x20, 0xFE, 0xF7, 0x3D, 0xFF, 0x78, 0x02, 0x41, 0x0F, 0x0F, 

+	0x22, 0x12, 0x04, 0x38, 0x46, 0x90, 0x43, 0x0F, 0xAA, 0x51, 0x5C, 0x09, 0x04, 0x01, 0x43, 0x3D, 

+	0x48, 0x01, 0x60, 0x3D, 0x48, 0xA1, 0x00, 0x08, 0x18, 0x01, 0x68, 0x01, 0x22, 0x12, 0x04, 0x11, 

+	0x43, 0x01, 0x60, 0x38, 0x48, 0x40, 0x38, 0x02, 0x6A, 0x0F, 0x21, 0x09, 0x06, 0x8A, 0x43, 0x02, 

+	0x62, 0x01, 0x6A, 0x07, 0x22, 0x12, 0x06, 0x6A, 0x43, 0x43, 0x05, 0xD2, 0x18, 0xC3, 0x05, 0x1A, 

+	0x43, 0x11, 0x43, 0x01, 0x62, 0x25, 0x48, 0x24, 0x21, 0x20, 0x38, 0x41, 0x5E, 0x30, 0x48, 0x01, 

+	0x60, 0x18, 0x48, 0x17, 0x21, 0x00, 0x68, 0x49, 0x01, 0x40, 0x18, 0x2E, 0x49, 0x08, 0x60, 0x16, 

+	0x99, 0x15, 0x98, 0xFE, 0xF7, 

+	0x00, 0x00, 0x73, 0x00, 0x80, 0x1D, 0xFF, 0xFF, 0xF7, 0x04, 0xFA, 0x00, 0x28, 0xFB, 0xD0, 0x26, 

+	0x49, 0xA0, 0x00, 0x41, 0x18, 0x0A, 0x68, 0x01, 0x23, 0x1B, 0x04, 0x9A, 0x43, 0x0A, 0x60, 0x21, 

+	0x49, 0x0F, 0x60, 0x00, 0x2D, 0x07, 0xD0, 0x32, 0x5A, 0x69, 0x46, 0x0A, 0x52, 0x82, 0x19, 0x52, 

+	0x88, 0x40, 0x18, 0x42, 0x80, 0x0A, 0xE0, 0x69, 0x46, 0x0A, 0x5A, 0x33, 0x5A, 0xD2, 0x1A, 0x0A, 

+	0x52, 0x41, 0x18, 0x80, 0x19, 0x4A, 0x88, 0x40, 0x88, 0x10, 0x1A, 0x48, 0x80, 0x64, 0x1E, 0x33, 

+	0xD3, 0x61, 0xE7, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x20, 0x84, 0xF4, 0x00, 0x00, 0x5C, 0x01, 0x00, 

+	0x20, 0x3B, 0x01, 0x00, 0x20, 0x5A, 0x01, 0x00, 0x20, 0x5E, 0x01, 0x00, 0x20, 0x60, 0x01, 0x00, 

+	0x20, 0xA8, 0x01, 0x00, 0x20, 0x00, 0xFA, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xC4, 0xF4, 0x00, 

+	0x00, 0x8C, 0xE6, 0x00, 0x00, 

+	0x00, 0x00, 0x74, 0x00, 0x80, 0xC4, 0x09, 0x00, 0x00, 0x00, 0x40, 0x0A, 0x40, 0xFF, 0xFF, 0xFF, 

+	0x7F, 0x0B, 0x0A, 0x08, 0x07, 0x06, 0x04, 0x04, 0x00, 0x8C, 0x00, 0x00, 0x20, 0x32, 0x01, 0x00, 

+	0x20, 0x58, 0x01, 0x00, 0x20, 0x80, 0x00, 0x0A, 0x40, 0x00, 0x70, 0x0A, 0x40, 0x20, 0xF6, 0x00, 

+	0x00, 0x90, 0x01, 0x00, 0x20, 0x94, 0x01, 0x00, 0x20, 0x6D, 0x1E, 0x00, 0xD3, 0x29, 0xE7, 0x1C, 

+	0x20, 0x6D, 0x46, 0x06, 0xE0, 0x41, 0x00, 0x69, 0x5E, 0x0E, 0x9A, 0x91, 0x42, 0x00, 0xDB, 0x11, 

+	0x46, 0x0E, 0x91, 0x40, 0x1E, 0xF6, 0xD2, 0x0E, 0x98, 0x1C, 0x24, 0x86, 0x03, 0x06, 0xE0, 0x67, 

+	0x00, 0xE9, 0x5F, 0x30, 0x46, 0x0A, 0xF0, 0x1E, 0xFC, 0x14, 0x99, 0xC8, 0x53, 0x64, 0x1E, 0xF6, 

+	0xD2, 0xFD, 0x48, 0x01, 0x6A, 0x2F, 0x22, 0x12, 0x06, 0x91, 0x43, 0x01, 0x62, 0xFB, 0x49, 0x12, 

+	0x98, 0x08, 0x70, 0xFB, 0x49, 

+	0x00, 0x00, 0x75, 0x00, 0x80, 0x00, 0x20, 0x08, 0x70, 0x17, 0xB0, 0xF0, 0xBD, 0x38, 0xB5, 0x0B, 

+	0x46, 0x04, 0x46, 0x92, 0xB2, 0x69, 0x46, 0x18, 0x46, 0xFF, 0xF7, 0x42, 0xFE, 0xF5, 0x48, 0x02, 

+	0x88, 0x00, 0x98, 0x11, 0x18, 0x20, 0x78, 0x00, 0xF0, 0xCF, 0xF9, 0x20, 0x70, 0x38, 0xBD, 0xFE, 

+	0xB5, 0x05, 0x46, 0xEF, 0x4A, 0x01, 0x20, 0x0C, 0x46, 0x50, 0x70, 0x1C, 0x20, 0x01, 0x21, 0x89, 

+	0x03, 0x02, 0xE0, 0x43, 0x00, 0x5B, 0x19, 0x99, 0x85, 0x40, 0x1E, 0xFA, 0xD2, 0xE8, 0x48, 0xEA, 

+	0x4F, 0x45, 0x60, 0x78, 0x69, 0x40, 0x03, 0x46, 0x0F, 0x00, 0x20, 0xFE, 0xF7, 0x47, 0xF9, 0x01, 

+	0x46, 0x38, 0x46, 0x40, 0x30, 0x82, 0x79, 0xFB, 0x8F, 0x30, 0x46, 0xFF, 0xF7, 0x43, 0xFE, 0xE8, 

+	0x70, 0x00, 0x2C, 0x04, 0xDB, 0x04, 0x22, 0x69, 0x46, 0xA8, 0x1C, 0xFF, 0xF7, 0x11, 0xFE, 0xDF, 

+	0x48, 0x02, 0x88, 0x00, 0x98, 

+	0x00, 0x00, 0x76, 0x00, 0x80, 0x11, 0x1A, 0xE8, 0x78, 0x00, 0xF0, 0x9E, 0xF9, 0x07, 0x46, 0xE8, 

+	0x70, 0x01, 0x24, 0x0A, 0x20, 0x60, 0x43, 0x46, 0x19, 0xA9, 0x78, 0x60, 0x1C, 0xB1, 0x70, 0xC0, 

+	0xB2, 0xFE, 0xF7, 0x24, 0xF9, 0x01, 0x90, 0x00, 0x20, 0xFE, 0xF7, 0x20, 0xF9, 0x78, 0x43, 0x01, 

+	0x99, 0x0A, 0xF0, 0xAE, 0xFB, 0x64, 0x1C, 0xF0, 0x70, 0x04, 0x2C, 0xEA, 0xD3, 0xCC, 0x48, 0x00, 

+	0x21, 0x41, 0x70, 0xFE, 0xBD, 0xFE, 0xB5, 0x8E, 0x46, 0xCD, 0x49, 0x8C, 0x46, 0xC6, 0x49, 0x74, 

+	0x31, 0x00, 0x23, 0x02, 0x91, 0x00, 0x22, 0xCB, 0x49, 0xD2, 0x43, 0x0A, 0x61, 0xC2, 0x4D, 0xCA, 

+	0x05, 0x40, 0x3D, 0x2A, 0x60, 0x01, 0x24, 0xAC, 0x60, 0x0A, 0x69, 0xD2, 0x07, 0xFC, 0xD0, 0x04, 

+	0x21, 0x00, 0x22, 0xC9, 0x1A, 0x01, 0x25, 0x8D, 0x40, 0x91, 0x00, 0x64, 0x46, 0x00, 0x91, 0x61, 

+	0x58, 0x89, 0x11, 0x49, 0xB2, 

+	0x00, 0x00, 0x77, 0x00, 0x80, 0x8C, 0x10, 0x21, 0x06, 0xC9, 0x0F, 0x01, 0x91, 0x02, 0x99, 0x0F, 

+	0x68, 0x01, 0x26, 0x96, 0x40, 0x37, 0x40, 0xD7, 0x40, 0x71, 0x46, 0xFF, 0xB2, 0x00, 0x29, 0x06, 

+	0xD0, 0x00, 0x26, 0x01, 0x99, 0x4E, 0x40, 0xBE, 0x42, 0x03, 0xD0, 0x29, 0x19, 0x02, 0xE0, 0x01, 

+	0x26, 0xF7, 0xE7, 0x61, 0x1B, 0x4C, 0xB2, 0x61, 0x06, 0x03, 0x26, 0x4F, 0x0C, 0xB6, 0x07, 0xBF, 

+	0x19, 0x00, 0x9E, 0x61, 0x46, 0x8F, 0x51, 0x04, 0x2B, 0x22, 0xD1, 0x71, 0x46, 0x00, 0x29, 0x1E, 

+	0xD0, 0x86, 0x56, 0x37, 0x46, 0x67, 0x40, 0x3F, 0x06, 0x13, 0xD5, 0xF7, 0x06, 0xE1, 0x06, 0xFF, 

+	0x0E, 0xC9, 0x0E, 0x7F, 0x1A, 0x7F, 0x10, 0x00, 0x2F, 0x03, 0xDD, 0xE0, 0x24, 0x26, 0x40, 0x37, 

+	0x43, 0x05, 0xE0, 0x00, 0x2F, 0x00, 0xDA, 0x7F, 0x42, 0xE0, 0x26, 0x34, 0x40, 0x27, 0x43, 0x87, 

+	0x54, 0x06, 0xE0, 0x31, 0x19, 

+	0x00, 0x00, 0x78, 0x00, 0x80, 0xCC, 0x0F, 0x61, 0x18, 0x49, 0x10, 0x81, 0x54, 0x00, 0xE0, 0x84, 

+	0x54, 0x52, 0x1C, 0x0E, 0x2A, 0xB0, 0xD3, 0x5B, 0x1C, 0x05, 0x2B, 0x9B, 0xD3, 0xFE, 0xBD, 0xF1, 

+	0xB5, 0x91, 0x4C, 0x00, 0x27, 0x40, 0x3C, 0x27, 0x60, 0x05, 0x20, 0x09, 0xF0, 0x6A, 0xFF, 0x96, 

+	0x48, 0x07, 0x60, 0x8D, 0x49, 0xC0, 0x05, 0x80, 0x31, 0x08, 0x63, 0x8B, 0x4D, 0x40, 0x35, 0x28, 

+	0x68, 0x07, 0x21, 0x09, 0x05, 0x08, 0x40, 0x8C, 0x49, 0xC9, 0x68, 0x08, 0x43, 0x28, 0x60, 0x86, 

+	0x48, 0x8E, 0x49, 0x01, 0x62, 0x1E, 0x20, 0x09, 0xF0, 0x0F, 0xFE, 0x03, 0x26, 0x82, 0x48, 0xB6, 

+	0x07, 0x06, 0x62, 0xC0, 0x03, 0x28, 0x63, 0x74, 0x22, 0x89, 0x49, 0x8A, 0x48, 0xFD, 0xF7, 0xAE, 

+	0xFE, 0x8A, 0x48, 0x89, 0x49, 0x01, 0x60, 0x8A, 0x49, 0x41, 0x60, 0x01, 0x20, 0x20, 0x62, 0xA7, 

+	0x62, 0x70, 0x10, 0x20, 0x60, 

+	0x00, 0x00, 0x79, 0x00, 0x80, 0x00, 0x24, 0x82, 0x48, 0x20, 0x21, 0x10, 0x38, 0x00, 0x5D, 0x08, 

+	0x43, 0x75, 0x49, 0x40, 0x31, 0x08, 0x62, 0x00, 0x20, 0x00, 0xF0, 0x4B, 0xF9, 0x81, 0x48, 0x06, 

+	0x60, 0x0E, 0x20, 0x00, 0x99, 0x60, 0x43, 0x45, 0x18, 0x2F, 0x46, 0x9C, 0x37, 0x00, 0x21, 0x38, 

+	0x46, 0xFF, 0xF7, 0x48, 0xFF, 0x01, 0x20, 0x00, 0xF0, 0x3C, 0xF9, 0x7A, 0x48, 0x06, 0x60, 0x38, 

+	0x46, 0x01, 0x21, 0xFF, 0xF7, 0x3F, 0xFF, 0x0E, 0x21, 0x05, 0xE0, 0x68, 0x18, 0x80, 0x30, 0x02, 

+	0x7F, 0x92, 0x06, 0x92, 0x0E, 0x02, 0x77, 0x49, 0x1E, 0xF7, 0xD2, 0x64, 0x1C, 0x07, 0x2C, 0xD2, 

+	0xD3, 0xF8, 0xBD, 0xF0, 0xB5, 0xFF, 0x27, 0xC1, 0xB0, 0x04, 0x46, 0x01, 0x37, 0x3A, 0x46, 0x6E, 

+	0x49, 0x68, 0x46, 0xFD, 0xF7, 0x6B, 0xFE, 0x00, 0x21, 0x08, 0x46, 0xFF, 0xF7, 0x41, 0xF8, 0x68, 

+	0x46, 0xFF, 0xF7, 0x8D, 0xFF, 

+	0x00, 0x00, 0x7A, 0x00, 0x80, 0xFE, 0xF7, 0x56, 0xF8, 0xFE, 0xF7, 0x38, 0xF8, 0x60, 0x07, 0x03, 

+	0xD5, 0x21, 0x46, 0x68, 0x46, 0xFF, 0xF7, 0xCB, 0xFE, 0xA0, 0x07, 0x02, 0xD0, 0x68, 0x46, 0x00, 

+	0xF0, 0xCB, 0xF8, 0x53, 0x4E, 0x00, 0x2C, 0x15, 0xDB, 0x01, 0x20, 0x70, 0x70, 0x6D, 0x46, 0x60, 

+	0x07, 0x05, 0xD5, 0x28, 0x46, 0xEA, 0x78, 0xA9, 0x78, 0x2C, 0x30, 0xFF, 0xF7, 0x90, 0xFD, 0xA0, 

+	0x07, 0x06, 0xD0, 0x68, 0x46, 0x42, 0x79, 0x01, 0x79, 0x28, 0x46, 0x64, 0x30, 0xFF, 0xF7, 0x87, 

+	0xFD, 0x00, 0x20, 0x70, 0x70, 0x55, 0x48, 0xC0, 0x7D, 0x00, 0x28, 0x05, 0xD0, 0xE0, 0x06, 0x80, 

+	0x0F, 0x02, 0xD0, 0x68, 0x46, 0xFF, 0xF7, 0x29, 0xFD, 0x6C, 0x46, 0xA0, 0x1C, 0xFE, 0x21, 0x50, 

+	0x4A, 0x0A, 0xF0, 0x74, 0xFB, 0x69, 0x46, 0x08, 0x80, 0x3A, 0x46, 0x21, 0x46, 0x4A, 0x48, 0x0A, 

+	0xF0, 0x73, 0xFB, 0x49, 0x48, 

+	0x00, 0x00, 0x7B, 0x00, 0x80, 0x70, 0x60, 0x41, 0xB0, 0xF0, 0xBD, 0x30, 0xB5, 0x39, 0x23, 0x13, 

+	0x60, 0x37, 0x4B, 0x1A, 0x24, 0x38, 0x25, 0x10, 0x28, 0x24, 0xD0, 0x09, 0xDC, 0x0A, 0x22, 0x00, 

+	0x28, 0x10, 0xD0, 0x04, 0x28, 0x12, 0xD0, 0x05, 0x28, 0x14, 0xD0, 0x07, 0x28, 0x07, 0xD1, 0x15, 

+	0xE0, 0x11, 0x28, 0x1C, 0xD0, 0x19, 0x24, 0x12, 0x28, 0x1E, 0xD0, 0x13, 0x28, 0x29, 0xD0, 0x00, 

+	0x20, 0x08, 0x80, 0x30, 0xBD, 0x0A, 0x80, 0x58, 0x68, 0x80, 0x1C, 0x30, 0xBD, 0x0A, 0x80, 0x58, 

+	0x68, 0x0C, 0x30, 0x30, 0xBD, 0x0A, 0x80, 0x58, 0x68, 0x16, 0x30, 0x30, 0xBD, 0x0A, 0x80, 0x58, 

+	0x68, 0x20, 0x30, 0x30, 0xBD, 0x14, 0x60, 0x0D, 0x80, 0x58, 0x68, 0x2C, 0x30, 0x30, 0xBD, 0x14, 

+	0x60, 0x0D, 0x80, 0x58, 0x68, 0x64, 0x30, 0x30, 0xBD, 0x58, 0x68, 0x25, 0x4D, 0x80, 0x78, 0x09, 

+	0x3D, 0x28, 0x5C, 0x14, 0x60, 

+	0x00, 0x00, 0x7C, 0x00, 0x80, 0x0E, 0x22, 0x0A, 0x80, 0x59, 0x68, 0x50, 0x43, 0x40, 0x18, 0x9C, 

+	0x30, 0x30, 0xBD, 0x14, 0x60, 0x25, 0x4A, 0x90, 0x7B, 0xD3, 0x7D, 0xC0, 0x18, 0x08, 0x80, 0xD3, 

+	0x7D, 0x00, 0x2B, 0x07, 0xD0, 0xD2, 0x7E, 0xD2, 0x43, 0x92, 0x07, 0xD2, 0x17, 0x52, 0x1C, 0x01, 

+	0xD0, 0x40, 0x1C, 0x08, 0x80, 0x1F, 0x48, 0x30, 0xBD, 0x88, 0x42, 0x01, 0xDD, 0x08, 0x46, 0x70, 

+	0x47, 0x90, 0x42, 0xFC, 0xDA, 0x10, 0x46, 0x70, 0x47, 0x10, 0xB5, 0x0B, 0x4B, 0x30, 0x24, 0x1B, 

+	0x8B, 0x9B, 0x04, 0x9B, 0x0F, 0xDC, 0x40, 0x48, 0x43, 0x11, 0x46, 0x0A, 0xF0, 0x19, 0xFA, 0x22, 

+	0x46, 0x7F, 0x21, 0xFF, 0xF7, 0xE9, 0xFF, 0x10, 0xBD, 0x40, 0x00, 0x0A, 0x40, 0x8C, 0x00, 0x00, 

+	0x20, 0xA8, 0x01, 0x00, 0x20, 0x5C, 0x01, 0x00, 0x20, 0xA4, 0xF4, 0x00, 0x00, 0x5A, 0x01, 0x00, 

+	0x20, 0x00, 0x70, 0x0A, 0x40, 

+	0x00, 0x00, 0x7D, 0x00, 0x80, 0xC0, 0x0F, 0x0A, 0x40, 0x00, 0x61, 0x0A, 0x40, 0x00, 0x00, 0x80, 

+	0xC0, 0x9C, 0xE6, 0x00, 0x00, 0x00, 0x50, 0x0A, 0x40, 0x00, 0x01, 0x02, 0x03, 0x00, 0x04, 0x0A, 

+	0x40, 0x06, 0x0E, 0x16, 0x1C, 0x00, 0x71, 0x0A, 0x40, 0x00, 0xFA, 0x00, 0x00, 0x84, 0xF4, 0x00, 

+	0x00, 0xFF, 0xFF, 0x00, 0x00, 0xA0, 0xF5, 0x00, 0x00, 0x70, 0xB5, 0x04, 0x46, 0x21, 0x4D, 0x01, 

+	0x20, 0x68, 0x70, 0x1C, 0x20, 0x01, 0x21, 0x89, 0x03, 0x03, 0xE0, 0x42, 0x00, 0x12, 0x19, 0x60, 

+	0x32, 0x91, 0x80, 0x40, 0x1E, 0xF9, 0xD2, 0x1C, 0x48, 0x6C, 0x60, 0x40, 0x69, 0x40, 0x03, 0x46, 

+	0x0F, 0x07, 0x20, 0xFD, 0xF7, 0x43, 0xFF, 0x01, 0x46, 0x17, 0x48, 0x40, 0x30, 0x03, 0x88, 0xC2, 

+	0x79, 0x30, 0x46, 0xFF, 0xF7, 0x3F, 0xFC, 0x60, 0x71, 0xE0, 0x71, 0x01, 0x22, 0x21, 0x1D, 0x60, 

+	0x1D, 0xFF, 0xF7, 0xC4, 0xFD, 

+	0x00, 0x00, 0x7E, 0x00, 0x80, 0x02, 0x22, 0xA1, 0x1D, 0xE0, 0x1D, 0xFF, 0xF7, 0xBF, 0xFD, 0x01, 

+	0x20, 0x0A, 0x21, 0x41, 0x43, 0x09, 0x19, 0x22, 0x79, 0x0A, 0x71, 0x62, 0x79, 0x4A, 0x71, 0xA2, 

+	0x79, 0x8A, 0x71, 0xE2, 0x79, 0x40, 0x1C, 0xCA, 0x71, 0x04, 0x28, 0xF1, 0xD3, 0x00, 0x20, 0x68, 

+	0x70, 0x70, 0xBD, 0x06, 0x4A, 0x11, 0x6B, 0x01, 0x23, 0x9B, 0x03, 0x99, 0x43, 0x80, 0x03, 0x08, 

+	0x43, 0x10, 0x63, 0x70, 0x47, 0xA8, 0x01, 0x00, 0x20, 0xA4, 0xF4, 0x00, 0x00, 0x80, 0x00, 0x0A, 

+	0x40, 0x70, 0xB5, 0x0A, 0x21, 0x48, 0x43, 0x1E, 0x49, 0x09, 0x68, 0x40, 0x18, 0xC1, 0x78, 0x80, 

+	0x78, 0xFE, 0xF7, 0xB4, 0xFD, 0x1B, 0x48, 0x01, 0x78, 0x1B, 0x48, 0x49, 0x1E, 0x01, 0x60, 0x1B, 

+	0x49, 0x09, 0x78, 0x81, 0x62, 0x1A, 0x49, 0x01, 0x22, 0x09, 0x78, 0x49, 0x00, 0x49, 0x1E, 0x12, 

+	0x04, 0x11, 0x43, 0x01, 0x62, 

+	0x00, 0x00, 0x7F, 0x00, 0x80, 0x17, 0x49, 0x05, 0x20, 0x09, 0xF0, 0xCC, 0xFE, 0x16, 0x48, 0x00, 

+	0x25, 0x05, 0x70, 0x16, 0x4C, 0x20, 0x78, 0x00, 0x28, 0x01, 0xD0, 0x00, 0x20, 0x00, 0xE0, 0x01, 

+	0x20, 0xFE, 0xF7, 0x04, 0xF9, 0x12, 0x48, 0x28, 0x21, 0x00, 0x78, 0x48, 0x43, 0x11, 0x49, 0x40, 

+	0x18, 0x11, 0x49, 0x08, 0x60, 0x21, 0x78, 0x00, 0x29, 0x01, 0xD1, 0xFE, 0xF7, 0xB8, 0xF8, 0x0F, 

+	0x4C, 0x01, 0x20, 0x20, 0x70, 0x00, 0x20, 0xFD, 0xF7, 0xDC, 0xFF, 0x25, 0x70, 0x70, 0xBD, 0x00, 

+	0x00, 0xAC, 0x01, 0x00, 0x20, 0x52, 0x01, 0x00, 0x20, 0x00, 0x00, 0x0A, 0x40, 0x55, 0x01, 0x00, 

+	0x20, 0x54, 0x01, 0x00, 0x20, 0xBB, 0x34, 0x00, 0x00, 0x40, 0x01, 0x00, 0x20, 0x38, 0x01, 0x00, 

+	0x20, 0xB0, 0x01, 0x00, 0x20, 0x20, 0xF6, 0x00, 0x00, 0x78, 0x01, 0x00, 0x20, 0x31, 0x01, 0x00, 

+	0x20, 0x10, 0xB5, 0x84, 0x48, 

+	0x00, 0x00, 0x80, 0x00, 0x80, 0x01, 0x24, 0x04, 0x61, 0x83, 0x48, 0x00, 0x6B, 0x03, 0x28, 0x01, 

+	0xD9, 0x82, 0x48, 0x04, 0x70, 0xFD, 0xF7, 0xA2, 0xFF, 0x81, 0x48, 0x04, 0x70, 0x10, 0xBD, 0xF7, 

+	0xB5, 0x07, 0x46, 0x80, 0x48, 0x0E, 0x46, 0x01, 0x25, 0xC0, 0x5D, 0xE9, 0x07, 0x40, 0x18, 0x7A, 

+	0x49, 0x82, 0xB0, 0x40, 0x31, 0x08, 0x60, 0x00, 0x20, 0xFD, 0xF7, 0xA3, 0xFF, 0x78, 0x4C, 0x20, 

+	0x78, 0x00, 0x28, 0xFC, 0xD0, 0x00, 0xF0, 0xD5, 0xF8, 0x00, 0xB2, 0x00, 0x90, 0x76, 0x48, 0x04, 

+	0x21, 0xBA, 0x00, 0x12, 0x18, 0x11, 0x60, 0xFF, 0x2E, 0x03, 0xD0, 0x01, 0x21, 0xB2, 0x00, 0x10, 

+	0x18, 0x01, 0x60, 0x00, 0x20, 0x20, 0x70, 0x6D, 0x4E, 0x30, 0x70, 0xFD, 0xF7, 0x8A, 0xFF, 0x20, 

+	0x78, 0x00, 0x28, 0xFC, 0xD0, 0x00, 0xF0, 0xBD, 0xF8, 0x00, 0x99, 0x40, 0x1A, 0x00, 0xD5, 0x40, 

+	0x42, 0x04, 0x99, 0x88, 0x42, 

+	0x00, 0x00, 0x81, 0x00, 0x80, 0x02, 0xD8, 0x30, 0x78, 0x00, 0x28, 0x00, 0xD0, 0x00, 0x25, 0x00, 

+	0x20, 0xFE, 0xF7, 0x8C, 0xF8, 0x00, 0x2D, 0x02, 0xD0, 0x01, 0x20, 0x05, 0xB0, 0xF0, 0xBD, 0x00, 

+	0x20, 0xFB, 0xE7, 0xF3, 0xB5, 0x87, 0xB0, 0x61, 0x48, 0x00, 0x90, 0x0E, 0x46, 0x01, 0x20, 0x03, 

+	0x90, 0x05, 0x21, 0x30, 0x46, 0x0A, 0xF0, 0xE8, 0xF8, 0x5D, 0x49, 0x5A, 0x4A, 0x40, 0x39, 0xC9, 

+	0x68, 0x5B, 0x48, 0x49, 0x02, 0x49, 0x0F, 0x08, 0x3A, 0x40, 0x89, 0x51, 0x5C, 0x48, 0x43, 0x03, 

+	0x21, 0x0A, 0xF0, 0xDE, 0xF8, 0x80, 0x09, 0x04, 0x90, 0xFD, 0xF7, 0x6C, 0xFE, 0xFD, 0xF7, 0x04, 

+	0xFF, 0x4D, 0x49, 0x80, 0x31, 0x08, 0x6B, 0xCA, 0x04, 0x90, 0x43, 0x08, 0x63, 0x0E, 0x20, 0x41, 

+	0x07, 0x50, 0x4A, 0x02, 0xE0, 0x83, 0x00, 0x9B, 0x18, 0x19, 0x60, 0x40, 0x1E, 0xFA, 0xD2, 0x46, 

+	0x4C, 0x47, 0x20, 0x20, 0x60, 

+	0x00, 0x00, 0x82, 0x00, 0x80, 0x4C, 0x49, 0xF5, 0x20, 0x08, 0x80, 0x00, 0x22, 0x01, 0x21, 0xFF, 

+	0x20, 0xFE, 0xF7, 0x11, 0xF9, 0x02, 0x20, 0xFE, 0xF7, 0xEA, 0xF8, 0x3F, 0x48, 0x47, 0x49, 0x40, 

+	0x30, 0x01, 0x62, 0x28, 0x20, 0xA0, 0x62, 0x46, 0x49, 0x05, 0x20, 0x09, 0xF0, 0xFB, 0xFD, 0x00, 

+	0x20, 0xFE, 0xF7, 0x3C, 0xF8, 0x00, 0x27, 0xFD, 0x08, 0x79, 0x07, 0x49, 0x0F, 0x01, 0x20, 0x88, 

+	0x40, 0x02, 0x90, 0x07, 0x98, 0x00, 0x28, 0x02, 0xD0, 0x01, 0x28, 0x13, 0xD0, 0x43, 0xE0, 0x00, 

+	0x98, 0x02, 0x99, 0x40, 0x5D, 0x08, 0x42, 0x3E, 0xD0, 0xFF, 0x21, 0x38, 0x46, 0x04, 0x9A, 0xFF, 

+	0xF7, 0x5E, 0xFF, 0x00, 0x28, 0x37, 0xD1, 0x70, 0x5D, 0x02, 0x99, 0x08, 0x43, 0x70, 0x55, 0x00, 

+	0x20, 0x03, 0x90, 0x30, 0xE0, 0x7C, 0x1C, 0x2C, 0xE0, 0xE0, 0x08, 0x61, 0x07, 0x01, 0x90, 0x49, 

+	0x0F, 0x01, 0x20, 0x88, 0x40, 

+	0x00, 0x00, 0x83, 0x00, 0x80, 0x05, 0x90, 0x00, 0x98, 0x02, 0x99, 0x40, 0x5D, 0x08, 0x42, 0x1F, 

+	0xD0, 0x01, 0x99, 0x00, 0x98, 0x40, 0x5C, 0x05, 0x99, 0x08, 0x42, 0x19, 0xD0, 0x21, 0x46, 0x38, 

+	0x46, 0x04, 0x9A, 0xFF, 0xF7, 0x3C, 0xFF, 0x00, 0x28, 0x12, 0xD1, 0x39, 0x46, 0x20, 0x46, 0x04, 

+	0x9A, 0xFF, 0xF7, 0x35, 0xFF, 0x00, 0x28, 0x0B, 0xD1, 0x70, 0x5D, 0x02, 0x99, 0x08, 0x43, 0x70, 

+	0x55, 0x01, 0x98, 0x05, 0x99, 0x30, 0x5C, 0x08, 0x43, 0x01, 0x99, 0x70, 0x54, 0x00, 0x20, 0x03, 

+	0x90, 0x64, 0x1C, 0x24, 0x2C, 0xD0, 0xD3, 0x7F, 0x1C, 0x24, 0x2F, 0xAC, 0xD3, 0x0E, 0x48, 0x00, 

+	0x21, 0x40, 0x30, 0x01, 0x60, 0xFD, 0xF7, 0xE6, 0xFD, 0xFD, 0xF7, 0x7E, 0xFE, 0x03, 0x98, 0x09, 

+	0xB0, 0xF0, 0xBD, 0x10, 0xB5, 0x00, 0x20, 0x20, 0x21, 0x12, 0x4B, 0x07, 0xE0, 0x4A, 0x00, 0xD2, 

+	0x18, 0x00, 0x24, 0x14, 0x57, 

+	0x00, 0x00, 0x84, 0x00, 0x80, 0x20, 0x18, 0x01, 0x24, 0x14, 0x57, 0x00, 0x1B, 0x49, 0x1E, 0xF5, 

+	0xD2, 0x10, 0xBD, 0x00, 0x00, 0xC0, 0x0F, 0x0A, 0x40, 0x00, 0x00, 0x0A, 0x40, 0xB1, 0x01, 0x00, 

+	0x20, 0x32, 0x01, 0x00, 0x20, 0x18, 0xE7, 0x00, 0x00, 0x00, 0x60, 0x0A, 0x40, 0x5C, 0xF5, 0x00, 

+	0x00, 0xE4, 0xF4, 0x00, 0x00, 0x00, 0x70, 0x0A, 0x40, 0x64, 0x01, 0x00, 0x20, 0x00, 0x10, 0x18, 

+	0x00, 0xFD, 0x3F, 0x00, 0x00, 0x00, 0x40, 0x0A, 0x40, 0xF7, 0xB5, 0x04, 0x46, 0xE9, 0x48, 0xAA, 

+	0xB0, 0x05, 0x68, 0xE9, 0x48, 0x90, 0x21, 0x06, 0x78, 0x05, 0xA8, 0x0A, 0xF0, 0x17, 0xF8, 0xE7, 

+	0x48, 0x01, 0x21, 0x01, 0x70, 0xE6, 0x48, 0x01, 0x8B, 0x89, 0x04, 0x8F, 0x0F, 0x50, 0x21, 0x4F, 

+	0x43, 0x04, 0x97, 0xC1, 0x68, 0xC0, 0x68, 0x49, 0x02, 0x49, 0x0F, 0x00, 0x03, 0x09, 0x01, 0x00, 

+	0x0F, 0x08, 0x18, 0x02, 0x90, 

+	0x00, 0x00, 0x85, 0x00, 0x80, 0x30, 0x46, 0x03, 0xE0, 0xE9, 0x07, 0x00, 0xD1, 0xB6, 0x1E, 0x6D, 

+	0x08, 0x40, 0x1E, 0xF9, 0xD2, 0xDA, 0x4D, 0x2B, 0x98, 0x29, 0x46, 0x20, 0x31, 0x40, 0x35, 0x00, 

+	0x91, 0x00, 0x28, 0x0F, 0xD0, 0x2E, 0x46, 0x40, 0x36, 0x01, 0x28, 0x71, 0xD0, 0xD5, 0x49, 0xC9, 

+	0x7D, 0x4A, 0x00, 0x49, 0x1C, 0x49, 0x00, 0x04, 0x92, 0x03, 0x91, 0x02, 0x28, 0x67, 0xD0, 0x03, 

+	0x28, 0x7E, 0xD1, 0x50, 0xE1, 0x00, 0x20, 0xFE, 0xF7, 0xC6, 0xFE, 0xCF, 0x48, 0x00, 0x68, 0xC1, 

+	0x78, 0x82, 0x78, 0xCE, 0x48, 0x80, 0x5C, 0x41, 0x43, 0x79, 0x43, 0x00, 0x98, 0x01, 0x91, 0x80, 

+	0x7B, 0x00, 0x28, 0x18, 0xD0, 0xA8, 0x89, 0x7D, 0x21, 0x40, 0x01, 0xC9, 0x00, 0x09, 0xF0, 0xD0, 

+	0xFF, 0x07, 0x46, 0x09, 0xF0, 0xE7, 0xFB, 0x01, 0x46, 0xC1, 0x48, 0x79, 0x43, 0x60, 0x30, 0x03, 

+	0x90, 0x82, 0x8A, 0xC3, 0x48, 

+	0x00, 0x00, 0x86, 0x00, 0x80, 0x80, 0x6A, 0x10, 0x1A, 0x41, 0x43, 0x14, 0x20, 0x41, 0x43, 0x48, 

+	0x09, 0x00, 0x27, 0x00, 0x90, 0x15, 0xE0, 0x00, 0x98, 0x01, 0x7B, 0xBE, 0x48, 0x47, 0x5C, 0xE8, 

+	0xE7, 0x78, 0x00, 0xBD, 0x49, 0x02, 0x90, 0x08, 0x5E, 0x00, 0x28, 0x00, 0xDA, 0x40, 0x42, 0x01, 

+	0x9A, 0x00, 0x99, 0x50, 0x43, 0x09, 0xF0, 0xAC, 0xFF, 0x05, 0x99, 0x41, 0x18, 0x02, 0x98, 0x7F, 

+	0x1C, 0x21, 0x52, 0xB0, 0x48, 0x40, 0x89, 0xB8, 0x42, 0xEA, 0xD8, 0xAE, 0x48, 0x47, 0x89, 0x00, 

+	0x20, 0xFD, 0xF7, 0x0C, 0xFD, 0x03, 0x99, 0x8A, 0x8A, 0xAD, 0x49, 0x89, 0x6A, 0x51, 0x1A, 0x49, 

+	0x00, 0x48, 0x43, 0xA9, 0x79, 0x64, 0x22, 0x48, 0x43, 0x31, 0x46, 0x51, 0x43, 0x09, 0xF0, 0x90, 

+	0xFF, 0x01, 0x9A, 0x00, 0x99, 0x50, 0x43, 0x09, 0xF0, 0x8B, 0xFF, 0x05, 0x99, 0x40, 0x18, 0x79, 

+	0x00, 0x60, 0x52, 0xA0, 0x48, 

+	0x00, 0x00, 0x87, 0x00, 0x80, 0x40, 0x89, 0x40, 0x1C, 0x40, 0x00, 0xE5, 0xE0, 0x00, 0xE0, 0xA8, 

+	0xE0, 0xFE, 0xF7, 0x7D, 0xFE, 0x9C, 0x48, 0x00, 0x68, 0xC1, 0x79, 0x82, 0x79, 0x9B, 0x48, 0x80, 

+	0x5C, 0x41, 0x43, 0x79, 0x43, 0x01, 0x91, 0x09, 0xF0, 0x8D, 0xFB, 0x9A, 0x49, 0x02, 0x9A, 0x09, 

+	0x1D, 0x89, 0x5C, 0x72, 0x88, 0x48, 0x43, 0x96, 0x49, 0x89, 0x6A, 0x51, 0x1A, 0x14, 0x22, 0x00, 

+	0xE0, 0xCC, 0xE0, 0x51, 0x43, 0x48, 0x43, 0x40, 0x09, 0x00, 0x27, 0x00, 0x90, 0x13, 0xE0, 0x78, 

+	0x00, 0x92, 0x49, 0x03, 0x90, 0x09, 0x68, 0x08, 0x5E, 0x00, 0x28, 0x00, 0xDA, 0x40, 0x42, 0x01, 

+	0x9A, 0x00, 0x99, 0x50, 0x43, 0x09, 0xF0, 0x54, 0xFF, 0xBA, 0x00, 0x05, 0xA9, 0x89, 0x5A, 0x41, 

+	0x18, 0x03, 0x98, 0x7F, 0x1C, 0x21, 0x52, 0x83, 0x48, 0x00, 0x7B, 0xB8, 0x42, 0xE7, 0xD8, 0x81, 

+	0x48, 0x07, 0x7B, 0x07, 0x20, 

+	0x00, 0x00, 0x88, 0x00, 0x80, 0xFD, 0xF7, 0xB2, 0xFC, 0x81, 0x49, 0x72, 0x88, 0x89, 0x6A, 0x51, 

+	0x1A, 0x48, 0x43, 0xE9, 0x79, 0x48, 0x43, 0x40, 0x00, 0x64, 0x21, 0x09, 0xF0, 0x39, 0xFF, 0x01, 

+	0x9A, 0x03, 0x90, 0x50, 0x43, 0x00, 0x99, 0x09, 0xF0, 0x33, 0xFF, 0x01, 0x46, 0x00, 0x20, 0x8A, 

+	0xB2, 0x74, 0x4B, 0x03, 0xE0, 0x39, 0x18, 0x49, 0x00, 0x62, 0x52, 0x40, 0x1C, 0x19, 0x7B, 0x81, 

+	0x42, 0xF8, 0xD8, 0x70, 0x48, 0x00, 0x7B, 0xC0, 0x19, 0x00, 0x90, 0xFE, 0xF7, 0x12, 0xFE, 0x6E, 

+	0x48, 0x00, 0x68, 0x47, 0x79, 0x01, 0x79, 0x6D, 0x48, 0x40, 0x5C, 0x47, 0x43, 0x04, 0x98, 0x47, 

+	0x43, 0x09, 0xF0, 0x30, 0xFB, 0x6B, 0x49, 0x02, 0x9A, 0x09, 0x1D, 0x89, 0x5C, 0x72, 0x88, 0x48, 

+	0x43, 0x67, 0x49, 0x89, 0x6A, 0x51, 0x1A, 0x14, 0x22, 0x51, 0x43, 0x48, 0x43, 0x46, 0x09, 0x00, 

+	0x25, 0x0F, 0xE0, 0x67, 0x48, 

+	0x00, 0x00, 0x89, 0x00, 0x80, 0x69, 0x00, 0x40, 0x5E, 0x31, 0x46, 0x78, 0x43, 0x09, 0xF0, 0x00, 

+	0xFF, 0xAA, 0x00, 0x05, 0xA9, 0x89, 0x5A, 0x41, 0x18, 0x00, 0x98, 0x40, 0x19, 0x40, 0x00, 0x21, 

+	0x52, 0x6D, 0x1C, 0x58, 0x48, 0x40, 0x7B, 0xA8, 0x42, 0xEB, 0xD8, 0x56, 0x48, 0x00, 0x99, 0x40, 

+	0x7B, 0x45, 0x18, 0x03, 0x98, 0x31, 0x46, 0x78, 0x43, 0x09, 0xF0, 0xEA, 0xFE, 0x01, 0x46, 0x00, 

+	0x20, 0x89, 0xB2, 0x50, 0x4A, 0x03, 0xE0, 0x2B, 0x18, 0x5B, 0x00, 0xE1, 0x52, 0x40, 0x1C, 0x53, 

+	0x7B, 0x83, 0x42, 0xF8, 0xD8, 0x10, 0x7B, 0xD9, 0xB2, 0x08, 0x18, 0x81, 0x00, 0x2C, 0x98, 0x01, 

+	0x80, 0x3C, 0xE0, 0x00, 0x20, 0xFE, 0xF7, 0xE1, 0xFD, 0x47, 0x48, 0x00, 0x68, 0x41, 0x7A, 0x02, 

+	0x7A, 0x46, 0x48, 0x80, 0x5C, 0x41, 0x43, 0x79, 0x43, 0x01, 0x91, 0x09, 0xF0, 0xE3, 0xFA, 0x00, 

+	0x99, 0x0A, 0x7B, 0x44, 0x49, 

+	0x00, 0x00, 0x8A, 0x00, 0x80, 0x89, 0x5C, 0xB2, 0x88, 0x48, 0x43, 0x41, 0x49, 0x89, 0x6A, 0x51, 

+	0x1A, 0x14, 0x22, 0x51, 0x43, 0x48, 0x43, 0x40, 0x09, 0x00, 0x27, 0x00, 0x90, 0x0E, 0xE0, 0x78, 

+	0x00, 0x40, 0x49, 0x02, 0x90, 0x08, 0x5E, 0x00, 0x28, 0x00, 0xDA, 0x40, 0x42, 0x01, 0x9A, 0x00, 

+	0x99, 0x50, 0x43, 0x09, 0xF0, 0xAD, 0xFE, 0x02, 0x99, 0x7F, 0x1C, 0x60, 0x52, 0x31, 0x48, 0xC0, 

+	0x7D, 0xB8, 0x42, 0xEC, 0xD8, 0x08, 0x20, 0xFD, 0xF7, 0x11, 0xFC, 0x31, 0x49, 0xB2, 0x88, 0x89, 

+	0x6A, 0x51, 0x1A, 0x48, 0x43, 0x29, 0x7A, 0x3F, 0xE0, 0x2C, 0x99, 0x08, 0x80, 0x27, 0x48, 0x00, 

+	0x21, 0x01, 0x70, 0x2D, 0xB0, 0xF0, 0xBD, 0xFE, 0xF7, 0xAE, 0xFD, 0x27, 0x48, 0x00, 0x68, 0xC1, 

+	0x7A, 0x82, 0x7A, 0x26, 0x48, 0x80, 0x5C, 0x41, 0x43, 0x79, 0x43, 0x01, 0x91, 0x09, 0xF0, 0xA2, 

+	0xFA, 0x24, 0x49, 0x02, 0x9A, 

+	0x00, 0x00, 0x8B, 0x00, 0x80, 0x09, 0x1D, 0x89, 0x5C, 0xF2, 0x88, 0x48, 0x43, 0x20, 0x49, 0x89, 

+	0x6A, 0x51, 0x1A, 0x14, 0x22, 0x51, 0x43, 0x48, 0x43, 0x40, 0x09, 0x00, 0x27, 0x00, 0x90, 0x0E, 

+	0xE0, 0x78, 0x00, 0x21, 0x49, 0x02, 0x90, 0x08, 0x5E, 0x00, 0x28, 0x00, 0xDA, 0x40, 0x42, 0x01, 

+	0x9A, 0x00, 0x99, 0x50, 0x43, 0x09, 0xF0, 0x6C, 0xFE, 0x02, 0x99, 0x7F, 0x1C, 0x60, 0x52, 0x11, 

+	0x48, 0xC0, 0x7D, 0xB8, 0x42, 0xEC, 0xD8, 0x09, 0x20, 0xFD, 0xF7, 0xD0, 0xFB, 0x10, 0x49, 0xF2, 

+	0x88, 0x89, 0x6A, 0x51, 0x1A, 0x48, 0x43, 0x69, 0x7A, 0x48, 0x43, 0x40, 0x00, 0x64, 0x21, 0x09, 

+	0xF0, 0x57, 0xFE, 0x01, 0x9A, 0x00, 0x99, 0x50, 0x43, 0x09, 0xF0, 0x52, 0xFE, 0x04, 0x99, 0x60, 

+	0x52, 0x03, 0x98, 0xB1, 0xE7, 0xA0, 0x01, 0x00, 0x20, 0x4B, 0x01, 0x00, 0x20, 0x35, 0x01, 0x00, 

+	0x20, 0xA4, 0xF4, 0x00, 0x00, 

+	0x00, 0x00, 0x8C, 0x00, 0x80, 0x84, 0xF4, 0x00, 0x00, 0xAC, 0x01, 0x00, 0x20, 0xF3, 0xE5, 0x00, 

+	0x00, 0x00, 0x00, 0x0A, 0x40, 0x3D, 0xE7, 0x00, 0x00, 0xE0, 0x04, 0x00, 0x20, 0xF4, 0x00, 0x00, 

+	0x20, 0x50, 0x04, 0x00, 0x20, 0x0E, 0x01, 0x00, 0x20, 0x16, 0x01, 0x00, 0x20, 0xF0, 0xB4, 0x1D, 

+	0x4F, 0x1D, 0x4E, 0x36, 0x68, 0x1A, 0x36, 0xF5, 0x57, 0x2D, 0x42, 0x11, 0xD4, 0xBF, 0x00, 0x2C, 

+	0xB4, 0x1A, 0x4B, 0xDB, 0x59, 0x1A, 0xB2, 0x1B, 0x14, 0xC5, 0x59, 0xAC, 0xB2, 0x2D, 0x0C, 0x62, 

+	0x43, 0x6B, 0x43, 0x9C, 0x18, 0x2C, 0xBC, 0x1C, 0x41, 0x14, 0x1B, 0x6D, 0x00, 0x4C, 0x53, 0xBF, 

+	0x08, 0x7F, 0x1E, 0xE8, 0xD2, 0xF0, 0xBC, 0x70, 0x47, 0xF0, 0xB4, 0x0E, 0x4F, 0x0E, 0x4E, 0x36, 

+	0x68, 0x1A, 0x36, 0xF5, 0x57, 0x2D, 0x42, 0x11, 0xD4, 0xBF, 0x00, 0x2C, 0xB4, 0x0B, 0x4B, 0xDB, 

+	0x59, 0x1A, 0xB2, 0x1B, 0x14, 

+	0x00, 0x00, 0x8D, 0x00, 0x80, 0xC5, 0x59, 0xAC, 0xB2, 0x2D, 0x0C, 0x62, 0x43, 0x6B, 0x43, 0x9C, 

+	0x18, 0x2C, 0xBC, 0x1C, 0x41, 0xA4, 0x1A, 0x6D, 0x00, 0x4C, 0x53, 0xBF, 0x08, 0x7F, 0x1E, 0xE8, 

+	0xD2, 0xF0, 0xBC, 0x70, 0x47, 0x0D, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x20, 0x00, 0x40, 0x0A, 

+	0x40, 0x41, 0x08, 0x01, 0x43, 0x88, 0x08, 0x08, 0x43, 0x01, 0x09, 0x01, 0x43, 0x08, 0x0A, 0x08, 

+	0x43, 0x01, 0x0C, 0x01, 0x43, 0x09, 0x4A, 0x48, 0x08, 0x10, 0x40, 0x08, 0x1A, 0x08, 0x4A, 0x81, 

+	0x08, 0x11, 0x40, 0x10, 0x40, 0x08, 0x18, 0x01, 0x09, 0x08, 0x18, 0x06, 0x49, 0x08, 0x40, 0x01, 

+	0x0A, 0x08, 0x18, 0x01, 0x0C, 0x08, 0x18, 0x80, 0x06, 0x80, 0x0E, 0x70, 0x47, 0x55, 0x55, 0x55, 

+	0x55, 0x33, 0x33, 0x33, 0x33, 0x0F, 0x0F, 0x0F, 0x0F, 0xFE, 0x48, 0x00, 0x21, 0x81, 0x60, 0xC1, 

+	0x60, 0x01, 0x61, 0x70, 0x47, 

+	0x00, 0x00, 0x8E, 0x00, 0x80, 0x10, 0xB5, 0xFC, 0x48, 0xC0, 0x7D, 0x00, 0x28, 0x06, 0xD0, 0x08, 

+	0x21, 0xFA, 0x48, 0x09, 0xF0, 0xB9, 0xFD, 0xF7, 0x48, 0x00, 0x21, 0x81, 0x61, 0x10, 0xBD, 0x10, 

+	0xB5, 0xF5, 0x48, 0xC0, 0x7D, 0x00, 0x28, 0x06, 0xD0, 0x08, 0x21, 0xF5, 0x48, 0x09, 0xF0, 0xAC, 

+	0xFD, 0xF0, 0x48, 0x00, 0x21, 0x41, 0x61, 0x10, 0xBD, 0x10, 0xB5, 0xEF, 0x48, 0x00, 0x7B, 0x41, 

+	0x00, 0xF0, 0x48, 0x00, 0x68, 0x09, 0xF0, 0xA0, 0xFD, 0x10, 0xBD, 0x10, 0xB5, 0xEA, 0x48, 0x40, 

+	0x7B, 0x41, 0x00, 0xED, 0x48, 0x09, 0xF0, 0x98, 0xFD, 0x10, 0xBD, 0x10, 0xB5, 0xA1, 0x21, 0x89, 

+	0x00, 0xEA, 0x48, 0x09, 0xF0, 0x91, 0xFD, 0x10, 0xBD, 0xF8, 0xB5, 0x04, 0x46, 0x09, 0xF0, 0x90, 

+	0xF8, 0x05, 0x46, 0x60, 0x07, 0x00, 0x27, 0xDF, 0x4E, 0x00, 0x28, 0x0C, 0xDA, 0xA1, 0x21, 0xB7, 

+	0x80, 0x89, 0x00, 0xE3, 0x48, 

+	0x00, 0x00, 0x8F, 0x00, 0x80, 0x09, 0xF0, 0x80, 0xFD, 0x00, 0x20, 0xFE, 0xF7, 0x64, 0xFC, 0xFF, 

+	0xF7, 0xE4, 0xFF, 0xB5, 0x60, 0xB7, 0x70, 0xE0, 0x07, 0x0B, 0xD0, 0xD7, 0x48, 0xF7, 0x70, 0x40, 

+	0x7B, 0x41, 0x00, 0xDC, 0x48, 0x09, 0xF0, 0x70, 0xFD, 0xFE, 0xF7, 0x63, 0xFC, 0xFF, 0xF7, 0xCD, 

+	0xFF, 0xF5, 0x60, 0xA0, 0x07, 0x0C, 0xD5, 0xD0, 0x48, 0xF7, 0x70, 0x00, 0x7B, 0x41, 0x00, 0xD6, 

+	0x48, 0x00, 0x68, 0x09, 0xF0, 0x61, 0xFD, 0xFE, 0xF7, 0x62, 0xFC, 0xFF, 0xF7, 0xB5, 0xFF, 0x35, 

+	0x61, 0x20, 0x07, 0x08, 0xD5, 0x08, 0x21, 0xD1, 0x48, 0x09, 0xF0, 0x56, 0xFD, 0x00, 0x20, 0xFE, 

+	0xF7, 0x64, 0xFC, 0xFF, 0xF7, 0x9C, 0xFF, 0xE0, 0x06, 0x07, 0xD5, 0x08, 0x21, 0xCC, 0x48, 0x09, 

+	0xF0, 0x4B, 0xFD, 0xFE, 0xF7, 0x68, 0xFC, 0xFF, 0xF7, 0x85, 0xFF, 0xF8, 0xBD, 0xF0, 0xB5, 0xBE, 

+	0x49, 0x40, 0x00, 0xC9, 0x7D, 

+	0x00, 0x00, 0x90, 0x00, 0x80, 0x85, 0xB0, 0x8E, 0x46, 0xC6, 0x49, 0x40, 0x18, 0x4C, 0x7D, 0x80, 

+	0x8C, 0x04, 0x90, 0xC8, 0x7D, 0x45, 0x07, 0xC0, 0x08, 0x6D, 0x0F, 0x84, 0x46, 0x00, 0x2D, 0x10, 

+	0xD0, 0x60, 0x19, 0x40, 0x1C, 0x01, 0x90, 0xC0, 0x49, 0x68, 0x00, 0x41, 0x18, 0x02, 0x20, 0x08, 

+	0x5E, 0x00, 0x90, 0xBE, 0x48, 0xC0, 0x7B, 0x03, 0x90, 0x01, 0x28, 0x00, 0xD0, 0x70, 0x46, 0x01, 

+	0x46, 0x08, 0xE0, 0x60, 0x00, 0x01, 0x90, 0x00, 0x20, 0xF2, 0xE7, 0xAA, 0x4B, 0x18, 0x33, 0x5A, 

+	0x5C, 0x52, 0x1C, 0x5A, 0x54, 0x49, 0x1E, 0xF8, 0xD2, 0x4A, 0xE0, 0xA8, 0x4A, 0x41, 0x00, 0x53, 

+	0x5E, 0x04, 0x9A, 0x93, 0x42, 0x13, 0xDD, 0xA3, 0x4A, 0x52, 0x78, 0x00, 0x2A, 0x1A, 0xD0, 0x03, 

+	0x9A, 0x01, 0x2A, 0x04, 0xD0, 0x9F, 0x4E, 0x00, 0x22, 0x14, 0x36, 0x32, 0x54, 0x07, 0xE0, 0x9D, 

+	0x4E, 0x72, 0x46, 0x14, 0x36, 

+	0x00, 0x00, 0x91, 0x00, 0x80, 0x01, 0xE0, 0x00, 0x27, 0xB7, 0x54, 0x52, 0x1E, 0xFB, 0xD2, 0x99, 

+	0x4A, 0x18, 0x32, 0x12, 0x5C, 0xA2, 0x42, 0x2B, 0xD3, 0xA2, 0x42, 0x07, 0xD1, 0x95, 0x4A, 0x24, 

+	0x32, 0x53, 0x52, 0x25, 0xE0, 0x93, 0x4E, 0x00, 0x22, 0x18, 0x36, 0xE6, 0xE7, 0x01, 0x9E, 0xB2, 

+	0x42, 0x22, 0xD2, 0x00, 0x2D, 0x1C, 0xD0, 0x8F, 0x4A, 0x24, 0x32, 0x52, 0x5E, 0x02, 0x92, 0x9A, 

+	0x1A, 0x16, 0x1E, 0x00, 0xDA, 0x56, 0x42, 0x67, 0x46, 0x66, 0x45, 0x05, 0xD9, 0x1F, 0x2F, 0x03, 

+	0xD0, 0x88, 0x4A, 0x18, 0x32, 0x14, 0x54, 0xE1, 0xE7, 0x00, 0x9B, 0x86, 0x4E, 0x5A, 0x43, 0x01, 

+	0x23, 0x12, 0x01, 0xDB, 0x03, 0xD2, 0x18, 0x13, 0x14, 0x02, 0x9A, 0x24, 0x36, 0x9A, 0x18, 0x72, 

+	0x52, 0x40, 0x1E, 0xB2, 0xD2, 0x05, 0xB0, 0xF0, 0xBD, 0x7E, 0x4E, 0x80, 0x4A, 0x24, 0x36, 0x77, 

+	0x5A, 0xDB, 0x1B, 0x53, 0x52, 

+	0x00, 0x00, 0x92, 0x00, 0x80, 0x00, 0x22, 0x33, 0x46, 0x0C, 0x3B, 0x1A, 0x54, 0xEF, 0xE7, 0xFC, 

+	0xB5, 0x84, 0x4A, 0x79, 0x49, 0x40, 0x00, 0x80, 0x18, 0xC9, 0x7D, 0x53, 0x7D, 0x80, 0x8C, 0x01, 

+	0x90, 0x90, 0x7D, 0x45, 0x07, 0x6D, 0x0F, 0xC6, 0x08, 0x00, 0x2D, 0x0A, 0xD0, 0x58, 0x19, 0x40, 

+	0x1C, 0x84, 0x46, 0x7D, 0x4A, 0x68, 0x00, 0x82, 0x18, 0x02, 0x20, 0x10, 0x5E, 0x86, 0x46, 0x08, 

+	0x46, 0x08, 0xE0, 0x58, 0x00, 0x84, 0x46, 0x00, 0x20, 0xF8, 0xE7, 0x6A, 0x4C, 0x14, 0x34, 0x22, 

+	0x5C, 0x52, 0x1C, 0x22, 0x54, 0x40, 0x1E, 0xF8, 0xD2, 0x46, 0xE0, 0x69, 0x4A, 0x48, 0x00, 0x12, 

+	0x5E, 0x01, 0x9C, 0xA2, 0x42, 0x10, 0xDD, 0x63, 0x4C, 0x64, 0x78, 0x00, 0x2C, 0x16, 0xD0, 0x6F, 

+	0x4C, 0xE4, 0x7B, 0x01, 0x2C, 0x04, 0xD0, 0x5F, 0x4F, 0x00, 0x24, 0x18, 0x37, 0x7C, 0x54, 0x03, 

+	0xE0, 0x5C, 0x4F, 0x00, 0x24, 

+	0x00, 0x00, 0x93, 0x00, 0x80, 0x18, 0x37, 0x3C, 0x70, 0x5A, 0x4C, 0x14, 0x34, 0x64, 0x5C, 0x9C, 

+	0x42, 0x2A, 0xD3, 0x9C, 0x42, 0x06, 0xD1, 0x57, 0x4C, 0x1C, 0x34, 0x24, 0xE0, 0x55, 0x4F, 0x00, 

+	0x24, 0x14, 0x37, 0xEB, 0xE7, 0x64, 0x45, 0x22, 0xD2, 0x00, 0x2D, 0x1D, 0xD0, 0x51, 0x4C, 0x1C, 

+	0x34, 0x24, 0x5E, 0x00, 0x94, 0x14, 0x1B, 0x27, 0x1E, 0x00, 0xDA, 0x67, 0x42, 0xB7, 0x42, 0x05, 

+	0xD9, 0x1F, 0x2E, 0x03, 0xD0, 0x4B, 0x4C, 0x14, 0x34, 0x63, 0x54, 0xE4, 0xE7, 0x72, 0x46, 0x54, 

+	0x43, 0x22, 0x01, 0x01, 0x24, 0xE4, 0x03, 0x12, 0x19, 0x17, 0x14, 0x46, 0x4A, 0x00, 0x9C, 0x1C, 

+	0x32, 0x3C, 0x19, 0x14, 0x52, 0x00, 0xE0, 0x22, 0x52, 0x49, 0x1E, 0xB6, 0xD2, 0xFC, 0xBD, 0x41, 

+	0x4C, 0x1C, 0x34, 0x27, 0x5A, 0xD2, 0x1B, 0x42, 0x4F, 0x3A, 0x52, 0x00, 0x22, 0x27, 0x46, 0x08, 

+	0x3F, 0x7A, 0x54, 0xF0, 0xE7, 

+	0x00, 0x00, 0x94, 0x00, 0x80, 0xF0, 0xB5, 0x00, 0x25, 0x8F, 0xB0, 0x3B, 0x4C, 0x0E, 0x95, 0x62, 

+	0x7B, 0x01, 0x92, 0x24, 0x7B, 0x46, 0x49, 0x54, 0x43, 0x00, 0x94, 0x42, 0x4C, 0xAC, 0x46, 0xA2, 

+	0x7A, 0x0D, 0x92, 0x44, 0x4A, 0x06, 0x92, 0x96, 0x88, 0x28, 0x46, 0xAE, 0x46, 0x2B, 0x46, 0x07, 

+	0x2E, 0x11, 0xD0, 0xE2, 0x7A, 0x0C, 0x92, 0x07, 0x2E, 0x0F, 0xD0, 0xA2, 0x79, 0x0B, 0x92, 0x22, 

+	0x7A, 0x0A, 0x92, 0x22, 0x88, 0x09, 0x92, 0x62, 0x7A, 0x12, 0x02, 0x08, 0x92, 0x62, 0x88, 0x12, 

+	0x02, 0x07, 0x92, 0x00, 0x9A, 0x1A, 0xE0, 0xE2, 0x7B, 0xEC, 0xE7, 0x0D, 0x22, 0xA2, 0x56, 0xED, 

+	0xE7, 0x2A, 0x4C, 0x56, 0x00, 0xA4, 0x5F, 0x26, 0x1E, 0x00, 0xDA, 0x66, 0x42, 0x2D, 0x4F, 0xBF, 

+	0x88, 0xBE, 0x42, 0x0B, 0xDD, 0xA5, 0x42, 0x00, 0xDC, 0x25, 0x46, 0x66, 0x46, 0xA6, 0x19, 0xB4, 

+	0x46, 0x00, 0x2C, 0x00, 0xDC, 

+	0x00, 0x00, 0x95, 0x00, 0x80, 0x00, 0x24, 0x5B, 0x1C, 0xA6, 0x44, 0xDB, 0xB2, 0x52, 0x1E, 0xE7, 

+	0xD2, 0x1E, 0x4F, 0x00, 0x22, 0xBA, 0x5E, 0x02, 0x92, 0x00, 0x2A, 0x00, 0xDA, 0x52, 0x42, 0x21, 

+	0x4C, 0xA6, 0x88, 0xB2, 0x42, 0x00, 0xDD, 0x02, 0x98, 0x01, 0x9A, 0x56, 0x1E, 0x52, 0x00, 0x05, 

+	0x92, 0x03, 0x96, 0x92, 0x1E, 0xBA, 0x5E, 0x00, 0x2A, 0x00, 0xDA, 0x52, 0x42, 0xA6, 0x88, 0xB2, 

+	0x42, 0x03, 0xDD, 0x03, 0x9A, 0x56, 0x00, 0xBA, 0x5F, 0x10, 0x18, 0x00, 0x9A, 0x56, 0x1E, 0x52, 

+	0x00, 0x04, 0x92, 0x03, 0x96, 0x92, 0x1E, 0xBA, 0x5E, 0x00, 0x2A, 0x00, 0xDA, 0x52, 0x42, 0xA6, 

+	0x88, 0xB2, 0x42, 0x03, 0xDD, 0x03, 0x9A, 0x56, 0x00, 0xBA, 0x5F, 0x10, 0x18, 0x01, 0x9E, 0x00, 

+	0x9A, 0x92, 0x1B, 0x21, 0xE0, 0xB4, 0x01, 0x00, 0x20, 0x84, 0xF4, 0x00, 0x00, 0x26, 0x01, 0x00, 

+	0x20, 0x1E, 0x01, 0x00, 0x20, 

+	0x00, 0x00, 0x96, 0x00, 0x80, 0xF8, 0x00, 0x00, 0x20, 0x98, 0x04, 0x00, 0x20, 0x64, 0x07, 0x00, 

+	0x20, 0xE0, 0x04, 0x00, 0x20, 0x50, 0x04, 0x00, 0x20, 0xF4, 0x00, 0x00, 0x20, 0x0E, 0x01, 0x00, 

+	0x20, 0x16, 0x01, 0x00, 0x20, 0xFC, 0xF6, 0x00, 0x00, 0x78, 0xE5, 0x00, 0x00, 0xC4, 0xF4, 0x00, 

+	0x00, 0x00, 0x80, 0xFF, 0xFF, 0x2C, 0x04, 0x00, 0x20, 0x56, 0x00, 0xD7, 0x4A, 0x97, 0x5F, 0x3A, 

+	0x1E, 0x00, 0xDA, 0x7A, 0x42, 0xA6, 0x88, 0xB2, 0x42, 0x00, 0xDD, 0x38, 0x18, 0x40, 0x00, 0x84, 

+	0x44, 0x02, 0x98, 0xB2, 0xB2, 0x90, 0x42, 0x00, 0xDC, 0x00, 0x20, 0x00, 0x90, 0xCE, 0x4A, 0x05, 

+	0x98, 0x82, 0x18, 0x20, 0x3A, 0x1E, 0x20, 0x10, 0x5E, 0xB2, 0xB2, 0x90, 0x42, 0x00, 0xDC, 0x00, 

+	0x20, 0x00, 0x9A, 0x86, 0x18, 0xC8, 0x4A, 0x04, 0x98, 0x82, 0x18, 0x20, 0x3A, 0x1E, 0x20, 0x10, 

+	0x5E, 0xA2, 0x88, 0x90, 0x42, 

+	0x00, 0x00, 0x97, 0x00, 0x80, 0x00, 0xDC, 0x00, 0x20, 0x82, 0x19, 0xA0, 0x88, 0x87, 0x42, 0x00, 

+	0xDC, 0x00, 0x27, 0xB8, 0x18, 0x42, 0x00, 0x70, 0x46, 0x14, 0x18, 0xC1, 0x4A, 0x01, 0x9E, 0x12, 

+	0x7B, 0xBE, 0x48, 0x96, 0x19, 0x06, 0xE0, 0x0A, 0x46, 0x00, 0x21, 0x41, 0x5E, 0x8A, 0x42, 0x00, 

+	0xDD, 0x11, 0x46, 0x80, 0x1C, 0x76, 0x1E, 0xF6, 0xD2, 0x60, 0x46, 0x82, 0x00, 0x0B, 0x98, 0xB9, 

+	0x4E, 0x58, 0x43, 0x00, 0x27, 0xF3, 0x57, 0x82, 0x42, 0x1A, 0xDD, 0x00, 0x2B, 0x03, 0xD0, 0x0A, 

+	0x98, 0x48, 0x43, 0xA8, 0x42, 0x14, 0xDB, 0x08, 0x98, 0x84, 0x42, 0x0E, 0xDD, 0x60, 0x46, 0xC2, 

+	0x00, 0x0D, 0x98, 0x60, 0x43, 0x82, 0x42, 0x08, 0xDA, 0x00, 0x2B, 0x03, 0xD0, 0x09, 0x98, 0x81, 

+	0x42, 0x06, 0xDD, 0x02, 0xE0, 0x07, 0x98, 0x84, 0x42, 0x02, 0xDB, 0x0E, 0x98, 0x01, 0x28, 0x0C, 

+	0xD1, 0xB0, 0x88, 0x0C, 0x99, 

+	0x00, 0x00, 0x98, 0x00, 0x80, 0x88, 0x42, 0x0A, 0xDB, 0x00, 0x2B, 0x04, 0xD0, 0xFF, 0xF7, 0x94, 

+	0xFD, 0xFF, 0xF7, 0x9B, 0xFD, 0x01, 0xE0, 0xFF, 0xF7, 0xA0, 0xFD, 0xB7, 0x80, 0x01, 0xE0, 0x40, 

+	0x1C, 0xB0, 0x80, 0xA1, 0x49, 0x9C, 0x48, 0x0A, 0x69, 0x82, 0x42, 0x01, 0xD1, 0x06, 0x98, 0xC5, 

+	0x82, 0x4C, 0x60, 0x08, 0x68, 0xB0, 0x60, 0x0F, 0xB0, 0xF0, 0xBD, 0xF1, 0xB5, 0x98, 0x49, 0x9A, 

+	0x4A, 0x4B, 0x7B, 0x88, 0xB0, 0x09, 0x7B, 0x02, 0x91, 0x40, 0x32, 0x00, 0x20, 0x92, 0x88, 0x97, 

+	0x4C, 0x01, 0x46, 0x07, 0x2A, 0x21, 0xD0, 0x24, 0x7B, 0x05, 0x94, 0x07, 0x2A, 0x1F, 0xD0, 0x93, 

+	0x4C, 0xE4, 0x79, 0x04, 0x94, 0x91, 0x4C, 0x07, 0x2A, 0x1D, 0xD0, 0x64, 0x8B, 0x64, 0x42, 0x07, 

+	0x2A, 0x8E, 0x4A, 0xA6, 0x46, 0x19, 0xD0, 0x92, 0x8B, 0x8A, 0x4E, 0x00, 0x25, 0x01, 0x92, 0xB5, 

+	0x70, 0x08, 0x9A, 0x2C, 0x46, 

+	0x00, 0x00, 0x99, 0x00, 0x80, 0xD6, 0x07, 0x88, 0x4A, 0x12, 0x68, 0x00, 0x92, 0x37, 0xD0, 0x83, 

+	0x4A, 0x5E, 0x00, 0xB2, 0x18, 0x9C, 0x46, 0x03, 0x92, 0x19, 0xE0, 0x24, 0x7C, 0xDC, 0xE7, 0x83, 

+	0x4D, 0x0E, 0x24, 0x2C, 0x57, 0xDD, 0xE7, 0x64, 0x8A, 0xE0, 0xE7, 0x52, 0x7C, 0xE4, 0xE7, 0x92, 

+	0x1E, 0x00, 0x23, 0xD3, 0x5E, 0x1E, 0x1E, 0x00, 0xDA, 0x5E, 0x42, 0x7C, 0x4F, 0xBF, 0x88, 0xBE, 

+	0x42, 0x02, 0xDD, 0x18, 0x18, 0x49, 0x1C, 0xC9, 0xB2, 0x73, 0x45, 0x00, 0xDA, 0x6D, 0x1C, 0x63, 

+	0x46, 0x5B, 0x1E, 0x9C, 0x46, 0x5B, 0x1C, 0xEA, 0xD1, 0x70, 0x4B, 0x00, 0x22, 0x73, 0x4E, 0x9A, 

+	0x5E, 0xB3, 0x88, 0x9A, 0x42, 0x00, 0xDD, 0x10, 0x18, 0x03, 0x9B, 0x1E, 0x22, 0x20, 0x3B, 0x9A, 

+	0x5E, 0xB3, 0x88, 0x9A, 0x42, 0x00, 0xDD, 0x10, 0x18, 0x6A, 0x4B, 0x00, 0x9A, 0xDA, 0x60, 0x08, 

+	0x9A, 0x92, 0x07, 0x31, 0xD5, 

+	0x00, 0x00, 0x9A, 0x00, 0x80, 0x02, 0x9A, 0x53, 0x00, 0x69, 0x4A, 0x12, 0x68, 0x06, 0x92, 0x9A, 

+	0x18, 0x02, 0x9B, 0x03, 0x92, 0x9C, 0x46, 0x0F, 0xE0, 0x92, 0x1E, 0x00, 0x23, 0xD3, 0x5E, 0x1E, 

+	0x1E, 0x00, 0xDA, 0x5E, 0x42, 0x61, 0x4F, 0xBF, 0x88, 0xBE, 0x42, 0x02, 0xDD, 0x18, 0x18, 0x49, 

+	0x1C, 0xC9, 0xB2, 0x73, 0x45, 0x00, 0xDA, 0x64, 0x1C, 0x63, 0x46, 0x5B, 0x1E, 0x9C, 0x46, 0x5B, 

+	0x1C, 0xEA, 0xD1, 0x06, 0x9B, 0x00, 0x22, 0x9A, 0x5E, 0x58, 0x4B, 0x9E, 0x88, 0xB2, 0x42, 0x00, 

+	0xDD, 0x10, 0x18, 0x03, 0x9E, 0x1E, 0x22, 0x20, 0x3E, 0xB2, 0x5E, 0x9B, 0x88, 0x9A, 0x42, 0x00, 

+	0xDD, 0x10, 0x18, 0x50, 0x4B, 0x00, 0x9A, 0x1A, 0x61, 0x01, 0x9A, 0x95, 0x42, 0x01, 0xDA, 0x94, 

+	0x42, 0x02, 0xDB, 0x4C, 0x4A, 0x01, 0x23, 0x93, 0x70, 0x82, 0x00, 0x04, 0x98, 0x48, 0x43, 0x82, 

+	0x42, 0x14, 0xDC, 0x48, 0x4C, 

+	0x00, 0x00, 0x9B, 0x00, 0x80, 0x05, 0x99, 0xE0, 0x78, 0x88, 0x42, 0x0D, 0xDB, 0x20, 0x78, 0x00, 

+	0x28, 0x02, 0xD0, 0xFF, 0xF7, 0xE2, 0xFC, 0x03, 0xE0, 0xFF, 0xF7, 0xCE, 0xFC, 0xFF, 0xF7, 0xD5, 

+	0xFC, 0x00, 0x20, 0xE0, 0x70, 0x09, 0xB0, 0xF0, 0xBD, 0x40, 0x1C, 0xFA, 0xE7, 0x3D, 0x49, 0x00, 

+	0x20, 0xC8, 0x70, 0xF7, 0xE7, 0xF8, 0xB5, 0x07, 0x46, 0x3B, 0x48, 0x0C, 0x46, 0x40, 0x30, 0x42, 

+	0x7A, 0x00, 0x21, 0x01, 0x2A, 0x01, 0xD9, 0x01, 0x75, 0xF8, 0xBD, 0xC2, 0x7E, 0x39, 0x4E, 0x35, 

+	0x4D, 0x00, 0x2A, 0x03, 0xD1, 0x31, 0x78, 0x01, 0x29, 0x00, 0xD0, 0x00, 0x21, 0x29, 0x70, 0x09, 

+	0x06, 0x09, 0x0E, 0x05, 0xD0, 0x61, 0x07, 0x03, 0xD5, 0xA1, 0x07, 0x01, 0xD0, 0x01, 0x21, 0x00, 

+	0xE0, 0x00, 0x21, 0x01, 0x75, 0xA0, 0x07, 0x02, 0xD0, 0x20, 0x46, 0xFF, 0xF7, 0x1E, 0xFF, 0x60, 

+	0x07, 0x01, 0xD5, 0xFF, 0xF7, 

+	0x00, 0x00, 0x9C, 0x00, 0x80, 0xFF, 0xFD, 0x30, 0x78, 0x01, 0x28, 0x05, 0xD1, 0x20, 0x07, 0x03, 

+	0xD5, 0xE0, 0x06, 0x01, 0xD5, 0x01, 0x20, 0x00, 0xE0, 0x00, 0x20, 0x68, 0x70, 0x20, 0x07, 0x7D, 

+	0x00, 0x25, 0x4E, 0x00, 0x28, 0x03, 0xDA, 0xA8, 0x19, 0x40, 0x78, 0xFF, 0xF7, 0x70, 0xFD, 0xE0, 

+	0x06, 0xCA, 0xD5, 0x70, 0x5D, 0xFF, 0xF7, 0xE2, 0xFC, 0xF8, 0xBD, 0x30, 0xB5, 0x1A, 0x49, 0x19, 

+	0x4A, 0x09, 0x68, 0x93, 0x68, 0x00, 0x20, 0xCC, 0x1A, 0x18, 0x4B, 0x1D, 0x8C, 0xAC, 0x42, 0x00, 

+	0xD3, 0x04, 0x20, 0x18, 0x4C, 0x24, 0x78, 0x01, 0x2C, 0x03, 0xD1, 0x11, 0x4C, 0x64, 0x7F, 0x03, 

+	0x2C, 0x04, 0xD0, 0x11, 0x4C, 0x40, 0x34, 0x24, 0x7F, 0x01, 0x2C, 0x0D, 0xD1, 0xD4, 0x68, 0x5D, 

+	0x8C, 0x0C, 0x1B, 0xAC, 0x42, 0x01, 0xD3, 0x01, 0x24, 0x20, 0x43, 0x12, 0x69, 0x89, 0x1A, 0xAA, 

+	0xB2, 0x91, 0x42, 0x01, 0xD3, 

+	0x00, 0x00, 0x9D, 0x00, 0x80, 0x02, 0x21, 0x08, 0x43, 0x30, 0xBD, 0x06, 0x49, 0x02, 0x20, 0x08, 

+	0x56, 0x70, 0x47, 0x06, 0x48, 0xC0, 0x8B, 0x70, 0x47, 0x64, 0x07, 0x00, 0x20, 0x98, 0x04, 0x00, 

+	0x20, 0x84, 0xF4, 0x00, 0x00, 0xB4, 0x01, 0x00, 0x20, 0xEC, 0x03, 0x00, 0x20, 0xFC, 0xF6, 0x00, 

+	0x00, 0xF8, 0x00, 0x00, 0x20, 0x88, 0x00, 0x00, 0x20, 0xC1, 0xE7, 0x00, 0x00, 0x54, 0x49, 0x00, 

+	0x20, 0x08, 0x60, 0x54, 0x48, 0x01, 0x78, 0x54, 0x48, 0x01, 0x77, 0x70, 0x47, 0xF0, 0xB5, 0xAD, 

+	0xB0, 0x53, 0x48, 0x2B, 0x90, 0x53, 0x48, 0x4F, 0x4E, 0x40, 0x7B, 0x2C, 0x90, 0x30, 0x78, 0x4F, 

+	0x4C, 0x00, 0x28, 0x47, 0xD0, 0x50, 0x48, 0x00, 0x78, 0x00, 0x28, 0x43, 0xD0, 0xF0, 0x88, 0x04, 

+	0x21, 0x00, 0x90, 0x01, 0x91, 0x48, 0x48, 0x32, 0x89, 0x02, 0x23, 0x02, 0xA9, 0x40, 0x38, 0x00, 

+	0xF0, 0x09, 0xF9, 0x28, 0xA8, 

+	0x00, 0x00, 0x9E, 0x00, 0x80, 0x01, 0x7A, 0x00, 0x20, 0x41, 0x4D, 0x00, 0x29, 0x31, 0xD0, 0x6B, 

+	0x46, 0x0C, 0x22, 0x71, 0x88, 0x9A, 0x5E, 0x89, 0x1A, 0x00, 0x29, 0x27, 0xDD, 0x08, 0x20, 0x0A, 

+	0x22, 0x18, 0x5E, 0x9A, 0x5E, 0x50, 0x43, 0x09, 0xF0, 0xBD, 0xF9, 0x00, 0x28, 0x14, 0xDB, 0xB1, 

+	0x88, 0x81, 0x42, 0x01, 0xDD, 0x88, 0xB2, 0x05, 0xE0, 0x01, 0x21, 0x89, 0x04, 0x88, 0x42, 0x01, 

+	0xDD, 0x08, 0x46, 0x01, 0xE0, 0x00, 0x28, 0x07, 0xDD, 0x29, 0x68, 0x00, 0x29, 0x03, 0xD0, 0x4A, 

+	0x00, 0x89, 0x18, 0x08, 0x18, 0x80, 0x10, 0x28, 0x60, 0x29, 0x68, 0x00, 0x29, 0x0A, 0xDD, 0x01, 

+	0x20, 0x40, 0x02, 0x81, 0x42, 0x08, 0xDD, 0x49, 0x12, 0x09, 0x22, 0x06, 0xE0, 0x29, 0x68, 0x00, 

+	0x29, 0x00, 0xDD, 0x28, 0x60, 0x2D, 0xB0, 0xF0, 0xBD, 0x00, 0x22, 0x00, 0x92, 0x09, 0xF0, 0x92, 

+	0xF9, 0xA1, 0x22, 0x01, 0x90, 

+	0x00, 0x00, 0x9F, 0x00, 0x80, 0x92, 0x00, 0x21, 0x46, 0x2B, 0x98, 0x09, 0xF0, 0x20, 0xF9, 0x00, 

+	0x20, 0x33, 0xE0, 0x0A, 0x21, 0x41, 0x43, 0x02, 0xA8, 0x0B, 0x18, 0x08, 0x22, 0x23, 0x48, 0x9A, 

+	0x56, 0x00, 0x68, 0x51, 0x00, 0x0C, 0x18, 0x22, 0xE0, 0x06, 0x20, 0x18, 0x56, 0x20, 0x4D, 0x41, 

+	0x00, 0x49, 0x19, 0x2C, 0x9D, 0x55, 0x43, 0xAE, 0x46, 0x13, 0xE0, 0x00, 0x26, 0x00, 0x27, 0x8E, 

+	0x5F, 0xE7, 0x5F, 0x89, 0x1C, 0x7E, 0x43, 0x01, 0x9F, 0x76, 0x12, 0x7E, 0x43, 0x00, 0x9F, 0x75, 

+	0x46, 0x3E, 0x41, 0x2F, 0x18, 0x7D, 0x00, 0x2B, 0x9F, 0x7F, 0x5B, 0xBE, 0x19, 0x2B, 0x9F, 0x40, 

+	0x1C, 0x7E, 0x53, 0x07, 0x25, 0x5D, 0x57, 0x85, 0x42, 0xE7, 0xD2, 0xA4, 0x1C, 0x52, 0x1C, 0x09, 

+	0x20, 0x18, 0x56, 0x90, 0x42, 0xD8, 0xD2, 0x60, 0x46, 0x40, 0x1C, 0x84, 0x46, 0x28, 0xA8, 0x01, 

+	0x7A, 0x60, 0x46, 0x61, 0x45, 

+	0x00, 0x00, 0xA0, 0x00, 0x80, 0xC5, 0xDC, 0x04, 0x49, 0x05, 0x48, 0x40, 0x39, 0x08, 0x61, 0xB1, 

+	0xE7, 0xE0, 0x01, 0x00, 0x20, 0x2C, 0xF7, 0x00, 0x00, 0x2C, 0x04, 0x00, 0x20, 0x64, 0x07, 0x00, 

+	0x20, 0xE8, 0x09, 0x00, 0x20, 0x84, 0xF4, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x20, 0xF8, 0x00, 0x00, 

+	0x20, 0x98, 0x04, 0x00, 0x20, 0xFF, 0xB5, 0x00, 0x21, 0x83, 0xB0, 0x8E, 0x46, 0x0A, 0x46, 0xAB, 

+	0x49, 0x01, 0x91, 0x0C, 0x9B, 0x06, 0x99, 0x59, 0x43, 0x02, 0x91, 0x04, 0x9B, 0x00, 0x21, 0x5B, 

+	0x1E, 0x00, 0x93, 0x57, 0xE0, 0x14, 0x46, 0x4B, 0x00, 0x00, 0x9D, 0xC2, 0x5E, 0xA9, 0x42, 0x01, 

+	0xD1, 0x00, 0x23, 0x02, 0xE0, 0x1D, 0x18, 0x02, 0x23, 0xEB, 0x5E, 0x06, 0x9D, 0xAA, 0x42, 0x48, 

+	0xDD, 0x9A, 0x42, 0x46, 0xDD, 0xA2, 0x42, 0x44, 0xDB, 0x9B, 0x18, 0x1B, 0x19, 0x02, 0x9C, 0xA3, 

+	0x42, 0x3F, 0xDB, 0x00, 0x9B, 

+	0x00, 0x00, 0xA1, 0x00, 0x80, 0x0C, 0x46, 0xA4, 0x46, 0x99, 0x42, 0x12, 0xDA, 0x4B, 0x1C, 0x0D, 

+	0xE0, 0x5E, 0x00, 0x85, 0x5F, 0xAF, 0x00, 0x97, 0x42, 0x0B, 0xDB, 0x36, 0x18, 0x20, 0x3E, 0x1E, 

+	0x27, 0xF7, 0x5F, 0x0A, 0x3D, 0xBD, 0x42, 0x04, 0xDC, 0x64, 0x1C, 0x5B, 0x1C, 0x04, 0x9D, 0xAB, 

+	0x42, 0xEE, 0xDB, 0x00, 0x29, 0x11, 0xDD, 0x4B, 0x1E, 0x0F, 0xD4, 0x5E, 0x00, 0x85, 0x5F, 0xAF, 

+	0x00, 0x97, 0x42, 0x0A, 0xDB, 0x36, 0x18, 0x02, 0x27, 0xF7, 0x5F, 0x0A, 0x3D, 0xBD, 0x42, 0x04, 

+	0xDC, 0x65, 0x46, 0x6D, 0x1E, 0xAC, 0x46, 0x5B, 0x1E, 0xEF, 0xD5, 0x73, 0x46, 0x06, 0x25, 0x6B, 

+	0x43, 0x05, 0x9D, 0x5E, 0x19, 0x31, 0x71, 0x05, 0x9D, 0xEA, 0x52, 0x63, 0x46, 0xB3, 0x70, 0xF4, 

+	0x70, 0x01, 0x9B, 0x93, 0x42, 0x00, 0xDA, 0x01, 0x92, 0x73, 0x46, 0x5B, 0x1C, 0x9E, 0x46, 0x04, 

+	0x2B, 0x03, 0xD0, 0x49, 0x1C, 

+	0x00, 0x00, 0xA2, 0x00, 0x80, 0x04, 0x9B, 0x99, 0x42, 0xA4, 0xDB, 0x05, 0x99, 0x70, 0x46, 0x08, 

+	0x76, 0x07, 0xB0, 0xF0, 0xBD, 0xFF, 0xB5, 0x97, 0xB0, 0x04, 0x46, 0x0E, 0x46, 0x00, 0x20, 0xA0, 

+	0x36, 0x30, 0x70, 0x00, 0x93, 0x1F, 0x46, 0x0D, 0x46, 0x21, 0x7B, 0x60, 0x69, 0x01, 0xAA, 0x19, 

+	0x9B, 0xFF, 0xF7, 0x80, 0xFF, 0x00, 0x97, 0x61, 0x7B, 0xA0, 0x69, 0x08, 0xAA, 0x19, 0x9B, 0xFF, 

+	0xF7, 0x79, 0xFF, 0x00, 0x20, 0x93, 0xE0, 0x00, 0x20, 0x88, 0xE0, 0x70, 0x46, 0x06, 0x21, 0x48, 

+	0x43, 0x01, 0xA9, 0x41, 0x18, 0x11, 0x91, 0x16, 0x90, 0x04, 0x20, 0x08, 0x56, 0x00, 0x90, 0x60, 

+	0x46, 0x06, 0x22, 0x50, 0x43, 0x08, 0xAA, 0x15, 0x90, 0x80, 0x18, 0x04, 0x22, 0x10, 0x90, 0x82, 

+	0x56, 0x0F, 0x92, 0x02, 0x22, 0x8A, 0x56, 0x14, 0x92, 0x03, 0x22, 0x8A, 0x56, 0x02, 0x21, 0x13, 

+	0x92, 0x41, 0x56, 0x12, 0x91, 

+	0x00, 0x00, 0xA3, 0x00, 0x80, 0x03, 0x21, 0x41, 0x56, 0x00, 0x22, 0x0D, 0xE0, 0x13, 0x98, 0x07, 

+	0xE0, 0x23, 0x7B, 0x27, 0x69, 0x4B, 0x43, 0x1B, 0x18, 0x5B, 0x00, 0xFB, 0x5E, 0x9A, 0x18, 0x40, 

+	0x1E, 0x14, 0x9B, 0x98, 0x42, 0xF4, 0xDA, 0x49, 0x1E, 0x12, 0x98, 0x81, 0x42, 0xEE, 0xDA, 0x21, 

+	0x99, 0x20, 0x98, 0x48, 0x43, 0x90, 0x42, 0x4F, 0xDA, 0x33, 0x78, 0x00, 0x9A, 0x0F, 0x98, 0x10, 

+	0x2B, 0x53, 0xD2, 0x21, 0x7B, 0x27, 0x69, 0x48, 0x43, 0x80, 0x18, 0x0A, 0x21, 0x40, 0x00, 0x4B, 

+	0x43, 0x38, 0x5A, 0x59, 0x19, 0x88, 0x80, 0x30, 0x78, 0x40, 0x1C, 0xC3, 0xB2, 0x58, 0x1E, 0x33, 

+	0x70, 0x10, 0x28, 0x42, 0xD0, 0x20, 0x7B, 0x0F, 0x99, 0x22, 0x69, 0x48, 0x43, 0x00, 0x99, 0x40, 

+	0x18, 0x0A, 0x21, 0x4B, 0x43, 0x40, 0x00, 0x59, 0x19, 0x10, 0x5A, 0x20, 0x39, 0x48, 0x83, 0x16, 

+	0x99, 0x01, 0xA8, 0x41, 0x5A, 

+	0x00, 0x00, 0xA4, 0x00, 0x80, 0x30, 0x78, 0x0A, 0x22, 0x50, 0x43, 0x40, 0x19, 0x20, 0x38, 0xC1, 

+	0x82, 0x15, 0x99, 0x08, 0xA8, 0x41, 0x5A, 0x30, 0x78, 0x50, 0x43, 0x40, 0x19, 0x20, 0x38, 0x01, 

+	0x83, 0x11, 0x98, 0x81, 0x78, 0x30, 0x78, 0x50, 0x43, 0x40, 0x19, 0x20, 0x38, 0x01, 0x77, 0x11, 

+	0x98, 0xC1, 0x78, 0x30, 0x78, 0x50, 0x43, 0x40, 0x19, 0x20, 0x38, 0x41, 0x77, 0x10, 0x98, 0x81, 

+	0x78, 0x30, 0x78, 0x50, 0x43, 0x40, 0x19, 0x20, 0x38, 0x81, 0x77, 0x10, 0x98, 0xC1, 0x78, 0x30, 

+	0x78, 0x50, 0x43, 0x40, 0x19, 0x20, 0x38, 0xC1, 0x77, 0x60, 0x46, 0x40, 0x1C, 0x84, 0x46, 0x08, 

+	0xA8, 0x18, 0x21, 0x41, 0x56, 0x61, 0x45, 0x00, 0xDD, 0x6F, 0xE7, 0x70, 0x46, 0x40, 0x1C, 0x86, 

+	0x46, 0x68, 0x46, 0x1C, 0x21, 0x41, 0x56, 0x71, 0x45, 0x00, 0xDD, 0x64, 0xE7, 0x28, 0x46, 0x00, 

+	0xF0, 0x02, 0xF8, 0x1B, 0xB0, 

+	0x00, 0x00, 0xA5, 0x00, 0x80, 0xF0, 0xBD, 0xF1, 0xB5, 0x84, 0xB0, 0x04, 0x98, 0x00, 0x25, 0xA0, 

+	0x30, 0x03, 0x90, 0x25, 0xE0, 0x6C, 0x1C, 0x1D, 0xE0, 0x0A, 0x20, 0x04, 0x99, 0x68, 0x43, 0x47, 

+	0x18, 0x0A, 0x21, 0x04, 0x9A, 0x61, 0x43, 0x8E, 0x18, 0x04, 0x20, 0x04, 0x21, 0x38, 0x5E, 0x71, 

+	0x5E, 0x88, 0x42, 0x0E, 0xDA, 0x39, 0x46, 0x0A, 0x22, 0x68, 0x46, 0x08, 0xF0, 0x88, 0xFF, 0x31, 

+	0x46, 0x38, 0x46, 0x0A, 0x22, 0x08, 0xF0, 0x83, 0xFF, 0x30, 0x46, 0x0A, 0x22, 0x69, 0x46, 0x08, 

+	0xF0, 0x7E, 0xFF, 0x64, 0x1C, 0x03, 0x98, 0x00, 0x78, 0xA0, 0x42, 0xDD, 0xDC, 0x03, 0x98, 0x6D, 

+	0x1C, 0x00, 0x78, 0x40, 0x1E, 0xA8, 0x42, 0xD5, 0xDC, 0x05, 0xB0, 0xF0, 0xBD, 0x00, 0x80, 0xFF, 

+	0xFF, 0x10, 0xB5, 0xF8, 0x48, 0x00, 0x21, 0x01, 0x70, 0xF7, 0x4A, 0x42, 0x60, 0x41, 0x70, 0x81, 

+	0x70, 0xC1, 0x60, 0xF6, 0x48, 

+	0x00, 0x00, 0xA6, 0x00, 0x80, 0x81, 0x72, 0xFF, 0xF7, 0xD9, 0xFD, 0x10, 0xBD, 0xFF, 0xB5, 0x8D, 

+	0xB0, 0x8E, 0x46, 0x00, 0x20, 0x17, 0x9E, 0xF2, 0x49, 0x06, 0x27, 0x7E, 0x43, 0x49, 0x7B, 0xF1, 

+	0x4F, 0x06, 0x90, 0xF7, 0x19, 0x09, 0x91, 0x08, 0x90, 0x79, 0x7F, 0x05, 0x91, 0x39, 0x7F, 0x1E, 

+	0x26, 0x04, 0x91, 0xBE, 0x5F, 0x0A, 0x96, 0xEB, 0x4E, 0x84, 0x46, 0x31, 0x56, 0x00, 0x91, 0x20, 

+	0x26, 0xBE, 0x5F, 0x04, 0x99, 0x02, 0x46, 0x05, 0x46, 0x04, 0x46, 0x03, 0x46, 0x02, 0x96, 0x03, 

+	0x96, 0xC9, 0x07, 0x04, 0xD0, 0x00, 0x99, 0x00, 0x29, 0x01, 0xD0, 0x01, 0x21, 0x00, 0xE0, 0x00, 

+	0x21, 0x37, 0x00, 0xDE, 0x4E, 0x0B, 0x91, 0x07, 0x96, 0x77, 0xD0, 0x04, 0x99, 0xC9, 0x07, 0x74, 

+	0xD0, 0x0E, 0x21, 0x01, 0x91, 0x27, 0xE0, 0x01, 0x9F, 0x10, 0x9E, 0xF6, 0x57, 0x00, 0x2E, 0x22, 

+	0xDB, 0x16, 0x9F, 0x09, 0x99, 

+	0x00, 0x00, 0xA7, 0x00, 0x80, 0x4F, 0x43, 0xF1, 0x19, 0x4F, 0x00, 0x71, 0x46, 0xC9, 0x5F, 0x0C, 

+	0x91, 0x0F, 0x99, 0xCF, 0x5F, 0x0C, 0x99, 0xCF, 0x1B, 0x71, 0x00, 0x0D, 0x9E, 0x76, 0x5E, 0xF6, 

+	0x1B, 0x08, 0x9F, 0x00, 0x2F, 0x03, 0xD1, 0x06, 0x9F, 0x9B, 0x19, 0x7F, 0x1C, 0x06, 0x97, 0x37, 

+	0x1E, 0x00, 0xDA, 0x77, 0x42, 0x03, 0x99, 0x8F, 0x42, 0x05, 0xDA, 0x6D, 0x1C, 0x80, 0x19, 0x00, 

+	0x2E, 0x01, 0xDA, 0x64, 0x1C, 0x92, 0x19, 0x01, 0x99, 0x49, 0x1E, 0x01, 0x91, 0x49, 0x1C, 0xD2, 

+	0xD1, 0x00, 0x2D, 0x08, 0xDD, 0x00, 0x28, 0x01, 0xDA, 0x69, 0x10, 0x08, 0x18, 0xC2, 0x49, 0x6D, 

+	0x00, 0x49, 0x5F, 0x41, 0x43, 0x08, 0x13, 0x00, 0x2C, 0x08, 0xDD, 0x00, 0x2A, 0x01, 0xDA, 0x61, 

+	0x10, 0x8A, 0x18, 0xBD, 0x49, 0x64, 0x00, 0x09, 0x5F, 0x51, 0x43, 0x0A, 0x13, 0x08, 0x99, 0x00, 

+	0x29, 0x46, 0xD1, 0xB8, 0x4E, 

+	0x00, 0x00, 0xA8, 0x00, 0x80, 0x18, 0x99, 0x34, 0x79, 0x00, 0x2C, 0x41, 0xD0, 0x07, 0x9C, 0xA4, 

+	0x7E, 0x00, 0x2C, 0x3D, 0xD1, 0x07, 0x9C, 0x75, 0x79, 0x64, 0x7E, 0xAC, 0x42, 0x03, 0xD3, 0x01, 

+	0x29, 0x36, 0xD0, 0x02, 0x29, 0x34, 0xD0, 0x00, 0x2B, 0x00, 0xDA, 0x5B, 0x42, 0x06, 0x99, 0x00, 

+	0x29, 0x2E, 0xD0, 0x4C, 0x00, 0xAC, 0x49, 0x09, 0x5F, 0x59, 0x43, 0xF3, 0x89, 0x09, 0x13, 0x5B, 

+	0x18, 0x03, 0x99, 0x8B, 0x42, 0x24, 0xDD, 0x18, 0x99, 0x02, 0x98, 0x04, 0x29, 0x0B, 0xD0, 0x05, 

+	0xDC, 0x01, 0x29, 0x0A, 0xD0, 0x02, 0x29, 0x13, 0xD1, 0x07, 0xE0, 0x38, 0xE0, 0x08, 0x29, 0x06, 

+	0xD0, 0x10, 0x29, 0x0D, 0xD1, 0x05, 0xE0, 0xF2, 0x88, 0x04, 0xE0, 0x32, 0x89, 0x02, 0xE0, 0x72, 

+	0x89, 0x00, 0xE0, 0xB2, 0x89, 0x19, 0x46, 0x9A, 0x42, 0x02, 0xDB, 0x98, 0x42, 0x00, 0xDC, 0x08, 

+	0x46, 0x03, 0x90, 0x01, 0x20, 

+	0x00, 0x00, 0xA9, 0x00, 0x80, 0x08, 0x90, 0x00, 0x20, 0x02, 0x46, 0x05, 0x46, 0x04, 0x46, 0x6F, 

+	0xE7, 0x0B, 0x99, 0x00, 0x29, 0x1B, 0xD0, 0x00, 0x28, 0x0C, 0xDD, 0x00, 0x99, 0x88, 0x42, 0x06, 

+	0xDD, 0x89, 0x00, 0x81, 0x42, 0x13, 0xDD, 0x00, 0x9B, 0x61, 0x46, 0xC9, 0x18, 0x0E, 0xE0, 0x61, 

+	0x46, 0x49, 0x1C, 0x0B, 0xE0, 0x00, 0x28, 0x0A, 0xDA, 0x00, 0x9B, 0x41, 0x42, 0x99, 0x42, 0x0C, 

+	0xDD, 0x9B, 0x00, 0x8B, 0x42, 0x03, 0xDD, 0x00, 0x9B, 0x61, 0x46, 0xC9, 0x1A, 0x8C, 0x46, 0x05, 

+	0x99, 0x49, 0x1C, 0x05, 0x91, 0x0E, 0x21, 0x01, 0x91, 0x73, 0xE0, 0x61, 0x46, 0x49, 0x1E, 0xF5, 

+	0xE7, 0x01, 0x9B, 0x10, 0x99, 0xC9, 0x56, 0x00, 0x29, 0x6B, 0xDB, 0x09, 0x9C, 0x16, 0x9B, 0x63, 

+	0x43, 0xCB, 0x18, 0x5F, 0x00, 0x73, 0x46, 0xDD, 0x5F, 0x0F, 0x9B, 0xDC, 0x5F, 0x00, 0x94, 0x2B, 

+	0x1B, 0x4C, 0x00, 0x0D, 0x99, 

+	0x00, 0x00, 0xAA, 0x00, 0x80, 0x1E, 0x46, 0x09, 0x5F, 0x04, 0x9C, 0xE4, 0x07, 0x13, 0xD0, 0x99, 

+	0x42, 0x02, 0xDB, 0x0C, 0x1A, 0x9C, 0x42, 0x04, 0xDB, 0x99, 0x42, 0x04, 0xDC, 0x0C, 0x1A, 0x9C, 

+	0x42, 0x01, 0xDD, 0x31, 0x46, 0x07, 0xE0, 0x84, 0x1A, 0x03, 0x2C, 0x03, 0xDD, 0xB1, 0x42, 0x01, 

+	0xDC, 0x89, 0x1A, 0x00, 0xE0, 0x09, 0x1A, 0x04, 0x9B, 0x9B, 0x07, 0x0C, 0xD5, 0x4B, 0x1B, 0x00, 

+	0xD5, 0x5B, 0x42, 0x0A, 0x9C, 0xA3, 0x42, 0x06, 0xD2, 0x05, 0x9C, 0x01, 0x23, 0xA3, 0x40, 0x5B, 

+	0x1E, 0x6B, 0x43, 0x59, 0x18, 0x21, 0x41, 0x65, 0x4B, 0x99, 0x42, 0x01, 0xDD, 0x19, 0x46, 0x04, 

+	0xE0, 0x62, 0x4B, 0xDB, 0x43, 0x99, 0x42, 0x00, 0xDA, 0x19, 0x46, 0x00, 0x9B, 0x5C, 0x18, 0x63, 

+	0x1B, 0x5F, 0x4C, 0x24, 0x78, 0x00, 0x2C, 0x07, 0xD1, 0x5C, 0x4C, 0xA3, 0x42, 0x02, 0xDC, 0xE4, 

+	0x43, 0xA3, 0x42, 0x01, 0xDA, 

+	0x00, 0x00, 0xAB, 0x00, 0x80, 0x23, 0x46, 0xF1, 0x18, 0x07, 0x9C, 0x64, 0x7A, 0x01, 0x2C, 0x0A, 

+	0xD9, 0x18, 0x9C, 0x04, 0x2C, 0x07, 0xD1, 0x00, 0x9C, 0x1C, 0x1B, 0x00, 0xD5, 0x64, 0x42, 0x4D, 

+	0x4D, 0x2E, 0x69, 0xA4, 0x19, 0x2C, 0x61, 0x0F, 0x9C, 0x61, 0x44, 0xE3, 0x53, 0x4F, 0x4B, 0x99, 

+	0x42, 0x02, 0xDC, 0xDB, 0x43, 0x99, 0x42, 0x02, 0xDA, 0x71, 0x46, 0xCB, 0x53, 0x01, 0xE0, 0x73, 

+	0x46, 0xD9, 0x53, 0x01, 0x99, 0x49, 0x1E, 0x01, 0x91, 0x49, 0x1C, 0x89, 0xD1, 0x11, 0xB0, 0xF0, 

+	0xBD, 0x3E, 0xB5, 0x00, 0x22, 0x47, 0x4C, 0x00, 0x92, 0x02, 0x91, 0x01, 0x90, 0x60, 0x78, 0x28, 

+	0x21, 0x48, 0x43, 0x45, 0x49, 0x33, 0x25, 0x43, 0x18, 0x46, 0x48, 0x2D, 0x01, 0x00, 0x68, 0x1A, 

+	0x33, 0x42, 0x4A, 0x43, 0x49, 0x40, 0x19, 0xFF, 0xF7, 0x89, 0xFE, 0xE0, 0x7B, 0x3F, 0x4B, 0x40, 

+	0x4C, 0x01, 0x28, 0x0A, 0xD1, 

+	0x00, 0x00, 0xAC, 0x00, 0x80, 0x36, 0x4D, 0x05, 0xE0, 0x41, 0x00, 0x1A, 0x88, 0x5A, 0x52, 0x22, 

+	0x88, 0x62, 0x52, 0x40, 0x1C, 0xE9, 0x7D, 0x81, 0x42, 0xF6, 0xD8, 0x30, 0x48, 0x40, 0x38, 0x84, 

+	0x63, 0x03, 0x62, 0x3E, 0xBD, 0xF3, 0xB5, 0x33, 0x4D, 0x83, 0xB0, 0xE8, 0x7B, 0x01, 0x28, 0x02, 

+	0xD0, 0x01, 0x24, 0x35, 0x4E, 0x19, 0xE0, 0x2A, 0x48, 0xC4, 0x7D, 0xFA, 0xE7, 0x00, 0x20, 0x04, 

+	0x9A, 0x03, 0x99, 0x6B, 0x46, 0x07, 0xC3, 0x68, 0x78, 0x28, 0x21, 0x48, 0x43, 0x2A, 0x49, 0x2D, 

+	0x4F, 0x43, 0x18, 0x60, 0x00, 0x2D, 0x49, 0x3F, 0x68, 0x82, 0x19, 0x41, 0x18, 0xC7, 0x19, 0x65, 

+	0x20, 0xC0, 0x00, 0x1A, 0x33, 0x38, 0x18, 0xFF, 0xF7, 0x51, 0xFE, 0x64, 0x1E, 0xE6, 0xD2, 0x1B, 

+	0x49, 0x26, 0x48, 0x40, 0x39, 0xCE, 0x61, 0x48, 0x63, 0x05, 0xB0, 0xF0, 0xBD, 0xF3, 0xB5, 0x0E, 

+	0x46, 0x1C, 0x49, 0x1C, 0x48, 

+	0x00, 0x00, 0xAD, 0x00, 0x80, 0x20, 0x39, 0xCA, 0x7F, 0x00, 0x78, 0x17, 0x27, 0x15, 0x18, 0x6D, 

+	0x1E, 0x83, 0xB0, 0xD4, 0xB2, 0x7F, 0x01, 0x11, 0xE0, 0x00, 0x21, 0x03, 0x98, 0x00, 0x91, 0x01, 

+	0x90, 0x28, 0x20, 0x15, 0x49, 0x60, 0x43, 0x43, 0x18, 0x16, 0x48, 0x02, 0x96, 0x00, 0x68, 0x1A, 

+	0x33, 0x17, 0x4A, 0x18, 0x49, 0xC0, 0x19, 0xFF, 0xF7, 0x29, 0xFE, 0x64, 0x1C, 0xAC, 0x42, 0xEB, 

+	0xD9, 0x15, 0x48, 0x01, 0x68, 0x05, 0x48, 0x40, 0x38, 0x81, 0x61, 0x14, 0x49, 0x09, 0x68, 0x01, 

+	0x63, 0xD2, 0xE7, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0x7F, 0x2C, 0x04, 0x00, 

+	0x20, 0x84, 0xF4, 0x00, 0x00, 0x38, 0xF7, 0x00, 0x00, 0x78, 0xE5, 0x00, 0x00, 0xFF, 0x7F, 0x00, 

+	0x00, 0x35, 0x01, 0x00, 0x20, 0xC4, 0xF4, 0x00, 0x00, 0x20, 0xF6, 0x00, 0x00, 0x26, 0x01, 0x00, 

+	0x20, 0x16, 0x01, 0x00, 0x20, 

+	0x00, 0x00, 0xAE, 0x00, 0x80, 0xE8, 0x00, 0x00, 0x20, 0x1E, 0x01, 0x00, 0x20, 0x0E, 0x01, 0x00, 

+	0x20, 0x98, 0x04, 0x00, 0x20, 0x50, 0x04, 0x00, 0x20, 0xF8, 0x00, 0x00, 0x20, 0xF4, 0x00, 0x00, 

+	0x20, 0xFE, 0xB5, 0x06, 0x46, 0xED, 0x48, 0x17, 0x27, 0x0D, 0x46, 0xC4, 0x7F, 0x7F, 0x01, 0x0F, 

+	0xE0, 0x00, 0x20, 0x00, 0x90, 0x28, 0x20, 0xEA, 0x49, 0x60, 0x43, 0x43, 0x18, 0xEB, 0x48, 0x01, 

+	0x96, 0x02, 0x95, 0x00, 0x68, 0x1A, 0x33, 0xE7, 0x4A, 0xE7, 0x49, 0xC0, 0x19, 0xFF, 0xF7, 0xDE, 

+	0xFD, 0x64, 0x1E, 0xED, 0xD2, 0xE6, 0x48, 0xE3, 0x49, 0x41, 0x61, 0xE3, 0x49, 0xC1, 0x62, 0xFE, 

+	0xBD, 0xF3, 0xB5, 0x01, 0x24, 0xA4, 0x02, 0x89, 0xB0, 0x20, 0x46, 0xFC, 0xF7, 0x63, 0xF9, 0xFD, 

+	0xF7, 0xD6, 0xFB, 0x20, 0x46, 0xFC, 0xF7, 0x5E, 0xF9, 0xDE, 0x48, 0x06, 0x7B, 0x40, 0x7B, 0x07, 

+	0x90, 0x77, 0x1E, 0xDD, 0x48, 

+	0x00, 0x00, 0xAF, 0x00, 0x80, 0x00, 0x21, 0x01, 0x61, 0xD4, 0x48, 0x85, 0x7F, 0x28, 0xE0, 0x28, 

+	0x20, 0xD3, 0x49, 0x68, 0x43, 0x41, 0x18, 0x1A, 0x31, 0x0E, 0x22, 0x03, 0xA8, 0x08, 0xF0, 0x17, 

+	0xFD, 0x00, 0x24, 0x1B, 0xE0, 0xD5, 0x48, 0xD6, 0x49, 0x00, 0x78, 0x09, 0x78, 0x41, 0x1A, 0xA1, 

+	0x42, 0x01, 0xDD, 0x20, 0x46, 0x01, 0xE0, 0x80, 0x1B, 0x00, 0x19, 0x0A, 0x9A, 0x09, 0x99, 0x02, 

+	0x92, 0x01, 0x91, 0x07, 0x99, 0x00, 0x94, 0x48, 0x43, 0x41, 0x00, 0xC8, 0x48, 0x03, 0xAB, 0x00, 

+	0x68, 0xCC, 0x4A, 0x08, 0x18, 0xCC, 0x49, 0xFF, 0xF7, 0x99, 0xFD, 0x64, 0x1C, 0xBC, 0x42, 0xE1, 

+	0xDD, 0x6D, 0x1E, 0xD4, 0xD2, 0xC2, 0x48, 0xC7, 0x49, 0x01, 0x61, 0xC7, 0x49, 0x81, 0x62, 0xC2, 

+	0x49, 0x09, 0x69, 0x81, 0x60, 0x0B, 0xB0, 0xF0, 0xBD, 0x70, 0xB5, 0x0C, 0x46, 0x4A, 0x07, 0x05, 

+	0x46, 0x06, 0x21, 0x48, 0x43, 

+	0x00, 0x00, 0xB0, 0x00, 0x80, 0xC1, 0x49, 0x00, 0x2A, 0x03, 0xDA, 0x08, 0x5C, 0x04, 0x21, 0xFF, 

+	0xF7, 0xA7, 0xFF, 0x06, 0x21, 0x4D, 0x43, 0xBD, 0x49, 0xE0, 0x07, 0x6D, 0x18, 0x00, 0x28, 0x03, 

+	0xD0, 0xA8, 0x78, 0x01, 0x21, 0xFF, 0xF7, 0x7C, 0xFF, 0xA0, 0x07, 0x03, 0xD5, 0x68, 0x78, 0x02, 

+	0x21, 0xFF, 0xF7, 0x24, 0xFF, 0xAE, 0x48, 0x40, 0x30, 0x01, 0x7D, 0x00, 0x29, 0x08, 0xD0, 0x80, 

+	0x7A, 0x00, 0x28, 0x05, 0xD0, 0xB2, 0x48, 0x40, 0x78, 0x00, 0x28, 0x01, 0xD0, 0x00, 0xF0, 0x6A, 

+	0xF9, 0xE0, 0x07, 0x04, 0xD0, 0xA0, 0x07, 0x02, 0xD5, 0x20, 0x46, 0xFF, 0xF7, 0x37, 0xFB, 0x20, 

+	0x07, 0x03, 0xD5, 0xE8, 0x78, 0x08, 0x21, 0xFF, 0xF7, 0xDD, 0xFE, 0xE0, 0x06, 0x03, 0xD5, 0x28, 

+	0x79, 0x10, 0x21, 0xFF, 0xF7, 0xAD, 0xFE, 0x70, 0xBD, 0xFE, 0xB5, 0x09, 0x9C, 0x06, 0x27, 0x7C, 

+	0x43, 0xA2, 0x4F, 0x04, 0x25, 

+	0x00, 0x00, 0xB1, 0x00, 0x80, 0x3C, 0x5D, 0x08, 0x9E, 0x00, 0x96, 0x02, 0x95, 0x01, 0x94, 0xFF, 

+	0xF7, 0x3D, 0xFD, 0xFE, 0xBD, 0xFF, 0xB5, 0x97, 0x49, 0x04, 0x46, 0x4A, 0x7B, 0x00, 0x20, 0x96, 

+	0x46, 0x0A, 0x7B, 0x17, 0xE0, 0x71, 0x46, 0x51, 0x43, 0x8C, 0x46, 0x01, 0x99, 0x0E, 0xE0, 0x65, 

+	0x46, 0x6D, 0x18, 0x6D, 0x00, 0x66, 0x5F, 0x2D, 0x19, 0x20, 0x3D, 0x1E, 0x27, 0xEF, 0x5F, 0xF5, 

+	0x1B, 0x00, 0xD5, 0x6D, 0x42, 0x9D, 0x42, 0x01, 0xDD, 0xED, 0x1A, 0x28, 0x18, 0x02, 0x9D, 0x49, 

+	0x1C, 0xA9, 0x42, 0xEC, 0xD3, 0x52, 0x1E, 0xE5, 0xD2, 0x04, 0xB0, 0xF0, 0xBD, 0x84, 0x48, 0x02, 

+	0x21, 0x40, 0x30, 0x81, 0x72, 0x84, 0x49, 0x01, 0x20, 0x08, 0x70, 0x70, 0x47, 0xF1, 0xB5, 0x81, 

+	0x4E, 0x84, 0xB0, 0xB0, 0x7F, 0x01, 0x28, 0x0B, 0xD1, 0x86, 0x48, 0x00, 0x78, 0x01, 0x28, 0x07, 

+	0xD1, 0x85, 0x48, 0x00, 0x78, 

+	0x00, 0x00, 0xB2, 0x00, 0x80, 0x00, 0x28, 0x04, 0xD0, 0x07, 0xF0, 0xC2, 0xFF, 0x7A, 0x49, 0xC8, 

+	0x60, 0xB2, 0xE6, 0x77, 0x4D, 0x40, 0x35, 0x68, 0x7A, 0x01, 0x28, 0x01, 0xD9, 0x00, 0x20, 0x90, 

+	0xE0, 0x7B, 0x4F, 0x72, 0x7B, 0xFB, 0x8A, 0x00, 0x21, 0x77, 0x48, 0xFF, 0xF7, 0xB3, 0xFF, 0x04, 

+	0x46, 0x30, 0x7B, 0x73, 0x7B, 0x39, 0x8B, 0x00, 0x26, 0x04, 0x9A, 0x01, 0x90, 0x02, 0x92, 0x77, 

+	0x48, 0x00, 0x96, 0x03, 0x91, 0x01, 0x68, 0x32, 0x46, 0x66, 0x48, 0x00, 0xF0, 0x8F, 0xF8, 0x6A, 

+	0x4F, 0x79, 0x68, 0x8C, 0x42, 0x0C, 0xDA, 0x79, 0x78, 0x49, 0x1C, 0xC9, 0xB2, 0x79, 0x70, 0x0A, 

+	0x29, 0x11, 0xD9, 0x6D, 0x49, 0x09, 0x78, 0x00, 0x29, 0x0D, 0xD1, 0x7E, 0x70, 0x7C, 0x60, 0x0A, 

+	0xE0, 0x67, 0x4A, 0x12, 0x8A, 0x7E, 0x70, 0x52, 0x18, 0xA2, 0x42, 0x04, 0xDD, 0x4A, 0x01, 0x51, 

+	0x1A, 0x09, 0x19, 0x49, 0x11, 

+	0x00, 0x00, 0xB3, 0x00, 0x80, 0x79, 0x60, 0x79, 0x68, 0x8C, 0x42, 0x01, 0xDD, 0x64, 0x1A, 0x00, 

+	0xE0, 0x00, 0x24, 0x57, 0x4A, 0xD4, 0x64, 0x10, 0x65, 0x3A, 0x78, 0x00, 0x2A, 0x02, 0xD0, 0x01, 

+	0x2A, 0x3C, 0xD1, 0x14, 0xE0, 0x5A, 0x49, 0x0A, 0x8A, 0xA2, 0x42, 0x36, 0xDA, 0x8A, 0x8A, 0x82, 

+	0x42, 0x33, 0xDB, 0xB8, 0x78, 0x40, 0x1C, 0xC0, 0xB2, 0xB8, 0x70, 0x89, 0x7E, 0x81, 0x42, 0x2D, 

+	0xD2, 0x01, 0x20, 0x38, 0x70, 0xBE, 0x70, 0x07, 0xF0, 0x63, 0xFF, 0xF8, 0x60, 0x26, 0xE0, 0xBA, 

+	0x68, 0xA2, 0x42, 0x06, 0xDD, 0x13, 0x1B, 0x92, 0x01, 0xD2, 0x09, 0x93, 0x42, 0x01, 0xD9, 0x60, 

+	0x18, 0x18, 0xE0, 0x4B, 0x49, 0x0A, 0x8A, 0xA2, 0x42, 0x0B, 0xDB, 0x8A, 0x8A, 0x82, 0x42, 0x08, 

+	0xDB, 0xB8, 0x78, 0x40, 0x1C, 0xC0, 0xB2, 0xB8, 0x70, 0xC9, 0x7E, 0x81, 0x42, 0x0E, 0xD2, 0x3E, 

+	0x70, 0x0B, 0xE0, 0x07, 0xF0, 

+	0x00, 0x00, 0xB4, 0x00, 0x80, 0x45, 0xFF, 0xF9, 0x68, 0x40, 0x1A, 0x45, 0x49, 0x88, 0x42, 0x04, 

+	0xD9, 0x78, 0x68, 0x20, 0x18, 0x78, 0x60, 0x3E, 0x70, 0x04, 0xE0, 0xBE, 0x70, 0xBC, 0x60, 0x38, 

+	0x78, 0x01, 0x28, 0x01, 0xD0, 0xAE, 0x72, 0x27, 0xE6, 0x39, 0x48, 0x41, 0x8A, 0xA1, 0x42, 0x01, 

+	0xDD, 0x01, 0x20, 0x06, 0xE0, 0x08, 0x04, 0x80, 0x0B, 0xA0, 0x42, 0x01, 0xDD, 0x02, 0x20, 0x00, 

+	0xE0, 0x03, 0x20, 0xA8, 0x72, 0x18, 0xE6, 0x10, 0xB5, 0x2A, 0x48, 0x81, 0x7F, 0x01, 0x29, 0x0C, 

+	0xD1, 0x30, 0x49, 0x09, 0x78, 0x01, 0x29, 0x08, 0xD1, 0x42, 0x7B, 0x2D, 0x48, 0x00, 0x21, 0xC3, 

+	0x8A, 0x29, 0x48, 0xFF, 0xF7, 0x17, 0xFF, 0x24, 0x49, 0x48, 0x60, 0x10, 0xBD, 0xF0, 0xB5, 0x8C, 

+	0x46, 0x00, 0x25, 0x07, 0x99, 0x06, 0x46, 0x08, 0x9C, 0x9E, 0x46, 0x28, 0x46, 0xC9, 0x07, 0x11, 

+	0xD0, 0x52, 0x1C, 0x72, 0x45, 

+	0x00, 0x00, 0xB5, 0x00, 0x80, 0x0D, 0xD2, 0x57, 0x00, 0xF1, 0x5F, 0xBF, 0x19, 0x20, 0x3F, 0x1E, 

+	0x23, 0xFB, 0x5E, 0xC9, 0x1A, 0x00, 0xD5, 0x49, 0x42, 0xA1, 0x42, 0xF1, 0xDD, 0x09, 0x1B, 0x08, 

+	0x18, 0xEE, 0xE7, 0x6D, 0x1C, 0x07, 0x99, 0x89, 0x07, 0x14, 0xD5, 0x05, 0x99, 0x0D, 0xE0, 0x4A, 

+	0x00, 0x63, 0x46, 0x9B, 0x5E, 0x62, 0x44, 0x20, 0x3A, 0x1E, 0x26, 0x96, 0x5F, 0x9A, 0x1B, 0x00, 

+	0xD5, 0x52, 0x42, 0xA2, 0x42, 0x01, 0xDD, 0x12, 0x1B, 0x10, 0x18, 0x06, 0x9A, 0x49, 0x1C, 0x91, 

+	0x42, 0xED, 0xD3, 0x6D, 0x1C, 0x02, 0x2D, 0x00, 0xD1, 0x40, 0x10, 0xF0, 0xBD, 0xA4, 0xF4, 0x00, 

+	0x00, 0x20, 0xF6, 0x00, 0x00, 0x98, 0x04, 0x00, 0x20, 0x50, 0x04, 0x00, 0x20, 0xE8, 0x00, 0x00, 

+	0x20, 0xEC, 0x03, 0x00, 0x20, 0x84, 0xF4, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x20, 0x3B, 0x01, 0x00, 

+	0x20, 0x4B, 0x01, 0x00, 0x20, 

+	0x00, 0x00, 0xB6, 0x00, 0x80, 0x64, 0x07, 0x00, 0x20, 0xE0, 0x04, 0x00, 0x20, 0xC9, 0xE7, 0x00, 

+	0x00, 0x38, 0xF7, 0x00, 0x00, 0x88, 0x00, 0x00, 0x20, 0xE0, 0x00, 0x00, 0x20, 0xF8, 0x00, 0x00, 

+	0x20, 0x60, 0xEA, 0x00, 0x00, 0xF8, 0xB5, 0x1F, 0x48, 0x1C, 0x4C, 0x05, 0x68, 0x1E, 0x48, 0x1C, 

+	0x4B, 0x01, 0x7B, 0x00, 0x91, 0x40, 0x7B, 0x1E, 0x49, 0x86, 0x46, 0x89, 0x78, 0x1B, 0x48, 0x00, 

+	0x29, 0x2A, 0xD0, 0x00, 0x21, 0x1E, 0xE0, 0x1B, 0x4A, 0x00, 0x21, 0x16, 0xE0, 0x00, 0x26, 0x00, 

+	0x27, 0x96, 0x5F, 0xEF, 0x5F, 0x7E, 0x43, 0x16, 0x4F, 0xBF, 0x78, 0x3E, 0x41, 0x00, 0x27, 0xE7, 

+	0x5F, 0x77, 0x43, 0x13, 0x4E, 0xB6, 0x78, 0x37, 0x41, 0x3E, 0xB2, 0x1E, 0x80, 0x86, 0x42, 0x00, 

+	0xDB, 0x30, 0x46, 0xA4, 0x1C, 0x9B, 0x1C, 0x92, 0x1C, 0x49, 0x1C, 0x71, 0x45, 0xE6, 0xD3, 0xAD, 

+	0x1C, 0x61, 0x46, 0x49, 0x1C, 

+	0x00, 0x00, 0xB7, 0x00, 0x80, 0x8C, 0x46, 0x00, 0x99, 0x8C, 0x45, 0xDC, 0xD3, 0x0A, 0x4A, 0x04, 

+	0x49, 0x11, 0x61, 0x11, 0x46, 0x40, 0x31, 0xC8, 0x82, 0xF8, 0xBD, 0x00, 0x00, 0x64, 0x07, 0x00, 

+	0x20, 0xC8, 0x0C, 0x00, 0x20, 0xF8, 0x00, 0x00, 0x20, 0x84, 0xF4, 0x00, 0x00, 0x00, 0x80, 0xFF, 

+	0xFF, 0x38, 0xF7, 0x00, 0x00, 0x98, 0x04, 0x00, 0x20, 0xEC, 0x03, 0x00, 0x20, 0xFE, 0x49, 0x00, 

+	0x20, 0xC8, 0x70, 0xC8, 0x71, 0x08, 0x70, 0xFD, 0x49, 0xFD, 0x48, 0xCA, 0x8B, 0x42, 0x80, 0x09, 

+	0x78, 0x89, 0x07, 0xC9, 0x0F, 0x01, 0x70, 0x70, 0x47, 0xF7, 0x48, 0x00, 0x21, 0xC1, 0x70, 0xC1, 

+	0x71, 0x70, 0x47, 0xFC, 0xB5, 0x82, 0x1E, 0x8B, 0x1E, 0x88, 0x42, 0x3C, 0xD0, 0x05, 0x28, 0x3A, 

+	0xD2, 0x05, 0x29, 0x38, 0xD2, 0xFF, 0x24, 0x44, 0x34, 0x62, 0x43, 0xF2, 0x4C, 0x12, 0x19, 0x00, 

+	0x92, 0x92, 0x78, 0x01, 0x92, 

+	0x00, 0x00, 0xB8, 0x00, 0x80, 0xFF, 0x22, 0x44, 0x32, 0x53, 0x43, 0x1A, 0x19, 0x96, 0x46, 0x92, 

+	0x78, 0x94, 0x46, 0xED, 0x4A, 0x53, 0x89, 0x24, 0xE0, 0x00, 0x22, 0x02, 0x28, 0x06, 0xD3, 0x00, 

+	0x9A, 0xD4, 0x18, 0x03, 0x22, 0xA2, 0x56, 0x01, 0x9C, 0x62, 0x43, 0x52, 0x42, 0x02, 0x29, 0x06, 

+	0xD3, 0x74, 0x46, 0xE5, 0x18, 0x03, 0x24, 0x2C, 0x57, 0x65, 0x46, 0x6C, 0x43, 0xA2, 0x18, 0xE3, 

+	0x4F, 0x5C, 0x00, 0x3D, 0x5F, 0xE2, 0x4E, 0xAA, 0x18, 0x15, 0x46, 0xB2, 0x42, 0x02, 0xDB, 0x76, 

+	0x0C, 0xB2, 0x42, 0x00, 0xDD, 0x32, 0x46, 0x3A, 0x53, 0xDE, 0x4F, 0xAA, 0x1A, 0x3E, 0x5B, 0xB2, 

+	0x1A, 0x3A, 0x53, 0x5B, 0x1E, 0xD8, 0xD2, 0xFC, 0xBD, 0xF3, 0xB5, 0x01, 0x20, 0x81, 0xB0, 0x0F, 

+	0x46, 0x00, 0x90, 0x00, 0x29, 0x02, 0xD0, 0xD8, 0x48, 0x80, 0x7F, 0x00, 0x90, 0x00, 0x25, 0x2E, 

+	0x46, 0x40, 0xE0, 0x00, 0x24, 

+	0x00, 0x00, 0xB9, 0x00, 0x80, 0x3A, 0xE0, 0x00, 0x2F, 0x02, 0xD0, 0xD4, 0x48, 0x04, 0x70, 0x03, 

+	0xE0, 0xC9, 0x48, 0xD2, 0x49, 0x00, 0x7A, 0x08, 0x70, 0x01, 0x98, 0xD1, 0x49, 0x40, 0x00, 0x09, 

+	0x5C, 0x80, 0x20, 0xFD, 0xF7, 0x6D, 0xF8, 0x00, 0x21, 0x01, 0x98, 0xFD, 0xF7, 0x1A, 0xFA, 0xFD, 

+	0xF7, 0x70, 0xF8, 0x00, 0x28, 0xFB, 0xD0, 0xCB, 0x49, 0x00, 0x20, 0x8C, 0x46, 0xCA, 0x49, 0x09, 

+	0x78, 0x0A, 0xE0, 0x4A, 0x00, 0x63, 0x46, 0x9A, 0x5E, 0x13, 0x1E, 0x00, 0xDA, 0x5A, 0x42, 0x82, 

+	0x42, 0x02, 0xDD, 0x18, 0x1E, 0x00, 0xDA, 0x58, 0x42, 0x49, 0x1E, 0xF2, 0xD2, 0x0A, 0x21, 0x08, 

+	0xF0, 0xE1, 0xFA, 0xFE, 0x28, 0x00, 0xDD, 0xFE, 0x20, 0xC0, 0xB2, 0xB3, 0x49, 0x85, 0x42, 0x48, 

+	0x71, 0x03, 0xDA, 0x00, 0x2F, 0x00, 0xD0, 0x0C, 0x72, 0x05, 0x46, 0x64, 0x1C, 0x00, 0x98, 0x84, 

+	0x42, 0xC1, 0xD3, 0x76, 0x1C, 

+	0x00, 0x00, 0xBA, 0x00, 0x80, 0xB9, 0x48, 0x00, 0x78, 0x86, 0x42, 0xBA, 0xDB, 0xAA, 0x48, 0x45, 

+	0x71, 0xFE, 0xBD, 0x70, 0xB5, 0xA8, 0x4C, 0xE0, 0x79, 0x02, 0x28, 0x01, 0xD9, 0x01, 0x20, 0x00, 

+	0xE0, 0x00, 0x20, 0x65, 0x79, 0x01, 0x21, 0xFF, 0xF7, 0x9F, 0xFF, 0x60, 0x79, 0x65, 0x71, 0x70, 

+	0xBD, 0xF8, 0xB5, 0xA1, 0x4E, 0x00, 0x25, 0xF0, 0x79, 0x00, 0x28, 0x59, 0xD0, 0x07, 0xF0, 0xA8, 

+	0xFD, 0xAB, 0x49, 0x04, 0x46, 0x48, 0x57, 0xAB, 0x49, 0x00, 0x27, 0x4A, 0x57, 0x10, 0x43, 0x00, 

+	0x28, 0x1F, 0xD1, 0xFF, 0xF7, 0xDE, 0xFF, 0x01, 0x46, 0x99, 0x48, 0x40, 0x88, 0x81, 0x42, 0x18, 

+	0xDA, 0xF0, 0x68, 0x21, 0x1A, 0x95, 0x48, 0x00, 0x69, 0x81, 0x42, 0x70, 0x78, 0x0D, 0xD9, 0x00, 

+	0x28, 0x0D, 0xD1, 0xF4, 0x60, 0xF0, 0x79, 0x01, 0x25, 0x02, 0x28, 0x03, 0xD9, 0x02, 0x20, 0xF0, 

+	0x71, 0x01, 0x20, 0x2C, 0xE0, 

+	0x00, 0x00, 0xBB, 0x00, 0x80, 0xF7, 0x71, 0xF7, 0x70, 0x32, 0xE0, 0x00, 0x28, 0x30, 0xD0, 0x77, 

+	0x70, 0x2D, 0xE0, 0x99, 0x48, 0x81, 0x68, 0x89, 0x48, 0x40, 0x69, 0x81, 0x42, 0x27, 0xD2, 0xFF, 

+	0xF7, 0xB8, 0xFF, 0x01, 0x46, 0x86, 0x48, 0x40, 0x88, 0x81, 0x42, 0x20, 0xDA, 0x83, 0x48, 0xF1, 

+	0x79, 0x80, 0x69, 0x40, 0x08, 0x02, 0x29, 0x04, 0xD8, 0xB2, 0x78, 0x00, 0x2A, 0x01, 0xD1, 0x7F, 

+	0x48, 0x80, 0x69, 0xF2, 0x68, 0xA2, 0x1A, 0x82, 0x42, 0x70, 0x78, 0x0C, 0xD9, 0x01, 0x28, 0x0C, 

+	0xD1, 0x01, 0x25, 0xF4, 0x60, 0x02, 0x29, 0x04, 0xD9, 0xB0, 0x70, 0x02, 0x21, 0xF1, 0x71, 0xF0, 

+	0x70, 0x06, 0xE0, 0xB7, 0x70, 0xCE, 0xE7, 0x01, 0x28, 0x02, 0xD0, 0x01, 0x20, 0x70, 0x70, 0xF4, 

+	0x60, 0x28, 0x46, 0xF8, 0xBD, 0x70, 0xB5, 0x71, 0x48, 0x6F, 0x4D, 0x86, 0x78, 0x20, 0xE0, 0x03, 

+	0x24, 0x1C, 0xE0, 0xE8, 0x78, 

+	0x00, 0x00, 0xBC, 0x00, 0x80, 0x40, 0x1C, 0x05, 0x28, 0x00, 0xD3, 0x02, 0x20, 0xC0, 0xB2, 0xE8, 

+	0x70, 0x01, 0x28, 0x0B, 0xD0, 0x03, 0x21, 0xE9, 0x71, 0x00, 0x21, 0xFF, 0xF7, 0x25, 0xFF, 0xE8, 

+	0x79, 0x02, 0x28, 0x06, 0xD9, 0x65, 0x48, 0x20, 0x30, 0x00, 0x7A, 0x04, 0xE0, 0x64, 0x1C, 0x02, 

+	0x21, 0xF1, 0xE7, 0x63, 0x48, 0x40, 0x88, 0x69, 0x79, 0x88, 0x42, 0x05, 0xD8, 0x64, 0x1E, 0xE0, 

+	0xD2, 0x76, 0x1E, 0xDC, 0xD2, 0x07, 0x20, 0xE8, 0x71, 0x70, 0xBD, 0xF8, 0xB5, 0x6A, 0x4A, 0x5E, 

+	0x4D, 0x40, 0x32, 0x59, 0x4B, 0x69, 0x7B, 0x00, 0x24, 0x12, 0x7D, 0x84, 0x46, 0xDE, 0x79, 0xC8, 

+	0xB2, 0x27, 0x46, 0x00, 0x2A, 0x1B, 0xD0, 0x6A, 0x7F, 0xD2, 0x43, 0xD3, 0x07, 0xDB, 0x17, 0x5B, 

+	0x1C, 0x00, 0xD0, 0x00, 0x21, 0x92, 0x07, 0xD2, 0x17, 0x52, 0x1C, 0x00, 0xD0, 0xA8, 0x7B, 0x00, 

+	0x2E, 0x0B, 0xD0, 0x0C, 0xE0, 

+	0x00, 0x00, 0xBD, 0x00, 0x80, 0x5D, 0x4A, 0x4B, 0x00, 0xD3, 0x5E, 0x4C, 0x4A, 0x26, 0x25, 0x55, 

+	0x5F, 0xAB, 0x42, 0x01, 0xDA, 0x01, 0x27, 0x02, 0xE0, 0x49, 0x1C, 0x81, 0x42, 0xF2, 0xD3, 0x46, 

+	0x4D, 0x07, 0x2E, 0x09, 0xD0, 0x45, 0x48, 0x46, 0x4E, 0x00, 0x78, 0xC0, 0x07, 0x02, 0xD0, 0x30, 

+	0x78, 0xC0, 0x07, 0x16, 0xD0, 0x00, 0x2F, 0x01, 0xD0, 0x01, 0x24, 0x14, 0xE0, 0xE8, 0x78, 0x00, 

+	0x28, 0x00, 0xD0, 0x84, 0x46, 0x01, 0x21, 0x60, 0x46, 0xFF, 0xF7, 0xCE, 0xFE, 0xE8, 0x79, 0x02, 

+	0x28, 0x03, 0xD9, 0x3A, 0x48, 0x20, 0x30, 0x00, 0x7A, 0x00, 0xE0, 0x70, 0x88, 0x69, 0x79, 0x88, 

+	0x42, 0xEA, 0xD9, 0x00, 0x2C, 0x02, 0xD0, 0x07, 0xF0, 0xD3, 0xFC, 0xE8, 0x60, 0x20, 0x46, 0xF8, 

+	0xBD, 0xFE, 0xB5, 0x31, 0x4E, 0x01, 0x46, 0xF0, 0x78, 0x00, 0x90, 0x3F, 0x4D, 0xF0, 0x79, 0x40, 

+	0x35, 0x01, 0x90, 0xA8, 0x7E, 

+	0x00, 0x00, 0xBE, 0x00, 0x80, 0x01, 0x24, 0x00, 0x28, 0x2C, 0x48, 0x03, 0xD0, 0x42, 0x7A, 0x80, 

+	0x7A, 0x10, 0x18, 0x00, 0xE0, 0x40, 0x7A, 0xC0, 0xB2, 0x02, 0x90, 0x00, 0x20, 0x30, 0x71, 0x70, 

+	0x71, 0xB0, 0x71, 0x37, 0x48, 0x40, 0x78, 0x01, 0x28, 0x75, 0xD1, 0x08, 0x46, 0xFF, 0xF7, 0x8D, 

+	0xFF, 0x31, 0x4F, 0x60, 0x37, 0x00, 0x28, 0x1A, 0xD0, 0x20, 0x48, 0x00, 0x7A, 0x00, 0x28, 0x0E, 

+	0xD0, 0x01, 0x98, 0x00, 0x28, 0x0B, 0xD1, 0x30, 0x78, 0x02, 0x99, 0x88, 0x42, 0x05, 0xD2, 0x40, 

+	0x1C, 0x30, 0x70, 0x01, 0x20, 0xB8, 0x70, 0x00, 0x24, 0x5D, 0xE0, 0x00, 0x20, 0x30, 0x70, 0x00, 

+	0x24, 0xFF, 0xF7, 0x48, 0xFF, 0xF1, 0x78, 0x00, 0x98, 0xFF, 0xF7, 0x3B, 0xFE, 0x53, 0xE0, 0xFF, 

+	0xF7, 0xDF, 0xFE, 0x00, 0x28, 0x10, 0xD0, 0x00, 0x24, 0xF1, 0x78, 0x00, 0x98, 0xFF, 0xF7, 0x31, 

+	0xFE, 0xF0, 0x79, 0x00, 0x28, 

+	0x00, 0x00, 0xBF, 0x00, 0x80, 0x47, 0xD1, 0x01, 0x98, 0x01, 0x28, 0x44, 0xD0, 0x3F, 0x20, 0xFE, 

+	0xF7, 0xEB, 0xFB, 0xFF, 0xF7, 0x58, 0xFD, 0x3E, 0xE0, 0x08, 0x48, 0x00, 0x7A, 0x00, 0x28, 0x3A, 

+	0xD0, 0x00, 0x20, 0x30, 0x70, 0x07, 0xF0, 0x74, 0xFC, 0xB9, 0x78, 0x00, 0x29, 0x02, 0xD0, 0x69, 

+	0x7E, 0x00, 0x29, 0x27, 0xD0, 0x30, 0x61, 0x2E, 0xE0, 0xF8, 0x01, 0x00, 0x20, 0xA8, 0xF7, 0x00, 

+	0x00, 0x90, 0x00, 0x00, 0x20, 0x00, 0xFB, 0x00, 0x00, 0x84, 0xF4, 0x00, 0x00, 0xE0, 0x04, 0x00, 

+	0x20, 0x00, 0x80, 0xFF, 0xFF, 0x64, 0x07, 0x00, 0x20, 0xA4, 0xF4, 0x00, 0x00, 0xB0, 0x01, 0x00, 

+	0x20, 0xFC, 0x00, 0x00, 0x20, 0x8E, 0x10, 0x00, 0x20, 0x57, 0x01, 0x00, 0x20, 0x56, 0x01, 0x00, 

+	0x20, 0xE0, 0x00, 0x00, 0x20, 0xE1, 0x00, 0x00, 0x20, 0xEC, 0x03, 0x00, 0x20, 0x98, 0x04, 0x00, 

+	0x20, 0x88, 0x00, 0x00, 0x20, 

+	0x00, 0x00, 0xC0, 0x00, 0x80, 0x31, 0x69, 0x42, 0x1A, 0xA3, 0x49, 0xC9, 0x68, 0x8A, 0x42, 0x02, 

+	0xD9, 0x00, 0x21, 0xB9, 0x70, 0xCE, 0xE7, 0xA1, 0x49, 0x30, 0x79, 0xC8, 0x73, 0x70, 0x79, 0x28, 

+	0x72, 0xF0, 0x79, 0x68, 0x72, 0xB0, 0x79, 0x28, 0x76, 0x20, 0x46, 0xFE, 0xBD, 0xF8, 0xB5, 0x01, 

+	0x21, 0x9B, 0x48, 0x05, 0x25, 0x01, 0x70, 0x1B, 0xE0, 0x28, 0x46, 0x2E, 0x21, 0x48, 0x43, 0x99, 

+	0x49, 0x00, 0x24, 0x6F, 0x00, 0x46, 0x18, 0x0F, 0xE0, 0x97, 0x48, 0x04, 0x70, 0x97, 0x48, 0xC1, 

+	0x5D, 0x80, 0x20, 0xFC, 0xF7, 0x95, 0xFE, 0x31, 0x46, 0x28, 0x46, 0xFD, 0xF7, 0x42, 0xF8, 0xFC, 

+	0xF7, 0x98, 0xFE, 0x00, 0x28, 0xFB, 0xD0, 0x64, 0x1C, 0x91, 0x48, 0x80, 0x7F, 0xA0, 0x42, 0xEB, 

+	0xD8, 0x6D, 0x1E, 0xE1, 0xD2, 0x8A, 0x48, 0x00, 0x21, 0x01, 0x70, 0xF8, 0xBD, 0x70, 0xB5, 0x05, 

+	0x46, 0x8C, 0x48, 0x40, 0x89, 

+	0x00, 0x00, 0xC1, 0x00, 0x80, 0x44, 0x00, 0x21, 0x46, 0x8B, 0x48, 0x08, 0xF0, 0xFD, 0xF8, 0x21, 

+	0x46, 0x8A, 0x48, 0x08, 0xF0, 0xF9, 0xF8, 0x85, 0x4C, 0x20, 0x78, 0xFC, 0xF7, 0xDC, 0xFF, 0xFE, 

+	0xF7, 0x5C, 0xFB, 0x68, 0x00, 0x20, 0x5C, 0xFC, 0xF7, 0xD6, 0xFF, 0x70, 0xBD, 0xF1, 0xB5, 0x84, 

+	0x4F, 0x82, 0xB0, 0x02, 0x24, 0x20, 0x46, 0xFF, 0xF7, 0xE1, 0xFF, 0x68, 0x46, 0x00, 0xF0, 0xC2, 

+	0xF8, 0x7C, 0x48, 0xA5, 0x1E, 0x42, 0x89, 0x7F, 0x48, 0x13, 0x46, 0x01, 0x68, 0x68, 0x46, 0x00, 

+	0x78, 0x08, 0x70, 0x49, 0x1C, 0x78, 0x4E, 0x02, 0xE0, 0x58, 0x00, 0x30, 0x5C, 0xC8, 0x54, 0x5B, 

+	0x1E, 0xFA, 0xD2, 0xFF, 0x20, 0x44, 0x30, 0x45, 0x43, 0xE8, 0x19, 0x49, 0x1E, 0x80, 0x1C, 0x52, 

+	0x1C, 0x08, 0xF0, 0xBA, 0xF9, 0x64, 0x1C, 0x05, 0x2C, 0xDC, 0xD3, 0xB8, 0x1C, 0x72, 0x49, 0x73, 

+	0x4A, 0x08, 0xF0, 0xAC, 0xF9, 

+	0x00, 0x00, 0xC2, 0x00, 0x80, 0x69, 0x46, 0x88, 0x80, 0x02, 0x22, 0x01, 0xA9, 0x6C, 0x48, 0x08, 

+	0xF0, 0xAB, 0xF9, 0x02, 0x98, 0xFB, 0xF7, 0xA4, 0xFC, 0xFF, 0xF7, 0x88, 0xFF, 0xFE, 0xBD, 0xF8, 

+	0xB5, 0x64, 0x4E, 0x00, 0x25, 0x70, 0x89, 0x41, 0x00, 0x40, 0x18, 0x00, 0x90, 0x68, 0x48, 0x40, 

+	0x78, 0x01, 0x28, 0x36, 0xD1, 0x62, 0x4F, 0x64, 0x49, 0xB8, 0x1C, 0x64, 0x4A, 0x08, 0xF0, 0x8E, 

+	0xF9, 0x39, 0x88, 0x88, 0x42, 0x01, 0xD0, 0x00, 0x20, 0xF8, 0xBD, 0x02, 0x24, 0xA6, 0x1E, 0x20, 

+	0x46, 0xFF, 0xF7, 0x94, 0xFF, 0xFF, 0x20, 0x44, 0x30, 0x46, 0x43, 0x59, 0x48, 0x55, 0x49, 0x30, 

+	0x18, 0x83, 0x78, 0x49, 0x89, 0x54, 0x4E, 0x0D, 0xE0, 0x47, 0x18, 0x03, 0x22, 0xBA, 0x56, 0x4F, 

+	0x00, 0xF7, 0x5F, 0x5A, 0x43, 0xBA, 0x1A, 0x00, 0xD5, 0x52, 0x42, 0x47, 0x4F, 0xBF, 0x8C, 0xBA, 

+	0x42, 0x00, 0xDA, 0x6D, 0x1C, 

+	0x00, 0x00, 0xC3, 0x00, 0x80, 0x49, 0x1E, 0xEF, 0xD2, 0x64, 0x1C, 0x05, 0x2C, 0xDE, 0xD3, 0x42, 

+	0x48, 0x00, 0x99, 0x20, 0x30, 0xC0, 0x78, 0x48, 0x43, 0x64, 0x21, 0x08, 0xF0, 0x79, 0xF8, 0xA8, 

+	0x42, 0xD1, 0xD8, 0x01, 0x20, 0xF8, 0xBD, 0xF7, 0xB5, 0x42, 0x48, 0x17, 0x46, 0x40, 0x7B, 0x00, 

+	0x25, 0x42, 0x00, 0x82, 0xB0, 0x0C, 0x46, 0x05, 0x29, 0x01, 0xD3, 0x00, 0x20, 0x00, 0xE0, 0x08, 

+	0x46, 0x2E, 0x21, 0x48, 0x43, 0x37, 0x49, 0x41, 0x18, 0x36, 0x48, 0x5C, 0x38, 0x07, 0xF0, 0xFF, 

+	0xFF, 0x34, 0x48, 0x2E, 0x21, 0x2E, 0x38, 0x08, 0xF0, 0x57, 0xF8, 0x33, 0x48, 0x28, 0x21, 0x00, 

+	0x78, 0x30, 0x4A, 0x48, 0x43, 0x3B, 0x49, 0x2E, 0x3A, 0x46, 0x18, 0x30, 0x49, 0x60, 0x00, 0x40, 

+	0x18, 0x40, 0x78, 0x00, 0x21, 0x00, 0x91, 0x1A, 0x36, 0x01, 0x90, 0x11, 0x46, 0x33, 0x46, 0x2E, 

+	0x39, 0x02, 0x98, 0xFF, 0xF7, 

+	0x00, 0x00, 0xC4, 0x00, 0x80, 0x39, 0xFB, 0x27, 0x49, 0x0E, 0x20, 0x2E, 0x39, 0x0F, 0xE0, 0x32, 

+	0x56, 0x00, 0x2A, 0x0C, 0xDB, 0x52, 0x00, 0x8C, 0x5E, 0x00, 0x2C, 0x01, 0xDB, 0x22, 0x46, 0x00, 

+	0xE0, 0x62, 0x42, 0xAA, 0x42, 0x03, 0xDD, 0x00, 0x2C, 0x00, 0xDA, 0x64, 0x42, 0x25, 0x46, 0x40, 

+	0x1E, 0xED, 0xD2, 0x1C, 0x49, 0x78, 0x00, 0xE6, 0x31, 0x0D, 0x52, 0x05, 0xB0, 0xF0, 0xBD, 0x16, 

+	0x48, 0xC0, 0x78, 0x70, 0x47, 0xF8, 0xB5, 0x04, 0x46, 0x00, 0x20, 0x1A, 0x4A, 0x20, 0x70, 0x51, 

+	0x89, 0x19, 0x4D, 0x10, 0xE0, 0x23, 0x78, 0x48, 0x00, 0x28, 0x5E, 0xDB, 0x01, 0x80, 0x33, 0x00, 

+	0x28, 0x01, 0xDB, 0x06, 0x46, 0x00, 0xE0, 0x46, 0x42, 0xB3, 0x42, 0x04, 0xDC, 0x00, 0x28, 0x00, 

+	0xDA, 0x40, 0x42, 0xC0, 0x11, 0x20, 0x70, 0x49, 0x1E, 0xEC, 0xD2, 0x20, 0x78, 0x40, 0x1C, 0x20, 

+	0x70, 0x56, 0x89, 0x05, 0xE0, 

+	0x00, 0x00, 0xC5, 0x00, 0x80, 0x77, 0x00, 0x21, 0x78, 0xE8, 0x5F, 0x08, 0xF0, 0x0B, 0xF8, 0xE8, 

+	0x53, 0x76, 0x1E, 0xF7, 0xD2, 0xF8, 0xBD, 0x00, 0x00, 0xA8, 0xF7, 0x00, 0x00, 0xEC, 0x03, 0x00, 

+	0x20, 0x38, 0x01, 0x00, 0x20, 0xA8, 0x0F, 0x00, 0x20, 0xB0, 0x01, 0x00, 0x20, 0xFC, 0x00, 0x00, 

+	0x20, 0xA4, 0xF4, 0x00, 0x00, 0x84, 0xF4, 0x00, 0x00, 0x64, 0x07, 0x00, 0x20, 0xE0, 0x04, 0x00, 

+	0x20, 0x00, 0xFB, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x20, 0xCA, 0x03, 0x00, 0x00, 0xFF, 0xFF, 0x00, 

+	0x00, 0x88, 0x00, 0x00, 0x20, 0x20, 0xF6, 0x00, 0x00, 0xD5, 0x48, 0x00, 0x21, 0x80, 0x78, 0xC0, 

+	0x43, 0x80, 0x07, 0xC2, 0x17, 0x52, 0x1C, 0xD3, 0x48, 0x00, 0x2A, 0x02, 0xD0, 0x07, 0x22, 0x02, 

+	0x80, 0x00, 0xE0, 0x01, 0x80, 0xD0, 0x4A, 0x41, 0x80, 0x52, 0x88, 0x82, 0x80, 0x01, 0x22, 0x82, 

+	0x71, 0xC1, 0x71, 0x01, 0x81, 

+	0x00, 0x00, 0xC6, 0x00, 0x80, 0x81, 0x72, 0x70, 0x47, 0xCA, 0x48, 0x10, 0xB5, 0x20, 0x38, 0x00, 

+	0x21, 0x02, 0x46, 0x26, 0x3A, 0x81, 0x60, 0xC2, 0x60, 0x01, 0x60, 0x01, 0x46, 0xEC, 0x39, 0x41, 

+	0x60, 0x01, 0x46, 0x14, 0x31, 0x01, 0x61, 0xC5, 0x48, 0xC3, 0x49, 0x02, 0x78, 0x0A, 0x70, 0xC2, 

+	0x78, 0x4A, 0x70, 0x82, 0x88, 0x4A, 0x80, 0xC2, 0x88, 0x8A, 0x80, 0x02, 0x89, 0xCA, 0x80, 0x00, 

+	0x7C, 0x08, 0x72, 0xFF, 0xF7, 0xC9, 0xFF, 0x00, 0xF0, 0x68, 0xF9, 0x00, 0xF0, 0x7D, 0xFC, 0x00, 

+	0xF0, 0x7D, 0xF9, 0x03, 0xF0, 0x15, 0xFF, 0x04, 0xF0, 0x2B, 0xFF, 0x00, 0xF0, 0x4E, 0xF9, 0x10, 

+	0xBD, 0xFF, 0xB5, 0x83, 0xB0, 0x0D, 0x98, 0x1D, 0x46, 0x40, 0x30, 0xC0, 0x7E, 0x0E, 0x46, 0x00, 

+	0x28, 0x31, 0xD1, 0x00, 0x24, 0x0C, 0x22, 0xAF, 0x49, 0x68, 0x46, 0x07, 0xF0, 0x28, 0xFF, 0x01, 

+	0x21, 0x68, 0x46, 0x81, 0x71, 

+	0x00, 0x00, 0xC7, 0x00, 0x80, 0x00, 0x27, 0xC7, 0x71, 0xAD, 0x48, 0xA1, 0x00, 0x42, 0x58, 0xA9, 

+	0x49, 0x08, 0x46, 0x20, 0x38, 0x90, 0x47, 0xA7, 0x4A, 0x68, 0x46, 0x51, 0x88, 0x40, 0x88, 0x01, 

+	0x43, 0x51, 0x80, 0x90, 0x79, 0xC0, 0x07, 0xC0, 0x0F, 0x00, 0xD0, 0x01, 0x20, 0x90, 0x71, 0x07, 

+	0x20, 0x10, 0x56, 0x38, 0x43, 0x00, 0xD0, 0x01, 0x20, 0xD0, 0x71, 0x69, 0x46, 0x10, 0x89, 0x09, 

+	0x89, 0x08, 0x43, 0x10, 0x81, 0x69, 0x46, 0x90, 0x88, 0x89, 0x88, 0x88, 0x42, 0x00, 0xD3, 0x08, 

+	0x46, 0x90, 0x80, 0x64, 0x1C, 0xCE, 0xD0, 0x97, 0x48, 0x05, 0x99, 0x02, 0x88, 0x0A, 0x60, 0x03, 

+	0x99, 0x42, 0x88, 0x0A, 0x80, 0x81, 0x79, 0x29, 0x70, 0x0C, 0x99, 0x82, 0x7A, 0x0A, 0x70, 0x81, 

+	0x88, 0x31, 0x60, 0x01, 0x89, 0x00, 0x29, 0x05, 0xD0, 0x00, 0x21, 0x31, 0x60, 0x29, 0x70, 0x01, 

+	0x89, 0x03, 0x98, 0x01, 0x80, 

+	0x00, 0x00, 0xC8, 0x00, 0x80, 0x07, 0xB0, 0xF0, 0xBD, 0x66, 0xE7, 0xF3, 0xB5, 0x83, 0xB0, 0x04, 

+	0x46, 0xFF, 0xF7, 0x62, 0xFF, 0x8A, 0x4A, 0x12, 0x1D, 0x00, 0x2C, 0x0A, 0xD0, 0xA0, 0x07, 0x04, 

+	0xD0, 0xA0, 0x08, 0x80, 0x00, 0x00, 0x1D, 0x10, 0x60, 0x00, 0xE0, 0x14, 0x60, 0x83, 0x20, 0xC0, 

+	0x00, 0x90, 0x80, 0x91, 0x88, 0x00, 0x27, 0x84, 0x29, 0x01, 0xD2, 0x38, 0x46, 0x05, 0xE0, 0x10, 

+	0x68, 0x03, 0x46, 0x84, 0x33, 0x84, 0x39, 0x13, 0x60, 0x91, 0x80, 0x7A, 0x49, 0x20, 0x39, 0x88, 

+	0x60, 0x07, 0x70, 0x47, 0x80, 0x7A, 0x48, 0x00, 0x1D, 0x80, 0x88, 0xC8, 0x28, 0x01, 0xD2, 0x3C, 

+	0x46, 0x07, 0xE0, 0x77, 0x4A, 0x12, 0x1D, 0x14, 0x68, 0x23, 0x46, 0xC8, 0x33, 0xC8, 0x38, 0x13, 

+	0x60, 0x90, 0x80, 0x70, 0x48, 0xC6, 0x21, 0x20, 0x38, 0x04, 0x60, 0x20, 0x46, 0x07, 0xF0, 0x04, 

+	0xFF, 0x04, 0x9E, 0x40, 0x36, 

+	0x00, 0x00, 0xC9, 0x00, 0x80, 0xF0, 0x7E, 0x00, 0x28, 0x13, 0xD0, 0x6A, 0x4A, 0x04, 0x98, 0x11, 

+	0x46, 0x20, 0x39, 0x04, 0xF0, 0x9A, 0xFF, 0xC0, 0x20, 0x00, 0x5B, 0x00, 0x28, 0x04, 0xD0, 0xFB, 

+	0xF7, 0x42, 0xFC, 0xFF, 0xF7, 0x19, 0xFF, 0xF7, 0x76, 0x20, 0x46, 0x00, 0xF0, 0xAB, 0xFB, 0x05, 

+	0xB0, 0xF0, 0xBD, 0x04, 0x98, 0x01, 0x90, 0x5F, 0x48, 0x20, 0x38, 0x00, 0x25, 0x00, 0x90, 0x60, 

+	0x48, 0xA9, 0x00, 0x00, 0x1F, 0x42, 0x58, 0x00, 0x99, 0x01, 0x98, 0x90, 0x47, 0x6D, 0x1C, 0x01, 

+	0x2D, 0xF5, 0xDB, 0x20, 0x46, 0x71, 0x7A, 0xC0, 0x30, 0x00, 0x90, 0x81, 0x70, 0x55, 0x4A, 0x04, 

+	0x98, 0x11, 0x46, 0x20, 0x39, 0x01, 0xF0, 0x54, 0xF9, 0x20, 0x78, 0xC0, 0x07, 0x0B, 0xD0, 0x51, 

+	0x49, 0x88, 0x7A, 0x00, 0x28, 0x05, 0xD1, 0xA0, 0x78, 0x00, 0x28, 0x02, 0xD1, 0xE0, 0x78, 0x00, 

+	0x28, 0x00, 0xD0, 0x01, 0x20, 

+	0x00, 0x00, 0xCA, 0x00, 0x80, 0x88, 0x72, 0x04, 0x98, 0x00, 0xF0, 0xA5, 0xFB, 0x4D, 0x4D, 0x49, 

+	0x48, 0x6A, 0x88, 0x29, 0x88, 0x20, 0x38, 0x00, 0xF0, 0x82, 0xFD, 0xA8, 0x7D, 0x02, 0x28, 0x03, 

+	0xD1, 0x44, 0x48, 0x20, 0x38, 0x01, 0xF0, 0xCB, 0xFD, 0x6A, 0x88, 0x29, 0x88, 0x20, 0x46, 0x04, 

+	0xF0, 0x26, 0xFD, 0x20, 0x78, 0x80, 0x07, 0x04, 0xD5, 0xB4, 0x20, 0x01, 0x5B, 0x3D, 0x48, 0x6C, 

+	0x38, 0x81, 0x82, 0x20, 0x78, 0x40, 0x4D, 0xC0, 0x07, 0x0C, 0xD0, 0xA0, 0x78, 0xA8, 0x70, 0xE0, 

+	0x78, 0xE8, 0x70, 0xB0, 0x22, 0x21, 0x1D, 0x28, 0x1D, 0x07, 0xF0, 0x39, 0xFE, 0x28, 0x46, 0xEC, 

+	0x30, 0x01, 0xF0, 0x62, 0xFE, 0x00, 0x98, 0x81, 0x78, 0x32, 0x48, 0x4C, 0x38, 0x81, 0x70, 0xA8, 

+	0x78, 0x70, 0x76, 0xE8, 0x78, 0xB0, 0x76, 0x20, 0x46, 0x00, 0xF0, 0x08, 0xFB, 0x2D, 0x4A, 0x11, 

+	0x89, 0x00, 0x29, 0x00, 0xD0, 

+	0x00, 0x00, 0xCB, 0x00, 0x80, 0x51, 0x80, 0x2E, 0x4A, 0x83, 0x23, 0x12, 0x1D, 0x91, 0x88, 0xDB, 

+	0x00, 0xC8, 0x31, 0x99, 0x42, 0x03, 0xD8, 0x91, 0x80, 0x11, 0x68, 0xC8, 0x39, 0x11, 0x60, 0x25, 

+	0x4C, 0x20, 0x3C, 0x27, 0x60, 0x91, 0x88, 0x84, 0x31, 0x99, 0x42, 0x03, 0xD8, 0x91, 0x80, 0x11, 

+	0x68, 0x84, 0x39, 0x11, 0x60, 0xA7, 0x60, 0x01, 0x88, 0x00, 0x29, 0x00, 0xD0, 0x77, 0xE7, 0x00, 

+	0x20, 0x75, 0xE7, 0x1C, 0x48, 0x20, 0x38, 0x40, 0x68, 0xA0, 0x30, 0x80, 0x8A, 0x70, 0x47, 0x70, 

+	0x47, 0x10, 0xB5, 0xFF, 0xF7, 0x81, 0xFE, 0x00, 0xF0, 0x20, 0xF8, 0x00, 0xF0, 0x0E, 0xF8, 0x10, 

+	0xBD, 0x10, 0xB5, 0x04, 0xF0, 0xEF, 0xFD, 0x01, 0x22, 0x12, 0x48, 0x00, 0x21, 0x42, 0x80, 0x81, 

+	0x80, 0x81, 0x71, 0x01, 0x81, 0xC2, 0x71, 0x01, 0x80, 0x10, 0xBD, 0x10, 0xB5, 0x01, 0xF0, 0x32, 

+	0xF8, 0x00, 0xF0, 0x2B, 0xF8, 

+	0x00, 0x00, 0xCC, 0x00, 0x80, 0x00, 0xF0, 0x8A, 0xFB, 0x04, 0xF0, 0xB5, 0xFC, 0x09, 0x48, 0x20, 

+	0x38, 0x01, 0xF0, 0xC8, 0xFA, 0x04, 0xF0, 0x78, 0xF9, 0x10, 0xBD, 0x10, 0xB5, 0xC6, 0x21, 0x0A, 

+	0x48, 0x07, 0xF0, 0x32, 0xFE, 0x03, 0x48, 0x24, 0x21, 0x46, 0x38, 0x07, 0xF0, 0x2D, 0xFE, 0x10, 

+	0xBD, 0x88, 0x00, 0x00, 0x20, 0xCC, 0x11, 0x00, 0x20, 0x94, 0x00, 0x00, 0x20, 0xD4, 0xF7, 0x00, 

+	0x00, 0x10, 0x02, 0x00, 0x20, 0x84, 0xF4, 0x00, 0x00, 0xC0, 0x10, 0x00, 0x20, 0xFE, 0x49, 0xFF, 

+	0x48, 0x0A, 0x78, 0x02, 0x70, 0x49, 0x78, 0x41, 0x70, 0x70, 0x47, 0x10, 0xB5, 0xFC, 0x49, 0x00, 

+	0x20, 0x08, 0x70, 0xC8, 0x80, 0x88, 0x80, 0x88, 0x70, 0xC6, 0x21, 0xFA, 0x48, 0x07, 0xF0, 0x0C, 

+	0xFE, 0xF8, 0x48, 0x16, 0x21, 0xC6, 0x30, 0x07, 0xF0, 0x07, 0xFE, 0x0B, 0x20, 0xF5, 0x4A, 0xFF, 

+	0x21, 0x02, 0xE0, 0x03, 0x01, 

+	0x00, 0x00, 0xCD, 0x00, 0x80, 0x9B, 0x18, 0xD9, 0x73, 0x40, 0x1E, 0xFA, 0xD2, 0x10, 0xBD, 0xFF, 

+	0xB5, 0x01, 0x21, 0x0C, 0x46, 0x84, 0xB0, 0x01, 0x91, 0xED, 0x49, 0x84, 0x40, 0x8D, 0x88, 0x05, 

+	0x99, 0xEC, 0x4F, 0x89, 0xB2, 0x00, 0x91, 0x06, 0x99, 0x42, 0x00, 0x89, 0xB2, 0x8C, 0x46, 0x50, 

+	0x3F, 0xD9, 0xB2, 0x26, 0x46, 0x8E, 0x46, 0x38, 0x18, 0x2E, 0x40, 0xD1, 0x19, 0x40, 0x30, 0x00, 

+	0x2E, 0x2F, 0xD0, 0x3E, 0x46, 0xB7, 0x5A, 0x05, 0x9E, 0xF6, 0x1B, 0x00, 0xD5, 0x76, 0x42, 0x03, 

+	0x96, 0x0F, 0x8C, 0x06, 0x9E, 0xF6, 0x1B, 0x00, 0xD5, 0x76, 0x42, 0x02, 0x96, 0x07, 0x78, 0xDE, 

+	0x1B, 0x00, 0xD5, 0x76, 0x42, 0x9F, 0x42, 0x14, 0xD2, 0xD7, 0x4F, 0xBB, 0x79, 0xB3, 0x42, 0x10, 

+	0xDA, 0x3E, 0x79, 0x03, 0x9B, 0x9E, 0x42, 0x0C, 0xDD, 0x02, 0x9B, 0xF6, 0xB2, 0x9E, 0x42, 0x08, 

+	0xDD, 0xD4, 0x4B, 0x00, 0x9C, 

+	0x00, 0x00, 0xCE, 0x00, 0x80, 0x50, 0x3B, 0x9C, 0x52, 0x62, 0x46, 0x0A, 0x84, 0x71, 0x46, 0x01, 

+	0x70, 0x04, 0xE0, 0x00, 0x20, 0x01, 0x90, 0xCE, 0x48, 0xA5, 0x43, 0x85, 0x80, 0x01, 0x98, 0x08, 

+	0xB0, 0xF0, 0xBD, 0xCB, 0x4B, 0x2C, 0x43, 0x9C, 0x80, 0x00, 0x9C, 0xBC, 0x52, 0xEC, 0xE7, 0xF3, 

+	0xB5, 0x91, 0xB0, 0x05, 0x46, 0x00, 0x26, 0xC7, 0x48, 0x04, 0x96, 0x0C, 0x96, 0x01, 0x88, 0x49, 

+	0x08, 0x49, 0x00, 0x01, 0x80, 0x28, 0x88, 0xC1, 0x07, 0x79, 0xD0, 0xBF, 0x49, 0x0A, 0x7A, 0xD2, 

+	0x07, 0x06, 0xD0, 0xC0, 0x06, 0x04, 0xD5, 0xE8, 0x78, 0x00, 0x28, 0x01, 0xD0, 0x00, 0x20, 0xA8, 

+	0x70, 0xBA, 0x4A, 0xB9, 0x49, 0x10, 0x78, 0x40, 0x43, 0x0B, 0x90, 0x50, 0x78, 0x40, 0x43, 0x0F, 

+	0x90, 0x08, 0x79, 0x40, 0x43, 0x0E, 0x90, 0xC8, 0x78, 0x69, 0x46, 0x40, 0x43, 0x0D, 0x90, 0x00, 

+	0x20, 0xFF, 0x22, 0x0A, 0x54, 

+	0x00, 0x00, 0xCF, 0x00, 0x80, 0x40, 0x1C, 0x0F, 0x28, 0xFB, 0xD9, 0x00, 0x20, 0xAB, 0x78, 0x0A, 

+	0xE0, 0x01, 0x01, 0x49, 0x19, 0xC9, 0x7B, 0x6A, 0x46, 0xC9, 0x06, 0xC9, 0x0E, 0x50, 0x54, 0x01, 

+	0x22, 0x8A, 0x40, 0x16, 0x43, 0x40, 0x1C, 0x83, 0x42, 0xF2, 0xD8, 0x00, 0x24, 0x27, 0x46, 0xBC, 

+	0xE0, 0xA8, 0x48, 0x39, 0x01, 0x08, 0x18, 0x06, 0x90, 0xC0, 0x7B, 0xC1, 0x06, 0xC9, 0x0E, 0x0F, 

+	0x29, 0x75, 0xD8, 0x40, 0x06, 0x80, 0x0F, 0x03, 0x28, 0x3A, 0xD0, 0x01, 0x20, 0x88, 0x40, 0x86, 

+	0x43, 0x09, 0x90, 0x05, 0x91, 0x68, 0x46, 0x40, 0x5C, 0xFF, 0x28, 0x37, 0xD0, 0x12, 0x99, 0x00, 

+	0x01, 0x49, 0x1E, 0x12, 0x91, 0x40, 0x19, 0x08, 0x90, 0x06, 0x99, 0xC2, 0x88, 0xC9, 0x88, 0x03, 

+	0x89, 0x51, 0x1A, 0x06, 0x9A, 0x49, 0x43, 0x12, 0x89, 0x9A, 0x1A, 0x52, 0x43, 0x89, 0x18, 0x07, 

+	0x91, 0x06, 0x99, 0x80, 0x7A, 

+	0x00, 0x00, 0xD0, 0x00, 0x80, 0x89, 0x7A, 0x7A, 0x00, 0x08, 0x1A, 0x0F, 0x99, 0x0A, 0x91, 0x91, 

+	0x49, 0xC6, 0x31, 0x8A, 0x5A, 0x0B, 0x99, 0x8A, 0x42, 0x05, 0xD2, 0x8B, 0x49, 0x89, 0x79, 0x81, 

+	0x42, 0x01, 0xDA, 0x0E, 0x98, 0x0A, 0x90, 0x08, 0x98, 0x81, 0x88, 0x87, 0x48, 0x40, 0x79, 0x81, 

+	0x42, 0x36, 0xD2, 0x87, 0x49, 0x09, 0x98, 0xC9, 0x88, 0x08, 0x42, 0x1C, 0xD0, 0x35, 0xE0, 0x59, 

+	0xE1, 0x84, 0x49, 0x00, 0x20, 0x7A, 0x00, 0xC6, 0x31, 0x88, 0x52, 0x6D, 0xE0, 0xBC, 0x42, 0x08, 

+	0xD0, 0x80, 0x48, 0x22, 0x01, 0x06, 0x99, 0x10, 0x18, 0x09, 0x1D, 0x00, 0x1D, 0x10, 0x22, 0x07, 

+	0xF0, 0xB6, 0xFC, 0x05, 0x98, 0x60, 0x21, 0x08, 0x43, 0x7A, 0x49, 0x22, 0x01, 0x51, 0x18, 0xC8, 

+	0x73, 0x01, 0x20, 0x04, 0x90, 0x57, 0xE0, 0x0D, 0x99, 0x07, 0x98, 0x88, 0x42, 0x18, 0xD2, 0x75, 

+	0x48, 0x22, 0x01, 0x10, 0x18, 

+	0x00, 0x00, 0xD1, 0x00, 0x80, 0x08, 0x99, 0x04, 0x90, 0x09, 0x1D, 0x00, 0x1D, 0x10, 0x22, 0x07, 

+	0xF0, 0x9E, 0xFC, 0x05, 0x99, 0x40, 0x20, 0x01, 0x43, 0x04, 0x98, 0xC1, 0x73, 0x01, 0x20, 0x04, 

+	0x90, 0x6B, 0x49, 0x09, 0x98, 0xC9, 0x88, 0x08, 0x42, 0x02, 0xD0, 0x0A, 0x98, 0x01, 0xE0, 0x46, 

+	0xE0, 0x0B, 0x98, 0x07, 0x99, 0x88, 0x42, 0x16, 0xD8, 0x66, 0x48, 0x22, 0x01, 0x10, 0x18, 0x08, 

+	0x99, 0x04, 0x90, 0x09, 0x1D, 0x00, 0x1D, 0x10, 0x22, 0x07, 0xF0, 0x81, 0xFC, 0x05, 0x99, 0x40, 

+	0x20, 0x01, 0x43, 0x04, 0x98, 0xC1, 0x73, 0x5E, 0x48, 0x09, 0x99, 0xC2, 0x88, 0x11, 0x43, 0xC1, 

+	0x80, 0x01, 0x20, 0x04, 0x90, 0x0F, 0xE0, 0xBC, 0x42, 0x08, 0xD0, 0x5A, 0x48, 0x22, 0x01, 0x06, 

+	0x99, 0x10, 0x18, 0x09, 0x1D, 0x00, 0x1D, 0x10, 0x22, 0x07, 0xF0, 0x69, 0xFC, 0x55, 0x49, 0x22, 

+	0x01, 0x51, 0x18, 0x05, 0x98, 

+	0x00, 0x00, 0xD2, 0x00, 0x80, 0xC8, 0x73, 0x54, 0x48, 0x07, 0x99, 0x81, 0x42, 0x00, 0xD8, 0x08, 

+	0x46, 0x50, 0x49, 0x62, 0x00, 0xC6, 0x31, 0x88, 0x52, 0x4E, 0x48, 0x21, 0x01, 0x08, 0x18, 0xC1, 

+	0x7B, 0x80, 0x22, 0x11, 0x43, 0xC1, 0x73, 0x64, 0x1C, 0x7F, 0x1C, 0x4C, 0x4A, 0x50, 0x7E, 0x0A, 

+	0x28, 0x01, 0xD2, 0xC0, 0xB2, 0x00, 0xE0, 0x0A, 0x20, 0xB8, 0x42, 0x00, 0xD9, 0x38, 0xE7, 0x00, 

+	0x27, 0x36, 0xE0, 0xF0, 0x07, 0x32, 0xD0, 0x68, 0x46, 0xC0, 0x5D, 0x05, 0x90, 0x3E, 0x48, 0xC0, 

+	0x79, 0xC0, 0x07, 0x0C, 0xD0, 0x05, 0x98, 0x00, 0x01, 0x40, 0x19, 0x83, 0x7A, 0x02, 0x89, 0xC1, 

+	0x88, 0x38, 0x46, 0xFF, 0xF7, 0x94, 0xFE, 0x0C, 0x90, 0x00, 0x28, 0x02, 0xD0, 0x1E, 0xE0, 0x0C, 

+	0x98, 0xFA, 0xE7, 0x05, 0x98, 0x22, 0x01, 0x00, 0x01, 0x41, 0x19, 0x36, 0x48, 0x09, 0x1D, 0x10, 

+	0x18, 0x04, 0x90, 0x00, 0x1D, 

+	0x00, 0x00, 0xD3, 0x00, 0x80, 0x10, 0x22, 0x07, 0xF0, 0x22, 0xFC, 0x39, 0x46, 0xA0, 0x20, 0x01, 

+	0x43, 0x04, 0x98, 0xC1, 0x73, 0x2E, 0x48, 0x01, 0x21, 0xC2, 0x88, 0xB9, 0x40, 0x8A, 0x43, 0xC2, 

+	0x80, 0x12, 0x98, 0x64, 0x1C, 0x40, 0x1E, 0x12, 0x90, 0x01, 0x20, 0x04, 0x90, 0x7F, 0x1C, 0x76, 

+	0x08, 0x00, 0x2E, 0x0B, 0xD0, 0x29, 0x48, 0x41, 0x7E, 0x0A, 0x29, 0x01, 0xD2, 0xC8, 0xB2, 0x00, 

+	0xE0, 0x0A, 0x20, 0xA0, 0x42, 0x02, 0xD9, 0x12, 0x98, 0x00, 0x28, 0xBA, 0xD1, 0x21, 0x48, 0x84, 

+	0x70, 0xA8, 0x78, 0x01, 0x28, 0x1E, 0xD1, 0x1F, 0x49, 0xE8, 0x88, 0xDC, 0x31, 0x4F, 0x88, 0x2A, 

+	0x89, 0x8E, 0x88, 0xC0, 0x1B, 0x91, 0x1B, 0x40, 0x43, 0x49, 0x43, 0x41, 0x18, 0x16, 0x48, 0x80, 

+	0x78, 0x40, 0x43, 0x88, 0x42, 0x05, 0xD9, 0x16, 0x48, 0x40, 0x78, 0x00, 0x28, 0x01, 0xD0, 0x01, 

+	0x2C, 0x10, 0xD0, 0x13, 0x48, 

+	0x00, 0x00, 0xD4, 0x00, 0x80, 0x81, 0x78, 0x00, 0x29, 0x5B, 0xD0, 0x00, 0x21, 0x41, 0x70, 0x10, 

+	0x49, 0x01, 0x20, 0x88, 0x70, 0x11, 0x49, 0x0F, 0x4A, 0x1F, 0x23, 0x48, 0x7E, 0x0A, 0x28, 0x5F, 

+	0xD2, 0xC0, 0xB2, 0x5E, 0xE0, 0x04, 0x98, 0x00, 0x28, 0xF1, 0xD0, 0x0A, 0x48, 0x10, 0x22, 0xC1, 

+	0x7B, 0x05, 0x91, 0x01, 0x46, 0xDC, 0x31, 0x00, 0x1D, 0x07, 0xF0, 0xC9, 0xFB, 0x68, 0x7C, 0x00, 

+	0x28, 0x18, 0xD0, 0x06, 0x49, 0x0A, 0x7B, 0x0B, 0xE0, 0xE8, 0xF7, 0x00, 0x00, 0xA0, 0x00, 0x00, 

+	0x20, 0x1C, 0x02, 0x00, 0x20, 0x28, 0x12, 0x00, 0x20, 0xFF, 0xFF, 0x00, 0x00, 0x84, 0xF4, 0x00, 

+	0x00, 0x92, 0x1E, 0x82, 0x42, 0x06, 0xDB, 0xA8, 0x7C, 0x00, 0x28, 0x03, 0xD0, 0x49, 0x7B, 0x89, 

+	0x1E, 0x81, 0x42, 0x0F, 0xDA, 0xE8, 0x88, 0xF9, 0x00, 0xC9, 0x1B, 0x40, 0x18, 0x40, 0x03, 0x01, 

+	0x0C, 0x6D, 0x48, 0xF2, 0x00, 

+	0x00, 0x00, 0xD5, 0x00, 0x80, 0xC1, 0x80, 0x29, 0x89, 0x92, 0x1B, 0x89, 0x18, 0x49, 0x03, 0x09, 

+	0x0C, 0x01, 0x81, 0x12, 0xE0, 0xE8, 0x88, 0x41, 0x00, 0x40, 0x18, 0xB9, 0x00, 0x79, 0x18, 0x40, 

+	0x18, 0x40, 0x03, 0x65, 0x49, 0x00, 0x0C, 0xC8, 0x80, 0x28, 0x89, 0x42, 0x00, 0x80, 0x18, 0xB2, 

+	0x00, 0xB2, 0x18, 0x80, 0x18, 0x40, 0x03, 0x00, 0x0C, 0x08, 0x81, 0x5F, 0x48, 0x05, 0x99, 0xC1, 

+	0x73, 0xA5, 0xE7, 0x01, 0x21, 0x41, 0x70, 0x5C, 0x49, 0x10, 0x22, 0x09, 0x1D, 0x08, 0x46, 0xD8, 

+	0x30, 0x07, 0xF0, 0x7D, 0xFB, 0x9B, 0xE7, 0x20, 0x01, 0x80, 0x18, 0xC3, 0x73, 0x64, 0x1C, 0x9C, 

+	0xE7, 0x0A, 0x20, 0xA0, 0x42, 0xF7, 0xD8, 0x04, 0x98, 0x00, 0x28, 0x03, 0xD0, 0x10, 0x88, 0x01, 

+	0x21, 0x08, 0x43, 0x10, 0x80, 0x50, 0x4A, 0x02, 0x24, 0x10, 0x88, 0xA0, 0x43, 0x10, 0x80, 0x29, 

+	0x78, 0x89, 0x07, 0x16, 0xD5, 

+	0x00, 0x00, 0xD6, 0x00, 0x80, 0x13, 0x46, 0x29, 0x46, 0xA0, 0x33, 0xA0, 0x31, 0x9E, 0x8A, 0x8F, 

+	0x8A, 0xBE, 0x42, 0x0E, 0xD0, 0x20, 0x43, 0x10, 0x80, 0x88, 0x8A, 0x98, 0x82, 0x00, 0x20, 0x41, 

+	0x00, 0x4B, 0x19, 0xA0, 0x33, 0x89, 0x18, 0xA0, 0x31, 0xDB, 0x8A, 0x40, 0x1C, 0xCB, 0x82, 0x04, 

+	0x28, 0xF5, 0xD3, 0x10, 0x88, 0x10, 0x21, 0x88, 0x43, 0x10, 0x80, 0x28, 0x88, 0xC3, 0x06, 0x23, 

+	0xD5, 0x3E, 0x4B, 0x1B, 0x7A, 0x9B, 0x07, 0x06, 0xD5, 0xC0, 0x07, 0x04, 0xD0, 0xA8, 0x78, 0x00, 

+	0x28, 0x01, 0xD0, 0x00, 0x20, 0xE8, 0x70, 0x3A, 0x48, 0x00, 0x7F, 0xC0, 0x43, 0x03, 0x07, 0xDB, 

+	0x17, 0x5B, 0x1C, 0x11, 0xD0, 0xD3, 0x78, 0xEC, 0x78, 0xA3, 0x42, 0x02, 0xD0, 0x13, 0x88, 0x0B, 

+	0x43, 0x13, 0x80, 0xC0, 0x06, 0x80, 0x0F, 0x05, 0xD1, 0xE8, 0x78, 0x00, 0x28, 0x02, 0xD0, 0x10, 

+	0x88, 0x08, 0x43, 0x10, 0x80, 

+	0x00, 0x00, 0xD7, 0x00, 0x80, 0xE8, 0x78, 0xD0, 0x70, 0x13, 0xB0, 0xF0, 0xBD, 0xF8, 0xB5, 0x2C, 

+	0x4A, 0x05, 0x46, 0x81, 0x78, 0x90, 0x7E, 0x00, 0x24, 0x0A, 0x28, 0x01, 0xD2, 0xC0, 0xB2, 0x00, 

+	0xE0, 0x0A, 0x20, 0x88, 0x42, 0x05, 0xD2, 0x90, 0x7E, 0x0A, 0x28, 0x01, 0xD2, 0xC1, 0xB2, 0x00, 

+	0xE0, 0x0A, 0x21, 0x28, 0x46, 0xFF, 0xF7, 0xBB, 0xFD, 0xA8, 0x78, 0x00, 0x26, 0x01, 0x22, 0x21, 

+	0x4D, 0x00, 0x28, 0x06, 0xD0, 0xAA, 0x70, 0x1C, 0x49, 0x0B, 0x88, 0xD8, 0x07, 0x03, 0xD0, 0x2A, 

+	0x70, 0x16, 0xE0, 0xAE, 0x70, 0xF7, 0xE7, 0x28, 0x78, 0x00, 0x28, 0x11, 0xD0, 0x88, 0x78, 0x07, 

+	0xE0, 0x07, 0x01, 0x7F, 0x18, 0xFF, 0x7B, 0x7F, 0x06, 0xBF, 0x0F, 0x03, 0x2F, 0x00, 0xD0, 0x01, 

+	0x24, 0x40, 0x1E, 0xF5, 0xD2, 0x00, 0x2C, 0x03, 0xD1, 0x13, 0x43, 0x0B, 0x80, 0x8E, 0x70, 0x2E, 

+	0x70, 0x0D, 0x48, 0xF8, 0xBD, 

+	0x00, 0x00, 0xD8, 0x00, 0x80, 0x70, 0xB5, 0x06, 0x46, 0x04, 0x46, 0xC0, 0x36, 0x30, 0x88, 0x0A, 

+	0x4D, 0x00, 0x28, 0x0D, 0xD0, 0xA0, 0x78, 0xA8, 0x70, 0x02, 0x01, 0x21, 0x1D, 0x28, 0x1D, 0x07, 

+	0xF0, 0xD6, 0xFA, 0x20, 0x88, 0x28, 0x80, 0x28, 0x46, 0x31, 0x88, 0xC0, 0x30, 0x01, 0x80, 0x01, 

+	0xE0, 0x00, 0x20, 0x28, 0x80, 0x00, 0x48, 0x70, 0xBD, 0x28, 0x12, 0x00, 0x20, 0xE8, 0xF7, 0x00, 

+	0x00, 0x84, 0xF4, 0x00, 0x00, 0x1C, 0x02, 0x00, 0x20, 0x10, 0xB5, 0x24, 0x22, 0xFD, 0x49, 0xFE, 

+	0x48, 0xFA, 0xF7, 0xBC, 0xFE, 0x10, 0xBD, 0x30, 0xB5, 0xFB, 0x4D, 0x40, 0x30, 0x84, 0x7A, 0xFB, 

+	0x49, 0x2B, 0x68, 0xAA, 0x68, 0x00, 0x2C, 0x03, 0xD0, 0xA3, 0x40, 0xA2, 0x40, 0x0B, 0x61, 0x06, 

+	0xE0, 0x40, 0x7A, 0x01, 0x28, 0x02, 0xD9, 0x68, 0x68, 0x08, 0x61, 0x00, 0xE0, 0x0B, 0x61, 0x4A, 

+	0x61, 0xE8, 0x68, 0x88, 0x61, 

+	0x00, 0x00, 0xD9, 0x00, 0x80, 0x30, 0xBD, 0x01, 0x21, 0xF0, 0x4A, 0x20, 0x28, 0x05, 0xD3, 0x20, 

+	0x38, 0x81, 0x40, 0x50, 0x89, 0x01, 0x43, 0x51, 0x81, 0x70, 0x47, 0x10, 0x28, 0x05, 0xD3, 0x10, 

+	0x38, 0x81, 0x40, 0xD0, 0x88, 0x01, 0x43, 0xD1, 0x80, 0x70, 0x47, 0x81, 0x40, 0x50, 0x88, 0x01, 

+	0x43, 0x51, 0x80, 0x70, 0x47, 0x01, 0x22, 0xE5, 0x49, 0x20, 0x28, 0x05, 0xD3, 0x20, 0x38, 0x82, 

+	0x40, 0x48, 0x89, 0x90, 0x43, 0x48, 0x81, 0x70, 0x47, 0x10, 0x28, 0x05, 0xD3, 0x10, 0x38, 0x82, 

+	0x40, 0xC8, 0x88, 0x90, 0x43, 0xC8, 0x80, 0x70, 0x47, 0x82, 0x40, 0x48, 0x88, 0x90, 0x43, 0x48, 

+	0x80, 0x70, 0x47, 0xF1, 0xB5, 0x00, 0x98, 0x86, 0x78, 0x07, 0x1D, 0x75, 0x1E, 0x13, 0xD4, 0x28, 

+	0x01, 0xC0, 0x19, 0xC0, 0x7A, 0x0F, 0x28, 0x0C, 0xD9, 0x6C, 0x1C, 0x07, 0xE0, 0x20, 0x01, 0xC1, 

+	0x19, 0x08, 0x46, 0x10, 0x38, 

+	0x00, 0x00, 0xDA, 0x00, 0x80, 0x10, 0x22, 0x07, 0xF0, 0x62, 0xFA, 0x64, 0x1C, 0xB4, 0x42, 0xF5, 

+	0xDB, 0x76, 0x1E, 0x6D, 0x1E, 0xEB, 0xD5, 0x00, 0x98, 0x86, 0x70, 0xF8, 0xBD, 0xCB, 0x49, 0x00, 

+	0x20, 0x88, 0x80, 0xC8, 0x81, 0x48, 0x80, 0x08, 0x81, 0xC8, 0x80, 0x88, 0x81, 0x48, 0x81, 0x08, 

+	0x70, 0xC7, 0x49, 0x08, 0x80, 0x70, 0x47, 0xF8, 0xB5, 0x04, 0x46, 0x12, 0x01, 0x13, 0x19, 0x0A, 

+	0x01, 0xC4, 0x49, 0xDE, 0x88, 0x51, 0x18, 0x4F, 0x88, 0xC3, 0x4D, 0xBA, 0x1B, 0xBE, 0x46, 0x1F, 

+	0x89, 0x8B, 0x88, 0x00, 0x93, 0xDB, 0x1B, 0x52, 0x43, 0x5B, 0x43, 0xC9, 0x7A, 0xD2, 0x18, 0xBC, 

+	0x46, 0x8B, 0x00, 0xEF, 0x58, 0xB9, 0x4D, 0x00, 0x20, 0xED, 0x69, 0xED, 0x1B, 0x77, 0x46, 0xF6, 

+	0x1B, 0xB6, 0x46, 0x00, 0x9E, 0x67, 0x46, 0xBF, 0x1B, 0xB4, 0x4E, 0x6D, 0x43, 0x36, 0x69, 0x1F, 

+	0x29, 0x29, 0xD8, 0xC0, 0x34, 

+	0x00, 0x00, 0xDB, 0x00, 0x80, 0xA4, 0x78, 0x01, 0x2C, 0x04, 0xD9, 0x6E, 0x43, 0x96, 0x42, 0x00, 

+	0xD2, 0x01, 0x20, 0xF8, 0xBD, 0x01, 0x24, 0xAD, 0x4D, 0x8C, 0x40, 0xE9, 0x89, 0x0C, 0x42, 0x1A, 

+	0xD0, 0xAD, 0x4C, 0x71, 0x46, 0x80, 0x3C, 0xE2, 0x5E, 0x1B, 0x19, 0x02, 0x24, 0x1C, 0x5F, 0x89, 

+	0x1A, 0x3B, 0x1B, 0x49, 0x43, 0x5B, 0x43, 0x6E, 0x69, 0x59, 0x18, 0xB1, 0x42, 0xE8, 0xD8, 0xAB, 

+	0x69, 0x00, 0x2B, 0xE6, 0xD0, 0x52, 0x43, 0x64, 0x43, 0xA2, 0x18, 0x9A, 0x42, 0xE1, 0xD2, 0xB2, 

+	0x08, 0x8A, 0x42, 0xDD, 0xD3, 0xF8, 0xBD, 0xB2, 0x42, 0xDA, 0xD8, 0xF8, 0xBD, 0xF8, 0xB5, 0x9B, 

+	0x4A, 0x84, 0x78, 0x12, 0x78, 0x94, 0x42, 0x01, 0xD3, 0x23, 0x46, 0x00, 0xE0, 0x13, 0x46, 0x9E, 

+	0x46, 0x94, 0x42, 0x00, 0xD2, 0x22, 0x46, 0x00, 0x92, 0x20, 0xE0, 0x00, 0x9A, 0x1C, 0xE0, 0x74, 

+	0x45, 0x05, 0xD1, 0x1D, 0x01, 

+	0x00, 0x00, 0xDC, 0x00, 0x80, 0x2F, 0x18, 0xBC, 0x46, 0xFE, 0x88, 0x17, 0x01, 0x04, 0xE0, 0x15, 

+	0x01, 0x2F, 0x18, 0xBC, 0x46, 0xFE, 0x88, 0x1F, 0x01, 0x8E, 0x4D, 0x7D, 0x19, 0x6F, 0x88, 0xAD, 

+	0x88, 0xBE, 0x1B, 0x67, 0x46, 0x3F, 0x89, 0x76, 0x43, 0xED, 0x1B, 0x6D, 0x43, 0x75, 0x19, 0x2C, 

+	0x26, 0x5E, 0x43, 0x76, 0x18, 0x97, 0x00, 0xF5, 0x51, 0x52, 0x1E, 0xE0, 0xD2, 0x5B, 0x1E, 0xDC, 

+	0xD2, 0xF8, 0xBD, 0x30, 0xB5, 0x83, 0x4D, 0x13, 0x01, 0x5A, 0x19, 0x09, 0x01, 0xD4, 0x7A, 0x09, 

+	0x18, 0xCC, 0x73, 0xE8, 0x5A, 0x40, 0x1C, 0x88, 0x80, 0x90, 0x7A, 0x43, 0x06, 0x0F, 0xD5, 0x83, 

+	0x06, 0x01, 0xD0, 0x40, 0x1E, 0x88, 0x73, 0xD2, 0x7A, 0x01, 0x20, 0x90, 0x40, 0x77, 0x4A, 0x53, 

+	0x88, 0x18, 0x42, 0x04, 0xD0, 0x92, 0x88, 0x10, 0x42, 0x01, 0xD0, 0x00, 0x20, 0x88, 0x73, 0x30, 

+	0xBD, 0xFF, 0xB5, 0x84, 0x46, 

+	0x00, 0x00, 0xDD, 0x00, 0x80, 0x0F, 0x46, 0x6F, 0x48, 0x13, 0x46, 0x20, 0x30, 0x71, 0x49, 0x00, 

+	0x7A, 0x3C, 0x01, 0x12, 0x01, 0x00, 0x26, 0x55, 0x18, 0x83, 0xB0, 0x64, 0x44, 0x00, 0x28, 0x01, 

+	0xD0, 0x28, 0x7B, 0x20, 0x74, 0xE8, 0x7A, 0xFF, 0xF7, 0x05, 0xFF, 0xE8, 0x7A, 0x0F, 0x28, 0x0A, 

+	0xD8, 0xFF, 0xF7, 0xE9, 0xFE, 0x1A, 0x46, 0x39, 0x46, 0x60, 0x46, 0xFF, 0xF7, 0xC2, 0xFF, 0x00, 

+	0x20, 0xA0, 0x73, 0xEF, 0x7A, 0x4C, 0xE0, 0x1F, 0x28, 0x18, 0xD8, 0xA9, 0x7A, 0x0A, 0x06, 0x11, 

+	0xD5, 0x3F, 0x22, 0x89, 0x06, 0x92, 0x06, 0x89, 0x18, 0x0C, 0xD0, 0x07, 0x46, 0xFF, 0xF7, 0xD3, 

+	0xFE, 0xE8, 0x7A, 0xE0, 0x73, 0xA8, 0x7A, 0x40, 0x1E, 0xA0, 0x73, 0x00, 0x20, 0xA0, 0x80, 0xFF, 

+	0x2F, 0x04, 0xD0, 0x35, 0xE0, 0x00, 0x20, 0xA0, 0x80, 0xA0, 0x73, 0x01, 0x26, 0x52, 0x48, 0x20, 

+	0x30, 0x80, 0x78, 0x00, 0x28, 

+	0x00, 0x00, 0xDE, 0x00, 0x80, 0x1D, 0xD0, 0xEF, 0x7A, 0x20, 0x2F, 0x07, 0xD2, 0x4F, 0x49, 0x88, 

+	0x89, 0x49, 0x89, 0x08, 0x43, 0x20, 0x21, 0x00, 0xF0, 0x3F, 0xFA, 0x07, 0x46, 0x4B, 0x49, 0x00, 

+	0x20, 0x8A, 0x88, 0x49, 0x88, 0x0A, 0x43, 0x00, 0xD1, 0x01, 0x20, 0x22, 0x89, 0xE1, 0x88, 0x0C, 

+	0x9B, 0x01, 0x96, 0x00, 0x93, 0x02, 0x90, 0x38, 0x46, 0x06, 0x9B, 0x00, 0xF0, 0x2F, 0xFB, 0x00, 

+	0x28, 0x07, 0xD1, 0x42, 0x49, 0x88, 0x88, 0x49, 0x88, 0x08, 0x43, 0x00, 0x21, 0x00, 0xF0, 0x24, 

+	0xFA, 0x07, 0x46, 0x38, 0x46, 0xFF, 0xF7, 0x97, 0xFE, 0xE7, 0x73, 0x00, 0x20, 0xA0, 0x80, 0xA0, 

+	0x73, 0x1F, 0x2F, 0x0F, 0xD8, 0x39, 0x48, 0x3C, 0x4A, 0xC1, 0x69, 0xB8, 0x00, 0x11, 0x50, 0xE1, 

+	0x88, 0x6A, 0x88, 0x8A, 0x1A, 0x38, 0x49, 0x80, 0x39, 0x0A, 0x52, 0x22, 0x89, 0xAB, 0x88, 0xD2, 

+	0x1A, 0x40, 0x18, 0x42, 0x80, 

+	0x00, 0x00, 0xDF, 0x00, 0x80, 0x07, 0xB0, 0xF0, 0xBD, 0xFF, 0xB5, 0x09, 0x01, 0x0C, 0x18, 0xA0, 

+	0x7B, 0x00, 0x27, 0x80, 0x06, 0x83, 0xB0, 0x80, 0x0E, 0x2C, 0x4E, 0xA7, 0x80, 0x00, 0x28, 0x07, 

+	0xD0, 0x80, 0x21, 0x08, 0x43, 0xA0, 0x73, 0x30, 0x89, 0xF1, 0x88, 0x08, 0x43, 0x10, 0x21, 0x23, 

+	0xE0, 0x25, 0x48, 0x20, 0x30, 0x80, 0x78, 0x00, 0x28, 0x1A, 0xD0, 0xB0, 0x89, 0x71, 0x89, 0x08,